diff --git a/.github/workflows/code_analysis.yml b/.github/workflows/code_analysis.yml index b4882e778d..8c5d325b11 100644 --- a/.github/workflows/code_analysis.yml +++ b/.github/workflows/code_analysis.yml @@ -20,6 +20,10 @@ on: schedule: - cron: '25 18 * * 2' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: analyze: name: Analyze @@ -38,11 +42,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -53,7 +57,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -67,4 +71,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/pytest-auth.yml b/.github/workflows/pytest-auth.yml index 6bbd6b0795..feaeca61bf 100644 --- a/.github/workflows/pytest-auth.yml +++ b/.github/workflows/pytest-auth.yml @@ -14,7 +14,21 @@ name: Testing platform auth # Determine what events are going to trigger a running of the workflow -on: [pull_request] +on: + workflow_dispatch: + push: + branches: + - develop + - releases/** + pull_request: + branches: + - main + - develop + - releases/** + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: # The job named build @@ -36,17 +50,17 @@ jobs: # Each step will be run in order of listing. steps: # checkout the volttron repository and set current direectory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # setup the python environment for the operating system - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} @@ -55,20 +69,20 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report path: output/test-auth-${{matrix.os}}-${{ matrix.python-version }}-results.xml - + # - name: Publish Unit Test Results # uses: EnricoMi/publish-unit-test-result-action@v1.5 # if: always() # with: # github_token: ${{ secrets.WORKFLOW_ACCESS_TOKEN }} # files: output/test-testutils*.xml - - + + #-cov=com --cov-report=xml --cov-report=html # pytest tests.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html # - name: Lint with flake8 diff --git a/.github/workflows/pytest-dbutils-backup_db.yml b/.github/workflows/pytest-dbutils-backup_db.yml index 5094808140..bc677c6b8d 100644 --- a/.github/workflows/pytest-dbutils-backup_db.yml +++ b/.github/workflows/pytest-dbutils-backup_db.yml @@ -15,15 +15,20 @@ name: Testing BackupDatabase # Determine what events are going to trigger a running of the workflow on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** + - main + - develop + - releases/** + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: @@ -46,11 +51,11 @@ jobs: steps: # checkout the volttron repository and set current directory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # setup the python environment for the operating system - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -60,7 +65,7 @@ jobs: # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 timeout-minutes: 600 with: python_version: ${{ matrix.python-version }} @@ -70,7 +75,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-influxdbfuncts.yml b/.github/workflows/pytest-dbutils-influxdbfuncts.yml index 74b34d8386..47b335e9e8 100644 --- a/.github/workflows/pytest-dbutils-influxdbfuncts.yml +++ b/.github/workflows/pytest-dbutils-influxdbfuncts.yml @@ -7,15 +7,19 @@ name: Testing influxdbutils on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: @@ -35,12 +39,12 @@ jobs: steps: # checkout the volttron repository and set current directory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -50,7 +54,7 @@ jobs: # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 timeout-minutes: 600 with: python_version: ${{ matrix.python-version }} @@ -60,7 +64,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-mysqlfuncts.yml b/.github/workflows/pytest-dbutils-mysqlfuncts.yml index 3feab4f759..6454fa4a86 100644 --- a/.github/workflows/pytest-dbutils-mysqlfuncts.yml +++ b/.github/workflows/pytest-dbutils-mysqlfuncts.yml @@ -7,15 +7,19 @@ name: Testing mysqlfuncts on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: @@ -35,12 +39,12 @@ jobs: steps: # checkout the volttron repository and set current directory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -50,7 +54,7 @@ jobs: # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 timeout-minutes: 600 with: python_version: ${{ matrix.python-version }} @@ -60,7 +64,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-postgresqlfuncts.yml b/.github/workflows/pytest-dbutils-postgresqlfuncts.yml index 27d4e44e9a..87499a2384 100644 --- a/.github/workflows/pytest-dbutils-postgresqlfuncts.yml +++ b/.github/workflows/pytest-dbutils-postgresqlfuncts.yml @@ -7,15 +7,19 @@ name: Testing postgresqlfuncts on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: @@ -35,12 +39,12 @@ jobs: steps: # checkout the volttron repository and set current directory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -50,7 +54,7 @@ jobs: # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 timeout-minutes: 600 with: python_version: ${{ matrix.python-version }} @@ -60,7 +64,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-sqlitefuncts.yml b/.github/workflows/pytest-dbutils-sqlitefuncts.yml index 9849b05a1c..e5bb742d7d 100644 --- a/.github/workflows/pytest-dbutils-sqlitefuncts.yml +++ b/.github/workflows/pytest-dbutils-sqlitefuncts.yml @@ -7,16 +7,19 @@ name: Testing sqlitefuncts on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** - + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: env: @@ -35,12 +38,12 @@ jobs: steps: # checkout the volttron repository and set current directory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -51,7 +54,7 @@ jobs: # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 timeout-minutes: 600 with: python_version: ${{ matrix.python-version }} @@ -60,7 +63,7 @@ jobs: test_output_suffix: ${{ env.OUTPUT_SUFFIX }} - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-timescaldbfuncts.yml b/.github/workflows/pytest-dbutils-timescaldbfuncts.yml index fe0ed71700..7639d195c7 100644 --- a/.github/workflows/pytest-dbutils-timescaldbfuncts.yml +++ b/.github/workflows/pytest-dbutils-timescaldbfuncts.yml @@ -7,16 +7,19 @@ name: Testing postgresql_timescaledb_functs on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** - + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: env: @@ -35,12 +38,12 @@ jobs: steps: # checkout the volttron repository and set current directory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -50,7 +53,7 @@ jobs: # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 timeout-minutes: 600 with: python_version: ${{ matrix.python-version }} @@ -60,7 +63,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-miscellaneous-tests.yml b/.github/workflows/pytest-miscellaneous-tests.yml index 7fdf36ed5b..80dc6d8d27 100644 --- a/.github/workflows/pytest-miscellaneous-tests.yml +++ b/.github/workflows/pytest-miscellaneous-tests.yml @@ -14,16 +14,19 @@ name: Miscellaneous platform tests on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** - + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: # The job named build build: @@ -32,10 +35,10 @@ jobs: strategy: fail-fast: false matrix: - # Each entry in the os and python-version matrix will be run + # Each entry in the os and python-version matrix will be run os: [ ubuntu-20.04 ] python-version: [ 3.8 ] - + # Run-on determines the operating system available to run on # - At the current time there is only ubuntu machine 20.04 available # - This uses the matrix os from the strategy above @@ -44,25 +47,25 @@ jobs: # Each step will be run in order of listing. steps: # Checkout the volttron repository and set current direectory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Setup the python environment for the operating system - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} # Run the specified tests and save the results to a unique file that can be archived for later analysis - name: Run certs test on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} test_path: volttrontesting/platform/web/test_certs.py test_output_suffix: misc - + - name: Run core agent test on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} @@ -70,7 +73,7 @@ jobs: test_output_suffix: misc - name: Run packaging test on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} @@ -78,15 +81,15 @@ jobs: test_output_suffix: misc - name: Run platform init test on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} test_path: volttrontesting/platform/test_platform_init.py test_output_suffix: misc - + - name: Run sqlite3 test on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} @@ -95,7 +98,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-testutils.yml b/.github/workflows/pytest-testutils.yml index fc66ffc531..fa1a06887b 100644 --- a/.github/workflows/pytest-testutils.yml +++ b/.github/workflows/pytest-testutils.yml @@ -9,16 +9,19 @@ name: Testing testutils directory on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** - + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: # The strategy allows customization of the build and allows matrixing the version of os and software @@ -34,18 +37,18 @@ jobs: steps: # checkout the volttron repository and set current directory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} @@ -54,7 +57,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-vctl.yml b/.github/workflows/pytest-vctl.yml index 22b2f165c1..b541753236 100644 --- a/.github/workflows/pytest-vctl.yml +++ b/.github/workflows/pytest-vctl.yml @@ -15,16 +15,19 @@ name: Testing volttron-ctl # Determine what events are going to trigger a running of the workflow on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** - + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: # The job named build build: @@ -45,18 +48,18 @@ jobs: # Each step will be run in order of listing. steps: # checkout the volttron repository and set current directory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} @@ -65,10 +68,9 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report # should match test-- ... path: output/test-control_tests-${{matrix.os}}-${{ matrix.python-version }}-results.xml - diff --git a/.github/workflows/pytest-web.yml b/.github/workflows/pytest-web.yml index 89045fe67a..fe0496f35a 100644 --- a/.github/workflows/pytest-web.yml +++ b/.github/workflows/pytest-web.yml @@ -14,16 +14,19 @@ name: Testing platform web on: + workflow_dispatch: push: branches: - develop - releases/** pull_request: branches: - - main - - develop - - releases/** - + - main + - develop + - releases/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: # The job named build build: @@ -44,17 +47,17 @@ jobs: # Each step will be run in order of listing. steps: # checkout the volttron repository and set current direectory to it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # setup the python environment for the operating system - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} # Run the specified tests and save the results to a unique file that can be archived for later analysis. - name: Run pytest on ${{ matrix.python-version }}, ${{ matrix.os }} - uses: volttron/volttron-build-action@v4 + uses: volttron/volttron-build-action@v6 with: python_version: ${{ matrix.python-version }} os: ${{ matrix.os }} @@ -63,20 +66,20 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report path: output/test-web-${{matrix.os}}-${{ matrix.python-version }}-results.xml - + # - name: Publish Unit Test Results # uses: EnricoMi/publish-unit-test-result-action@v1.5 # if: always() # with: # github_token: ${{ secrets.WORKFLOW_ACCESS_TOKEN }} # files: output/test-testutils*.xml - - + + #-cov=com --cov-report=xml --cov-report=html # pytest tests.py --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html # - name: Lint with flake8 diff --git a/.gitignore b/.gitignore index 728a25c41f..305e73e838 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ node_modules applications .cache .idea +.vscode/ /env/ /Agents/*/{build,dist}/ /Agents/*.egg @@ -38,3 +39,4 @@ rabbitmq-server.download.tar.xz /docs/source/volttron_api/ *ecobee_*.json .env* +dist/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..40ba57ee61 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,95 @@ +# This file is a template, and might need editing before it works on your project. +# You can copy and paste this template into a new `.gitlab-ci.yml` file. +# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. +# +# To contribute improvements to CI/CD templates, please follow the Development guide at: +# https://docs.gitlab.com/ee/development/cicd/templates.html +# This specific template is located at: +# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Bash.gitlab-ci.yml + +# See https://docs.gitlab.com/ee/ci/yaml/index.html for all available options + +# you can delete this line if you're not using Docker +# image: busybox:latest + +stages: + - build + - test + +.parallel-tests: + parallel: + matrix: + - TEST: + - services/core/ActuatorAgent/tests + - services/core/DataMover/tests/ + - services/core/DNP3OutstationAgent/tests + - services/core/OpenADRVenAgent/tests + - services/core/PlatformDriverAgent/tests + - services/core/SQLHistorian/tests + - services/core/VolttronCentral/tests + - services/core/VolttronCentralPlatform/tests + - services/core/WeatherDotGov/tests + - services/ops + - volttrontesting/gevent/yield_test.py + - volttrontesting/platform/auth_tests + - volttrontesting/platform/control_tests + - volttrontesting/platform/dbutils + - volttrontesting/platform/web + - volttrontesting/platform/test_basehistorian.py + - volttrontesting/platform/test_connection.py + - volttrontesting/platform/test_core_agent.py + - volttrontesting/platform/test_instance_setup.py + - volttrontesting/platform/test_keystore.py + - volttrontesting/platform/test_packaging.py + - volttrontesting/platform/test_platform_init.py + - volttrontesting/platform/test_platform_rmq.py + - volttrontesting/platform/test_platform_web.py + - volttrontesting/platform/test_rmq_platform_shutdown.py + - volttrontesting/platform/test_sqlite3_fix.py + - volttrontesting/services/historian + - volttrontesting/services/aggregate_historian + - volttrontesting/services/tagging + - volttrontesting/services/weather + - volttrontesting/services/test_pubsub_service.py + - volttrontesting/subsystems + - volttrontesting/testutils + - volttrontesting/zmq + +build 20.04: + stage: build + tags: + - ubuntu2004 + + before_script: + #- killall -9 volttron beam.smp python + - rm -rf dist ~/.volttron ~/.volttron_instances + - rm -rf /tmp/tmp* + - rm -rf ~/rabbitmq_server + + script: + - python3 bootstrap.py --all + - source env/bin/activate + - python3 bootstrap.py --rabbitmq + - echo "BUILD_DIR_20_04=`pwd`" >> build.env + - echo "$BUILD_DIR_20_04" + - echo `pwd` + + artifacts: + reports: + dotenv: build.env + +test 20.04: + stage: test + needs: [build 20.04] + variables: + GIT_CHECKOUT: "false" + tags: + - ubuntu2004 + extends: .parallel-tests + script: + - cd $BUILD_DIR_20_04 + - echo `pwd` + - source env/bin/activate + - pytest $TEST + + diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..4c033a1021 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: debug-statements + - id: requirements-txt-fixer diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c4456b33e0..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: python2.7 - -# Each array entry will execute 1 job. -env: - - NUM_PROCESSES=10 CI="travis" - -services: - - docker - -script: ci-integration/run-test-docker.sh - diff --git a/COPYRIGHT b/COPYRIGHT deleted file mode 100644 index e90bc43195..0000000000 --- a/COPYRIGHT +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022, Battelle Memorial Institute. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# diff --git a/DISCLAIMER b/DISCLAIMER new file mode 100644 index 0000000000..23106ccc96 --- /dev/null +++ b/DISCLAIMER @@ -0,0 +1,26 @@ +Disclaimer + +This material was prepared as an account of work sponsored by an agency +of the United States Government. Neither the United States Government +nor the United States Department of Energy, nor Battelle, nor any of +their employees, nor any jurisdiction or organization that has cooperated +in the development of these materials, makes any warranty, express or +implied, or assumes any legal liability or responsibility for the accuracy, +completeness, or usefulness or any information, apparatus, product, software, +or process disclosed, or represents that its use would not infringe privately +owned rights. + +Reference herein to any specific commercial product, process, or service by +trade name, trademark, manufacturer, or otherwise does not necessarily +constitute or imply its endorsement, recommendation, or favoring by the United +States Government or any agency thereof, or Battelle Memorial Institute. The +views and opinions of authors expressed herein do not necessarily state or +reflect those of the United States Government or any agency thereof. + + + PACIFIC NORTHWEST NATIONAL LABORATORY + operated by + BATTELLE + for the + UNITED STATES DEPARTMENT OF ENERGY + under Contract DE-AC05-76RL01830 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..8e86760c69 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ + +Copyright 2023, Battelle Memorial Institute. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy +of the License at + + + +The patent license grant shall only be applicable to the following patent +and patent application (Battelle IPID 17008-E), as assigned to the Battelle +Memorial Institute, as used in conjunction with this Work: +• US Patent No. 9,094,385, issued 7/28/15 • USPTO Patent App. No. 14/746,577, +filed 6/22/15, published as US 2016-0006569. + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 5eced6f461..0000000000 --- a/LICENSE.md +++ /dev/null @@ -1,11 +0,0 @@ - - -Copyright 2022, Battelle Memorial Institute. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -The patent license grant shall only be applicable to the following patent and patent application (Battelle IPID 17008-E), as assigned to the Battelle Memorial Institute, as used in conjunction with this Work: • US Patent No. 9,094,385, issued 7/28/15 • USPTO Patent App. No. 14/746,577, filed 6/22/15, published as US 2016-0006569. - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/README.md b/README.md index 7f888a3744..bea8985a36 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,23 @@ ![image](docs/source/files/VOLLTRON_Logo_Black_Horizontal_with_Tagline.png) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/fcf58045b4804edf8f4d3ecde3016f76)](https://app.codacy.com/gh/VOLTTRON/volttron?utm_source=github.com&utm_medium=referral&utm_content=VOLTTRON/volttron&utm_campaign=Badge_Grade_Settings) +# VOLTTRON + +This repository is for the current production VOLTTRON. We are working on VOLTTRON 10 (modular) which is available under +github at https://github.com/eclipse-volttron/. The modular version of VOLTTRON will help ease deployment and support +flexible deployment where in only required agents/applications can be installed, thereby simplifying setup and upgrade +steps for the end user. The VOLTTRON team are currently working on porting agents from monolithic VOLTTRON to the +modular version of VOLTTRON. To know more about modular VOLTTRON, please visit our new documentation site available +at https://eclipse-volttron.readthedocs.io/en/latest/. We would love for you to try it out and give us early +feedback. Also, until our work on modular VOLTTRON is completed, please continue cloning and using this +repository for your production systems. VOLTTRON™ is an open source platform for distributed sensing and control. The platform provides services for collecting and storing data from buildings and devices and provides an environment for developing applications which interact with that data. -## Upgrading to VOLTTRON 8.x +## Upgrading Pre-8 to VOLTTRON 9.x VOLTTRON 8 introduces four changes that require an explict upgrade step when upgrading from an earlier VOLTTRON version @@ -113,36 +123,42 @@ You can deactivate the environment at any time by running `deactivate`. #### Steps for RabbitMQ -##### 1. Install Erlang version 24 packages - -For RabbitMQ based VOLTTRON, some RabbitMQ specific software packages must be installed. - -###### On Debian based systems and CentOS 6/7 +##### 1. Install Erlang version 25 packages -If you are running an Debian or CentOS system, you can install the RabbitMQ dependencies by running the rabbit - dependencies script, passing in the OS name and appropriate distribution as parameters. The following are supported: - -- `debian focal` (for Ubuntu 20.04) +###### Install Erlang pre-requisites +```shell +sudo apt-get update +sudo apt-get install -y gnupg apt-transport-https libsctp1 libncurses5 +``` +Please note there could be other pre-requisites that erlang requires based on the version of Erlang and OS. If there are other pre-requisites required, +install of erlang should fail with appropriate error message. -- `debian bionic` (for Ubuntu 18.04) +###### Purge previous versions of Erlang +```shell +sudo apt-get purge -yf erlang-base +``` -- `debian stretch` (for Debian Stretch) +###### Install Erlang -- `debian buster` (for Debian Buster) +Download and install ErlangOTP from [Erlang Solutions](https://www.erlang-solutions.com/downloads/). +RMQ uses components - ssl, public_key, asn1, and crypto. These are by default included in the OTP +RabbitMQ 3.9.29 is compatible with Erlang versions 24.3.4.2 to 25.2. VOLTTRON was tested with Erlang version 25.2-1 -- `raspbian buster` (for Raspbian/Raspberry Pi OS buster) +Example: -Example command: +On Ubuntu 22.04: -```sh -./scripts/rabbit_dependencies.sh debian xenial +```shell +wget https://binaries2.erlang-solutions.com/ubuntu/pool/contrib/e/esl-erlang/esl-erlang_25.2-1~ubuntu~jammy_amd64.deb +sudo dpkg -i esl-erlang_25.2-1~ubuntu~jammy_amd64.deb ``` -###### Alternatively +On Ubuntu 20.04: +```shell +wget https://binaries2.erlang-solutions.com/ubuntu/pool/contrib/e/esl-erlang/esl-erlang_25.2-1~ubuntu~focal_amd64.deb +sudo dpkg -i esl-erlang_25.2-1~ubuntu~focal_amd64.deb +``` -You can download and install Erlang from [Erlang Solutions](https://www.erlang-solutions.com/resources/download.html). -Please include OTP/components - ssl, public_key, asn1, and crypto. -Also lock your version of Erlang using the [yum-plugin-versionlock](https://access.redhat.com/solutions/98873) ##### 2. Configure hostname @@ -155,9 +171,14 @@ connect to empd (port 4369) on ." Note: RabbitMQ startup error would s and not in RabbitMQ logs (/var/log/rabbitmq/rabbitmq@hostname.log) ##### 3. Bootstrap +Remove older version of rabbitmq_server directory if you are upgrading from a older version. +Defaults to /rabbitmq_server/rabbitmq_server-3.9.7 + +Run the rabbitmq boostrap command within an activated VOLTTRON environment ```sh cd volttron +source env/bin/activate python3 bootstrap.py --rabbitmq [optional install directory. defaults to /rabbitmq_server] ``` @@ -175,7 +196,7 @@ it needs to be set to the RabbitMQ installation directory (default path is `/rabbitmq_server/rabbitmq_server-`) ```sh -echo 'export RABBITMQ_HOME=$HOME/rabbitmq_server/rabbitmq_server-3.9.7'|sudo tee --append ~/.bashrc +echo 'export RABBITMQ_HOME=$HOME/rabbitmq_server/rabbitmq_server-3.9.29'|sudo tee --append ~/.bashrc source ~/.bashrc $RABBITMQ_HOME/sbin/rabbitmqctl status @@ -232,7 +253,7 @@ Your VOLTTRON_HOME currently set to: /home/vdev/new_vhome2 Is this the volttron you are attempting to setup? [Y]: Creating rmq config yml -RabbitMQ server home: [/home/vdev/rabbitmq_server/rabbitmq_server-3.9.7]: +RabbitMQ server home: [/home/vdev/rabbitmq_server/rabbitmq_server-3.9.29]: Fully qualified domain name of the system: [cs_cbox.pnl.gov]: Enable SSL Authentication: [Y]: @@ -252,7 +273,7 @@ AMQPS (SSL) port RabbitMQ address: [5671]: https port for the RabbitMQ management plugin: [15671]: INFO:rmq_setup.pyc:Starting rabbitmq server Warning: PID file not written; -detached was passed. -INFO:rmq_setup.pyc:**Started rmq server at /home/vdev/rabbitmq_server/rabbitmq_server-3.9.7 +INFO:rmq_setup.pyc:**Started rmq server at /home/vdev/rabbitmq_server/rabbitmq_server-3.9.29 INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost @@ -266,7 +287,7 @@ INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost INFO:rmq_setup.pyc:**Stopped rmq server Warning: PID file not written; -detached was passed. -INFO:rmq_setup.pyc:**Started rmq server at /home/vdev/rabbitmq_server/rabbitmq_server-3.9.7 +INFO:rmq_setup.pyc:**Started rmq server at /home/vdev/rabbitmq_server/rabbitmq_server-3.9.29 INFO:rmq_setup.pyc: ####################### diff --git a/bootstrap.py b/bootstrap.py index 7e66288328..8121b03c4c 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """bootstrap - Prepare a VOLTTRON virtual environment. @@ -86,7 +72,7 @@ _WINDOWS = sys.platform.startswith('win') default_rmq_dir = os.path.join(os.path.expanduser("~"), "rabbitmq_server") -rmq_version = "3.9.7" +rmq_version = "3.9.29" rabbitmq_server = f"rabbitmq_server-{rmq_version}" @@ -137,7 +123,7 @@ def update(operation, verbose=None, offline=False, optional_requirements=[], rab # option_requirements contains wheel as first entry # Build option_requirements separately to pass install options - build_option = '--build-option' if wheeling else '--install-option' + build_option = '--build-option' if wheeling else '--config-settings' for requirement, options in option_requirements: args = [] @@ -241,8 +227,8 @@ def main(argv=sys.argv): sys.exit(77) # Python3 for life! - if sys.version_info.major < 3 or sys.version_info.minor < 6: - sys.stderr.write('error: Python >= 3.6 is required\n') + if sys.version_info.major < 3 or sys.version_info.minor < 8: + sys.stderr.write('error: Python >= 3.8 is required\n') sys.exit(1) # Build the parser diff --git a/ci-integration/run-tests.sh b/ci-integration/run-tests.sh index 9266b0b883..e0ede38058 100755 --- a/ci-integration/run-tests.sh +++ b/ci-integration/run-tests.sh @@ -46,12 +46,12 @@ echo "bootstrapping RABBITMQ" python bootstrap.py --rabbitmq --market echo "rabbitmq status" -"$HOME/rabbitmq_server/rabbitmq_server-3.9.7/sbin/rabbitmqctl" status +"$HOME/rabbitmq_server/rabbitmq_server-3.9.29/sbin/rabbitmqctl" status echo "TestDirs" for dir in $testdirs; do echo "*********TESTDIR: $dir" - py.test -s -v "$dir" + pytest -s -v "$dir" tmp_code=$? exit_code=$tmp_code @@ -79,7 +79,7 @@ for dir in $splitdirs; do if [ -d "${D}" ]; then echo "*********SPLITDIR: $D" - py.test -s -v "${D}" + pytest -s -v "${D}" tmp_code=$? if [ $tmp_code -ne 0 ]; then if [ $tmp_code -ne 5 ]; then @@ -100,7 +100,7 @@ for dir in $filedirs; do for testfile in "$dir"/*.py; do echo "Using testfile: $testfile" if [ "$testfile" != "volttrontesting/platform/packaging-tests.py" ]; then - py.test -s -v "$testfile" + pytest -s -v "$testfile" tmp_code=$? exit_code=$tmp_code diff --git a/ci-integration/virtualization/Dockerfile b/ci-integration/virtualization/Dockerfile index 58346d044b..18af962aac 100644 --- a/ci-integration/virtualization/Dockerfile +++ b/ci-integration/virtualization/Dockerfile @@ -31,8 +31,8 @@ RUN chmod +x /startup/entrypoint.sh && \ USER $VOLTTRON_USER RUN mkdir $RMQ_ROOT RUN set -eux \ - && wget -P $VOLTTRON_USER_HOME https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.9.7/rabbitmq-server-generic-unix-3.9.7.tar.xz \ - && tar -xf $VOLTTRON_USER_HOME/rabbitmq-server-generic-unix-3.9.7.tar.xz --directory $RMQ_ROOT \ + && wget -P $VOLTTRON_USER_HOME https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.9.29/rabbitmq-server-generic-unix-3.9.29.tar.xz \ + && tar -xf $VOLTTRON_USER_HOME/rabbitmq-server-generic-unix-3.9.29.tar.xz --directory $RMQ_ROOT \ && $RMQ_HOME/sbin/rabbitmq-plugins enable rabbitmq_management rabbitmq_federation rabbitmq_federation_management rabbitmq_shovel rabbitmq_shovel_management rabbitmq_auth_mechanism_ssl rabbitmq_trust_store RUN python3 -m pip install gevent-pika --user ############################################ diff --git a/debugging_utils/peerlist-watcher.py b/debugging_utils/peerlist-watcher.py index 1170e50b76..715498590c 100644 --- a/debugging_utils/peerlist-watcher.py +++ b/debugging_utils/peerlist-watcher.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/deprecated/Ambient/ambient/agent.py b/deprecated/Ambient/ambient/agent.py index 1de617306e..e69b55c9e1 100644 --- a/deprecated/Ambient/ambient/agent.py +++ b/deprecated/Ambient/ambient/agent.py @@ -1,58 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright (c) 2017, Battelle Memorial Institute -# All rights reserved. +# Component of Eclipse VOLTTRON # -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: +# ===----------------------------------------------------------------------=== # -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. +# Copyright 2023 Battelle Memorial Institute # -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -# FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# The views and conclusions contained in the software and documentation are -# those of the authors and should not be interpreted as representing official, -# policies either expressed or implied, of the FreeBSD Project. +# http://www.apache.org/licenses/LICENSE-2.0 # - -# This material was prepared as an account of work sponsored by an -# agency of the United States Government. Neither the United States -# Government nor the United States Department of Energy, nor Battelle, -# nor any of their employees, nor any jurisdiction or organization -# that has cooperated in the development of these materials, makes -# any warranty, express or implied, or assumes any legal liability -# or responsibility for the accuracy, completeness, or usefulness or -# any information, apparatus, product, software, or process disclosed, -# or represents that its use would not infringe privately owned rights. -# -# Reference herein to any specific commercial product, process, or -# service by trade name, trademark, manufacturer, or otherwise does -# not necessarily constitute or imply its endorsement, recommendation, -# r favoring by the United States Government or any agency thereof, -# or Battelle Memorial Institute. The views and opinions of authors -# expressed herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY -# operated by BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 - +# ===----------------------------------------------------------------------=== # }}} __docformat__ = 'reStructuredText' diff --git a/deprecated/Ambient/setup.py b/deprecated/Ambient/setup.py index ba2057fae8..94d0434a01 100644 --- a/deprecated/Ambient/setup.py +++ b/deprecated/Ambient/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path @@ -73,4 +59,3 @@ ] } ) - diff --git a/deprecated/Ambient/tests/test_ambient_agent.py b/deprecated/Ambient/tests/test_ambient_agent.py index 6c7d56c448..64757dcef8 100644 --- a/deprecated/Ambient/tests/test_ambient_agent.py +++ b/deprecated/Ambient/tests/test_ambient_agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2017, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest @@ -347,5 +333,3 @@ def test_polling_locations_valid_config(volttron_instance, query_agent, config, if agent_uuid: volttron_instance.stop_agent(agent_uuid) volttron_instance.remove_agent(agent_uuid) - - diff --git a/deprecated/CrateHistorian/cratedb/historian.py b/deprecated/CrateHistorian/cratedb/historian.py index 2e57e8545f..b6368b2b50 100644 --- a/deprecated/CrateHistorian/cratedb/historian.py +++ b/deprecated/CrateHistorian/cratedb/historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -167,9 +153,9 @@ def configure(self, configuration): """ The expectation that configuration will have at least the following items - + .. code: python - + { "connection": { "params": { @@ -177,8 +163,8 @@ def configure(self, configuration): } } } - - :param configuration: + + :param configuration: """ connection = configuration.get("connection", {}) tables_def, table_names = self.parse_table_def(configuration.get("tables_def")) diff --git a/deprecated/CrateHistorian/setup.py b/deprecated/CrateHistorian/setup.py index b5b7604d05..ce3fdb17dd 100644 --- a/deprecated/CrateHistorian/setup.py +++ b/deprecated/CrateHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/deprecated/CrateHistorian/tests/test_crate_historian.py b/deprecated/CrateHistorian/tests/test_crate_historian.py index fd57b0b61a..47c2c20f57 100644 --- a/deprecated/CrateHistorian/tests/test_crate_historian.py +++ b/deprecated/CrateHistorian/tests/test_crate_historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/deprecated/Darksky/darksky/agent.py b/deprecated/Darksky/darksky/agent.py index 0342b9a841..647a22041f 100644 --- a/deprecated/Darksky/darksky/agent.py +++ b/deprecated/Darksky/darksky/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} __docformat__ = 'reStructuredText' @@ -525,7 +511,7 @@ def generate_response_error(self, url, response_code): def main(): """Main method called to start the agent.""" - utils.vip_main(darksky, + utils.vip_main(darksky, version=__version__) diff --git a/deprecated/Darksky/setup.py b/deprecated/Darksky/setup.py index e26f70ed6a..202a385e40 100644 --- a/deprecated/Darksky/setup.py +++ b/deprecated/Darksky/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/deprecated/Darksky/tests/test_darksky.py b/deprecated/Darksky/tests/test_darksky.py index a4a1b93b24..38c62cb95a 100644 --- a/deprecated/Darksky/tests/test_darksky.py +++ b/deprecated/Darksky/tests/test_darksky.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest @@ -365,11 +351,10 @@ def test_success_forecast(volttron_instance, cleanup_cache, weather, query_agent num_records = cursor.fetchone()[0] if service_name == service: assert num_records is records_amount * len(locations) + elif identity == 'platform.darksky_perf': + assert num_records is 0 else: - if identity == 'platform.darksky_perf': - assert num_records is 0 - else: - assert num_records is records_amount * len(locations) + assert num_records is records_amount * len(locations) assert len(query_data) == len(locations) diff --git a/deprecated/ExternalData/external_data/agent.py b/deprecated/ExternalData/external_data/agent.py index 0a2ba4fd41..52dbb9c599 100644 --- a/deprecated/ExternalData/external_data/agent.py +++ b/deprecated/ExternalData/external_data/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/deprecated/ExternalData/setup.py b/deprecated/ExternalData/setup.py index 693d687415..2bcb2c0b88 100644 --- a/deprecated/ExternalData/setup.py +++ b/deprecated/ExternalData/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/deprecated/FailoverAgent/failover/agent.py b/deprecated/FailoverAgent/failover/agent.py index a5d233baf4..f026abc1e9 100644 --- a/deprecated/FailoverAgent/failover/agent.py +++ b/deprecated/FailoverAgent/failover/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/deprecated/FailoverAgent/setup.py b/deprecated/FailoverAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/deprecated/FailoverAgent/setup.py +++ b/deprecated/FailoverAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/deprecated/MongodbAggregateHistorian/aggregator/aggregator.py b/deprecated/MongodbAggregateHistorian/aggregator/aggregator.py index 30f3417203..e0ee5f70e7 100644 --- a/deprecated/MongodbAggregateHistorian/aggregator/aggregator.py +++ b/deprecated/MongodbAggregateHistorian/aggregator/aggregator.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/deprecated/MongodbAggregateHistorian/setup.py b/deprecated/MongodbAggregateHistorian/setup.py index 83401c09f0..727121352e 100644 --- a/deprecated/MongodbAggregateHistorian/setup.py +++ b/deprecated/MongodbAggregateHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/deprecated/MongodbHistorian/mongodb/historian.py b/deprecated/MongodbHistorian/mongodb/historian.py index fbfc33f271..7c4a465af1 100644 --- a/deprecated/MongodbHistorian/mongodb/historian.py +++ b/deprecated/MongodbHistorian/mongodb/historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/deprecated/MongodbHistorian/scripts/count_data_by_topic_pattern.py b/deprecated/MongodbHistorian/scripts/count_data_by_topic_pattern.py index 872d39ac6b..6078fb22c2 100644 --- a/deprecated/MongodbHistorian/scripts/count_data_by_topic_pattern.py +++ b/deprecated/MongodbHistorian/scripts/count_data_by_topic_pattern.py @@ -21,5 +21,5 @@ count = count + db.data.find( {"topic_id":x['_id'], "ts":{"$gte":s_dt, "$lt":e_dt}}).count() -print (count) -print ("time taken: {}".format(datetime.datetime.now()-start)) \ No newline at end of file +print(count) +print("time taken: {}".format(datetime.datetime.now() - start)) diff --git a/deprecated/MongodbHistorian/scripts/rollup_data_by_time.py b/deprecated/MongodbHistorian/scripts/rollup_data_by_time.py index c351d4713d..52514f00e4 100644 --- a/deprecated/MongodbHistorian/scripts/rollup_data_by_time.py +++ b/deprecated/MongodbHistorian/scripts/rollup_data_by_time.py @@ -236,7 +236,7 @@ def execute_batch(table_type, bulk, count, topic_id, topic_name): "bulk execute of {} data for {}:{}.\nnumber of op sent to " "bulk execute ({}) does not match nModified count".format( table_type, topic_id, topic_name, count)) - print ("bulk execute result {}".format(result)) + print("bulk execute result {}".format(result)) errors = True except BulkWriteError as ex: print(str(ex.details)) @@ -338,7 +338,7 @@ def init_hourly_data(db, data_collection, start_dt, end_dt): if __name__ == '__main__': start = datetime.utcnow() - print ("Starting rollup of data from {} to {}. current time: {}".format( + print("Starting rollup of data from {} to {}. current time: {}".format( start_date, end_date, start)) pool = Pool(size=10) @@ -370,13 +370,13 @@ def init_hourly_data(db, data_collection, start_dt, end_dt): source_db = connect_mongodb(local_source_params) s_dt = datetime.strptime(start_date, '%d%b%YT%H:%M:%S.%f') e_dt = datetime.strptime(end_date, '%d%b%YT%H:%M:%S.%f') - print ("Starting init of tables") + print("Starting init of tables") init_start = datetime.utcnow() init_daily_data(source_db, source_tables['data_table'], s_dt, e_dt) - print ("Total time for init of daily data " + print("Total time for init of daily data " "between {} and {} : {} " "".format(start_date, end_date, datetime.utcnow() - init_start)) @@ -385,7 +385,7 @@ def init_hourly_data(db, data_collection, start_dt, end_dt): source_tables['data_table'], s_dt, e_dt) - print ("Total time for init of hourly data " + print("Total time for init of hourly data " "between {} and {} : {} " "".format(start_date, end_date, datetime.utcnow() - init_start)) @@ -419,7 +419,7 @@ def init_hourly_data(db, data_collection, start_dt, end_dt): print("Exception processing data: {}".format(e.args)) finally: pool.kill() - print ("Total time for roll up of data : {}".format( + print("Total time for roll up of data : {}".format( datetime.utcnow() - start)) if log: log.close() diff --git a/deprecated/MongodbHistorian/scripts/rollup_data_using_groupby.py b/deprecated/MongodbHistorian/scripts/rollup_data_using_groupby.py index b67b1f9c55..9f8d603f71 100644 --- a/deprecated/MongodbHistorian/scripts/rollup_data_using_groupby.py +++ b/deprecated/MongodbHistorian/scripts/rollup_data_using_groupby.py @@ -32,13 +32,13 @@ def connect_mongodb(connection_params): - print ("setup mongodb") + print("setup mongodb") mongo_conn_str = 'mongodb://{user}:{passwd}@{host}:{port}/{database}' if connection_params.get('authSource'): mongo_conn_str = mongo_conn_str+ '?authSource={authSource}' params = connection_params mongo_conn_str = mongo_conn_str.format(**params) - print (mongo_conn_str) + print(mongo_conn_str) mongo_client = pymongo.MongoClient(mongo_conn_str) db = mongo_client[connection_params['database']] return db diff --git a/deprecated/MongodbHistorian/setup.py b/deprecated/MongodbHistorian/setup.py index b5b7604d05..ce3fdb17dd 100644 --- a/deprecated/MongodbHistorian/setup.py +++ b/deprecated/MongodbHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/deprecated/MongodbHistorian/tests/test_mongohistorian.py b/deprecated/MongodbHistorian/tests/test_mongohistorian.py index b82da3ee33..0ca3144285 100644 --- a/deprecated/MongodbHistorian/tests/test_mongohistorian.py +++ b/deprecated/MongodbHistorian/tests/test_mongohistorian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os diff --git a/deprecated/ObixHistoryPublish/obix_history/agent.py b/deprecated/ObixHistoryPublish/obix_history/agent.py index afb35ed3e8..b4aaacee01 100644 --- a/deprecated/ObixHistoryPublish/obix_history/agent.py +++ b/deprecated/ObixHistoryPublish/obix_history/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} __docformat__ = 'reStructuredText' diff --git a/deprecated/ObixHistoryPublish/setup.py b/deprecated/ObixHistoryPublish/setup.py index f1e7b2c1c6..bb876a55fe 100644 --- a/deprecated/ObixHistoryPublish/setup.py +++ b/deprecated/ObixHistoryPublish/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from setuptools import setup, find_packages diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/IEEE2030_5.py b/deprecated/OldPlatformDrivers/Old2030_5Driver/IEEE2030_5.py similarity index 86% rename from services/core/PlatformDriverAgent/platform_driver/interfaces/IEEE2030_5.py rename to deprecated/OldPlatformDrivers/Old2030_5Driver/IEEE2030_5.py index 3c24056045..30fd686647 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/IEEE2030_5.py +++ b/deprecated/OldPlatformDrivers/Old2030_5Driver/IEEE2030_5.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from datetime import datetime, timedelta diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3.py b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/PlatformDriverAgent/platform_driver/interfaces/dnp3.py similarity index 99% rename from services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3.py rename to deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/PlatformDriverAgent/platform_driver/interfaces/dnp3.py index 93e1690465..90334d57ed 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3.py +++ b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/PlatformDriverAgent/platform_driver/interfaces/dnp3.py @@ -35,7 +35,7 @@ from datetime import datetime, timedelta import logging -from . import BaseInterface, BaseRegister, BasicRevert +from services.core.PlatformDriverAgent.platform_driver.interfaces import BaseInterface, BaseRegister, BasicRevert _log = logging.getLogger(__name__) type_mapping = {"string": str, diff --git a/services/core/PlatformDriverAgent/tests/test_dnp3_driver.py b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/PlatformDriverAgent/tests/test_dnp3_driver.py similarity index 95% rename from services/core/PlatformDriverAgent/tests/test_dnp3_driver.py rename to deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/PlatformDriverAgent/tests/test_dnp3_driver.py index f0a12f4dfb..44fc8d0b06 100644 --- a/services/core/PlatformDriverAgent/tests/test_dnp3_driver.py +++ b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/PlatformDriverAgent/tests/test_dnp3_driver.py @@ -80,7 +80,7 @@ def agent(request, volttron_instance): test_agent = volttron_instance.build_agent() def update_config(agent_id, name, value, cfg_type): - test_agent.vip.rpc.call('config.store', 'manage_store', agent_id, name, value, config_type=cfg_type) + test_agent.vip.rpc.call('config.store', 'set_config', agent_id, name, value, config_type=cfg_type) capabilities = {'edit_config_store': {'identity': PLATFORM_DRIVER}} volttron_instance.add_capabilities(test_agent.core.publickey, capabilities) @@ -95,7 +95,7 @@ def update_config(agent_id, name, value, cfg_type): # Build and start PlatformDriverAgent - test_agent.vip.rpc.call('config.store', 'manage_delete_store', PLATFORM_DRIVER) + test_agent.vip.rpc.call('config.store', 'delete_store', PLATFORM_DRIVER) platform_uuid = volttron_instance.install_agent(agent_dir=get_services_core("PlatformDriverAgent"), config_file={}, diff --git a/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/dnp3-driver.rst b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/dnp3-driver.rst new file mode 100644 index 0000000000..d35c51e056 --- /dev/null +++ b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driver/dnp3-driver.rst @@ -0,0 +1,89 @@ +.. _DNP3-Driver: + +=========== +DNP3 Driver +=========== + +VOLTTRON's DNP3 driver enables the use of `DNP3 `_ (Distributed Network Protocol) +communications, reading and writing points via a DNP3 Outstation. + +In order to use a DNP3 driver to read and write point data, VOLTTRON's DNP3 Agent must also +be configured and running. All communication between the VOLTTRON Outstation and a +DNP3 Master happens through the DNP3 Agent. + +For information about the DNP3 Agent, please see the :ref:`DNP3 Platform Specification `. + + +Requirements +============ + +The DNP3 driver requires the PyDNP3 package. This package can be installed in an activated environment with: + +.. code-block:: bash + + pip install pydnp3 + + +Driver Configuration +==================== + +There is one argument for the "driver_config" section of the DNP3 driver configuration file: + + - **dnp3_agent_id** - ID of VOLTTRON's DNP3Agent. + +Here is a sample DNP3 driver configuration file: + +.. code-block:: json + + { + "driver_config": { + "dnp3_agent_id": "dnp3agent" + }, + "campus": "campus", + "building": "building", + "unit": "dnp3", + "driver_type": "dnp3", + "registry_config": "config://dnp3.csv", + "interval": 15, + "timezone": "US/Pacific", + "heart_beat_point": "Heartbeat" + } + +A sample DNP3 driver configuration file can be found in the VOLTTRON repository +in ``services/core/PlatformDriverAgent/example_configurations/test_dnp3.config``. + + +DNP3 Registry Configuration File +================================ + +The driver's registry configuration file, a `CSV `_ file, +specifies which DNP3 points the driver will read and/or write. Each row configures a single DNP3 point. + +The following columns are required for each row: + + - **Volttron Point Name** - The name used by the VOLTTRON platform and agents to refer to the point. + - **Group** - The point's DNP3 group number. + - **Index** - The point's index number within its DNP3 data type (which is derived from its DNP3 group number). + - **Scaling** - A factor by which to multiply point values. + - **Units** - Point value units. + - **Writable** - TRUE or FALSE, indicating whether the point can be written by the driver (FALSE = read-only). + +Consult the **DNP3 data dictionary** for a point's Group and Index values. Point +definitions in the data dictionary are by agreement between the DNP3 Outstation and Master. +The VOLTTRON DNP3Agent loads the data dictionary of point definitions from the JSON file +at "point_definitions_path" in the DNP3Agent's config file. + +A sample data dictionary is available in ``services/core/DNP3Agent/dnp3/mesa_points.config``. + +Point definitions in the DNP3 driver's registry should look something like this: + +.. csv-table:: DNP3 + :header: Volttron Point Name,Group,Index,Scaling,Units,Writable + + DCHD.WTgt,41,65,1.0,NA,FALSE + DCHD.WTgt-In,30,90,1.0,NA,TRUE + DCHD.WinTms,41,66,1.0,NA,FALSE + DCHD.RmpTms,41,67,1.0,NA,FALSE + +A sample DNP3 driver registry configuration file is available +in ``services/core/PlatformDriverAgent/example_configurations/dnp3.csv``. diff --git a/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driverexamples/configurations/drivers/dnp3.csv b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driverexamples/configurations/drivers/dnp3.csv new file mode 100644 index 0000000000..571d2e9a8e --- /dev/null +++ b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driverexamples/configurations/drivers/dnp3.csv @@ -0,0 +1,13 @@ +Volttron Point Name,Group,Index,Scaling,Units,Writable +DCHD.WTgt,41,65,1.0,NA,FALSE +DCHD.WTgt-In,30,90,1.0,NA,TRUE +DCHD.WinTms,41,66,1.0,NA,FALSE +DCHD.RmpTms,41,67,1.0,NA,FALSE +DCHD.RevtTms,41,68,1.0,NA,FALSE +DCHD.RmpUpRte,41,69,1.0,NA,FALSE +DCHD.RmpDnRte,41,70,1.0,NA,FALSE +DCHD.ChaRmpUpRte,41,71,1.0,NA,FALSE +DCHD.ChaRmpDnRte,41,72,1.0,NA,FALSE +DCHD.ModPrty,41,9,1.0,NA,FALSE +DCHD.VArAct,41,10,1.0,NA,FALSE +DCHD.ModEna,12,5,1.0,NA,FALSE diff --git a/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driverexamples/configurations/drivers/test_dnp3.config b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driverexamples/configurations/drivers/test_dnp3.config new file mode 100644 index 0000000000..7296eae4bc --- /dev/null +++ b/deprecated/OldPlatformDrivers/OldDnp3/OldDnp3Driverexamples/configurations/drivers/test_dnp3.config @@ -0,0 +1,13 @@ +{ + "driver_config": { + "dnp3_agent_id": "dnp3agent" + }, + "campus": "campus", + "building": "building", + "unit": "dnp3", + "driver_type": "dnp3", + "registry_config": "config://dnp3.csv", + "interval": 15, + "timezone": "US/Pacific", + "heart_beat_point": "Heartbeat" +} \ No newline at end of file diff --git a/deprecated/OpenEISHistorian/openeis/historian.py b/deprecated/OpenEISHistorian/openeis/historian.py index 585183d760..482d09b09f 100644 --- a/deprecated/OpenEISHistorian/openeis/historian.py +++ b/deprecated/OpenEISHistorian/openeis/historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -57,16 +43,16 @@ def historian(config_path, **kwargs): config = utils.load_config(config_path) connection = config.get('connection') - + assert connection assert connection.get('type') == 'openeis' - + params = connection.get('params') assert params - + uri = params.get('uri') assert uri - + login = params.get('login') assert login @@ -74,61 +60,61 @@ def historian(config_path, **kwargs): assert password # Auth will get passed to the server through the requests python framework. auth = (login, password) - + datasets = config.get("dataset_definitions") assert datasets assert len(datasets) > 0 - + headers = {'content-type': 'application/json'} class OpenEISHistorian(BaseHistorian): '''An OpenEIS historian which allows the publishing of dynamic. - - This historian publishes to an openeis instance with the following + + This historian publishes to an openeis instance with the following example json payload: - + dataset_extension = { "dataset_id": dataset_id, - "point_map": + "point_map": { "New building/WholeBuildingPower": [["2/5/2014 10:00",48.78], ["2/5/2014 10:05",50.12], ["2/5/2014 10:10",48.54]], "New building/OutdoorAirTemperature": [["2/5/2014 10:00",48.78], ["2/5/2014 10:05",10.12], ["2/5/2014 10:10",48.54]] } } - + The dataset must exist on the openeis webserver. The mapping (defined) in the configuration file must include both the input (from device) topic and output (openeis schema topic). See openeis.historian.config for a full description of how those are specified in the coniguration file. - + This service will publish to server/api/datasets/append endpoint. ''' @doc_inherit def publish_to_historian(self, to_publish_list): _log.debug("publish_to_historian number of items: {}".format(len(to_publish_list))) - + # print(to_publish_list) dataset_uri = uri + "/api/datasets/append" - + # Build a payload for each of the points in each of the dataset definitions. for dsk, dsv in datasets.items(): ds_id = dsv["dataset_id"] ds_points = dsv['points'] # [unicode(p) for p in dsv['points']] - ignore_unmapped = dsv.get('ignore_unmapped_points', 0) - + ignore_unmapped = dsv.get('ignore_unmapped_points', 0) + point_map = {} try_publish = [] for to_pub in to_publish_list: - for point in ds_points: + for point in ds_points: if to_pub['topic'] in point.keys(): try_publish.append(to_pub) # gets the value of the sensor for publishing. openeis_sensor = point[to_pub['topic']] if not openeis_sensor in point_map: point_map[openeis_sensor] = [] - + point_map[openeis_sensor].append([to_pub['timestamp'], to_pub['value']]) else: if ignore_unmapped: @@ -136,9 +122,9 @@ def publish_to_historian(self, to_publish_list): else: err = 'Point {topic} was not found in point map.'.format(**to_pub) _log.error(err) - + # pprint(point_map) - + if len(point_map) > 0: payload = {'dataset_id': ds_id, 'point_map': point_map} @@ -146,17 +132,17 @@ def publish_to_historian(self, to_publish_list): try: # resp = requests.post(login_uri, auth=auth) resp = requests.put(dataset_uri, verify=False, headers=headers, data=payload) - if resp.status_code == requests.codes.ok: + if resp.status_code == requests.codes.ok: self.report_handled(try_publish) except ConnectionError: _log.error('Unable to connect to openeis at {}'.format(uri)) return ''' Transform the to_publish_list into a dictionary like the following - + dataset_extension = { "dataset_id": dataset_id, - "point_map": + "point_map": { "New building/WholeBuildingPower": [["2/5/2014 10:00",48.78], ["2/5/2014 10:05",50.12], ["2/5/2014 10:10",48.54]], "New building/OutdoorAirTemperature": [["2/5/2014 10:00",48.78], ["2/5/2014 10:05",10.12], ["2/5/2014 10:10",48.54]] diff --git a/deprecated/OpenEISHistorian/setup.py b/deprecated/OpenEISHistorian/setup.py index 9bcacbd697..ed132974bf 100644 --- a/deprecated/OpenEISHistorian/setup.py +++ b/deprecated/OpenEISHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/docs/.readthedocs.yaml b/docs/.readthedocs.yaml new file mode 100644 index 0000000000..8915bd8d0d --- /dev/null +++ b/docs/.readthedocs.yaml @@ -0,0 +1,29 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.10" + # You can also specify other tool versions: + # nodejs: "19" + # rust: "1.64" + # golang: "1.19" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/source/conf.py + +# If using Sphinx, optionally build your docs in additional formats such as PDF +# formats: +# - pdf + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: docs/requirements.txt diff --git a/docs/requirements.txt b/docs/requirements.txt index 84232c5b90..b30f7a5b2a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,7 +1,7 @@ -sphinx_rtd_theme -sphinx-autobuild -sphinx==3.3.0 -m2r2 +sphinx==5.1.1 +sphinx-rtd-theme==1.0.0 +m2r2==0.3.2 +sphinxcontrib-mermaid bacpypes enum34 funcsigs @@ -27,3 +27,5 @@ zmq ply psutil ws4py +Jinja2==3.1.2 +PyYaml diff --git a/docs/source/agent-framework/core-service-agents/ieee-2030_5-agent/ieee-2030_5-agent.rst b/docs/source/agent-framework/core-service-agents/ieee-2030_5-agent/ieee-2030_5-agent.rst index 636ee06db8..e45704ffb3 100644 --- a/docs/source/agent-framework/core-service-agents/ieee-2030_5-agent/ieee-2030_5-agent.rst +++ b/docs/source/agent-framework/core-service-agents/ieee-2030_5-agent/ieee-2030_5-agent.rst @@ -1,118 +1,36 @@ .. _IEEE-2030_5-Agent: -===================== -IEEE 2030.5 DER Agent -===================== +=========================== +IEEE 2030.5 EndDevice Agent +=========================== -The IEEE 2030.5 Agent (IEEE2030_5 in the VOLTTRON repository) implements a IEEE 2030.5 server that receives HTTP -`POST`/`PUT` requests from IEEE 2030.5 devices. The requests are routed to the IEEE 2030.5 Agent over the VOLTTRON -message bus by VOLTTRON's Master Web Service. The IEEE 2030.5 Agent returns an appropriate HTTP response. In some -cases (e.g., DERControl requests), this response includes a data payload. +The IEEE 2030.5 Agent (IEEE_2030_5 in the VOLTTRON repository) acts as an IEEE 2030.5 EndDevice (client). This +agent establishes a secure connection to a TLS-enabled 2030.5 server and discovers its capabilities. It verifies +the server's identity based on the Registration function set and uses the FunctionSetAssignments function set to +determine the appropriate DERProgram to run. The agent regularly checks for changes in default controls and +active DERControls and responds accordingly. It also listens to one or more subscriptions to the VOLTTRON message +bus for information (points) to POST/PUT to the 2030.5 server. -The IEEE 2030.5 Agent maps IEEE 2030.5 resource data to a VOLTTRON IEEE 2030.5 data model based on SunSpec, using block -numbers and point names as defined in the SunSpec Information Model, which in turn is harmonized with 61850. The data -model is given in detail below. +You can access the agent code, README, and demo from `IEEE_2030_5 Agent `_. -Each device's data is stored by the IEEE 2030.5 Agent in an `EndDevice` memory structure. This structure is not -persisted to a database. Each `EndDevice` retains only the most recently received value for each field. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Common Smart Inverter Profile (CSIP) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The IEEE2030_5 Agent exposes RPC calls for getting and setting EndDevice data. +This agent is not a fully compliant CSIP client, meaning it does not support all of the function sets +within the CSIP Profile of 2030.5. It provides the following function sets: +- End Device +- Time +- Distributed Energy Resources +- Metering +- Metering Mirror -VOLTTRON IEEE 2030.5 Device Driver ----------------------------------- +As time goes on it is likely that this list will be extended through user supported additions and project needs. -The :ref:`IEEE 2030.5 device driver ` is a new addition to VOLTTRON Platform Driver Agent's -family of standard device drivers. It exposes ``get_point``/``set_point calls`` for IEEE 2030.5 EndDevice fields. +################ +2030.5 Reference +################ -The IEEE 2030.5 device driver periodically issues IEEE2030_5 Agent RPC calls to refresh its cached representation of -EndDevice data. It issues RPC calls to IEEE2030_5Agent as needed when responding to ``get_point``, ``set_point`` and -``scrape_all`` calls. - - -Field Definitions -^^^^^^^^^^^^^^^^^ - -These field IDs correspond to the ones in the IEEE 2030.5 device driver's configuration file, ``ieee2030_5.csv``. -They have been used in that file's "Volttron Point Name" column and also in its "Point Name" column. - -================= ============================= ==================================================== ======= ====== -Field ID IEEE 2030.5 Resource/Property Description Units Type -================= ============================= ==================================================== ======= ====== -b1_Md device_information Model (32 char lim). string - mfModel -b1_Opt device_information Long-form device identifier (32 char lim). string - lfdi -b1_SN abstract_device Short-form device identifier (32 char lim). string - sfdi -b1_Vr device_information Version (16 char lim). string - mfHwVer -b113_A mirror_meter_reading AC current. A float - PhaseCurrentAvg -b113_DCA mirror_meter_reading DC current. A float - InstantPackCurrent -b113_DCV mirror_meter_reading DC voltage. V float - LineVoltageAvg -b113_DCW mirror_meter_reading DC power. W float - PhasePowerAvg -b113_PF mirror_meter_reading AC power factor. % float - PhasePFA -b113_WH mirror_meter_reading AC energy. Wh float - EnergyIMP -b120_AhrRtg der_capability Usable capacity of the battery. Ah float - rtgAh Maximum charge minus minimum charge. -b120_ARtg der_capability Maximum RMS AC current level capability of the A float - rtgA inverter. -b120_MaxChaRte der_capability Maximum rate of energy transfer into the device. W float - rtgMaxChargeRate -b120_MaxDisChaRte der_capability Maximum rate of energy transfer out of the device. W float - rtgMaxDischargeRate -b120_WHRtg der_capability Nominal energy rating of the storage device. Wh float - rtgWh -b120_WRtg der_capability Continuous power output capability of the inverter. W float - rtgW -b121_WMax der_settings Maximum power output. Default to WRtg. W float - setMaxChargeRate -b122_ActWh mirror_meter_reading AC lifetime active (real) energy output. Wh float - EnergyEXP -b122_StorConn der_status CONNECTED=0, AVAILABLE=1, OPERATING=2, TEST=3. enum - storConnectStatus -b124_WChaMax der_control Setpoint for maximum charge. This is the only W float - opModFixedFlow field that is writable with a set_point call. -b403_Tmp mirror_meter_reading Pack temperature. C float - InstantPackTemp -b404_DCW PEVInfo Power flow in or out of the inverter. W float - chargingPowerNow -b404_DCWh der_availability Output energy (absolute SOC). Wh float - availabilityDuration Calculated as (availabilityDuration / 3600) * WMax. -b802_LocRemCtl der_status Control Mode: REMOTE=0, LOCAL=1. enum - localControlModeStatus -b802_SoC der_status State of Charge %. % WHRtg float - stateOfChargeStatus -b802_State der_status DISCONNECTED=1, INITIALIZING=2, CONNECTED=3, enum - inverterStatus STANDBY=4, SOC PROTECTION=5, FAULT=99. -================= ============================= ==================================================== ======= ====== - - -Revising and Expanding the Field Definitions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The IEEE 2030.5-to-SunSpec field mappings in this implementation are a relatively thin subset of all possible -field definitions. Developers are encouraged to expand the definitions. - -The procedure for expanding the field mappings requires you to make changes in two places: - -1. Update the driver's point definitions in ``services/core/PlatformDriverAgent/platform_driver/ieee2030_5.csv`` -2. Update the IEEE 2030.5-to-SunSpec field mappings in ``services/core/IEEE2030_5Agent/ieee2030_5/end_device.py`` and - ``__init__.py`` - -When updating VOLTTRON's IEEE 2030.5 data model, please use field IDs that conform to the SunSpec -block-number-and-field-name model outlined in the SunSpec Information Model Reference (see the link below). - -View the :ref:`IEEE 2030.5 agent specification document ` to learn more about IEEE 2030.5 and -the IEEE 2030.5 agent and driver. - - -.. toctree:: - - ieee-2030_5-specification +`IEEE 2030.5 Standards `_ +`IEEE_2030_5 Agent `_ diff --git a/docs/source/agent-framework/core-service-agents/ieee-2030_5-agent/ieee-2030_5-specification.rst b/docs/source/agent-framework/core-service-agents/ieee-2030_5-agent/ieee-2030_5-specification.rst deleted file mode 100644 index 361f9e1150..0000000000 --- a/docs/source/agent-framework/core-service-agents/ieee-2030_5-agent/ieee-2030_5-specification.rst +++ /dev/null @@ -1,207 +0,0 @@ -.. _IEEE-2030_5-Specification: - -======================= -IEEE 2030.5 DER Support -======================= - -Version 1.0 - -Smart Energy Profile 2.0 (SEP 2.0, IEEE 2030.5) specifies a REST architecture built around the core HTTP verbs: GET, -HEAD, PUT, POST and DELETE. A specification for the IEEE 2030.5 protocol can be found -`here `_. - -IEEE 2030.5 EndDevices (clients) POST XML resources representing their state, and GET XML resources containing command -and control information from the server. The server never reaches out to the client unless a "subscription" is -registered and supported for a particular resource type. This implementation does not use IEEE 2030.5 registered -subscriptions. - -The IEEE 2030.5 specification requires HTTP headers, and it explicitly requires RESTful response codes, for example: - - - 201 - "Created" - - 204 - "No Content" - - 301 - "Moved Permanently" - - etc. - -IEEE 2030.5 message encoding may be either XML or EXI. Only XML is supported in this implementation. - -IEEE 2030.5 requires HTTPS/TLS version 1.2 along with support for the cipher suite TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8. -Production installation requires a certificate issued by a IEEE 2030.5 CA. The encryption requirement can be met by -using a web server such as Apache to proxy the HTTPs traffic. - -IEEE 2030.5 discovery, if supported, must be implemented by an xmDNS server. Avahi can be modified to perform this -function. - - -Function Sets -============= - -IEEE 2030.5 groups XML resources into "Function Sets." Some of these function sets provide a core set of functionality -used across higher-level function sets. This implementation implements resources from the following function sets: - - - Time - - Device Information - - Device Capabilities - - End Device - - Function Set Assignments - - Power Status - - Distributed Energy Resources - - -Distributed Energy Resources (DERs) ------------------------------------ - -Distributed energy resources (DERs) are devices that generate energy, e.g., solar inverters, or store energy, e.g., -battery storage systems, electric vehicle supply equipment (EVSEs). These devices are managed by a IEEE 2030.5 DER -server using DERPrograms which are described by the IEEE 2030.5 specification as follows: - - Servers host one or more DERPrograms, which in turn expose DERControl events to DER clients. - DERControl instances contain attributes that allow DER clients to respond to events - that are targeted to their device type. A DERControl instance also includes scheduling - attributes that allow DER clients to store and process future events. These attributes - include start time and duration, as well an indication of the need for randomization of - the start and / or duration of the event. The IEEE 2030.5 DER client model is based on the - SunSpec Alliance Inverter Control Model [SunSpec] which is derived from - IEC 61850-90-7 [61850] and [EPRI]. - -EndDevices post multiple IEEE 2030.5 resources describing their status. The following is an -example of a Power Status resource that might be posted by an EVSE (vehicle charging station): - -.. code-block:: xml - - - 4 - 1487812095 - 1 - 9300 - - - 3 - -5 - - - 3 - 22 - - - 3 - 7 - - 11280 - 10000 - 9223372036854775807 - 1487812095 - - - - -Design Details --------------- - -.. image:: files/volttron_ieee2030_5.jpg - -VOLTTRON's IEEE 2030.5 implementation includes a IEEE 2030.5 Agent and a IEEE 2030.5 device driver, as described below. - - -VOLTTRON IEEE 2030.5 Device Driver -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The IEEE 2030.5 device driver is a new addition to VOLTTRON Platform Driver Agent's family of standard device drivers. It -exposes `get_point`/`set_point` calls for IEEE 2030.5 EndDevice fields. - -The IEEE 2030.5 device driver periodically issues the IEEE 2030.5 Agent RPC calls to refresh its cached representation -of EndDevice data. It issues RPC calls to the IEEE 2030.5 Agent as needed when responding to `get_point`, `set_point` -and `scrape_all` calls. - -Field Definitions -^^^^^^^^^^^^^^^^^ - -These field IDs correspond to the ones in the IEEE 2030.5 device driver's configuration file, `ieee2030_5.csv`. -They have been used in that file's `Volttron Point Name` column and also in its `Point Name` column. - -================= ============================= ==================================================== ======= ====== -Field ID IEEE 2030.5 Resource/Property Description Units Type -================= ============================= ==================================================== ======= ====== -b1_Md device_information Model (32 char lim). string - mfModel -b1_Opt device_information Long-form device identifier (32 char lim). string - lfdi -b1_SN abstract_device Short-form device identifier (32 char lim). string - sfdi -b1_Vr device_information Version (16 char lim). string - mfHwVer -b113_A mirror_meter_reading AC current. A float - PhaseCurrentAvg -b113_DCA mirror_meter_reading DC current. A float - InstantPackCurrent -b113_DCV mirror_meter_reading DC voltage. V float - LineVoltageAvg -b113_DCW mirror_meter_reading DC power. W float - PhasePowerAvg -b113_PF mirror_meter_reading AC power factor. % float - PhasePFA -b113_WH mirror_meter_reading AC energy. Wh float - EnergyIMP -b120_AhrRtg der_capability Usable capacity of the battery. Ah float - rtgAh Maximum charge minus minimum charge. -b120_ARtg der_capability Maximum RMS AC current level capability of the A float - rtgA inverter. -b120_MaxChaRte der_capability Maximum rate of energy transfer into the device. W float - rtgMaxChargeRate -b120_MaxDisChaRte der_capability Maximum rate of energy transfer out of the device. W float - rtgMaxDischargeRate -b120_WHRtg der_capability Nominal energy rating of the storage device. Wh float - rtgWh -b120_WRtg der_capability Continuous power output capability of the inverter. W float - rtgW -b121_WMax der_settings Maximum power output. Default to WRtg. W float - setMaxChargeRate -b122_ActWh mirror_meter_reading AC lifetime active (real) energy output. Wh float - EnergyEXP -b122_StorConn der_status CONNECTED=0, AVAILABLE=1, OPERATING=2, TEST=3. enum - storConnectStatus -b124_WChaMax der_control Setpoint for maximum charge. This is the only W float - opModFixedFlow field that is writable with a set_point call. -b403_Tmp mirror_meter_reading Pack temperature. C float - InstantPackTemp -b404_DCW PEVInfo Power flow in or out of the inverter. W float - chargingPowerNow -b404_DCWh der_availability Output energy (absolute SOC). Wh float - availabilityDuration Calculated as (availabilityDuration / 3600) * WMax. -b802_LocRemCtl der_status Control Mode: REMOTE=0, LOCAL=1. enum - localControlModeStatus -b802_SoC der_status State of Charge %. % WHRtg float - stateOfChargeStatus -b802_State der_status DISCONNECTED=1, INITIALIZING=2, CONNECTED=3, enum - inverterStatus STANDBY=4, SOC PROTECTION=5, FAULT=99. -================= ============================= ==================================================== ======= ====== - - -Revising and Expanding the Field Definitions --------------------------------------------- - -The IEEE 2030.5-to-SunSpec field mappings in this implementation are a relatively thin subset of all possible -field definitions. Developers are encouraged to expand the definitions. - -The procedure for expanding the field mappings requires you to make changes in two places: - -1. Update the driver's point definitions in `services/core/PlatformDriverAgent/platform_driver/ieee2030_5.csv` -2. Update the IEEE 2030.5-to-SunSpec field mappings in `services/core/IEEE2030_5Agent/ieee2030_5/end_device.py` and - `__init__.py` - -When updating VOLTTRON's IEEE 2030.5 data model, please use field IDs that conform to the SunSpec -block-number-and-field-name model outlined in the SunSpec Information Model Reference (see the link below). - - -For Further Information -======================= - -SunSpec References: - - - Information model specification: http://sunspec.org/wp-content/uploads/2015/06/SunSpec-Information-Models-12041.pdf - - Information model reference spreadsheet: http://sunspec.org/wp-content/uploads/2015/06/SunSpec-Information-Model-Reference.xlsx - - Inverter models: http://sunspec.org/wp-content/uploads/2015/06/SunSpec-Inverter-Models-12020.pdf - - Energy storage models: http://sunspec.org/wp-content/uploads/2015/06/SunSpec-Energy-Storage-Models-12032.pdf - -Questions? Please contact: - - - Rob Calvert (rob@kisensum.com) or James Sheridan (james@kisensum.com) diff --git a/docs/source/agent-framework/driver-framework/dnp3-driver/dnp3-driver.rst b/docs/source/agent-framework/driver-framework/dnp3-driver/dnp3-driver.rst index d35c51e056..8aa7b03839 100644 --- a/docs/source/agent-framework/driver-framework/dnp3-driver/dnp3-driver.rst +++ b/docs/source/agent-framework/driver-framework/dnp3-driver/dnp3-driver.rst @@ -7,21 +7,18 @@ DNP3 Driver VOLTTRON's DNP3 driver enables the use of `DNP3 `_ (Distributed Network Protocol) communications, reading and writing points via a DNP3 Outstation. -In order to use a DNP3 driver to read and write point data, VOLTTRON's DNP3 Agent must also -be configured and running. All communication between the VOLTTRON Outstation and a -DNP3 Master happens through the DNP3 Agent. - -For information about the DNP3 Agent, please see the :ref:`DNP3 Platform Specification `. - +In order to use a DNP3 driver to read and write point data, a server component (i.e., Outstation) must also +be configured and running. Requirements ============ -The DNP3 driver requires the PyDNP3 package. This package can be installed in an activated environment with: +The DNP3 driver requires the `dnp3-python `_ package, a wrapper on Pydnp3 package. +This package can be installed in an activated environment with: .. code-block:: bash - pip install pydnp3 + pip install dnp3-python Driver Configuration @@ -29,24 +26,23 @@ Driver Configuration There is one argument for the "driver_config" section of the DNP3 driver configuration file: - - **dnp3_agent_id** - ID of VOLTTRON's DNP3Agent. - Here is a sample DNP3 driver configuration file: .. code-block:: json { - "driver_config": { - "dnp3_agent_id": "dnp3agent" - }, - "campus": "campus", - "building": "building", - "unit": "dnp3", - "driver_type": "dnp3", - "registry_config": "config://dnp3.csv", - "interval": 15, - "timezone": "US/Pacific", - "heart_beat_point": "Heartbeat" + "driver_config": {"master_ip": "0.0.0.0", "outstation_ip": "127.0.0.1", + "master_id": 2, "outstation_id": 1, + "port": 20000}, + "registry_config":"config://udd-Dnp3.csv", + "driver_type": "udd_dnp3", + "interval": 5, + "timezone": "UTC", + "campus": "campus-vm", + "building": "building-vm", + "unit": "Dnp3", + "publish_depth_first_all": true, + "heart_beat_point": "random_bool" } A sample DNP3 driver configuration file can be found in the VOLTTRON repository @@ -63,6 +59,7 @@ The following columns are required for each row: - **Volttron Point Name** - The name used by the VOLTTRON platform and agents to refer to the point. - **Group** - The point's DNP3 group number. + - **Variation** - THe permit negotiated exchange of data formatted, i.e., data type. - **Index** - The point's index number within its DNP3 data type (which is derived from its DNP3 group number). - **Scaling** - A factor by which to multiply point values. - **Units** - Point value units. @@ -78,12 +75,16 @@ A sample data dictionary is available in ``services/core/DNP3Agent/dnp3/mesa_poi Point definitions in the DNP3 driver's registry should look something like this: .. csv-table:: DNP3 - :header: Volttron Point Name,Group,Index,Scaling,Units,Writable + :header: Point Name,Volttron Point Name,Group,Variation,Index,Scaling,Units,Writable,Notes + + AnalogInput_index0,AnalogInput_index0,30,6,0,1,NA,FALSE,Double Analogue input without status + BinaryInput_index0,BinaryInput_index0,1,2,0,1,NA,FALSE,Single bit binary input with status + AnalogOutput_index0,AnalogOutput_index0,40,4,0,1,NA,TRUE,Double-precision floating point with flags + BinaryOutput_index0,BinaryOutput_index0,10,2,0,1,NA,TRUE,Binary Output with flags - DCHD.WTgt,41,65,1.0,NA,FALSE - DCHD.WTgt-In,30,90,1.0,NA,TRUE - DCHD.WinTms,41,66,1.0,NA,FALSE - DCHD.RmpTms,41,67,1.0,NA,FALSE A sample DNP3 driver registry configuration file is available in ``services/core/PlatformDriverAgent/example_configurations/dnp3.csv``. + +For more information about Group Variation definition, please refer to `dnp3.Variation +`_. diff --git a/docs/source/agent-framework/driver-framework/drivers-overview.rst b/docs/source/agent-framework/driver-framework/drivers-overview.rst index ab5d00fc5d..c0077381a6 100644 --- a/docs/source/agent-framework/driver-framework/drivers-overview.rst +++ b/docs/source/agent-framework/driver-framework/drivers-overview.rst @@ -175,3 +175,4 @@ To view data being published from the fake driver on the message bus, one can modbus/modbus-tk-driver obix/obix ted-driver/the-energy-detective-driver + home-assistant/HomeAssistantDriver \ No newline at end of file diff --git a/docs/source/agent-framework/driver-framework/home-assistant/HomeAssistantDriver.rst b/docs/source/agent-framework/driver-framework/home-assistant/HomeAssistantDriver.rst new file mode 100644 index 0000000000..ac6d51fa10 --- /dev/null +++ b/docs/source/agent-framework/driver-framework/home-assistant/HomeAssistantDriver.rst @@ -0,0 +1,186 @@ +.. _HomeAssistant-Driver: + +Home Assistant Driver +===================== + +The Home Assistant driver enables VOLTTRON to read any data point from any Home Assistant controlled device. +Currently control(write access) is supported only for lights(state and brightness) and thermostats(state and temperature). + +The following diagram shows interaction between platform driver agent and home assistant driver. + +.. mermaid:: + + sequenceDiagram + HomeAssistant Driver->>HomeAssistant: Retrieve Entity Data (REST API) + HomeAssistant-->>HomeAssistant Driver: Entity Data (Status Code: 200) + HomeAssistant Driver->>PlatformDriverAgent: Publish Entity Data + PlatformDriverAgent->>Controller Agent: Publish Entity Data + + Controller Agent->>HomeAssistant Driver: Instruct to Turn Off Light + HomeAssistant Driver->>HomeAssistant: Send Turn Off Light Command (REST API) + HomeAssistant-->>HomeAssistant Driver: Command Acknowledgement (Status Code: 200) + +Pre-requisites +-------------- +Before proceeding, find your Home Assistant IP address and long-lived access token from `here `_. + +Clone the repository, start volttron, install the listener agent, and the platform driver agent. + +- `Listener agent `_ +- `Platform driver agent `_ + +Configuration +-------------- + +After cloning, generate configuration files. Each device requires one device configuration file and one registry file. +Ensure your registry_config parameter in your device configuration file, links to correct registry config name in the +config store. For more details on how volttron platform driver agent works with volttron configuration store see, +`Platform driver configuration `_ +Examples for lights and thermostats are provided below. + +Device configuration +++++++++++++++++++++ + +Device configuration file contains the connection details to you home assistant instance and driver_type as "home_assistant" + +.. code-block:: json + + { + "driver_config": { + "ip_address": "Your Home Assistant IP", + "access_token": "Your Home Assistant Access Token", + "port": "Your Port" + }, + "driver_type": "home_assistant", + "registry_config": "config://light.example.json", + "interval": 30, + "timezone": "UTC" + } + +Registry Configuration ++++++++++++++++++++++++ + +Registry file can contain one single device and its attributes or a logical group of devices and its +attributes. Each entry should include the full entity id of the device, including but not limited to home assistant provided prefix +such as "light.", "climate." etc. The driver uses these prefixes to convert states into integers. +Like mentioned before, the driver can only control lights and thermostats but can get data from all devices +controlled by home assistant + +Each entry in a registry file should also have a 'Entity Point' and a unique value for 'Volttron Point Name'. The 'Entity ID' maps to the device instance, the 'Entity Point' extracts the attribute or state, and 'Volttron Point Name' determines the name of that point as it appears in VOLTTRON. + +Attributes can be located in the developer tools in the Home Assistant GUI. + +.. image:: home-assistant.png + + +Below is an example file named light.example.json which has attributes of a single light instance with entity +id 'light.example': + + +.. code-block:: json + + [ + { + "Entity ID": "light.example", + "Entity Point": "state", + "Volttron Point Name": "light_state", + "Units": "On / Off", + "Units Details": "on/off", + "Writable": true, + "Starting Value": true, + "Type": "boolean", + "Notes": "lights hallway" + }, + { + "Entity ID": "light.example", + "Entity Point": "brightness", + "Volttron Point Name": "light_brightness", + "Units": "int", + "Units Details": "light level", + "Writable": true, + "Starting Value": 0, + "Type": "int", + "Notes": "brightness control, 0 - 255" + } + ] + + +.. note:: + +When using a single registry file to represent a logical group of multiple physical entities, make sure the +"Volttron Point Name" is unique within a single registry file. + +For example, if a registry file contains entities with +id 'light.instance1' and 'light.instance2' the entry for the attribute brightness for these two light instances could +have "Volttron Point Name" as 'light1/brightness' and 'light2/brightness' respectively. This would ensure that data +is posted to unique topic names and brightness data from light1 is not overwritten by light2 or vice-versa. + +Example Thermostat Registry +*************************** + +For thermostats, the state is converted into numbers as follows: "0: Off, 2: heat, 3: Cool, 4: Auto", + +.. code-block:: json + + [ + { + "Entity ID": "climate.my_thermostat", + "Entity Point": "state", + "Volttron Point Name": "thermostat_state", + "Units": "Enumeration", + "Units Details": "0: Off, 2: heat, 3: Cool, 4: Auto", + "Writable": true, + "Starting Value": 1, + "Type": "int", + "Notes": "Mode of the thermostat" + }, + { + "Entity ID": "climate.my_thermostat", + "Entity Point": "current_temperature", + "Volttron Point Name": "volttron_current_temperature", + "Units": "F", + "Units Details": "Current Ambient Temperature", + "Writable": true, + "Starting Value": 72, + "Type": "float", + "Notes": "Current temperature reading" + }, + { + "Entity ID": "climate.my_thermostat", + "Entity Point": "temperature", + "Volttron Point Name": "set_temperature", + "Units": "F", + "Units Details": "Desired Temperature", + "Writable": true, + "Starting Value": 75, + "Type": "float", + "Notes": "Target Temp" + } + ] + + + +Transfer the registers files and the config files into the VOLTTRON config store using the commands below: + +.. code-block:: bash + + vctl config store platform.driver light.example.json HomeAssistant_Driver/light.example.json + vctl config store platform.driver devices/BUILDING/ROOM/light.example HomeAssistant_Driver/light.example.config + +Upon completion, initiate the platform driver. Utilize the listener agent to verify the driver output: + +.. code-block:: bash + + 2023-09-12 11:37:00,226 (listeneragent-3.3 211531) __main__ INFO: Peer: pubsub, Sender: platform.driver:, Bus: , Topic: devices/BUILDING/ROOM/light.example/all, Headers: {'Date': '2023-09-12T18:37:00.224648+00:00', 'TimeStamp': '2023-09-12T18:37:00.224648+00:00', 'SynchronizedTimeStamp': '2023-09-12T18:37:00.000000+00:00', 'min_compatible_version': '3.0', 'max_compatible_version': ''}, Message: + [{'light_brightness': 254, 'state': 'on'}, + {'light_brightness': {'type': 'integer', 'tz': 'UTC', 'units': 'int'}, + 'state': {'type': 'integer', 'tz': 'UTC', 'units': 'On / Off'}}] + +Running Tests ++++++++++++++++++++++++ +To run tests on the VOLTTRON home assistant driver you need to create a helper in your home assistant instance. This can be done by going to **Settings > Devices & services > Helpers > Create Helper > Toggle**. Name this new toggle **volttrontest**. After that run the pytest from the root of your VOLTTRON file. + +.. code-block:: bash + pytest volttron/services/core/PlatformDriverAgent/tests/test_home_assistant.py + +If everything works, you will see 6 passed tests. diff --git a/docs/source/agent-framework/driver-framework/home-assistant/home-assistant.png b/docs/source/agent-framework/driver-framework/home-assistant/home-assistant.png new file mode 100644 index 0000000000..d75333222b Binary files /dev/null and b/docs/source/agent-framework/driver-framework/home-assistant/home-assistant.png differ diff --git a/docs/source/conf.py b/docs/source/conf.py index 87aafc3224..dc75f60eb2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -16,37 +16,83 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) +import os import subprocess import sys -import os from glob import glob -from mock import Mock as MagicMock + import yaml +from mock import Mock as MagicMock -from volttron.platform.agent.utils import execute_command + +# Copied from volttron.platform.agent.util because it is not required +# that volttron be installed to utilize this script. +def execute_command(cmds, + env=None, + cwd=None, + logger=None, + err_prefix=None, + use_shell=False) -> str: + """ Executes a command as a subprocess + + If the return code of the call is 0 then return stdout otherwise + raise a RuntimeError. If logger is specified then write the exception + to the logger otherwise this call will remain silent. + + :param cmds:list of commands to pass to subprocess.run + :param env: environment to run the command with + :param cwd: working directory for the command + :param logger: a logger to use if errors occure + :param err_prefix: an error prefix to allow better tracing through the error message + :return: stdout string if successful + + :raises RuntimeError: if the return code is not 0 from suprocess.run + """ + + results = subprocess.run(cmds, + env=env, + cwd=cwd, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + shell=use_shell) + if results.returncode != 0: + err_prefix = err_prefix if err_prefix is not None else "Error executing command" + err_message = "\n{}: Below Command failed with non zero exit code.\n" \ + "Command:{} \nStderr:\n{}\n".format(err_prefix, + results.args, + results.stderr) + if logger: + logger.exception(err_message) + raise RuntimeError(err_message) + else: + raise RuntimeError(err_message) + + return results.stdout.decode('utf-8') class Mock(MagicMock): + @classmethod def __getattr__(cls, name): - return Mock() + return Mock() -autodoc_mock_imports = ['loadshape', 'numpy', 'sympy', 'xlrd', 'stomp', 'oadr2', 'pyodbc', 'lxml', 'pytest', - 'pint', 'pandas', 'suds', 'paho', 'pymongo', 'bson', 'subprocess32', 'heaters', 'meters', - 'hvac', 'blinds', 'vehicles'] +autodoc_mock_imports = [ + 'loadshape', 'numpy', 'sympy', 'xlrd', 'stomp', 'oadr2', 'pyodbc', 'lxml', + 'pytest', 'pint', 'pandas', 'suds', 'paho', 'pymongo', 'bson', + 'subprocess32', 'heaters', 'meters', 'hvac', 'blinds', 'vehicles' +] # -- Project information ----------------------------------------------------- project = 'VOLTTRON' -copyright = '2022, The VOLTTRON Community' +copyright = '2023, The VOLTTRON Community' author = 'The VOLTTRON Community' # The short X.Y version -version = '8.2' +version = '9.0' # The full version, including alpha/beta/rc tags -release = '8.2' - +release = '9.0' # -- General configuration --------------------------------------------------- @@ -71,7 +117,8 @@ def __getattr__(cls, name): # http://www.sphinx-doc.org/en/master/usage/extensions/todo.html 'sphinx.ext.todo', 'sphinx.ext.intersphinx', - 'm2r2' + 'm2r2', + 'sphinxcontrib.mermaid' ] # prefix sections with the document so that we can cross link @@ -108,7 +155,6 @@ def __getattr__(cls, name): # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' - # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for @@ -137,13 +183,11 @@ def __getattr__(cls, name): # # html_sidebars = {} - # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'VOLTTRONdoc' - # -- Options for LaTeX output ------------------------------------------------ latex_elements = { @@ -172,16 +216,11 @@ def __getattr__(cls, name): 'The VOLTTRON Community', 'manual'), ] - # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (main_doc, 'volttron', 'VOLTTRON Documentation', - [author], 1) -] - +man_pages = [(main_doc, 'volttron', 'VOLTTRON Documentation', [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -189,20 +228,22 @@ def __getattr__(cls, name): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (main_doc, 'VOLTTRON', 'VOLTTRON Documentation', - author, 'VOLTTRON', 'One line description of project.', - 'Miscellaneous'), + (main_doc, 'VOLTTRON', 'VOLTTRON Documentation', author, 'VOLTTRON', + 'One line description of project.', 'Miscellaneous'), ] - # -- Extension configuration ------------------------------------------------- # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/3.6': None, - 'volttron-ansible': ('https://volttron.readthedocs.io/projects/volttron-ansible/en/main/', - None)} +intersphinx_mapping = { + 'https://docs.python.org/3.6': + None, + 'volttron-ansible': + ('https://volttron.readthedocs.io/projects/volttron-ansible/en/main/', + None) +} # -- Options for todo extension ---------------------------------------------- @@ -247,11 +288,15 @@ def generate_apidoc(app): # generate api-docs for each api docs directory for docs_subdir in config.keys(): docs_subdir_path = os.path.join(apidocs_base_dir, docs_subdir) - agent_dirs = glob(os.path.join(volttron_root, config[docs_subdir]["path"], "*/")) + agent_dirs = glob( + os.path.join(volttron_root, config[docs_subdir]["path"], "*/")) file_excludes = [] if config[docs_subdir].get("file_excludes"): - for exclude_pattern in config[docs_subdir].get("file_excludes", []): - file_excludes.append(os.path.join(volttron_root, config[docs_subdir]["path"], exclude_pattern)) + for exclude_pattern in config[docs_subdir].get( + "file_excludes", []): + file_excludes.append( + os.path.join(volttron_root, config[docs_subdir]["path"], + exclude_pattern)) print("after file excludes. calling apidoc") agent_excludes = \ config[docs_subdir].get("agent_excludes") if config[docs_subdir].get("agent_excludes", []) else [] @@ -268,19 +313,24 @@ def run_apidoc(docs_dir, agent_dirs, agent_excludes, exclude_pattern): :param agent_excludes: agent directories to be skipped :param exclude_pattern: file name patterns to be excluded. This passed on to sphinx-apidoc command for exclude """ - print(f"In run apidoc params {docs_dir}, {agent_dirs}, {agent_excludes}, {exclude_pattern}") + print( + f"In run apidoc params {docs_dir}, {agent_dirs}, {agent_excludes}, {exclude_pattern}" + ) for agent_src_dir in agent_dirs: agent_src_dir = os.path.abspath(agent_src_dir) - agent_src_dir = agent_src_dir[:-1] if agent_src_dir.endswith("/") else agent_src_dir + agent_src_dir = agent_src_dir[:-1] if agent_src_dir.endswith( + "/") else agent_src_dir name = os.path.basename(agent_src_dir) agent_doc_dir = os.path.join(docs_dir, name) if name not in agent_excludes: sys.path.insert(0, agent_src_dir) - cmd = ["sphinx-apidoc", '-e', '-a', '-M', '-d 4', - '-t', os.path.join(script_dir, 'apidocs-templates'), - '--force', '-o', agent_doc_dir, agent_src_dir, - os.path.join(agent_src_dir, "setup.py"), os.path.join(agent_src_dir, "conftest.py") - ] + cmd = [ + "sphinx-apidoc", '-e', '-a', '-M', '-d 4', '-t', + os.path.join(script_dir, 'apidocs-templates'), '--force', '-o', + agent_doc_dir, agent_src_dir, + os.path.join(agent_src_dir, "setup.py"), + os.path.join(agent_src_dir, "conftest.py") + ] cmd.extend(exclude_pattern) subprocess.check_call(cmd) @@ -320,5 +370,6 @@ def clean_api_rst(app, exception): global apidocs_base_dir import shutil if os.path.exists(apidocs_base_dir): - print("Cleanup: Removing apidocs directory {}".format(apidocs_base_dir)) + print( + "Cleanup: Removing apidocs directory {}".format(apidocs_base_dir)) shutil.rmtree(apidocs_base_dir) diff --git a/docs/source/deploying-volttron/multi-platform/multi-platform-multi-bus.rst b/docs/source/deploying-volttron/multi-platform/multi-platform-multi-bus.rst index e58f9ed497..e01563c1c6 100644 --- a/docs/source/deploying-volttron/multi-platform/multi-platform-multi-bus.rst +++ b/docs/source/deploying-volttron/multi-platform/multi-platform-multi-bus.rst @@ -83,7 +83,7 @@ Platform agent, SQL historian agent and a Listener agent. The following shows an Is this the volttron you are attempting to setup? [Y]: What type of message bus (rmq/zmq)? [zmq]: rmq Name of this volttron instance: [volttron1]: central - RabbitMQ server home: [/home/user/rabbitmq_server/rabbitmq_server-3.9.7]: + RabbitMQ server home: [/home/user/rabbitmq_server/rabbitmq_server-3.9.29]: Fully qualified domain name of the system: [central]: Would you like to create a new self signed root CAcertificate for this instance: [Y]: @@ -95,7 +95,7 @@ Platform agent, SQL historian agent and a Listener agent. The following shows an Organization Unit: volttron Do you want to use default values for RabbitMQ home, ports, and virtual host: [Y]: 2020-04-13 13:29:36,347 rmq_setup.py INFO: Starting RabbitMQ server - 2020-04-13 13:29:46,528 rmq_setup.py INFO: Rmq server at /home/user/rabbitmq_server/rabbitmq_server-3.9.7 is running at + 2020-04-13 13:29:46,528 rmq_setup.py INFO: Rmq server at /home/user/rabbitmq_server/rabbitmq_server-3.9.29 is running at 2020-04-13 13:29:46,554 volttron.utils.rmq_mgmt DEBUG: Creating new VIRTUAL HOST: volttron 2020-04-13 13:29:46,582 volttron.utils.rmq_mgmt DEBUG: Create READ, WRITE and CONFIGURE permissions for the user: central-admin Create new exchange: volttron, {'durable': True, 'type': 'topic', 'arguments': {'alternate-exchange': 'undeliverable'}} @@ -108,7 +108,7 @@ Platform agent, SQL historian agent and a Listener agent. The following shows an 2020-04-13 13:29:46,601 rmq_setup.py INFO: Creating root ca with the following info: {'C': 'US', 'ST': 'WA', 'L': 'Richland', 'O': 'PNNL', 'OU': 'VOLTTRON', 'CN': 'central-root-ca'} Created CA cert 2020-04-13 13:29:49,668 rmq_setup.py INFO: **Stopped rmq server - 2020-04-13 13:30:00,556 rmq_setup.py INFO: Rmq server at /home/user/rabbitmq_server/rabbitmq_server-3.9.7 is running at + 2020-04-13 13:30:00,556 rmq_setup.py INFO: Rmq server at /home/user/rabbitmq_server/rabbitmq_server-3.9.29 is running at 2020-04-13 13:30:00,557 rmq_setup.py INFO: ####################### @@ -443,7 +443,7 @@ name is set to "collector2". Is this the volttron you are attempting to setup? [Y]: What type of message bus (rmq/zmq)? [zmq]: rmq Name of this volttron instance: [volttron1]: collector2 - RabbitMQ server home: [/home/user/rabbitmq_server/rabbitmq_server-3.9.7]: + RabbitMQ server home: [/home/user/rabbitmq_server/rabbitmq_server-3.9.29]: Fully qualified domain name of the system: [node-rmq]: Would you like to create a new self signed root CA certificate for this instance: [Y]: @@ -455,7 +455,7 @@ name is set to "collector2". Organization Unit: volttron Do you want to use default values for RabbitMQ home, ports, and virtual host: [Y]: 2020-04-13 13:29:36,347 rmq_setup.py INFO: Starting RabbitMQ server - 2020-04-13 13:29:46,528 rmq_setup.py INFO: Rmq server at /home/user/rabbitmq_server/rabbitmq_server-3.9.7 is running at + 2020-04-13 13:29:46,528 rmq_setup.py INFO: Rmq server at /home/user/rabbitmq_server/rabbitmq_server-3.9.29 is running at 2020-04-13 13:29:46,554 volttron.utils.rmq_mgmt DEBUG: Creating new VIRTUAL HOST: volttron 2020-04-13 13:29:46,582 volttron.utils.rmq_mgmt DEBUG: Create READ, WRITE and CONFIGURE permissions for the user: collector2-admin Create new exchange: volttron, {'durable': True, 'type': 'topic', 'arguments': {'alternate-exchange': 'undeliverable'}} @@ -468,7 +468,7 @@ name is set to "collector2". 2020-04-13 13:29:46,601 rmq_setup.py INFO: Creating root ca with the following info: {'C': 'US', 'ST': 'WA', 'L': 'Richland', 'O': 'PNNL', 'OU': 'VOLTTRON', 'CN': 'collector2-root-ca'} Created CA cert 2020-04-13 13:29:49,668 rmq_setup.py INFO: **Stopped rmq server - 2020-04-13 13:30:00,556 rmq_setup.py INFO: Rmq server at /home/user/rabbitmq_server/rabbitmq_server-3.9.7 is running at + 2020-04-13 13:30:00,556 rmq_setup.py INFO: Rmq server at /home/user/rabbitmq_server/rabbitmq_server-3.9.29 is running at 2020-04-13 13:30:00,557 rmq_setup.py INFO: ####################### diff --git a/docs/source/deploying-volttron/platform-configuration.rst b/docs/source/deploying-volttron/platform-configuration.rst index 569d86485c..b3b9f5f390 100644 --- a/docs/source/deploying-volttron/platform-configuration.rst +++ b/docs/source/deploying-volttron/platform-configuration.rst @@ -6,11 +6,11 @@ Platform Configuration Each instance of the VOLTTRON platform includes a `config` file which is used to configure the platform instance on startup. This file is kept in :term:`VOLTTRON_HOME` and is created using the `volttron-cfg` (`vcfg`) command, or will -be created with default values on start up of the platform otherwise. +be created with default values on start up of the platform otherwise. `vcfg` also provides commands to configure and +install few frequently used agents and update configuration-store entries Following is helpful information about the `config` file and the `vcfg` command. - VOLTTRON_HOME ============= @@ -75,9 +75,13 @@ The example consists of the following entries: VOLTTRON Config =============== -The `volttron-cfg` or `vcfg` command allows for an easy configuration of the VOLTTRON environment. The command includes -the ability to set up the platform configuration, an instance of the platform historian, VOLTTRON Central UI, and -VOLTTRON Central Platform agent. +The `volttron-cfg` or `vcfg` command allows for an easy configuration of the VOLTTRON environment. +The `vcfg` command can be run without any arguments to go through all available configuration steps sequentially and +pick what is appropriate for a given instance of VOLTTRON. This is useful when starting with a new VOLTTRON instance. + +`vcfg` command can also be used with specific subcommands to configure and install specific agents such as +listener agent, platform historian, VOLTTRON Central UI, and VOLTTRON Central Platform agent +or add one or more agent configurations to VOLTTRON's configuration store. Running `vcfg` will create a `config` file in `VOLTTRON_HOME` which will be populated according to the answers to prompts. This process should be repeated for each platform instance, and can be re-run to reconfigure a platform @@ -158,12 +162,52 @@ Optional Arguments - **-v, --verbose** - Enables verbose output in standard-output (PIP output, etc.) - **--vhome VHOME** - Provide a path to set `VOLTTRON_HOME` for this instance - **--instance-name INSTANCE_NAME** - Provide a name for this instance. Required for running secure agents mode - - **--list-agents** - Display a list of configurable agents (Listener, Platform Driver, Platform Historian, VOLTTRON - Central, VOLTTRON Central Platform) - - **--agent AGENT [AGENT ...]** - Configure listed agents - **--agent-isolation-mode** - Require that agents run as their own Unix users (this requires running `scripts/secure_user_permissions.sh` as `sudo`) +Sub commands +------------ +**--list-agents** +~~~~~~~~~~~~~~~~~~ + Display a list of configurable agents (Listener, Platform Driver, Platform Historian, VOLTTRON + Central, VOLTTRON Central Platform) + +**--agent AGENT [AGENT ...]** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configure and install one of the listed agents for a specific VOLTTRON instance + +**update-config-store --metadata-file METADATA_FILE_OR_DIR [METADATA_FILE_OR_DIR ...]** +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Command to bulk add/update multiple agent configurations to VOLTTRON's configuration store. This is especially useful +for automated deployment use cases. For example, a automated deployment setup where devices in a network are +detected, and configurations for platform driver and control agents such as ILCAgent are auto generated using semantic +tags. In such as scenario, adding all the generated configurations to the configuration store using the below command +is more efficient than running the "vctl config store" command once for each configuration + +This command can only be used when volttron instance is not running. + +Usage: + +.. code-block:: bash + + vcfg update-config-store --metadata-file + + +Format for Metadata file: + +.. code-block:: + + { "vip-id": [ + { + "config-name": "optional. name. defaults to config + "config": "json config or string config or config file name", + "config-type": "optional. type of config - csv or json or raw. defaults to json" + }, ... + ],... + } + + RabbitMQ Arguments ------------------ vcfg command to configure a single RabbitMQ instance of VOLTTRON. diff --git a/docs/source/deploying-volttron/secure-deployment-considerations.rst b/docs/source/deploying-volttron/secure-deployment-considerations.rst index 7d3719a333..ba5b97408e 100644 --- a/docs/source/deploying-volttron/secure-deployment-considerations.rst +++ b/docs/source/deploying-volttron/secure-deployment-considerations.rst @@ -179,3 +179,23 @@ system files outside of VOLTTRON_HOME For more information, refer to :ref:`Agent Isolation Mode: Running Users as unique Unix user`. +Non-Auth Implementation +======================= + +There may be some use-cases, such as simulating deployments or agent development, where security is not a consideration. +In these cases, it is possible to disable VOLTTRON's authentication and authorization, stripping away the security layer from the +VIP messagebus and simplifying agent connection and RPC communication. Since this is not ideal for any deployment, this can only +be done by manually modifying the volttron configuration file. + +Within the config file located within VOLTTRON_HOME, the allow-auth option must be added and set to False. + +.. code-block:: console + + [volttron] + message-bus = zmq + vip-address = tcp://127.0.0.1:22916 + instance-name = volttron1 + allow-auth = False + +In simulation environments where multiple volttron instances are used, it is important to ensure that auth settings are +the same across all instances. diff --git a/docs/source/developing-volttron/community.rst b/docs/source/developing-volttron/community.rst index 05f32dde04..24718c7d1c 100644 --- a/docs/source/developing-volttron/community.rst +++ b/docs/source/developing-volttron/community.rst @@ -12,18 +12,10 @@ Contributing back to the project, which is encouraged but not required, enhances To learn more, check out :ref:`Contributing ` and :ref:`Documentation `. -Slack Channel -============= - -volttron-community.slack.com is where the |VOLTTRON| community at large can ask questions and meet with others -using |VOLTTRON|. To be added to Slack please email the VOLTTRON team at -`volttron@pnnl.gov `__. - - Mailing List ============ -Join the mailing list by emailing `volttron@pnnl.gov `__. +Join the mailing list at Eclipse: https://projects.eclipse.org/projects/iot.volttron/contact Stack Overflow @@ -39,8 +31,8 @@ Office Hours PNNL hosts office hours every other week on Fridays at 11 AM (PST). These meetings are designed to be very informal where VOLTTRON developers can answer specific questions about the inner workings of VOLTTRON. These meetings are also available for topical discussions of different aspects of the VOLTTRON platform. Currently the office hours are -available through a Zoom meeting. To be invited to the link meeting, contact the volttron team via email: -``__ +available through a Zoom meeting. All members of the mailing list will receive invites to the meetings. Join the +mailing list https://projects.eclipse.org/projects/iot.volttron/contact. Meetings are recorded and can be reviewed `here `__. diff --git a/docs/source/developing-volttron/developing-agents/agent-development.rst b/docs/source/developing-volttron/developing-agents/agent-development.rst index 69b87b78ca..92cec9a8f7 100644 --- a/docs/source/developing-volttron/developing-agents/agent-development.rst +++ b/docs/source/developing-volttron/developing-agents/agent-development.rst @@ -918,7 +918,7 @@ VOLTTRON uses *pytest* as a framework for executing tests. All unit tests shoul For instructions on writing unit and integration tests with *pytest*, refer to the :ref:`Writing Agent Tests ` documentation. -*pytest* is not installed with the distribution by default. To install py.test and it's dependencies execute the +*pytest* is not installed with the distribution by default. To install pytest and it's dependencies execute the following: .. code-block:: bash diff --git a/docs/source/developing-volttron/developing-agents/example-agents/scheduler-example-agent.rst b/docs/source/developing-volttron/developing-agents/example-agents/scheduler-example-agent.rst index 83817ae8e8..36939d3535 100644 --- a/docs/source/developing-volttron/developing-agents/example-agents/scheduler-example-agent.rst +++ b/docs/source/developing-volttron/developing-agents/example-agents/scheduler-example-agent.rst @@ -41,7 +41,7 @@ The agent listens to schedule announcements from the actuator and then issues a @PubSub.subscribe('pubsub', topics.ACTUATOR_SCHEDULE_ANNOUNCE(campus='campus', building='building',unit='unit')) def actuate(self, peer, sender, bus, topic, headers, message): - print ("response:",topic,headers,message) + print("response:", topic, headers, message) if headers[headers_mod.REQUESTER_ID] != agent_id: return '''Match the announce for our fake device with our ID diff --git a/docs/source/developing-volttron/development-environment/pycharm/index.rst b/docs/source/developing-volttron/development-environment/pycharm/index.rst index c2044d04d0..1001ff61eb 100644 --- a/docs/source/developing-volttron/development-environment/pycharm/index.rst +++ b/docs/source/developing-volttron/development-environment/pycharm/index.rst @@ -6,7 +6,7 @@ Pycharm Development Environment Pycharm is an IDE dedicated to developing python projects. It provides coding assistance and easy access to debugging tools as well as integration with -py.test. It is a popular tool for working with VOLTTRON. +pytest. It is a popular tool for working with VOLTTRON. Jetbrains provides a free community version that can be downloaded from https://www.jetbrains.com/pycharm/ @@ -98,8 +98,8 @@ top level source directory; git will ignore changes to these files. Testing an Agent ---------------- -Agent tests written in py.test can be run simply by right-clicking the tests -directory and selecting `Run 'py.test in tests`, so long as the root directory +Agent tests written in pytest can be run simply by right-clicking the tests +directory and selecting `Run 'pytest in tests`, so long as the root directory is set as the VOLTTRON source root. |Run Tests| diff --git a/docs/source/index.rst b/docs/source/index.rst index 6bdc1ac7a2..83b1b4b283 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -150,6 +150,15 @@ at our bi-weekly office-hours and on Slack. To be invited to office-hours or sla tutorials/quick-start + +.. toctree:: + :caption: Tutorials + :hidden: + :titlesonly: + :maxdepth: 1 + + tutorials/quick-start + Indices and tables ================== diff --git a/docs/source/introduction/platform-install.rst b/docs/source/introduction/platform-install.rst index c17e1f0d74..5b77d8ae82 100644 --- a/docs/source/introduction/platform-install.rst +++ b/docs/source/introduction/platform-install.rst @@ -194,37 +194,40 @@ Step 2 - Install Erlang packages For RabbitMQ based VOLTTRON, some of the RabbitMQ specific software packages have to be installed. +Install Erlang pre-requisites ++++++++++++++++++++++++++++++ +.. code-block:: bash + sudo apt-get update + sudo apt-get install -y gnupg apt-transport-https libsctp1 libncurses5 -On Debian based systems and CentOS 8 -"""""""""""""""""""""""""""""""""""" +Please note there could be other pre-requisites that erlang requires based on the version of Erlang and OS. If there are other pre-requisites required, install of erlang should fail with appropriate error message. -If you are running a Debian or CentOS 8 system, you can install the RabbitMQ dependencies by running the -"rabbit_dependencies.sh" script, passing in the OS name and appropriate distribution as parameters. The -following are supported: +Purge previous versions of Erlang ++++++++++++++++++++++++++++++++++ -* `debian bionic` (for Ubuntu 18.04) +.. code-block:: bash -* `debian focal` (for Ubuntu 20.04) + sudo apt-get purge -yf erlang-base +Install Erlang +++++++++++++++ -Example command: +Download and install ErlangOTP from [Erlang Solutions](https://www.erlang-solutions.com/downloads/). +RMQ uses components - ssl, public_key, asn1, and crypto. These are by default included in the OTP +RabbitMQ 3.9.29 is compatible with Erlang versions 24.3.4.2 to 25.2. VOLTTRON was tested with Erlang version 25.2-1 +Example: Ubuntu 22.04 .. code-block:: bash - ./scripts/rabbit_dependencies.sh debian xenial - + wget https://binaries2.erlang-solutions.com/ubuntu/pool/contrib/e/esl-erlang/esl-erlang_25.2-1~ubuntu~jammy_amd64.deb + sudo dpkg -i esl-erlang_25.2-1~ubuntu~jammy_amd64.deb -Alternatively -""""""""""""" -You can download and install Erlang from `Erlang Solutions `_. -Please include OTP/components - ssl, public_key, asn1, and crypto. -Also lock your version of Erlang using the `yum-plugin-versionlock `_. +Example: Ubuntu 20.04 +.. code-block:: bash -.. note:: - Currently VOLTTRON only officially supports specific versions of Erlang for each operating system: - * 1:24.1.7-1 for Debian - * 24.2-1.el8 for CentOS 8 + wget https://binaries2.erlang-solutions.com/ubuntu/pool/contrib/e/esl-erlang/esl-erlang_25.2-1~ubuntu~focal_amd64.deb + sudo dpkg -i esl-erlang_25.2-1~ubuntu~focal_amd64.deb Step 3 - Configure hostname @@ -246,10 +249,14 @@ to connect to empd (port 4369) on ." Step 4 - Bootstrap the environment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Remove older version of rabbitmq_server directory if you are upgrading from a older version. Defaults to +/rabbitmq_server/rabbitmq_server-3.9.7 +Run the rabbitmq bootstrap step from within an VOLTTRON activated environment. .. code-block:: bash cd volttron + source env/bin/activate python3 bootstrap.py --rabbitmq [optional install directory. defaults to /rabbitmq_server] This will build the platform and create a virtual Python environment and dependencies for RabbitMQ. It also installs @@ -272,11 +279,11 @@ Thus, you can use $RABBITMQ_HOME to see if the RabbitMQ server is installed by c .. note:: The `RABBITMQ_HOME` environment variable can be set in ~/.bashrc. If doing so, it needs to be set to the RabbitMQ - installation directory (default path is `/rabbitmq_server/rabbitmq_server-3.9.7`) + installation directory (default path is `/rabbitmq_server/rabbitmq_server-3.9.29`) .. code-block:: bash - echo 'export RABBITMQ_HOME=$HOME/rabbitmq_server/rabbitmq_server-3.9.7'|sudo tee --append ~/.bashrc + echo 'export RABBITMQ_HOME=$HOME/rabbitmq_server/rabbitmq_server-3.9.29'|sudo tee --append ~/.bashrc source ~/.bashrc $RABBITMQ_HOME/sbin/rabbitmqctl status @@ -334,7 +341,7 @@ prompts for necessary details. Is this the volttron you are attempting to setup? [Y]: Creating rmq config yml - RabbitMQ server home: [/home/vdev/rabbitmq_server/rabbitmq_server-3.9.7]: + RabbitMQ server home: [/home/vdev/rabbitmq_server/rabbitmq_server-3.9.29]: Fully qualified domain name of the system: [cs_cbox.pnl.gov]: Enable SSL Authentication: [Y]: @@ -354,7 +361,7 @@ prompts for necessary details. https port for the RabbitMQ management plugin: [15671]: INFO:rmq_setup.pyc:Starting rabbitmq server Warning: PID file not written; -detached was passed. - INFO:rmq_setup.pyc:**Started rmq server at /home/vdev/rabbitmq_server/rabbitmq_server-3.9.7 + INFO:rmq_setup.pyc:**Started rmq server at /home/vdev/rabbitmq_server/rabbitmq_server-3.9.29 INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost @@ -368,7 +375,7 @@ prompts for necessary details. INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): localhost INFO:rmq_setup.pyc:**Stopped rmq server Warning: PID file not written; -detached was passed. - INFO:rmq_setup.pyc:**Started rmq server at /home/vdev/rabbitmq_server/rabbitmq_server-3.9.7 + INFO:rmq_setup.pyc:**Started rmq server at /home/vdev/rabbitmq_server/rabbitmq_server-3.9.29 INFO:rmq_setup.pyc: ####################### diff --git a/docs/source/platform-features/config-store/agent-configuration-store.rst b/docs/source/platform-features/config-store/agent-configuration-store.rst index fbf55ecd3c..aea72e2ac6 100644 --- a/docs/source/platform-features/config-store/agent-configuration-store.rst +++ b/docs/source/platform-features/config-store/agent-configuration-store.rst @@ -312,36 +312,66 @@ Platform RPC Methods -------------------- -Methods for Agents -^^^^^^^^^^^^^^^^^^ - -Agent methods that change configurations do not trigger any callbacks unless trigger_callback is True. - -**set_config(config_name, contents, trigger_callback=False)** - Change/create a configuration file on the platform. +**set_config(identity, config_name, contents, config_type="raw", trigger_callback=True, send_update=True)** - +Change/create a configuration on the platform for an agent with the specified identity. Requires the +authorization capability 'edit_config_store'. By default agents have access to edit only their own config store entries. + +**manage_store(identity, config_name, contents, config_type="raw", trigger_callback=True, send_update=True)** - +Deprecated method. Please use set_config instead. Will be removed in VOLTTRON version 10. +Change/create a configuration on the platform for an agent with the specified identity. Requires the +authorization capability 'edit_config_store'. By default agents have access to edit only their own config store entries. + +**delete_config(identity, config_name, trigger_callback=True, send_update=True)** - Delete a configuration for an +agent with the specified identity. Requires the authorization capability 'edit_config_store'. By default agents have +access to edit only their own config store entries. + +**manage_delete_config(identity, config_name, trigger_callback=True, send_update=True)** - +Deprecated method. Please use delete_config instead. Will be removed in VOLTTRON version 10. +Delete a configuration for an agent with the specified identity. Requires the authorization capability +'edit_config_store'. By default agents have access to edit only their own config store entries. + +**delete_store(identity)** - Delete all configurations for an agent with the specified identity. Requires the +authorization capability 'edit_config_store'. By default agents have access to edit only their own config store entries. +Calls the agent's update_config with the action `DELETE_ALL` and no configuration name. -**get_configs()** - Get all of the configurations for an Agent. +**manage_delete_store(identity)** - +Deprecated method. Please use delete_store instead. Will be removed in VOLTTRON version 10. +Delete all configurations for an agent with the specified identity. Requires the +authorization capability 'edit_config_store'. By default agents have access to edit only their own config store entries. +Calls the agent's update_config with the action `DELETE_ALL` and no configuration name. -**delete_config(config_name, trigger_callback=False)** - Delete a configuration. +**list_configs(identity)** - Get a list of configurations for an agent with the specified identity. +**manage_list_configs(identity)** - +Deprecated method. Please use list_configs instead. Will be removed in VOLTTRON version 10. +Get a list of configurations for an agent with the specified identity. -Methods for Management -^^^^^^^^^^^^^^^^^^^^^^ +**list_stores()** - Get a list of all the agents with configurations. -**manage_store_config(identity, config_name, contents, config_type="raw")** - Change/create a configuration on the -platform for an agent with the specified identity +**manage_list_stores()** - +Deprecated method. Please use list_stores instead. Will be removed in VOLTTRON version 10. +Get a list of all the agents with configurations. -**manage_delete_config(identity, config_name)** - Delete a configuration for an agent with the specified identity. -Calls the agent's update_config with the action `DELETE_ALL` and no configuration name. -**manage_delete_store(identity)** - Delete all configurations for a :term:`VIP Identity`. +**get_config(identity, config_name, raw=True)** - Get the contents of a configuration file. If raw is set to +`True` this function will return the original file, otherwise it will return the parsed representation of the file. -**manage_list_config(identity)** - Get a list of configurations for an agent with the specified identity. +**manage_get_config(identity, config_name, raw=True)** - +Deprecated method. Please use get_config instead. Will be removed in VOLTTRON version 10. +Get the contents of a configuration file. If raw is set to `True` this function will return the original file, +otherwise it will return the parsed representation of the file. -**manage_get_config(identity, config_name, raw=True)** - Get the contents of a configuration file. If raw is set to -`True` this function will return the original file, otherwise it will return the parsed representation of the file. +**initialize_configs(identity)** - Called by an Agent at startup to trigger initial configuration state push. +Requires the authorization capability 'edit_config_store'. By default agents have access to edit only their own +config store entries. -**manage_list_stores()** - Get a list of all the agents with configurations. +**get_metadata(identity, config_name)** - Get the metadata of configuration named *config_name* of agent +identified by *identity*. Returns the type(json, csv, raw) of the configuration, modified date and actual content +**manage_get_metadata(identity, config_name)** - +Deprecated method. Please use get_metadata instead. Will be removed in VOLTTRON version 10. +Get the metadata of configuration named *config_name* of agent +identified by *identity*. Returns the type(json, csv, raw) of the configuration, modified date and actual content Direct Call Methods ^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/platform-features/message-bus/rabbitmq/rabbitmq-ssl-auth.rst b/docs/source/platform-features/message-bus/rabbitmq/rabbitmq-ssl-auth.rst index 5549b6beaf..37fc7efdc3 100644 --- a/docs/source/platform-features/message-bus/rabbitmq/rabbitmq-ssl-auth.rst +++ b/docs/source/platform-features/message-bus/rabbitmq/rabbitmq-ssl-auth.rst @@ -14,7 +14,7 @@ configurations can be seen by running the following command: .. code-block:: bash - cat ~/rabbitmq_server/rabbitmq_server-3.9.7/etc/rabbitmq/rabbitmq.conf + cat ~/rabbitmq_server/rabbitmq_server-3.9.29/etc/rabbitmq/rabbitmq.conf The configurations required to enable SSL: @@ -78,8 +78,8 @@ To configure RabbitMQ-VOLTTRON to use SSL based authentication, we need to add S # defaults to true ssl: 'true' - # defaults to ~/rabbitmq_server/rabbbitmq_server-3.9.7 - rmq-home: "~/rabbitmq_server/rabbitmq_server-3.9.7" + # defaults to ~/rabbitmq_server/rabbbitmq_server-3.9.29 + rmq-home: "~/rabbitmq_server/rabbitmq_server-3.9.29" The parameters of interest for SSL based configuration are diff --git a/docs/source/platform-features/message-bus/rabbitmq/rabbitmq-volttron.rst b/docs/source/platform-features/message-bus/rabbitmq/rabbitmq-volttron.rst index 249b382cd7..5d29152ee1 100644 --- a/docs/source/platform-features/message-bus/rabbitmq/rabbitmq-volttron.rst +++ b/docs/source/platform-features/message-bus/rabbitmq/rabbitmq-volttron.rst @@ -56,8 +56,8 @@ Path: `$VOLTTRON_HOME/rabbitmq_config.yml` # defaults to true ssl: 'true' - # defaults to ~/rabbitmq_server/rabbbitmq_server-3.9.7 - rmq-home: "~/rabbitmq_server/rabbitmq_server-3.9.7" + # defaults to ~/rabbitmq_server/rabbbitmq_server-3.9.29 + rmq-home: "~/rabbitmq_server/rabbitmq_server-3.9.29" Each VOLTTRON instance resides within a RabbitMQ virtual host. The name of the virtual host needs to be unique per VOLTTRON instance if there are multiple virtual instances within a single host/machine. The hostname needs to be able diff --git a/examples/CAgent/c_agent/agent.py b/examples/CAgent/c_agent/agent.py index 0d44579ff5..ceab4b456a 100644 --- a/examples/CAgent/c_agent/agent.py +++ b/examples/CAgent/c_agent/agent.py @@ -1,47 +1,33 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from ctypes import CDLL, cdll, c_float from datetime import datetime import logging -import sys import os +import sys from volttron.platform.vip.agent import Agent, Core, PubSub, compat from volttron.platform.agent import utils diff --git a/examples/CAgent/c_agent/driver/cdriver.py b/examples/CAgent/c_agent/driver/cdriver.py index 59e63b123f..044bac3ebf 100644 --- a/examples/CAgent/c_agent/driver/cdriver.py +++ b/examples/CAgent/c_agent/driver/cdriver.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} __docformat__ = 'reStructuredText' @@ -70,7 +56,7 @@ def so_lookup_function(shared_object, function_name): return function class CRegister(BaseRegister): - def __init__(self,read_only, pointName, units, description = ''): + def __init__(self, read_only, pointName, units, description=''): super(CRegister, self).__init__("byte", read_only, pointName, units, description = '') diff --git a/examples/CAgent/setup.py b/examples/CAgent/setup.py index 9e23adad76..7af7170053 100644 --- a/examples/CAgent/setup.py +++ b/examples/CAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os diff --git a/examples/CSVDriver/csvdriver.py b/examples/CSVDriver/csvdriver.py index f06ac60c78..81a1791df6 100644 --- a/examples/CSVDriver/csvdriver.py +++ b/examples/CSVDriver/csvdriver.py @@ -1,45 +1,33 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2017, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} -import os -from platform_driver.interfaces import BaseInterface, BaseRegister, BasicRevert from csv import DictReader, DictWriter import logging +import os + +from platform_driver.interfaces import BaseInterface, BaseRegister, BasicRevert + # Use the csv fields and default dictionary to create a CSV "device" for testing CSV_FIELDNAMES = ["Point Name", "Point Value"] diff --git a/examples/CSVHistorian/csv_historian/historian.py b/examples/CSVHistorian/csv_historian/historian.py index ed08a94410..32096d02f6 100644 --- a/examples/CSVHistorian/csv_historian/historian.py +++ b/examples/CSVHistorian/csv_historian/historian.py @@ -1,50 +1,35 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} +import csv +import logging import os import sys -import logging from volttron.platform.agent import utils from volttron.platform.agent.base_historian import BaseHistorian -import csv - utils.setup_logging() _log = logging.getLogger(__name__) diff --git a/examples/CSVHistorian/setup.py b/examples/CSVHistorian/setup.py index 203cd3945b..4b94fd8659 100644 --- a/examples/CSVHistorian/setup.py +++ b/examples/CSVHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/ConfigActuation/config_actuation/agent.py b/examples/ConfigActuation/config_actuation/agent.py index 273c1dc220..8ffe4b6da6 100644 --- a/examples/ConfigActuation/config_actuation/agent.py +++ b/examples/ConfigActuation/config_actuation/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime diff --git a/examples/ConfigActuation/setup.py b/examples/ConfigActuation/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/ConfigActuation/setup.py +++ b/examples/ConfigActuation/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/ConfigActuation/tests/test_config_actuation.py b/examples/ConfigActuation/tests/test_config_actuation.py index 9fd17c1f3f..07455c99e7 100644 --- a/examples/ConfigActuation/tests/test_config_actuation.py +++ b/examples/ConfigActuation/tests/test_config_actuation.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -87,7 +73,7 @@ def publish_agent(request, volttron_instance): assert process.returncode == 0 # Add platform driver configuration files to config store. - cmd = ['volttron-ctl', 'config', 'store',PLATFORM_DRIVER, + cmd = ['volttron-ctl', 'config', 'store', PLATFORM_DRIVER, 'fake.csv', 'fake_unit_testing.csv', '--csv'] process = Popen(cmd, env=volttron_instance.env, cwd='scripts/scalability-testing', @@ -157,7 +143,7 @@ def test_thing(publish_agent): assert value == 10.0 publish_agent.vip.rpc.call(CONFIGURATION_STORE, - "manage_store", + "set_config", "config_actuation", "fakedriver", jsonapi.dumps({"SampleWritableFloat1": 42.0}), diff --git a/examples/ConfigActuation/update_config.py b/examples/ConfigActuation/update_config.py index abf1ebc774..593d7e0a62 100644 --- a/examples/ConfigActuation/update_config.py +++ b/examples/ConfigActuation/update_config.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """Script for adding or updating a JSON file in an agent's @@ -97,21 +83,21 @@ def main(): agent = build_agent(**get_keys()) files = agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_list_configs', + 'list_configs', vip_id).get(timeout=10) if filename not in files: config = {key: value} else: config = agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_get', + 'get_config', vip_id, filename).get(timeout=10) config = jsonapi.loads(config) config[key] = value agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', vip_id, filename, jsonapi.dumps(config), diff --git a/examples/DDSAgent/ddsagent/agent.py b/examples/DDSAgent/ddsagent/agent.py index 1768f2fd8d..d1db5ddd81 100644 --- a/examples/DDSAgent/ddsagent/agent.py +++ b/examples/DDSAgent/ddsagent/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime diff --git a/examples/DataCleaner/data_cleaner/agent.py b/examples/DataCleaner/data_cleaner/agent.py index c80bab3579..d5cb346890 100644 --- a/examples/DataCleaner/data_cleaner/agent.py +++ b/examples/DataCleaner/data_cleaner/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} __docformat__ = 'reStructuredText' @@ -198,7 +184,7 @@ def process_point(self, now, topic, min_value=None, max_value=None, output_topic def main(): """Main method called to start the agent.""" - utils.vip_main(data_cleaner, + utils.vip_main(data_cleaner, version=__version__) diff --git a/examples/DataPublisher/datapublisher/agent.py b/examples/DataPublisher/datapublisher/agent.py index b461c1911c..6ae9fb5f74 100644 --- a/examples/DataPublisher/datapublisher/agent.py +++ b/examples/DataPublisher/datapublisher/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import csv import datetime @@ -41,14 +27,15 @@ import re import sys -from volttron.platform.vip.agent import * from volttron.platform.agent import utils from volttron.platform.messaging.utils import normtopic from volttron.platform.messaging import headers as headers_mod +from volttron.platform.vip.agent import Agent, RPC import gevent from collections import defaultdict + utils.setup_logging() _log = logging.getLogger(__name__) __version__ = '4.0.0' @@ -93,7 +80,7 @@ def DataPub(config_path, **kwargs): # unittype_map maps the point name to the proper units. unittype_map = conf.get('unittype_map', {}) - + # should we keep playing the file over and over again. replay_data = conf.get('replay_data', False) @@ -272,7 +259,7 @@ def build_publish_with_meta(self, row): meta_results[topic][point] = self._meta_data[topic][point] except ValueError: _log.error(f"Missing parseable float value for topic {topic}/{point}") - + return results, meta_results def check_frequency(self, now): @@ -317,7 +304,7 @@ def publish_loop(self): continue self._line_marker += 1 - + if self._use_timestamp and "Timestamp" in row: now = row['Timestamp'] if not self.check_frequency(now): diff --git a/examples/DataPublisher/setup.py b/examples/DataPublisher/setup.py index cb5acdb326..86d2806539 100644 --- a/examples/DataPublisher/setup.py +++ b/examples/DataPublisher/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/DataPuller/puller/agent.py b/examples/DataPuller/puller/agent.py index 18e897ae85..50bfa2a06e 100644 --- a/examples/DataPuller/puller/agent.py +++ b/examples/DataPuller/puller/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -139,7 +125,7 @@ def on_message(self, peer, sender, bus, topic, headers, message): _log.debug("data in capture_data {}".format(data)) if isinstance(data, dict): data = data - elif isinstance(data, (int,float)): + elif isinstance(data, (int, float)): data = data # else: # data = data[0] diff --git a/examples/DataPuller/setup.py b/examples/DataPuller/setup.py index 65bf2b0a14..e671e235b2 100644 --- a/examples/DataPuller/setup.py +++ b/examples/DataPuller/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from setuptools import setup, find_packages diff --git a/examples/EnergyPlusAgent/energyplus/agent.py b/examples/EnergyPlusAgent/energyplus/agent.py index 3535fd6ac8..cb661eaac5 100644 --- a/examples/EnergyPlusAgent/energyplus/agent.py +++ b/examples/EnergyPlusAgent/energyplus/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -362,29 +348,28 @@ def check_advance(self): timestep = int(60 / self.EnergyPlus_sim.timestep) if not self.EnergyPlus_sim.real_time_flag: - self.cosim_sync_counter += timestep - if self.cosim_sync_counter < self.EnergyPlus_sim.co_sim_timestep: + self.EnergyPlus_sim.cosim_sync_counter += timestep + if self.EnergyPlus_sim.cosim_sync_counter < self.EnergyPlus_sim.co_sim_timestep: self.advance_simulation(None, None, None, None, None, None) else: - self.cosim_sync_counter = 0 + self.EnergyPlus_sim.cosim_sync_counter = 0 self.vip.pubsub.publish('pubsub', self.tns_actuate, headers={}, message={}).get(timeout=10) - else: - if self.EnergyPlus_sim.hour > self.EnergyPlus_sim.currenthour or self.EnergyPlus_sim.passtime: - self.EnergyPlus_sim.passtime = True - self.cosim_sync_counter += timestep - if self.cosim_sync_counter < self.EnergyPlus_sim.co_sim_timestep: - self.advance_simulation(None, None, None, None, None, None) - else: - self.cosim_sync_counter = 0 - self.vip.pubsub.publish('pubsub', - self.tns_actuate, - headers={}, - message={}).get(timeout=10) - else: + elif self.EnergyPlus_sim.hour > self.EnergyPlus_sim.currenthour or self.EnergyPlus_sim.passtime: + self.EnergyPlus_sim.passtime = True + self.EnergyPlus_sim.cosim_sync_counter += timestep + if self.EnergyPlus_sim.cosim_sync_counter < self.EnergyPlus_sim.co_sim_timestep: self.advance_simulation(None, None, None, None, None, None) + else: + self.EnergyPlus_sim.cosim_sync_counter = 0 + self.vip.pubsub.publish('pubsub', + self.tns_actuate, + headers={}, + message={}).get(timeout=10) + else: + self.advance_simulation(None, None, None, None, None, None) return diff --git a/examples/EnergyPlusAgent/ep_building1.config b/examples/EnergyPlusAgent/ep_building1.config index aeb4109e59..dec08275d4 100644 --- a/examples/EnergyPlusAgent/ep_building1.config +++ b/examples/EnergyPlusAgent/ep_building1.config @@ -1,3041 +1,3041 @@ { - "properties": { - "identity": "platform.actuator", - "model": "~/git/volttron/eplus/BUILDING1.idf", - "weather": "~/git/volttron/eplus/USA_WA_Pasco-Tri.Cities.AP.727845_TMY3.epw", - "bcvtb_home": "~/git/volttron/bcvtb", - "size" :40960, - "startmonth":8, - "startday":1, - "endmonth":8, - "endday":31, - "timestep":60, - "time_scale": 6, - "cosimulation_sync": true, - "realtime": true, - "co_sim_timestep": 5, - "real_time_flag": false - }, - "inputs": { - "CLGTEMPSETPOINT Zone-VAV-102": { - "name": "CLGTEMPSETPOINT Zone-VAV-102", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV102", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-118": { - "name": "CLGTEMPSETPOINT Zone-VAV-118", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV118", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-119": { - "name": "CLGTEMPSETPOINT Zone-VAV-119", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV119", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-120": { - "name": "CLGTEMPSETPOINT Zone-VAV-120", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV120", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-123A": { - "name": "CLGTEMPSETPOINT Zone-VAV-123A", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV123A", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-123B": { - "name": "CLGTEMPSETPOINT Zone-VAV-123B", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV123B", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-127A": { - "name": "CLGTEMPSETPOINT Zone-VAV-127A", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV127A", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-127B": { - "name": "CLGTEMPSETPOINT Zone-VAV-127B", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV127B", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-129": { - "name": "CLGTEMPSETPOINT Zone-VAV-129", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV129", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-131": { - "name": "CLGTEMPSETPOINT Zone-VAV-131", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV131", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-133": { - "name": "CLGTEMPSETPOINT Zone-VAV-133", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV133", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-136": { - "name": "CLGTEMPSETPOINT Zone-VAV-136", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV136", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-142": { - "name": "CLGTEMPSETPOINT Zone-VAV-142", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV142", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-143": { - "name": "CLGTEMPSETPOINT Zone-VAV-143", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV143", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-150": { - "name": "CLGTEMPSETPOINT Zone-VAV-150", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV150", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-100": { - "name": "CLGTEMPSETPOINT Zone-VAV-CORRIDOR", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV100", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-121": { - "name": "CLGTEMPSETPOINT Zone-VAV-RESTROOM", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU1/VAV121", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-104": { - "name": "CLGTEMPSETPOINT Zone-VAV-104", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU3/VAV104", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-105": { - "name": "CLGTEMPSETPOINT Zone-VAV-105", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU3/VAV105", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-107": { - "name": "CLGTEMPSETPOINT Zone-VAV-107", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU3/VAV107", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-108": { - "name": "CLGTEMPSETPOINT Zone-VAV-108", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU3/VAV108", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-112": { - "name": "CLGTEMPSETPOINT Zone-VAV-112", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU3/VAV112", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-VAV-116": { - "name": "CLGTEMPSETPOINT Zone-VAV-116", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU3/VAV116", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-AHU-002": { - "name": "CLGTEMPSETPOINT Zone-AHU-002", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU2", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "CLGTEMPSETPOINT Zone-AHU-004": { - "name": "CLGTEMPSETPOINT Zone-AHU-004", - "type": "schedule", - "topic": "PNNL/BUILDING1/AHU4", - "field": "ZoneCoolingTemperatureSetPoint", - "default": 21.11, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-102": { - "name": "BLDG LIGHT SCH Zone-VAV-102", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE102", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-104": { - "name": "BLDG LIGHT SCH Zone-VAV-104", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE104", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-105": { - "name": "BLDG LIGHT SCH Zone-VAV-105", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE105", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-107": { - "name": "BLDG LIGHT SCH Zone-VAV-107", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE107", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-108": { - "name": "BLDG LIGHT SCH Zone-VAV-108", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE108", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-112": { - "name": "BLDG LIGHT SCH Zone-VAV-112", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE112", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-116": { - "name": "BLDG LIGHT SCH Zone-VAV-116", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE116", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-118": { - "name": "BLDG LIGHT SCH Zone-VAV-118", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE118", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-119": { - "name": "BLDG LIGHT SCH Zone-VAV-119", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE119", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-120": { - "name": "BLDG LIGHT SCH Zone-VAV-120", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE120", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-123A": { - "name": "BLDG LIGHT SCH Zone-VAV-123A", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE123A", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-123B": { - "name": "BLDG LIGHT SCH Zone-VAV-123B", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE123B", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-127A": { - "name": "BLDG LIGHT SCH Zone-VAV-127A", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE127A", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-127B": { - "name": "BLDG LIGHT SCH Zone-VAV-127B", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE127B", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-129": { - "name": "BLDG LIGHT SCH Zone-VAV-129", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE129", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-131": { - "name": "BLDG LIGHT SCH Zone-VAV-131", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE131", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-133": { - "name": "BLDG LIGHT SCH Zone-VAV-133", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE133", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-142": { - "name": "BLDG LIGHT SCH Zone-VAV-142", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE142", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-143": { - "name": "BLDG LIGHT SCH Zone-VAV-143", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE143", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-150": { - "name": "BLDG LIGHT SCH Zone-VAV-150", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE150", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - }, - "BLDG LIGHT SCH Zone-VAV-136": { - "name": "BLDG LIGHT SCH Zone-VAV-136", - "type": "schedule", - "topic": "PNNL/BUILDING1/LIGHTING/ZONE136", - "field": "DimmingLevelOutput", - "default": 1.0, - "dynamic_default": 1.0 - } - }, - "outputs": { - "ENVIRONMENT Site Outdoor Air Drybulb Temperature1": { - "name": "ENVIRONMENT", - "type": "Site Outdoor Air Drybulb Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/all", - "field": "OutdoorAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "ENVIRONMENT Site Outdoor Air Drybulb Temperature2": { - "name": "ENVIRONMENT", - "type": "Site Outdoor Air Drybulb Temperature", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "OutdoorAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "ENVIRONMENT Site Outdoor Air Drybulb Temperature3": { - "name": "ENVIRONMENT", - "type": "Site Outdoor Air Drybulb Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/all", - "field": "OutdoorAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "ENVIRONMENT Site Outdoor Air Drybulb Temperature4": { - "name": "ENVIRONMENT", - "type": "Site Outdoor Air Drybulb Temperature", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "OutdoorAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-102 Zone Mean Air Temperature": { - "name": "Zone-VAV-102", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-118 Zone Mean Air Temperature": { - "name": "Zone-VAV-118", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-119 Zone Mean Air Temperature": { - "name": "Zone-VAV-119", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-120 Zone Mean Air Temperature": { - "name": "Zone-VAV-120", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123A Zone Mean Air Temperature": { - "name": "Zone-VAV-123A", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123B Zone Mean Air Temperature": { - "name": "Zone-VAV-123B", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127A Zone Mean Air Temperature": { - "name": "Zone-VAV-127A", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127B Zone Mean Air Temperature": { - "name": "Zone-VAV-127B", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-129 Zone Mean Air Temperature": { - "name": "Zone-VAV-129", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-131 Zone Mean Air Temperature": { - "name": "Zone-VAV-131", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-133 Zone Mean Air Temperature": { - "name": "Zone-VAV-133", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-136 Zone Mean Air Temperature": { - "name": "Zone-VAV-136", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-142 Zone Mean Air Temperature": { - "name": "Zone-VAV-142", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-143 Zone Mean Air Temperature": { - "name": "Zone-VAV-143", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-150 Zone Mean Air Temperature": { - "name": "Zone-VAV-150", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-100 Zone Mean Air Temperature": { - "name": "Zone-VAV-CORRIDOR", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-121 Zone Mean Air Temperature": { - "name": "Zone-VAV-RESTROOM", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-104 Zone Mean Air Temperature": { - "name": "Zone-VAV-104", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-105 Zone Mean Air Temperature": { - "name": "Zone-VAV-105", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-107 Zone Mean Air Temperature": { - "name": "Zone-VAV-107", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-108 Zone Mean Air Temperature": { - "name": "Zone-VAV-108", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-112 Zone Mean Air Temperature": { - "name": "Zone-VAV-112", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-116 Zone Mean Air Temperature": { - "name": "Zone-VAV-116", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-AHU-002 Zone Mean Air Temperature": { - "name": "Zone-AHU-002", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-AHU-004 Zone Mean Air Temperature": { - "name": "Zone-AHU-004", - "type": "Zone Mean Air Temperature", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "ZoneTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-Corridor VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-Corridor VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-102 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-102 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-104 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-104 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-105 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-105 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-107 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-107 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-108 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-108 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-112 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-112 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-116 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-116 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-118 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-118 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-119 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-119 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-120 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-120 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123A VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-123A VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123B VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-123B VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127A VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-127A VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127B VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-127B VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-129 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-129 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-131 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-131 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-133 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-133 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-136 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-136 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-142 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-142 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-143 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-143 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-150 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-150 VAV BOX COMPONENT", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-Restroom VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { - "name": "Zone-VAV-Restroom VAV Box Component", - "type": "Zone Air Terminal VAV Damper Position", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", - "field": "TerminalBoxDamperPosition", - "meta": { - "units": "percentage", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-102 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-102 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-118 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-118 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-119 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-119 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-120 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-120 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123A VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-123A VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123B VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-123B VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127A VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-127A VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127B VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-127B VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-129 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-129 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-131 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-131 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-133 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-133 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-136 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-136 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-142 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-142 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-143 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-143 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-150 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-150 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-100 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-CORRIDOR VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-121 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-RESTROOM VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-104 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-104 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-105 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-105 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-107 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-107 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-108 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-108 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-112 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-112 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-116 VAV BOX OUTLET NODE System Node Mass Flow Rate": { - "name": "Zone-VAV-116 VAV BOX OUTLET NODE", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-AHU-002 Direct Air Inlet Node Name System Node Mass Flow Rate": { - "name": "Zone-AHU-002 Direct Air Inlet Node Name", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "SupplyAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-AHU-004 Direct Air Inlet Node Name System Node Mass Flow Rate": { - "name": "Zone-AHU-004 Direct Air Inlet Node Name", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-102 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-102 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-118 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-118 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-119 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-119 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-120 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-120 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123A VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-123A VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123B VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-123B VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127A VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-127A VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127B VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-127B VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-129 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-129 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-131 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-131 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-133 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-133 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-136 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-136 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-142 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-142 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-143 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-143 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-150 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-150 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-100 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-CORRIDOR VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-121 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-RESTROOM VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-104 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-104 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-105 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-105 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-107 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-107 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-108 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-108 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-112 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-112 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-116 VAV BOX OUTLET NODE System Node Temperature": { - "name": "Zone-VAV-116 VAV BOX OUTLET NODE", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-AHU-002 Direct Air Inlet Node Name System Node Temperature": { - "name": "Zone-AHU-002 Direct Air Inlet Node Name", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-AHU-004 Direct Air Inlet Node Name System Node Temperature": { - "name": "Zone-AHU-004 Direct Air Inlet Node Name", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "ZoneDischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-001 Supply Equipment Outlet Node System Node Temperature": { - "name": "AHU-001 Supply Equipment Outlet Node", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/all", - "field": "DischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-001 Supply Equipment Outlet Node System Node Mass Flow Rate": { - "name": "AHU-001 Supply Equipment Outlet Node", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU1/all", - "field": "SupplyAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-001 Supply Equipment Inlet Node System Node Temperature": { - "name": "AHU-001 Supply Equipment Inlet Node", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/all", - "field": "ReturnAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-001 OA CoolCNode System Node Temperature": { - "name": "AHU-001 OA CoolCNode", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU1/all", - "field": "MixedAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-002 Supply Equipment Outlet Node System Node Temperature": { - "name": "AHU-002 Supply Equipment Outlet Node", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "DischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-002 Supply Equipment Outlet Node System Node Mass Flow Rate": { - "name": "AHU-002 Supply Equipment Outlet Node", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "ZoneAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-002 Supply Equipment Inlet Node System Node Temperature": { - "name": "AHU-002 Supply Equipment Inlet Node", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "ReturnAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-002 OA CoolCNode System Node Temperature": { - "name": "AHU-002 OA CoolCNode", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "MixedAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-003 Supply Equipment Outlet Node System Node Temperature": { - "name": "AHU-003 Supply Equipment Outlet Node", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/all", - "field": "DischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-003 Supply Equipment Outlet Node System Node Mass Flow Rate": { - "name": "AHU-003 Supply Equipment Outlet Node", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU3/all", - "field": "SupplyAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-003 Supply Equipment Inlet Node System Node Temperature": { - "name": "AHU-003 Supply Equipment Inlet Node", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/all", - "field": "ReturnAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-003 OA CoolCNode System Node Temperature": { - "name": "AHU-003 OA CoolCNode", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU3/all", - "field": "MixedAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-004 Supply Equipment Outlet Node System Node Temperature": { - "name": "AHU-004 Supply Equipment Outlet Node", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "DischargeAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-004 Supply Equipment Outlet Node System Node Mass Flow Rate": { - "name": "AHU-004 Supply Equipment Outlet Node", - "type": "System Node Mass Flow Rate", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "SupplyAirFlow", - "meta": { - "units": "cubicMetersPerSecond", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-004 Supply Equipment Inlet Node System Node Temperature": { - "name": "AHU-004 Supply Equipment Inlet Node", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "ReturnAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU-004 OA CoolCNode System Node Temperature": { - "name": "AHU-004 OA CoolCNode", - "type": "System Node Temperature", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "MixedAirTemperature", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "HVACOperationSchd Schedule Value1": { - "name": "HVACOperationSchd", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/all", - "field": "SupplyFanStatus", - "meta": { - "units": "Enum", - "tz": "US/Pacific", - "type": "float" - } - }, - "HVACOperationSchd Schedule Value2": { - "name": "HVACOperationSchd", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "SupplyFanStatus", - "meta": { - "units": "Enum", - "tz": "US/Pacific", - "type": "float" - } - }, - "HVACOperationSchd Schedule Value3": { - "name": "HVACOperationSchd", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/all", - "field": "SupplyFanStatus", - "meta": { - "units": "Enum", - "tz": "US/Pacific", - "type": "float" - } - }, - "HVACOperationSchd Schedule Value4": { - "name": "HVACOperationSchd", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "SupplyFanStatus", - "meta": { - "units": "Enum", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAVCorridor": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV102": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV118": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV119": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV120": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV123A": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV123B": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV127A": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV127B": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV129": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV131": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV136": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV133": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV142": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV143": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV150": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV104": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV105": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV107": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV108": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV112": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAV116": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "float" - } - }, - "ALWAYS ON Schedule Value VAVRESTROOM": { - "name": "ALWAYS ON", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", - "field": "OccupancyMode", - "meta": { - "units": "None", - "tz": "US/Pacific", - "type": "boolean" - } - }, - "AHU 1 Power": { - "name": "AHU-001 Fan", - "type": "Fan Electric Power", - "topic": "devices/PNNL/BUILDING1/AHU1/all", - "field": "SupplyFanPower", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU 2 Power": { - "name": "AHU-002 Fan", - "type": "Fan Electric Power", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "SupplyFanPower", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU 3 Power": { - "name": "AHU-003 Fan", - "type": "Fan Electric Power", - "topic": "devices/PNNL/BUILDING1/AHU3/all", - "field": "SupplyFanPower", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "AHU 4 Power": { - "name": "AHU-004 Fan", - "type": "Fan Electric Power", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "SupplyFanPower", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "DISTRICT COOLING District Cooling Rate": { - "name": "DISTRICT COOLING", - "type": "District Cooling Rate", - "topic": "devices/PNNL/BUILDING1/Chiller/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-102 Lights Electric Power": { - "name": "Zone-VAV-102 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE102/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-104 Lights Electric Power": { - "name": "Zone-VAV-104 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE104/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-105 Lights Electric Power": { - "name": "Zone-VAV-105 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE105/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-107 Lights Electric Power": { - "name": "Zone-VAV-107 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE107/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-108 Lights Electric Power": { - "name": "Zone-VAV-108 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE108/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-112 Lights Electric Power": { - "name": "Zone-VAV-112 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE112/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-116 Lights Electric Power": { - "name": "Zone-VAV-116 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE116/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-118 Lights Electric Power": { - "name": "Zone-VAV-118 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE118/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-119 Lights Electric Power": { - "name": "Zone-VAV-119 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE119/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-120 Lights Electric Power": { - "name": "Zone-VAV-120 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE120/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123A Lights Electric Power": { - "name": "Zone-VAV-123A Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE123A/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-123B Lights Electric Power": { - "name": "Zone-VAV-123B Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE123B/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127A Lights Electric Power": { - "name": "Zone-VAV-127A Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE127A/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-127B Lights Electric Power": { - "name": "Zone-VAV-127B Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE127B/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-129 Lights Electric Power": { - "name": "Zone-VAV-129 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE129/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-131 Lights Electric Power": { - "name": "Zone-VAV-131 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE131/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-133 Lights Electric Power": { - "name": "Zone-VAV-133 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE133/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-136 Lights Electric Power": { - "name": "Zone-VAV-136 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE136/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-142 Lights Electric Power": { - "name": "Zone-VAV-142 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE142/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-143 Lights Electric Power": { - "name": "Zone-VAV-143 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE143/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "Zone-VAV-150 Lights Electric Power": { - "name": "Zone-VAV-150 Lights", - "type": "Lights Electric Power", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE150/all", - "field": "Power", - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-102": { - "name": "BLDG LIGHT SCH Zone-VAV-102", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE102/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-104": { - "name": "BLDG LIGHT SCH Zone-VAV-104", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE104/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-105": { - "name": "BLDG LIGHT SCH Zone-VAV-105", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE105/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-107": { - "name": "BLDG LIGHT SCH Zone-VAV-107", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE107/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-108": { - "name": "BLDG LIGHT SCH Zone-VAV-108", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE108/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-112": { - "name": "BLDG LIGHT SCH Zone-VAV-112", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE112/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-116": { - "name": "BLDG LIGHT SCH Zone-VAV-116", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE116/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-118": { - "name": "BLDG LIGHT SCH Zone-VAV-118", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE118/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-119": { - "name": "BLDG LIGHT SCH Zone-VAV-119", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE119/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-120": { - "name": "BLDG LIGHT SCH Zone-VAV-120", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE120/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-123A": { - "name": "BLDG LIGHT SCH Zone-VAV-123A", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE123A/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-123B": { - "name": "BLDG LIGHT SCH Zone-VAV-123B", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE123B/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-127A": { - "name": "BLDG LIGHT SCH Zone-VAV-127A", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE127A/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-127B": { - "name": "BLDG LIGHT SCH Zone-VAV-127B", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE127B/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-129": { - "name": "BLDG LIGHT SCH Zone-VAV-129", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE129/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-131": { - "name": "BLDG LIGHT SCH Zone-VAV-131", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE131/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-133": { - "name": "BLDG LIGHT SCH Zone-VAV-133", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE133/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-136": { - "name": "BLDG LIGHT SCH Zone-VAV-136", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE136/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-142": { - "name": "BLDG LIGHT SCH Zone-VAV-142", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE142/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-143": { - "name": "BLDG LIGHT SCH Zone-VAV-143", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE143/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "BLDG LIGHT SCH Zone-VAV-150": { - "name": "BLDG LIGHT SCH Zone-VAV-150", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE150/all", - "field": "DimmingLevelOutput", - "meta": { - "units": "fraction", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-102": { - "name": "CLGTEMPSETPOINT Zone-VAV-102", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-118": { - "name": "CLGTEMPSETPOINT Zone-VAV-118", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-119": { - "name": "CLGTEMPSETPOINT Zone-VAV-119", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-120": { - "name": "CLGTEMPSETPOINT Zone-VAV-120", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-123A": { - "name": "CLGTEMPSETPOINT Zone-VAV-123A", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-123B": { - "name": "CLGTEMPSETPOINT Zone-VAV-123B", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-127A": { - "name": "CLGTEMPSETPOINT Zone-VAV-127A", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-127B": { - "name": "CLGTEMPSETPOINT Zone-VAV-127B", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-129": { - "name": "CLGTEMPSETPOINT Zone-VAV-129", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-131": { - "name": "CLGTEMPSETPOINT Zone-VAV-131", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-133": { - "name": "CLGTEMPSETPOINT Zone-VAV-133", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-136": { - "name": "CLGTEMPSETPOINT Zone-VAV-136", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-142": { - "name": "CLGTEMPSETPOINT Zone-VAV-142", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-143": { - "name": "CLGTEMPSETPOINT Zone-VAV-143", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-150": { - "name": "CLGTEMPSETPOINT Zone-VAV-150", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-100": { - "name": "CLGTEMPSETPOINT Zone-VAV-CORRIDOR", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-121": { - "name": "CLGTEMPSETPOINT Zone-VAV-RESTROOM", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-104": { - "name": "CLGTEMPSETPOINT Zone-VAV-104", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-105": { - "name": "CLGTEMPSETPOINT Zone-VAV-105", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-107": { - "name": "CLGTEMPSETPOINT Zone-VAV-107", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-108": { - "name": "CLGTEMPSETPOINT Zone-VAV-108", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-112": { - "name": "CLGTEMPSETPOINT Zone-VAV-112", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-VAV-116": { - "name": "CLGTEMPSETPOINT Zone-VAV-116", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-AHU-002": { - "name": "CLGTEMPSETPOINT Zone-AHU-002", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU2/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "CLGTEMPSETPOINT Zone-AHU-004": { - "name": "CLGTEMPSETPOINT Zone-AHU-004", - "type": "Schedule Value", - "topic": "devices/PNNL/BUILDING1/AHU4/all", - "field": "ZoneCoolingTemperatureSetPoint", - "meta": { - "units": "degreesCentigrade", - "tz": "US/Pacific", - "type": "float" - } - }, - "Whole Building Power": { - "name": "Whole Building", - "type": "Facility Total Electric Demand Power", - "topic": "devices/PNNL/BUILDING1/METERS/all", - "field": "WholeBuildingPower", - "publish_last": true, - "meta": { - "units": "WATTS", - "tz": "US/Pacific", - "type": "float" - } - }, - "currentMonthV" : { - "name" : "EMS", - "type" : "currentMonthV" - }, - "currentDayOfMonthV" : { - "name" : "EMS", - "type" : "currentDayOfMonthV" - }, - "currentHourV" : { - "name" : "EMS", - "type" : "currentHourV" - }, - "currentMinuteV" : { - "name" : "EMS", - "type" : "currentMinuteV" - }, - "Dynamic_default1" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-102" - }, - "Dynamic_default2" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-104" - }, - "Dynamic_default3" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-105" - }, - "Dynamic_default4" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-107" - }, - "Dynamic_default5" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-108" - }, - "Dynamic_default6" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-112" - }, - "Dynamic_default7" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-116" - }, - "Dynamic_default8" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-118" - }, - "Dynamic_default9" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-119" - }, - "Dynamic_default10" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-120" - }, - "Dynamic_default11" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-123A" - }, - "Dynamic_default12" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-123B" - }, - "Dynamic_default13" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-127A" - }, - "Dynamic_default14" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-127B" - }, - "Dynamic_default15" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-129" - }, - "Dynamic_default16" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-131" - }, - "Dynamic_default17" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-133" - }, - "Dynamic_default18" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-142" - }, - "Dynamic_default19" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-143" - }, - "Dynamic_default20" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-150" - }, - "Dynamic_default21" : { - "name" : "BLDG LIGHT SCH bak", - "type" : "Schedule Value", - "default" : "BLDG LIGHT SCH Zone-VAV-136" - }, - "Dynamic_VAVdefault1" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-102" - }, - "Dynamic_VAVdefault2" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-118" - }, - "Dynamic_VAVdefault3" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-119" - }, - "Dynamic_VAVdefault4" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-120" - }, - "Dynamic_VAVdefault5" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-123A" - }, - "Dynamic_VAVdefault6" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-123B" - }, - "Dynamic_VAVdefault7" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-127A" - }, - "Dynamic_VAVdefault8" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-127B" - }, - "Dynamic_VAVdefault9" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-129" - }, - "Dynamic_VAVdefault10" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-131" - }, - "Dynamic_VAVdefault11" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-133" - }, - "Dynamic_VAVdefault12" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-136" - }, - "Dynamic_VAVdefault13" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-142" - }, - "Dynamic_VAVdefault14" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-143" - }, - "Dynamic_VAVdefault15" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-150" - }, - "Dynamic_VAVdefault16" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-CORRIDOR" - }, - "Dynamic_VAVdefault17" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-RESTROOM" - }, - "Dynamic_VAVdefault18" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-104" - }, - "Dynamic_VAVdefault19" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-105" - }, - "Dynamic_VAVdefault20" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-107" - }, - "Dynamic_VAVdefault21" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-108" - }, - "Dynamic_VAVdefault22" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-112" - }, - "Dynamic_VAVdefault23" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-VAV-116" - }, - "Dynamic_VAVdefault24" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-AHU-002" - }, - "Dynamic_VAVdefault25" : { - "name" : "CLGTEMPSETPOINT", - "type" : "Schedule Value", - "default" : "CLGTEMPSETPOINT Zone-AHU-004" - }, - "operation": { - "name": "HVACOperationSchd", - "type": "Schedule Value", - "field": "operation" - } + "properties": { + "identity": "platform.actuator", + "model": "~/eplus/building1/BUILDING1.idf", + "weather": "~/eplus/building1/USA_WA_Pasco-Tri.Cities.AP.727845_TMY3.epw", + "bcvtb_home": "~/eplus/bcvtb/", + "size": 40960, + "startmonth": 8, + "startday": 1, + "endmonth": 8, + "endday": 31, + "timestep": 60, + "time_scale": 6, + "cosimulation_sync": true, + "real_time_periodic": true, + "co_sim_timestep": 5, + "real_time_flag": false + }, + "inputs": { + "CLGTEMPSETPOINT Zone-VAV-102": { + "name": "CLGTEMPSETPOINT Zone-VAV-102", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV102", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-118": { + "name": "CLGTEMPSETPOINT Zone-VAV-118", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV118", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-119": { + "name": "CLGTEMPSETPOINT Zone-VAV-119", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV119", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-120": { + "name": "CLGTEMPSETPOINT Zone-VAV-120", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV120", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-123A": { + "name": "CLGTEMPSETPOINT Zone-VAV-123A", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV123A", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-123B": { + "name": "CLGTEMPSETPOINT Zone-VAV-123B", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV123B", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-127A": { + "name": "CLGTEMPSETPOINT Zone-VAV-127A", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV127A", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-127B": { + "name": "CLGTEMPSETPOINT Zone-VAV-127B", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV127B", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-129": { + "name": "CLGTEMPSETPOINT Zone-VAV-129", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV129", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-131": { + "name": "CLGTEMPSETPOINT Zone-VAV-131", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV131", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-133": { + "name": "CLGTEMPSETPOINT Zone-VAV-133", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV133", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-136": { + "name": "CLGTEMPSETPOINT Zone-VAV-136", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV136", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-142": { + "name": "CLGTEMPSETPOINT Zone-VAV-142", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV142", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-143": { + "name": "CLGTEMPSETPOINT Zone-VAV-143", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV143", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-150": { + "name": "CLGTEMPSETPOINT Zone-VAV-150", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV150", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-100": { + "name": "CLGTEMPSETPOINT Zone-VAV-CORRIDOR", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV100", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-121": { + "name": "CLGTEMPSETPOINT Zone-VAV-RESTROOM", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU1/VAV121", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-104": { + "name": "CLGTEMPSETPOINT Zone-VAV-104", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU3/VAV104", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-105": { + "name": "CLGTEMPSETPOINT Zone-VAV-105", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU3/VAV105", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-107": { + "name": "CLGTEMPSETPOINT Zone-VAV-107", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU3/VAV107", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-108": { + "name": "CLGTEMPSETPOINT Zone-VAV-108", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU3/VAV108", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-112": { + "name": "CLGTEMPSETPOINT Zone-VAV-112", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU3/VAV112", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-VAV-116": { + "name": "CLGTEMPSETPOINT Zone-VAV-116", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU3/VAV116", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-AHU-002": { + "name": "CLGTEMPSETPOINT Zone-AHU-002", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU2", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "CLGTEMPSETPOINT Zone-AHU-004": { + "name": "CLGTEMPSETPOINT Zone-AHU-004", + "type": "schedule", + "topic": "PNNL/BUILDING1/AHU4", + "field": "ZoneCoolingTemperatureSetPoint", + "default": 21.11, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-102": { + "name": "BLDG LIGHT SCH Zone-VAV-102", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE102", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-104": { + "name": "BLDG LIGHT SCH Zone-VAV-104", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE104", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-105": { + "name": "BLDG LIGHT SCH Zone-VAV-105", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE105", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-107": { + "name": "BLDG LIGHT SCH Zone-VAV-107", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE107", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-108": { + "name": "BLDG LIGHT SCH Zone-VAV-108", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE108", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-112": { + "name": "BLDG LIGHT SCH Zone-VAV-112", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE112", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-116": { + "name": "BLDG LIGHT SCH Zone-VAV-116", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE116", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-118": { + "name": "BLDG LIGHT SCH Zone-VAV-118", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE118", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-119": { + "name": "BLDG LIGHT SCH Zone-VAV-119", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE119", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-120": { + "name": "BLDG LIGHT SCH Zone-VAV-120", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE120", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-123A": { + "name": "BLDG LIGHT SCH Zone-VAV-123A", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE123A", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-123B": { + "name": "BLDG LIGHT SCH Zone-VAV-123B", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE123B", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-127A": { + "name": "BLDG LIGHT SCH Zone-VAV-127A", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE127A", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-127B": { + "name": "BLDG LIGHT SCH Zone-VAV-127B", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE127B", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-129": { + "name": "BLDG LIGHT SCH Zone-VAV-129", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE129", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-131": { + "name": "BLDG LIGHT SCH Zone-VAV-131", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE131", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-133": { + "name": "BLDG LIGHT SCH Zone-VAV-133", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE133", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-142": { + "name": "BLDG LIGHT SCH Zone-VAV-142", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE142", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-143": { + "name": "BLDG LIGHT SCH Zone-VAV-143", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE143", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-150": { + "name": "BLDG LIGHT SCH Zone-VAV-150", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE150", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + }, + "BLDG LIGHT SCH Zone-VAV-136": { + "name": "BLDG LIGHT SCH Zone-VAV-136", + "type": "schedule", + "topic": "PNNL/BUILDING1/LIGHTING/ZONE136", + "field": "DimmingLevelOutput", + "default": 1.0, + "dynamic_default": 1.0 + } + }, + "outputs": { + "ENVIRONMENT Site Outdoor Air Drybulb Temperature1": { + "name": "ENVIRONMENT", + "type": "Site Outdoor Air Drybulb Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/all", + "field": "OutdoorAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "ENVIRONMENT Site Outdoor Air Drybulb Temperature2": { + "name": "ENVIRONMENT", + "type": "Site Outdoor Air Drybulb Temperature", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "OutdoorAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "ENVIRONMENT Site Outdoor Air Drybulb Temperature3": { + "name": "ENVIRONMENT", + "type": "Site Outdoor Air Drybulb Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/all", + "field": "OutdoorAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "ENVIRONMENT Site Outdoor Air Drybulb Temperature4": { + "name": "ENVIRONMENT", + "type": "Site Outdoor Air Drybulb Temperature", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "OutdoorAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-102 Zone Mean Air Temperature": { + "name": "Zone-VAV-102", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-118 Zone Mean Air Temperature": { + "name": "Zone-VAV-118", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-119 Zone Mean Air Temperature": { + "name": "Zone-VAV-119", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-120 Zone Mean Air Temperature": { + "name": "Zone-VAV-120", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123A Zone Mean Air Temperature": { + "name": "Zone-VAV-123A", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123B Zone Mean Air Temperature": { + "name": "Zone-VAV-123B", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127A Zone Mean Air Temperature": { + "name": "Zone-VAV-127A", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127B Zone Mean Air Temperature": { + "name": "Zone-VAV-127B", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-129 Zone Mean Air Temperature": { + "name": "Zone-VAV-129", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-131 Zone Mean Air Temperature": { + "name": "Zone-VAV-131", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-133 Zone Mean Air Temperature": { + "name": "Zone-VAV-133", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-136 Zone Mean Air Temperature": { + "name": "Zone-VAV-136", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-142 Zone Mean Air Temperature": { + "name": "Zone-VAV-142", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-143 Zone Mean Air Temperature": { + "name": "Zone-VAV-143", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-150 Zone Mean Air Temperature": { + "name": "Zone-VAV-150", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-100 Zone Mean Air Temperature": { + "name": "Zone-VAV-CORRIDOR", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-121 Zone Mean Air Temperature": { + "name": "Zone-VAV-RESTROOM", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-104 Zone Mean Air Temperature": { + "name": "Zone-VAV-104", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-105 Zone Mean Air Temperature": { + "name": "Zone-VAV-105", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-107 Zone Mean Air Temperature": { + "name": "Zone-VAV-107", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-108 Zone Mean Air Temperature": { + "name": "Zone-VAV-108", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-112 Zone Mean Air Temperature": { + "name": "Zone-VAV-112", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-116 Zone Mean Air Temperature": { + "name": "Zone-VAV-116", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-AHU-002 Zone Mean Air Temperature": { + "name": "Zone-AHU-002", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-AHU-004 Zone Mean Air Temperature": { + "name": "Zone-AHU-004", + "type": "Zone Mean Air Temperature", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "ZoneTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-Corridor VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-Corridor VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-102 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-102 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-104 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-104 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-105 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-105 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-107 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-107 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-108 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-108 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-112 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-112 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-116 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-116 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-118 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-118 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-119 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-119 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-120 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-120 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123A VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-123A VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123B VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-123B VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127A VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-127A VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127B VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-127B VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-129 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-129 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-131 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-131 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-133 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-133 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-136 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-136 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-142 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-142 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-143 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-143 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-150 VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-150 VAV BOX COMPONENT", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-Restroom VAV BOX COMPONENT Zone Air Terminal VAV Damper Position": { + "name": "Zone-VAV-Restroom VAV Box Component", + "type": "Zone Air Terminal VAV Damper Position", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", + "field": "TerminalBoxDamperPosition", + "meta": { + "units": "percentage", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-102 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-102 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-118 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-118 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-119 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-119 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-120 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-120 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123A VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-123A VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123B VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-123B VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127A VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-127A VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127B VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-127B VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-129 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-129 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-131 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-131 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-133 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-133 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-136 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-136 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-142 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-142 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-143 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-143 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-150 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-150 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-100 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-CORRIDOR VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-121 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-RESTROOM VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-104 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-104 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-105 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-105 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-107 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-107 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-108 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-108 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-112 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-112 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-116 VAV BOX OUTLET NODE System Node Mass Flow Rate": { + "name": "Zone-VAV-116 VAV BOX OUTLET NODE", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-AHU-002 Direct Air Inlet Node Name System Node Mass Flow Rate": { + "name": "Zone-AHU-002 Direct Air Inlet Node Name", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "SupplyAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-AHU-004 Direct Air Inlet Node Name System Node Mass Flow Rate": { + "name": "Zone-AHU-004 Direct Air Inlet Node Name", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-102 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-102 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-118 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-118 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-119 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-119 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-120 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-120 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123A VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-123A VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123B VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-123B VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127A VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-127A VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127B VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-127B VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-129 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-129 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-131 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-131 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-133 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-133 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-136 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-136 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-142 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-142 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-143 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-143 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-150 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-150 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-100 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-CORRIDOR VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-121 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-RESTROOM VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-104 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-104 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-105 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-105 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-107 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-107 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-108 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-108 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-112 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-112 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-116 VAV BOX OUTLET NODE System Node Temperature": { + "name": "Zone-VAV-116 VAV BOX OUTLET NODE", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-AHU-002 Direct Air Inlet Node Name System Node Temperature": { + "name": "Zone-AHU-002 Direct Air Inlet Node Name", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-AHU-004 Direct Air Inlet Node Name System Node Temperature": { + "name": "Zone-AHU-004 Direct Air Inlet Node Name", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "ZoneDischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-001 Supply Equipment Outlet Node System Node Temperature": { + "name": "AHU-001 Supply Equipment Outlet Node", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/all", + "field": "DischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-001 Supply Equipment Outlet Node System Node Mass Flow Rate": { + "name": "AHU-001 Supply Equipment Outlet Node", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU1/all", + "field": "SupplyAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-001 Supply Equipment Inlet Node System Node Temperature": { + "name": "AHU-001 Supply Equipment Inlet Node", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/all", + "field": "ReturnAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-001 OA CoolCNode System Node Temperature": { + "name": "AHU-001 OA CoolCNode", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU1/all", + "field": "MixedAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-002 Supply Equipment Outlet Node System Node Temperature": { + "name": "AHU-002 Supply Equipment Outlet Node", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "DischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-002 Supply Equipment Outlet Node System Node Mass Flow Rate": { + "name": "AHU-002 Supply Equipment Outlet Node", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "ZoneAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-002 Supply Equipment Inlet Node System Node Temperature": { + "name": "AHU-002 Supply Equipment Inlet Node", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "ReturnAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-002 OA CoolCNode System Node Temperature": { + "name": "AHU-002 OA CoolCNode", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "MixedAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-003 Supply Equipment Outlet Node System Node Temperature": { + "name": "AHU-003 Supply Equipment Outlet Node", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/all", + "field": "DischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-003 Supply Equipment Outlet Node System Node Mass Flow Rate": { + "name": "AHU-003 Supply Equipment Outlet Node", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU3/all", + "field": "SupplyAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-003 Supply Equipment Inlet Node System Node Temperature": { + "name": "AHU-003 Supply Equipment Inlet Node", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/all", + "field": "ReturnAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-003 OA CoolCNode System Node Temperature": { + "name": "AHU-003 OA CoolCNode", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU3/all", + "field": "MixedAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-004 Supply Equipment Outlet Node System Node Temperature": { + "name": "AHU-004 Supply Equipment Outlet Node", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "DischargeAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-004 Supply Equipment Outlet Node System Node Mass Flow Rate": { + "name": "AHU-004 Supply Equipment Outlet Node", + "type": "System Node Mass Flow Rate", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "SupplyAirFlow", + "meta": { + "units": "cubicMetersPerSecond", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-004 Supply Equipment Inlet Node System Node Temperature": { + "name": "AHU-004 Supply Equipment Inlet Node", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "ReturnAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU-004 OA CoolCNode System Node Temperature": { + "name": "AHU-004 OA CoolCNode", + "type": "System Node Temperature", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "MixedAirTemperature", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "HVACOperationSchd Schedule Value1": { + "name": "HVACOperationSchd", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/all", + "field": "SupplyFanStatus", + "meta": { + "units": "Enum", + "tz": "US/Pacific", + "type": "float" + } + }, + "HVACOperationSchd Schedule Value2": { + "name": "HVACOperationSchd", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "SupplyFanStatus", + "meta": { + "units": "Enum", + "tz": "US/Pacific", + "type": "float" + } + }, + "HVACOperationSchd Schedule Value3": { + "name": "HVACOperationSchd", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/all", + "field": "SupplyFanStatus", + "meta": { + "units": "Enum", + "tz": "US/Pacific", + "type": "float" + } + }, + "HVACOperationSchd Schedule Value4": { + "name": "HVACOperationSchd", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "SupplyFanStatus", + "meta": { + "units": "Enum", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAVCorridor": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV102": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV118": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV119": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV120": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV123A": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV123B": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV127A": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV127B": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV129": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV131": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV136": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV133": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV142": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV143": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV150": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV104": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV105": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV107": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV108": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV112": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAV116": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "float" + } + }, + "ALWAYS ON Schedule Value VAVRESTROOM": { + "name": "ALWAYS ON", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", + "field": "OccupancyMode", + "meta": { + "units": "None", + "tz": "US/Pacific", + "type": "boolean" + } + }, + "AHU 1 Power": { + "name": "AHU-001 Fan", + "type": "Fan Electric Power", + "topic": "devices/PNNL/BUILDING1/AHU1/all", + "field": "SupplyFanPower", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU 2 Power": { + "name": "AHU-002 Fan", + "type": "Fan Electric Power", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "SupplyFanPower", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU 3 Power": { + "name": "AHU-003 Fan", + "type": "Fan Electric Power", + "topic": "devices/PNNL/BUILDING1/AHU3/all", + "field": "SupplyFanPower", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "AHU 4 Power": { + "name": "AHU-004 Fan", + "type": "Fan Electric Power", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "SupplyFanPower", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "DISTRICT COOLING District Cooling Rate": { + "name": "DISTRICT COOLING", + "type": "District Cooling Rate", + "topic": "devices/PNNL/BUILDING1/Chiller/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-102 Lights Electric Power": { + "name": "Zone-VAV-102 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE102/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-104 Lights Electric Power": { + "name": "Zone-VAV-104 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE104/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-105 Lights Electric Power": { + "name": "Zone-VAV-105 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE105/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-107 Lights Electric Power": { + "name": "Zone-VAV-107 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE107/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-108 Lights Electric Power": { + "name": "Zone-VAV-108 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE108/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-112 Lights Electric Power": { + "name": "Zone-VAV-112 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE112/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-116 Lights Electric Power": { + "name": "Zone-VAV-116 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE116/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-118 Lights Electric Power": { + "name": "Zone-VAV-118 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE118/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-119 Lights Electric Power": { + "name": "Zone-VAV-119 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE119/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-120 Lights Electric Power": { + "name": "Zone-VAV-120 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE120/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123A Lights Electric Power": { + "name": "Zone-VAV-123A Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE123A/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-123B Lights Electric Power": { + "name": "Zone-VAV-123B Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE123B/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127A Lights Electric Power": { + "name": "Zone-VAV-127A Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE127A/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-127B Lights Electric Power": { + "name": "Zone-VAV-127B Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE127B/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-129 Lights Electric Power": { + "name": "Zone-VAV-129 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE129/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-131 Lights Electric Power": { + "name": "Zone-VAV-131 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE131/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-133 Lights Electric Power": { + "name": "Zone-VAV-133 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE133/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-136 Lights Electric Power": { + "name": "Zone-VAV-136 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE136/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-142 Lights Electric Power": { + "name": "Zone-VAV-142 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE142/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-143 Lights Electric Power": { + "name": "Zone-VAV-143 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE143/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "Zone-VAV-150 Lights Electric Power": { + "name": "Zone-VAV-150 Lights", + "type": "Lights Electric Power", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE150/all", + "field": "Power", + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-102": { + "name": "BLDG LIGHT SCH Zone-VAV-102", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE102/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-104": { + "name": "BLDG LIGHT SCH Zone-VAV-104", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE104/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-105": { + "name": "BLDG LIGHT SCH Zone-VAV-105", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE105/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-107": { + "name": "BLDG LIGHT SCH Zone-VAV-107", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE107/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-108": { + "name": "BLDG LIGHT SCH Zone-VAV-108", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE108/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-112": { + "name": "BLDG LIGHT SCH Zone-VAV-112", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE112/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-116": { + "name": "BLDG LIGHT SCH Zone-VAV-116", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE116/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-118": { + "name": "BLDG LIGHT SCH Zone-VAV-118", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE118/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-119": { + "name": "BLDG LIGHT SCH Zone-VAV-119", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE119/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-120": { + "name": "BLDG LIGHT SCH Zone-VAV-120", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE120/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-123A": { + "name": "BLDG LIGHT SCH Zone-VAV-123A", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE123A/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-123B": { + "name": "BLDG LIGHT SCH Zone-VAV-123B", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE123B/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-127A": { + "name": "BLDG LIGHT SCH Zone-VAV-127A", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE127A/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-127B": { + "name": "BLDG LIGHT SCH Zone-VAV-127B", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE127B/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-129": { + "name": "BLDG LIGHT SCH Zone-VAV-129", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE129/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-131": { + "name": "BLDG LIGHT SCH Zone-VAV-131", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE131/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-133": { + "name": "BLDG LIGHT SCH Zone-VAV-133", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE133/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-136": { + "name": "BLDG LIGHT SCH Zone-VAV-136", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE136/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-142": { + "name": "BLDG LIGHT SCH Zone-VAV-142", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE142/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-143": { + "name": "BLDG LIGHT SCH Zone-VAV-143", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE143/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "BLDG LIGHT SCH Zone-VAV-150": { + "name": "BLDG LIGHT SCH Zone-VAV-150", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/LIGHTING/ZONE150/all", + "field": "DimmingLevelOutput", + "meta": { + "units": "fraction", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-102": { + "name": "CLGTEMPSETPOINT Zone-VAV-102", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV102/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-118": { + "name": "CLGTEMPSETPOINT Zone-VAV-118", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV118/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-119": { + "name": "CLGTEMPSETPOINT Zone-VAV-119", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV119/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-120": { + "name": "CLGTEMPSETPOINT Zone-VAV-120", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV120/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-123A": { + "name": "CLGTEMPSETPOINT Zone-VAV-123A", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123A/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-123B": { + "name": "CLGTEMPSETPOINT Zone-VAV-123B", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV123B/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-127A": { + "name": "CLGTEMPSETPOINT Zone-VAV-127A", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127A/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-127B": { + "name": "CLGTEMPSETPOINT Zone-VAV-127B", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV127B/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-129": { + "name": "CLGTEMPSETPOINT Zone-VAV-129", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV129/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-131": { + "name": "CLGTEMPSETPOINT Zone-VAV-131", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV131/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-133": { + "name": "CLGTEMPSETPOINT Zone-VAV-133", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV133/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-136": { + "name": "CLGTEMPSETPOINT Zone-VAV-136", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV136/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-142": { + "name": "CLGTEMPSETPOINT Zone-VAV-142", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV142/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-143": { + "name": "CLGTEMPSETPOINT Zone-VAV-143", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV143/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-150": { + "name": "CLGTEMPSETPOINT Zone-VAV-150", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV150/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-100": { + "name": "CLGTEMPSETPOINT Zone-VAV-CORRIDOR", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV100/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-121": { + "name": "CLGTEMPSETPOINT Zone-VAV-RESTROOM", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU1/VAV121/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-104": { + "name": "CLGTEMPSETPOINT Zone-VAV-104", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV104/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-105": { + "name": "CLGTEMPSETPOINT Zone-VAV-105", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV105/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-107": { + "name": "CLGTEMPSETPOINT Zone-VAV-107", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV107/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-108": { + "name": "CLGTEMPSETPOINT Zone-VAV-108", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV108/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-112": { + "name": "CLGTEMPSETPOINT Zone-VAV-112", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV112/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-VAV-116": { + "name": "CLGTEMPSETPOINT Zone-VAV-116", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU3/VAV116/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-AHU-002": { + "name": "CLGTEMPSETPOINT Zone-AHU-002", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU2/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "CLGTEMPSETPOINT Zone-AHU-004": { + "name": "CLGTEMPSETPOINT Zone-AHU-004", + "type": "Schedule Value", + "topic": "devices/PNNL/BUILDING1/AHU4/all", + "field": "ZoneCoolingTemperatureSetPoint", + "meta": { + "units": "degreesCentigrade", + "tz": "US/Pacific", + "type": "float" + } + }, + "Whole Building Power": { + "name": "Whole Building", + "type": "Facility Total Electric Demand Power", + "topic": "devices/PNNL/BUILDING1/METERS/all", + "field": "WholeBuildingPower", + "publish_last": true, + "meta": { + "units": "WATTS", + "tz": "US/Pacific", + "type": "float" + } + }, + "currentMonthV": { + "name": "EMS", + "type": "currentMonthV" + }, + "currentDayOfMonthV": { + "name": "EMS", + "type": "currentDayOfMonthV" + }, + "currentHourV": { + "name": "EMS", + "type": "currentHourV" + }, + "currentMinuteV": { + "name": "EMS", + "type": "currentMinuteV" + }, + "Dynamic_default1": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-102" + }, + "Dynamic_default2": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-104" + }, + "Dynamic_default3": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-105" + }, + "Dynamic_default4": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-107" + }, + "Dynamic_default5": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-108" + }, + "Dynamic_default6": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-112" + }, + "Dynamic_default7": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-116" + }, + "Dynamic_default8": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-118" + }, + "Dynamic_default9": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-119" + }, + "Dynamic_default10": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-120" + }, + "Dynamic_default11": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-123A" + }, + "Dynamic_default12": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-123B" + }, + "Dynamic_default13": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-127A" + }, + "Dynamic_default14": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-127B" + }, + "Dynamic_default15": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-129" + }, + "Dynamic_default16": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-131" + }, + "Dynamic_default17": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-133" + }, + "Dynamic_default18": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-142" + }, + "Dynamic_default19": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-143" + }, + "Dynamic_default20": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-150" + }, + "Dynamic_default21": { + "name": "BLDG LIGHT SCH bak", + "type": "Schedule Value", + "default": "BLDG LIGHT SCH Zone-VAV-136" + }, + "Dynamic_VAVdefault1": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-102" + }, + "Dynamic_VAVdefault2": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-118" + }, + "Dynamic_VAVdefault3": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-119" + }, + "Dynamic_VAVdefault4": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-120" + }, + "Dynamic_VAVdefault5": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-123A" + }, + "Dynamic_VAVdefault6": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-123B" + }, + "Dynamic_VAVdefault7": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-127A" + }, + "Dynamic_VAVdefault8": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-127B" + }, + "Dynamic_VAVdefault9": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-129" + }, + "Dynamic_VAVdefault10": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-131" + }, + "Dynamic_VAVdefault11": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-133" + }, + "Dynamic_VAVdefault12": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-136" + }, + "Dynamic_VAVdefault13": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-142" + }, + "Dynamic_VAVdefault14": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-143" + }, + "Dynamic_VAVdefault15": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-150" + }, + "Dynamic_VAVdefault16": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-CORRIDOR" + }, + "Dynamic_VAVdefault17": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-RESTROOM" + }, + "Dynamic_VAVdefault18": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-104" + }, + "Dynamic_VAVdefault19": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-105" + }, + "Dynamic_VAVdefault20": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-107" + }, + "Dynamic_VAVdefault21": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-108" + }, + "Dynamic_VAVdefault22": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-112" + }, + "Dynamic_VAVdefault23": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-VAV-116" + }, + "Dynamic_VAVdefault24": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-AHU-002" + }, + "Dynamic_VAVdefault25": { + "name": "CLGTEMPSETPOINT", + "type": "Schedule Value", + "default": "CLGTEMPSETPOINT Zone-AHU-004" + }, + "operation": { + "name": "HVACOperationSchd", + "type": "Schedule Value", + "field": "operation" } + } } diff --git a/examples/EnergyPlusAgent/ep_building1.yml b/examples/EnergyPlusAgent/ep_building1.yml index 2bcf71276c..6a65a2ad32 100644 --- a/examples/EnergyPlusAgent/ep_building1.yml +++ b/examples/EnergyPlusAgent/ep_building1.yml @@ -1,9 +1,9 @@ # Config parameters for setting up EnergyPlus agent properties: identity: platform.actuator - model: ~/git/sim_volttron/volttron/eplus/BUILDING1.idf - weather: ~/git/sim_volttron/volttron/eplus/USA_WA_Pasco-Tri.Cities.AP.727845_TMY3.epw - bcvtb_home: ~/git/sim_volttron/volttron/bcvtb + model: ~/eplus/building1/BUILDING1.idf + weather: ~/eplus/building1/USA_WA_Pasco-Tri.Cities.AP.727845_TMY3.epw + bcvtb_home: ~/eplus/bcvtb/ size: 40960 startmonth: 8 startday: 1 diff --git a/examples/ExampleMatlabApplication/matlab/matlab_example.py b/examples/ExampleMatlabApplication/matlab/matlab_example.py index e0f5842469..6d7e73a2b0 100644 --- a/examples/ExampleMatlabApplication/matlab/matlab_example.py +++ b/examples/ExampleMatlabApplication/matlab/matlab_example.py @@ -21,11 +21,11 @@ print("Sending config_params") config_params = {"zone_temperature_list": ["ZoneTemperature1", "ZoneTemperature2"], "zone_setpoint_list": ["ZoneTemperatureSP1", "ZoneTemperatureSP2"]} - config_socket.send_json(config_params,zmq.NOBLOCK) + config_socket.send_json(config_params, zmq.NOBLOCK) print("Sending data") data = {"zone_temperature_list": ["72.3", "78.5"]} - data_socket.send_json(data,zmq.NOBLOCK) + data_socket.send_json(data, zmq.NOBLOCK) except ZMQError: print("No Matlab process running to send message") diff --git a/examples/ExampleSubscriber/setup.py b/examples/ExampleSubscriber/setup.py index d831b7e574..9e860a8057 100644 --- a/examples/ExampleSubscriber/setup.py +++ b/examples/ExampleSubscriber/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/ExampleSubscriber/subscriber/subscriber_agent.py b/examples/ExampleSubscriber/subscriber/subscriber_agent.py index 2ea9b899d0..8cd96f2657 100644 --- a/examples/ExampleSubscriber/subscriber/subscriber_agent.py +++ b/examples/ExampleSubscriber/subscriber/subscriber_agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from datetime import datetime @@ -54,7 +40,7 @@ __version__ = '3.0' ''' -Structuring the agent this way allows us to grab config file settings +Structuring the agent this way allows us to grab config file settings for use in subscriptions instead of hardcoding them. ''' @@ -66,77 +52,77 @@ def subscriber_agent(config_path, **kwargs): 'devices/Building/LAB/Device/MixedAirTemperature') damper_point= config.get('damper_point', 'devices/Building/LAB/Device/DamperSignal') - all_topic = config.get('all_topic', + all_topic = config.get('all_topic', 'devices/Building/LAB/Device/all') query_point= config.get('query_point', 'Building/LAB/Device/OutsideAirTemperature') - - + + class ExampleSubscriber(Agent): ''' - This agent demonstrates usage of the 3.0 pubsub service as well as - interfacting with the historian. This agent is mostly self-contained, + This agent demonstrates usage of the 3.0 pubsub service as well as + interfacting with the historian. This agent is mostly self-contained, but requires the historian to be running to demonstrate the query feature. ''' - + def __init__(self, **kwargs): super(ExampleSubscriber, self).__init__(**kwargs) - + @Core.receiver('onsetup') def setup(self, sender, **kwargs): # Demonstrate accessing a value from the config file self._agent_id = config['agentid'] - - + + @PubSub.subscribe('pubsub', all_topic) def match_device_all(self, peer, sender, bus, topic, headers, message): ''' - This method subscribes to all points under a device then pulls out + This method subscribes to all points under a device then pulls out the specific point it needs. - The first element of the list in message is a dictionairy of points + The first element of the list in message is a dictionairy of points under the device. The second element is a dictionary of metadata for points. ''' - + print("Whole message", message) - + #The time stamp is in the headers print('Date', headers['Date']) - + #Pull out the value for the point of interest print("Value", message[0]['OutsideAirTemperature']) - + #Pull out the metadata for the point print('Unit', message[1]['OutsideAirTemperature']['units']) print('Timezone', message[1]['OutsideAirTemperature']['tz']) print('Type', message[1]['OutsideAirTemperature']['type']) - - + + @PubSub.subscribe('pubsub', oat_point) def on_match_OAT(self, peer, sender, bus, topic, headers, message): ''' This method subscribes to the specific point topic. - For these topics, the value is the first element of the list + For these topics, the value is the first element of the list in message. ''' - + print("Whole message", message) print('Date', headers['Date']) print("Value", message[0]) print("Units", message[1]['units']) print("TimeZone", message[1]['tz']) print("Type", message[1]['type']) - - + + @PubSub.subscribe('pubsub', '') def on_match_all(self, peer, sender, bus, topic, headers, message): - ''' This method subscibes to all topics. It simply prints out the + ''' This method subscibes to all topics. It simply prints out the topic seen. ''' - + print(topic) -# +# # Demonstrate periodic decorator and settings access @Core.schedule(periodic(10)) def lookup_data(self): @@ -144,75 +130,75 @@ def lookup_data(self): This method demonstrates how to query the platform historian for data This will require that the historian is already running on the platform. ''' - - try: - + + try: + result = self.vip.rpc.call( #Send this message to the platform historian #Using the reserved ID - 'platform.historian', + 'platform.historian', #Call the query method on this agent - 'query', + 'query', #query takes the keyword arguments of: #topic, then optional: start, end, count, order # start= "2015-10-14T20:51:56", topic=query_point, count = 20, #RPC uses gevent and we must call .get(timeout=10) - #to make it fetch the result and tell + #to make it fetch the result and tell #us if there is an error order = "FIRST_TO_LAST").get(timeout=10) print('Query Result', result) except Exception as e: - print ("Could not contact historian. Is it running?") + print("Could not contact historian. Is it running?") print(e) @Core.schedule(periodic(10)) def pub_fake_data(self): ''' This method publishes fake data for use by the rest of the agent. The format mimics the format used by VOLTTRON drivers. - + This method can be removed if you have real data to work against. ''' - + #Make some random readings - oat_reading = random.uniform(30,100) - mixed_reading = oat_reading + random.uniform(-5,5) - damper_reading = random.uniform(0,100) - + oat_reading = random.uniform(30, 100) + mixed_reading = oat_reading + random.uniform(-5, 5) + damper_reading = random.uniform(0, 100) + # Create a message for all points. - all_message = [{'OutsideAirTemperature': oat_reading, 'MixedAirTemperature': mixed_reading, + all_message = [{'OutsideAirTemperature': oat_reading, 'MixedAirTemperature': mixed_reading, 'DamperSignal': damper_reading}, {'OutsideAirTemperature': {'units': 'F', 'tz': 'UTC', 'type': 'float'}, - 'MixedAirTemperature': {'units': 'F', 'tz': 'UTC', 'type': 'float'}, + 'MixedAirTemperature': {'units': 'F', 'tz': 'UTC', 'type': 'float'}, 'DamperSignal': {'units': '%', 'tz': 'UTC', 'type': 'float'} }] - + #Create messages for specific points oat_message = [oat_reading,{'units': 'F', 'tz': 'UTC', 'type': 'float'}] mixed_message = [mixed_reading,{'units': 'F', 'tz': 'UTC', 'type': 'float'}] damper_message = [damper_reading,{'units': '%', 'tz': 'UTC', 'type': 'float'}] - + #Create timestamp now = utils.format_timestamp(datetime.utcnow()) headers = { headers_mod.DATE: now, headers_mod.TIMESTAMP: now } - + #Publish messages self.vip.pubsub.publish( 'pubsub', all_topic, headers, all_message) - + self.vip.pubsub.publish( 'pubsub', oat_point, headers, oat_message) - + self.vip.pubsub.publish( 'pubsub', mixed_point, headers, mixed_message) - + self.vip.pubsub.publish( 'pubsub', damper_point, headers, damper_message) - + return ExampleSubscriber(**kwargs) diff --git a/examples/FNCS/fncs_example/agent.py b/examples/FNCS/fncs_example/agent.py index 011135a1a1..220a56197e 100644 --- a/examples/FNCS/fncs_example/agent.py +++ b/examples/FNCS/fncs_example/agent.py @@ -46,7 +46,7 @@ def fncs_example(config_path, **kwargs): stop_agent_when_sim_complete = config.get("stop_agent_when_sim_complete", False) subscription_topic = config.get("subscription_topic", None) return FncsExample(topic_mapping=topic_mapping, federate_name=federate, broker_location=broker_location, - time_delta=time_delta,subscription_topic=subscription_topic, sim_length=sim_length, + time_delta=time_delta, subscription_topic=subscription_topic, sim_length=sim_length, stop_agent_when_sim_complete=stop_agent_when_sim_complete, **kwargs) @@ -56,7 +56,7 @@ class FncsExample(Agent): """ def __init__(self, topic_mapping, federate_name=None, broker_location="tcp://localhost:5570", - time_delta="1s",subscription_topic=None, simulation_start_time=None, sim_length="10s", + time_delta="1s", subscription_topic=None, simulation_start_time=None, sim_length="10s", stop_agent_when_sim_complete=False, **kwargs): super(FncsExample, self).__init__(enable_fncs=True, enable_store=False, **kwargs) _log.debug("vip_identity: " + self.core.identity) diff --git a/examples/GridAPPS-D/gridappsd_example/agent.py b/examples/GridAPPS-D/gridappsd_example/agent.py index 18c53ac9aa..f6565446c2 100644 --- a/examples/GridAPPS-D/gridappsd_example/agent.py +++ b/examples/GridAPPS-D/gridappsd_example/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -167,12 +153,12 @@ def do_work(self): :return: """ pass - + def on_receive_publisher_message(self, peer, sender, bus, topic, headers, message): """ - Subscribe to publisher publications and change the data accordingly - """ - # Update controller data + Subscribe to publisher publications and change the data accordingly + """ + # Update controller data val = message[0] # Do something with message diff --git a/examples/HELICS/helics_example/agent.py b/examples/HELICS/helics_example/agent.py index 3bd3ca56d7..bc2028c69d 100644 --- a/examples/HELICS/helics_example/agent.py +++ b/examples/HELICS/helics_example/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -190,12 +176,12 @@ def do_work(self): # Request HELICS to advance timestep self.helics_sim.make_time_request() - + def on_receive_publisher_message(self, peer, sender, bus, topic, headers, message): """ - Subscribe to publisher publications and change the data accordingly - """ - # Update controller data + Subscribe to publisher publications and change the data accordingly + """ + # Update controller data val = message[0] # Do something with message diff --git a/examples/HELICS/helics_federate.py b/examples/HELICS/helics_federate.py index 5674aca904..c4f8db075f 100644 --- a/examples/HELICS/helics_federate.py +++ b/examples/HELICS/helics_federate.py @@ -1,40 +1,25 @@ -# -*- coding: utf-8 -*- -# {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import time @@ -73,7 +58,7 @@ def federate_example(config_path): endid = {} subid = {} pubid = {} - for i in range(0,endpoint_count): + for i in range(0, endpoint_count): endid["m{}".format(i)] = h.helicsFederateGetEndpointByIndex(fed, i) end_name = h.helicsEndpointGetName(endid["m{}".format(i)]) logger.info( 'Registered Endpoint ---> {}'.format(end_name)) @@ -126,7 +111,7 @@ def federate_example(config_path): print('######################## Get from Endpoint #########################################') idx = endid["m{}".format(0)] - while h.helicsEndpointHasMessage(idx): + while h.helicsEndpointHasMessage(idx): msg = h.helicsEndpointGetMessage(idx) end_name = h.helicsEndpointGetName(idx) print("Value from endpoint name: {} is {}".format(end_name, msg.data)) diff --git a/examples/ListenerAgent/listener/agent.py b/examples/ListenerAgent/listener/agent.py index a1991724c1..14f6586d1e 100644 --- a/examples/ListenerAgent/listener/agent.py +++ b/examples/ListenerAgent/listener/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/examples/ListenerAgent/setup.py b/examples/ListenerAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/ListenerAgent/setup.py +++ b/examples/ListenerAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/MarketAgents/AHUAgent/ahu/agent.py b/examples/MarketAgents/AHUAgent/ahu/agent.py index 7b956fb156..7b8caaebf1 100644 --- a/examples/MarketAgents/AHUAgent/ahu/agent.py +++ b/examples/MarketAgents/AHUAgent/ahu/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys @@ -61,7 +47,7 @@ def ahu_agent(config_path, **kwargs): :type config_path: str :returns: Market Service Agent :rtype: MarketServiceAgent - """ + """ try: config = utils.load_config(config_path) except Exception: @@ -77,16 +63,18 @@ def ahu_agent(config_path, **kwargs): c1= config.get('c1') c2= config.get('c2') c3= config.get('c3') - COP= config.get('COP') + COP= config.get('COP') verbose_logging= config.get('verbose_logging', True) - return AHUAgent(air_market_name,electric_market_name,agent_name,subscribing_topic,c0,c1,c2,c3,COP,verbose_logging, **kwargs) + return AHUAgent(air_market_name, electric_market_name, agent_name, + subscribing_topic, c0, c1, c2, c3, COP, verbose_logging, **kwargs) class AHUAgent(MarketAgent, AhuChiller): """ The SampleElectricMeterAgent serves as a sample of an electric meter that sells electricity for a single building at a fixed price. """ - def __init__(self, air_market_name, electric_market_name, agent_name,subscribing_topic,c0,c1,c2,c3,COP,verbose_logging, **kwargs): + def __init__(self, air_market_name, electric_market_name, agent_name, + subscribing_topic, c0, c1, c2, c3, COP, verbose_logging, **kwargs): super(AHUAgent, self).__init__(verbose_logging, **kwargs) self.air_market_name = air_market_name @@ -108,14 +96,14 @@ def __init__(self, air_market_name, electric_market_name, agent_name,subscribing self.iniState() self.old_price = None self.old_quantity = None - + @Core.receiver('onstart') def setup(self, sender, **kwargs): _log.debug('Subscribing to '+self.subscribing_topic) self.vip.pubsub.subscribe(peer='pubsub', prefix=self.subscribing_topic, callback=self.updateState) - + def air_aggregate_callback(self, timestamp, market_name, buyer_seller, aggregate_air_demand): if buyer_seller == BUYER: electric_demand = self.create_electric_demand_curve(aggregate_air_demand) @@ -155,12 +143,12 @@ def create_air_supply_curve(self, electric_price, electric_quantity): supply_curve = PolyLine() price = 65 quantity = 100000 - supply_curve.add(Point(price=price,quantity=quantity)) + supply_curve.add(Point(price=price, quantity=quantity)) price = 65 quantity = 0 # negative quantities are not real -1*10000 - supply_curve.add(Point(price=price,quantity=quantity)) + supply_curve.add(Point(price=price, quantity=quantity)) return supply_curve - + def create_electric_demand_curve(self, aggregate_air_demand): curve = PolyLine() for point in aggregate_air_demand.points: @@ -184,7 +172,7 @@ def updateState(self, peer, sender, bus, topic, headers, message): tAirMixed= info['MixedAirTemperature'] tAirReturn= info['ReturnAirTemperature'] tAirSupply= info['DischargeAirTemperature'] - mDotAir= info['DischargeAirFlow'] + mDotAir= info['DischargeAirFlow'] diff --git a/examples/MarketAgents/AHUAgent/setup.py b/examples/MarketAgents/AHUAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/MarketAgents/AHUAgent/setup.py +++ b/examples/MarketAgents/AHUAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/MarketAgents/ElectricBuyerAgent/electric_buyer/agent.py b/examples/MarketAgents/ElectricBuyerAgent/electric_buyer/agent.py index 2b76920610..e8c92b6da5 100644 --- a/examples/MarketAgents/ElectricBuyerAgent/electric_buyer/agent.py +++ b/examples/MarketAgents/ElectricBuyerAgent/electric_buyer/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys diff --git a/examples/MarketAgents/ElectricBuyerAgent/setup.py b/examples/MarketAgents/ElectricBuyerAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/MarketAgents/ElectricBuyerAgent/setup.py +++ b/examples/MarketAgents/ElectricBuyerAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/MarketAgents/ElectricMeterAgent/electric_meter/agent.py b/examples/MarketAgents/ElectricMeterAgent/electric_meter/agent.py index f967cdc534..0c7e1fdbcc 100644 --- a/examples/MarketAgents/ElectricMeterAgent/electric_meter/agent.py +++ b/examples/MarketAgents/ElectricMeterAgent/electric_meter/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys diff --git a/examples/MarketAgents/ElectricMeterAgent/setup.py b/examples/MarketAgents/ElectricMeterAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/MarketAgents/ElectricMeterAgent/setup.py +++ b/examples/MarketAgents/ElectricMeterAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/MarketAgents/LightingAgent/light/agent.py b/examples/MarketAgents/LightingAgent/light/agent.py index aae5fa11da..68cc6b21be 100644 --- a/examples/MarketAgents/LightingAgent/light/agent.py +++ b/examples/MarketAgents/LightingAgent/light/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import gevent import random @@ -61,7 +47,7 @@ def light_agent(config_path, **kwargs): :type config_path: str :returns: Market Service Agent :rtype: MarketServiceAgent - """ + """ try: config = utils.load_config(config_path) except Exception: @@ -73,8 +59,8 @@ def light_agent(config_path, **kwargs): market_name = config.get('market_name') k= config.get('k', 0) qmax= float(config.get('Pmax', 0)) - Pabsnom= float(config.get('Pabsnom', 0)) - nonResponsive= config.get('nonResponsive', False) + Pabsnom= float(config.get('Pabsnom', 0)) + nonResponsive= config.get('nonResponsive', False) agent_name= config.get('agent_name') subscribing_topic= config.get('subscribing_topic', '') verbose_logging= config.get('verbose_logging', True) @@ -89,10 +75,10 @@ class LightAgent(MarketAgent, FirstOrderZone): def __init__(self, market_name,agent_name,k,qmax,Pabsnom,nonResponsive,verbose_logging,subscribing_topic, **kwargs): super(LightAgent, self).__init__(verbose_logging, **kwargs) self.market_name = market_name - self.agent_name = agent_name + self.agent_name = agent_name self.k = k self.qmax = qmax - self.Pabsnom=Pabsnom + self.Pabsnom=Pabsnom self.nonResponsive = nonResponsive self.iniState() self.subscribing_topic=subscribing_topic @@ -133,7 +119,7 @@ def iniState(self): self.qMax = self.qmax self.qNorm=self.qMax self.qClear=self.qNorm - + def updateState(self, peer, sender, bus, topic, headers, message): '''Subscribe to device data from message bus @@ -142,7 +128,7 @@ def updateState(self, peer, sender, bus, topic, headers, message): info = message[0].copy() self.hvacAvail = info['SupplyFanStatus'] if (self.hvacAvail > 0): - self.qNorm=self.qMax + self.qNorm=self.qMax else: self.qNorm=0 @@ -158,12 +144,12 @@ def updateSet(self): def clamp(self, value, x1, x2): minValue = min(x1, x2) maxValue = max(x1, x2) - return min(max(value, minValue), maxValue) - + return min(max(value, minValue), maxValue) + def price_callback(self, timestamp, market_name, buyer_seller, price, quantity): _log.debug("the price is {}".format(price)) self.pClear=price - if self.pClear is not None: + if self.pClear is not None: self.updateSet() _log.debug("the new lightingt is {}".format(self.qClear)) gevent.sleep(random.random()) @@ -173,10 +159,10 @@ def price_callback(self, timestamp, market_name, buyer_seller, price, quantity): def error_callback(self, timestamp, market_name, buyer_seller, error_code, error_message, aux): _log.debug("the new lightingt is {}".format(self.qNorm)) self.vip.rpc.call('platform.actuator','set_point', self.agent_name,self.subscribing_topic+'/'+self.agent_name,round(self.qNorm,2)).get(timeout=5) - + def ease(self, target, current, limit): - return current - np.sign(current-target)*min(abs(current-target), abs(limit)) + return current - np.sign(current-target)*min(abs(current-target), abs(limit)) def main(): diff --git a/examples/MarketAgents/LightingAgent/setup.py b/examples/MarketAgents/LightingAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/MarketAgents/LightingAgent/setup.py +++ b/examples/MarketAgents/LightingAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/MarketAgents/MeterAgent/meter/agent.py b/examples/MarketAgents/MeterAgent/meter/agent.py index 14460bedf5..ec4e620d37 100644 --- a/examples/MarketAgents/MeterAgent/meter/agent.py +++ b/examples/MarketAgents/MeterAgent/meter/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys @@ -96,7 +82,7 @@ def offer_callback(self, timestamp, market_name, buyer_seller): _log.debug("No offer for Market: {} {}".format(market_name, buyer_seller)) - + def reservation_callback(self, timestamp, market_name, buyer_seller): if (self.num % 2) == 0: self.want_reservation = True @@ -106,7 +92,7 @@ def reservation_callback(self, timestamp, market_name, buyer_seller): self.num = (self.num + 1) % 256 # We don't want this number to get very large. return self.want_reservation - + def create_supply_curve(self): supply_curve = PolyLine() price = self.price diff --git a/examples/MarketAgents/MeterAgent/setup.py b/examples/MarketAgents/MeterAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/MarketAgents/MeterAgent/setup.py +++ b/examples/MarketAgents/MeterAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/MarketAgents/VAVAgent/setup.py b/examples/MarketAgents/VAVAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/MarketAgents/VAVAgent/setup.py +++ b/examples/MarketAgents/VAVAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/MarketAgents/VAVAgent/vav/agent.py b/examples/MarketAgents/VAVAgent/vav/agent.py index 366ce61bda..9198f8aabf 100644 --- a/examples/MarketAgents/VAVAgent/vav/agent.py +++ b/examples/MarketAgents/VAVAgent/vav/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys @@ -61,7 +47,7 @@ def vav_agent(config_path, **kwargs): :type config_path: str :returns: Market Service Agent :rtype: MarketServiceAgent - """ + """ try: config = utils.load_config(config_path) except Exception: @@ -80,15 +66,15 @@ def vav_agent(config_path, **kwargs): c1= config.get('c1', 0) c2= config.get('c2', 0) c3= config.get('c3', 0) - c4= config.get('c4', 0) + c4= config.get('c4', 0) tMinAdj= config.get('tMin', 0) tMaxAdj= config.get('tMax', 0) mDotMin= config.get('mDotMin', 0) mDotMax= config.get('mDotMax', 0) tIn= config.get('tIn', 0) - nonResponsive= config.get('nonResponsive', False) + nonResponsive= config.get('nonResponsive', False) agent_name= config.get('agent_name') - subscribing_topic= config.get('subscribing_topic') + subscribing_topic= config.get('subscribing_topic') verbose_logging= config.get('verbose_logging', True) return VAVAgent(market_name,agent_name,x0,x1,x2,x3,x4,c0,c1,c2,c3,c4,tMinAdj,tMaxAdj,mDotMin,mDotMax,tIn,nonResponsive,verbose_logging,subscribing_topic, **kwargs) @@ -101,7 +87,7 @@ class VAVAgent(MarketAgent, FirstOrderZone): def __init__(self, market_name,agent_name,x0,x1,x2,x3,x4,c0,c1,c2,c3,c4,tMinAdj,tMaxAdj,mDotMin,mDotMax,tIn,nonResponsive,verbose_logging,subscribing_topic, **kwargs): super(VAVAgent, self).__init__(verbose_logging, **kwargs) self.market_name = market_name - self.agent_name = agent_name + self.agent_name = agent_name self.x0 = x0 self.x1 = x1 self.x2 = x2 @@ -122,19 +108,19 @@ def __init__(self, market_name,agent_name,x0,x1,x2,x3,x4,c0,c1,c2,c3,c4,tMinAdj, self.iniState() self.subscribing_topic=subscribing_topic self.join_market(self.market_name, BUYER, None, self.offer_callback, None, self.price_callback, self.error_callback) - + @Core.receiver('onstart') def setup(self, sender, **kwargs): _log.debug('Subscribing to '+self.subscribing_topic) self.vip.pubsub.subscribe(peer='pubsub', prefix=self.subscribing_topic, callback=self.updateState) - + def offer_callback(self, timestamp, market_name, buyer_seller): self.make_offer(market_name, buyer_seller, self.create_demand_curve()) def create_demand_curve(self): - self.demand_curve = PolyLine() + self.demand_curve = PolyLine() pMin = 10 pMax = 100 qMin = abs(self.getQMin()) @@ -157,13 +143,13 @@ def iniState(self): self.occupied = 0 self.tSet=22 self.tDel=0.5 - self.tEase=0.25 - self.qHvacSens = self.mDot*1006.*(self.tSup-self.tNomAdj) + self.tEase=0.25 + self.qHvacSens = self.mDot*1006.*(self.tSup-self.tNomAdj) self.qMin = min(0, self.mDotMin*1006.*(self.tSupHvac-self.tNomAdj)) self.qMax = min(0, self.mDotMax*1006.*(self.tSupHvac-self.tNomAdj)) self.pClear = None - - + + def updateState(self, peer, sender, bus, topic, headers, message): '''Subscribe to device data from message bus ''' @@ -175,7 +161,7 @@ def updateState(self, peer, sender, bus, topic, headers, message): self.mDot = info['VAV'+self.agent_name+'_ZoneAirFlow'] self.tSup = info['VAV'+self.agent_name+'_ZoneDischargeAirTemperature'] self.tIn = info['VAV'+self.agent_name+'_ZoneTemperature'] - self.qHvacSens = self.mDot*1006.*(self.tSup-self.tIn) + self.qHvacSens = self.mDot*1006.*(self.tSup-self.tIn) self.qMin = min(0, self.mDotMin*1006.*(self.tSupHvac-self.tIn)) self.qMax = min(0, self.mDotMax*1006.*(self.tSupHvac-self.tIn)) @@ -189,7 +175,7 @@ def updateTSet(self): if self.qClear is None: self.qClear = 0. - + def getQMin(self): t = self.clamp(self.tSet+self.tDel, self.tMinAdj, self.tMaxAdj) q = self.clamp(self.getQ(t), self.qMax, self.qMin) @@ -204,8 +190,8 @@ def getQMax(self): def clamp(self, value, x1, x2): minValue = min(x1, x2) maxValue = max(x1, x2) - return min(max(value, minValue), maxValue) - + return min(max(value, minValue), maxValue) + def price_callback(self, timestamp, market_name, buyer_seller, price, quantity): _log.debug("the price is {}".format(price)) self.pClear=price @@ -213,19 +199,19 @@ def price_callback(self, timestamp, market_name, buyer_seller, price, quantity): _log.debug("the new set point is {}".format(self.tSet)) _log.debug("the set point is {}".format(self.subscribing_topic.replace('all','')+'VAV'+self.agent_name+'/ZoneCoolingTemperatureSetPoint')) self.vip.rpc.call('platform.actuator','set_point', self.agent_name,self.subscribing_topic.replace('all','')+'VAV'+self.agent_name+'/ZoneCoolingTemperatureSetPoint',self.tSet).get(timeout=5) - + def error_callback(self, timestamp, market_name, buyer_seller, error_code, error_message, aux): if error_code == NO_INTERSECT: self.vip.rpc.call('platform.actuator','set_point', self.agent_name,self.subscribing_topic.replace('all','')+'VAV'+self.agent_name+'/ZoneCoolingTemperatureSetPoint',self.tNomAdj).get(timeout=5) - - - + + + def ease(self, target, current, limit): - return current - np.sign(current-target)*min(abs(current-target), abs(limit)) - - - + return current - np.sign(current-target)*min(abs(current-target), abs(limit)) + + + def main(): """Main method called to start the agent.""" diff --git a/examples/NodeRed/node_red_publisher.py b/examples/NodeRed/node_red_publisher.py index d537b5c86f..b783a6492e 100644 --- a/examples/NodeRed/node_red_publisher.py +++ b/examples/NodeRed/node_red_publisher.py @@ -1,10 +1,9 @@ from datetime import datetime +import logging import os import sys - import gevent -import logging from gevent.core import callback from gevent import Timeout diff --git a/examples/NodeRed/node_red_subscriber.py b/examples/NodeRed/node_red_subscriber.py index f8206a7c5d..6658a62dc6 100644 --- a/examples/NodeRed/node_red_subscriber.py +++ b/examples/NodeRed/node_red_subscriber.py @@ -2,7 +2,6 @@ import os import sys - import gevent from volttron.platform.messaging import headers as headers_mod diff --git a/examples/SCPAgent/scp/agent.py b/examples/SCPAgent/scp/agent.py index a589757e28..348dccc268 100644 --- a/examples/SCPAgent/scp/agent.py +++ b/examples/SCPAgent/scp/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from enum import Enum, auto diff --git a/examples/SCPAgent/setup.py b/examples/SCPAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/SCPAgent/setup.py +++ b/examples/SCPAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/SCPAgent/trigger_scp.py b/examples/SCPAgent/trigger_scp.py index 31a40adf8b..a70f8bb546 100644 --- a/examples/SCPAgent/trigger_scp.py +++ b/examples/SCPAgent/trigger_scp.py @@ -1,46 +1,34 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} -from pathlib import Path + +import argparse import os +from pathlib import Path import shutil -import argparse import gevent + from volttron.platform.vip.agent.utils import build_agent diff --git a/examples/SchedulerExample/schedule_example/agent.py b/examples/SchedulerExample/schedule_example/agent.py index 3371418261..8d5c9975ad 100644 --- a/examples/SchedulerExample/schedule_example/agent.py +++ b/examples/SchedulerExample/schedule_example/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -71,35 +57,35 @@ def schedule_example(config_path, **kwargs): agent_id = config['agentid'] class SchedulerExample(Agent): - '''This agent can be used to demonstrate scheduling and + '''This agent can be used to demonstrate scheduling and acutation of devices. It reserves a non-existent device, then - acts when its time comes up. Since there is no device, this + acts when its time comes up. Since there is no device, this will cause an error. ''' - - + + def __init__(self, **kwargs): super(SchedulerExample, self).__init__(**kwargs) - + @Core.receiver('onsetup') def setup(self, sender, **kwargs): self._agent_id = config['agentid'] - @Core.receiver('onstart') + @Core.receiver('onstart') def startup(self, sender, **kwargs): # self.publish_schedule() self.use_rpc() - - - + + + @PubSub.subscribe('pubsub', topics.ACTUATOR_SCHEDULE_ANNOUNCE(campus='campus', building='building',unit='unit')) def actuate(self, peer, sender, bus, topic, headers, message): - print ("response:",topic,headers,message) + print("response:", topic, headers, message) if headers[headers_mod.REQUESTER_ID] != agent_id: return '''Match the announce for our fake device with our ID - Then take an action. Note, this command will fail since there is no + Then take an action. Note, this command will fail since there is no actual device''' headers = { 'requesterID': agent_id, @@ -109,8 +95,8 @@ def actuate(self, peer, sender, bus, topic, headers, message): building='building',unit='unit', point='point'), headers, str(0.0)) - - + + def publish_schedule(self): '''Periodically publish a schedule request''' headers = { @@ -119,12 +105,12 @@ def publish_schedule(self): 'requesterID': agent_id, #The name of the requesting agent. 'taskID': agent_id + "-ExampleTask", #The desired task ID for this task. It must be unique among all other scheduled tasks. 'priority': 'LOW', #The desired task priority, must be 'HIGH', 'LOW', or 'LOW_PREEMPT' - } - + } + start = str(datetime.datetime.now()) end = str(datetime.datetime.now() + datetime.timedelta(minutes=1)) - - + + msg = [ ['campus/building/unit', start, end], ["campus/building/device1", #First time slot. @@ -139,20 +125,20 @@ def publish_schedule(self): ] self.vip.pubsub.publish( 'pubsub', topics.ACTUATOR_SCHEDULE_REQUEST, headers, msg) - - + + def use_rpc(self): - try: + try: start = str(datetime.datetime.now()) end = str(datetime.datetime.now() + datetime.timedelta(minutes=1)) - + msg = [ ['campus/building/unit3',start,end] ] result = self.vip.rpc.call( - 'platform.actuator', + 'platform.actuator', 'request_new_schedule', - agent_id, + agent_id, "some task", 'LOW', msg).get(timeout=10) @@ -161,13 +147,13 @@ def use_rpc(self): print("Could not contact actuator. Is it running?") print(e) return - + try: if result['result'] == 'SUCCESS': result = self.vip.rpc.call( - 'platform.actuator', + 'platform.actuator', 'set_point', - agent_id, + agent_id, 'campus/building/unit3/some_point', '0.0').get(timeout=10) print("Set result", result) @@ -185,13 +171,13 @@ def use_rpc(self): print("Set_multiple_points result", result) except Exception as e: print("Expected to fail since there is no real device to set") - print(e) + print(e) Agent.__name__ = 'ScheduleExampleAgent' return SchedulerExample(**kwargs) - - - + + + def main(argv=sys.argv): '''Main method called by the eggsecutable.''' try: diff --git a/examples/SchedulerExample/setup.py b/examples/SchedulerExample/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/SchedulerExample/setup.py +++ b/examples/SchedulerExample/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/SimpleForwarder/setup.py b/examples/SimpleForwarder/setup.py index ae953a32cf..b8ca2e1416 100644 --- a/examples/SimpleForwarder/setup.py +++ b/examples/SimpleForwarder/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/SimpleForwarder/simpleforwarder/simpleforwarder.py b/examples/SimpleForwarder/simpleforwarder/simpleforwarder.py index 552291e46f..3b15bdb2a9 100644 --- a/examples/SimpleForwarder/simpleforwarder/simpleforwarder.py +++ b/examples/SimpleForwarder/simpleforwarder/simpleforwarder.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -76,19 +62,19 @@ def simpleforwarder(config_path, **kwargs): identity = config.get('identity', kwargs.pop('identity', None)) forward_identity = config.get('forward_identity', None) forward_points = config.get('forward_points', []) - + point_ex = [re.compile(v) for v in forward_points] has_point_ex = len(point_ex) > 0 - + assert destination_vip - + class SimpleForwarder(Agent): '''This is a simple example of a historian agent that writes stuff to a SQLite database. It is designed to test some of the functionality of the BaseHistorianAgent. ''' - + @Core.receiver("onstart") def starting(self, sender, **kwargs): ''' @@ -96,27 +82,27 @@ def starting(self, sender, **kwargs): datalogger, and device topics to capture data. ''' _log.info('Starting forwarder to {}'.format(destination_vip)) - - + + agent = Agent(identity=forward_identity, address=destination_vip) event = gevent.event.Event() - + # agent.core.run set the event flag to true when agent is running gevent.spawn(agent.core.run, event) - - # Wait until the agent is fully initialized and ready to + + # Wait until the agent is fully initialized and ready to # send and receive messages. event.wait() self._target_platform = agent - + #subscribe to everything on the local bus. - self.vip.pubsub.subscribe(peer='pubsub', prefix='', + self.vip.pubsub.subscribe(peer='pubsub', prefix='', callback=self.data_received) - + def data_received(self, peer, sender, bus, topic, headers, message): - + def publish_external(agent, topic, headers, message): try: _log.debug('Attempting to publish remotely {}, {}, {}'.format(topic, headers, message)) @@ -140,15 +126,15 @@ def publish_external(agent, topic, headers, message): assert 'units' in v assert 'type' in v #message = [jsonapi.loads(message[0]), jsonapi.loads(message[1])] - + if has_point_ex: for rex in point_ex: if rex.match(topic): publish_external(self._target_platform, topic, headers, message) else: publish_external(self._target_platform, topic, headers, message) - - + + @Core.receiver("onstop") def stopping(self, sender, **kwargs): ''' diff --git a/examples/SimpleWebAgent/setup.py b/examples/SimpleWebAgent/setup.py index 1b78e26043..d184863a32 100644 --- a/examples/SimpleWebAgent/setup.py +++ b/examples/SimpleWebAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/SimpleWebAgent/simpleweb/agent.py b/examples/SimpleWebAgent/simpleweb/agent.py index 04aeb71a9a..00b6533d1e 100644 --- a/examples/SimpleWebAgent/simpleweb/agent.py +++ b/examples/SimpleWebAgent/simpleweb/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -100,10 +86,10 @@ def starting(self, sender, **kwargs): # (default) endpoint and one that returns a different content-type. # With the JSON-RPC example from vc we only allow post requests, however # this is not required. - + # Endpoint will be available at http://localhost:8080/simple/text self.vip.web.register_endpoint("/simple/text", callback=self.text) - + # Endpoint will be available at http://localhost:8080/simpleweb/jsonrpc self.vip.web.register_endpoint("/simpleweb/jsonrpc", callback=self.rpcendpoint) diff --git a/examples/StandAloneFileWatcher/standalonefilewatchpublisher.py b/examples/StandAloneFileWatcher/standalonefilewatchpublisher.py index 5b1cf17f40..9ddb5a95a3 100644 --- a/examples/StandAloneFileWatcher/standalonefilewatchpublisher.py +++ b/examples/StandAloneFileWatcher/standalonefilewatchpublisher.py @@ -1,17 +1,15 @@ from datetime import datetime +import logging import os import sys import gevent -import logging - from volttron.platform.vip.agent import Agent, PubSub, RPC, Core from volttron.platform.agent import utils from volttron.platform.agent.utils import watch_file_with_fullpath from volttron.platform import jsonapi - # These are the options that can be set from the settings module. from settings import remote_url, config diff --git a/examples/StandAloneListener/standalonelistener.py b/examples/StandAloneListener/standalonelistener.py index 4acd2b61ce..f326cf2410 100644 --- a/examples/StandAloneListener/standalonelistener.py +++ b/examples/StandAloneListener/standalonelistener.py @@ -1,9 +1,9 @@ from datetime import datetime +import logging import os import sys import gevent -import logging from volttron.platform.messaging import headers as headers_mod from volttron.platform.vip.agent import Agent, PubSub, Core diff --git a/examples/StandAloneMatLab/standalone_matlab.py b/examples/StandAloneMatLab/standalone_matlab.py index 325e335fe9..2d07cd2038 100644 --- a/examples/StandAloneMatLab/standalone_matlab.py +++ b/examples/StandAloneMatLab/standalone_matlab.py @@ -1,10 +1,10 @@ from scriptwrapper import script_runner -import os -import sys -import json import gevent +import json import logging +import os +import sys from volttron.platform.vip.agent import Agent, PubSub, Core from volttron.platform.agent import utils diff --git a/examples/StandAloneWithAuth/standalonewithauth.py b/examples/StandAloneWithAuth/standalonewithauth.py index f0c4284c63..77598b0602 100644 --- a/examples/StandAloneWithAuth/standalonewithauth.py +++ b/examples/StandAloneWithAuth/standalonewithauth.py @@ -21,11 +21,11 @@ """ from datetime import datetime +import logging import os import sys import gevent -import logging from gevent.core import callback from volttron.platform.vip.agent import Agent, Core, RPC diff --git a/examples/WeatherUndergroundAgent/setup.py b/examples/WeatherUndergroundAgent/setup.py index 0df83e9979..ea8fe8f165 100644 --- a/examples/WeatherUndergroundAgent/setup.py +++ b/examples/WeatherUndergroundAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/examples/WeatherUndergroundAgent/tests/test_weather_agent.py b/examples/WeatherUndergroundAgent/tests/test_weather_agent.py index 52be042f91..e4ca867d8a 100644 --- a/examples/WeatherUndergroundAgent/tests/test_weather_agent.py +++ b/examples/WeatherUndergroundAgent/tests/test_weather_agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -41,8 +27,8 @@ from volttron.platform import get_services_core, get_examples """ -Pytest test cases for testing weather agent both using pubsub request and -regular polling. +Pytest test cases for testing weather agent both using pubsub request and +regular polling. """ from datetime import datetime, timedelta diff --git a/examples/WeatherUndergroundAgent/weather/weather.py b/examples/WeatherUndergroundAgent/weather/weather.py index 98c0c1b09d..c93fa4bed8 100644 --- a/examples/WeatherUndergroundAgent/weather/weather.py +++ b/examples/WeatherUndergroundAgent/weather/weather.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys import logging diff --git a/examples/WebSocketAgent/setup.py b/examples/WebSocketAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/examples/WebSocketAgent/setup.py +++ b/examples/WebSocketAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/examples/WebSocketAgent/websocketagent/agent.py b/examples/WebSocketAgent/websocketagent/agent.py index 0e44e125ab..b10b90ceec 100644 --- a/examples/WebSocketAgent/websocketagent/agent.py +++ b/examples/WebSocketAgent/websocketagent/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/examples/configurations/drivers/dnp3.csv b/examples/configurations/drivers/dnp3.csv index 571d2e9a8e..e71b832b3d 100644 --- a/examples/configurations/drivers/dnp3.csv +++ b/examples/configurations/drivers/dnp3.csv @@ -1,13 +1,17 @@ -Volttron Point Name,Group,Index,Scaling,Units,Writable -DCHD.WTgt,41,65,1.0,NA,FALSE -DCHD.WTgt-In,30,90,1.0,NA,TRUE -DCHD.WinTms,41,66,1.0,NA,FALSE -DCHD.RmpTms,41,67,1.0,NA,FALSE -DCHD.RevtTms,41,68,1.0,NA,FALSE -DCHD.RmpUpRte,41,69,1.0,NA,FALSE -DCHD.RmpDnRte,41,70,1.0,NA,FALSE -DCHD.ChaRmpUpRte,41,71,1.0,NA,FALSE -DCHD.ChaRmpDnRte,41,72,1.0,NA,FALSE -DCHD.ModPrty,41,9,1.0,NA,FALSE -DCHD.VArAct,41,10,1.0,NA,FALSE -DCHD.ModEna,12,5,1.0,NA,FALSE +Point Name,Volttron Point Name,Group,Variation,Index,Scaling,Units,Writable,Notes +AnalogInput_index0,AnalogInput_index0,30,6,0,1,NA,FALSE,Double Analogue input without status +AnalogInput_index1,AnalogInput_index1,30,6,1,1,NA,FALSE,Double Analogue input without status +AnalogInput_index2,AnalogInput_index2,30,6,2,1,NA,FALSE,Double Analogue input without status +AnalogInput_index3,AnalogInput_index3,30,6,3,1,NA,FALSE,Double Analogue input without status +BinaryInput_index0,BinaryInput_index0,1,2,0,1,NA,FALSE,Single bit binary input with status +BinaryInput_index1,BinaryInput_index1,1,2,1,1,NA,FALSE,Single bit binary input with status +BinaryInput_index2,BinaryInput_index2,1,2,2,1,NA,FALSE,Single bit binary input with status +BinaryInput_index3,BinaryInput_index3,1,2,3,1,NA,FALSE,Single bit binary input with status +AnalogOutput_index0,AnalogOutput_index0,40,4,0,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index1,AnalogOutput_index1,40,4,1,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index2,AnalogOutput_index2,40,4,2,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index3,AnalogOutput_index3,40,4,3,1,NA,TRUE,Double-precision floating point with flags +BinaryOutput_index0,BinaryOutput_index0,10,2,0,1,NA,TRUE,Binary Output with flags +BinaryOutput_index1,BinaryOutput_index1,10,2,1,1,NA,TRUE,Binary Output with flags +BinaryOutput_index2,BinaryOutput_index2,10,2,2,1,NA,TRUE,Binary Output with flags +BinaryOutput_index3,BinaryOutput_index3,10,2,3,1,NA,TRUE,Binary Output with flags diff --git a/examples/configurations/drivers/test_dnp3.config b/examples/configurations/drivers/test_dnp3.config index 7296eae4bc..3f66b07e9f 100644 --- a/examples/configurations/drivers/test_dnp3.config +++ b/examples/configurations/drivers/test_dnp3.config @@ -1,13 +1,14 @@ { - "driver_config": { - "dnp3_agent_id": "dnp3agent" - }, - "campus": "campus", - "building": "building", - "unit": "dnp3", - "driver_type": "dnp3", - "registry_config": "config://dnp3.csv", - "interval": 15, - "timezone": "US/Pacific", - "heart_beat_point": "Heartbeat" -} \ No newline at end of file + "driver_config": {"master_ip": "0.0.0.0", "outstation_ip": "127.0.0.1", + "master_id": 2, "outstation_id": 1, + "port": 20000}, + "registry_config":"config://udd-Dnp3.csv", + "driver_type": "udd_dnp3", + "interval": 5, + "timezone": "UTC", + "campus": "campus-vm", + "building": "building-vm", + "unit": "Dnp3", + "publish_depth_first_all": true, + "heart_beat_point": "random_bool" +} diff --git a/examples/configurations/rabbitmq/rabbitmq_config.yml b/examples/configurations/rabbitmq/rabbitmq_config.yml index e6bf802fdc..e34a3a97bc 100644 --- a/examples/configurations/rabbitmq/rabbitmq_config.yml +++ b/examples/configurations/rabbitmq/rabbitmq_config.yml @@ -48,8 +48,8 @@ ssl: true #use-existing-certs: True -# defaults to ~/rabbitmq_server/rabbbitmq_server-3.9.7 -rmq-home: ~/rabbitmq_server/rabbitmq_server-3.9.7 +# defaults to ~/rabbitmq_server/rabbbitmq_server-3.9.29 +rmq-home: ~/rabbitmq_server/rabbitmq_server-3.9.29 # RabbitMQ reconnect retry delay (in seconds) reconnect-delay: 30 diff --git a/integrations/energyplus_integration.py b/integrations/energyplus_integration.py index bb178d5e5e..7941cc796c 100644 --- a/integrations/energyplus_integration.py +++ b/integrations/energyplus_integration.py @@ -1,49 +1,37 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} -import os import logging -from gevent import monkey, sleep -import weakref +from calendar import monthrange +from datetime import datetime +import os import socket import subprocess -from datetime import datetime -from calendar import monthrange +import weakref + +from gevent import monkey, sleep + from volttron.platform.agent.base_simulation_integration.base_sim_integration import BaseSimIntegration monkey.patch_socket() @@ -116,8 +104,21 @@ def register_inputs(self, config=None, callback=None, **kwargs): Save the user agent callback :return: """ - self.inputs = self.config.get('inputs', []) - self.outputs = self.config.get('outputs', []) + def parse_input_output(input_output): + if isinstance(input_output, list): + parsed = input_output + elif isinstance(input_output, dict): + parsed = [] + for k, v in input_output.items(): + v['sim_topic'] = k + parsed.append(v) + else: + raise ValueError( + 'Inputs from configuration must be a list of dictionaries or a dictionary of dictionaries') + return parsed + + self.inputs = parse_input_output(self.config.get('inputs', [])) + self.outputs = parse_input_output(self.config.get('outputs', [])) if 'properties' in self.config and isinstance(self.config['properties'], dict): self.__dict__.update(self.config['properties']) self.callback = callback @@ -237,7 +238,7 @@ def send_eplus_msg(self): _log.info('Sending message to EnergyPlus: ' + msg) self.sent = self.sent.encode() self.socket_server.send(self.sent) - + def recv_eplus_msg(self, msg): """ Receive outputs from EnergyPlus, parse the messages and hand it over @@ -248,13 +249,13 @@ def recv_eplus_msg(self, msg): # Call Agent callback to do whatever with the message if self.callback is not None: self.callback() - + def parse_eplus_msg(self, msg): """ Parse EnergyPlus message to update output values and simulation datetime """ - msg = msg.decode("utf-8") + msg = msg.decode("utf-8") msg = msg.rstrip() _log.info(f"Received message from EnergyPlus: {msg}") arry = msg.split() diff --git a/integrations/gridappsd_integration.py b/integrations/gridappsd_integration.py index 1ccb6ed5f7..3602faf59f 100644 --- a/integrations/gridappsd_integration.py +++ b/integrations/gridappsd_integration.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} try: @@ -46,11 +32,12 @@ HAS_GAPPSD = False RuntimeError('GridAPPSD must be installed before running this script ') -import os import logging -import gevent +import os import weakref +import gevent + from volttron.platform.agent.base_simulation_integration.base_sim_integration import BaseSimIntegration _log = logging.getLogger(__name__) @@ -216,5 +203,3 @@ def stop_simulation(self, *args, **kwargs): self.gridappsd.disconnect() except Exception: _log.error("Error stop GridAPPSD simulation") - - diff --git a/integrations/helics_integration.py b/integrations/helics_integration.py index 2a660f4cac..86fbab72b8 100644 --- a/integrations/helics_integration.py +++ b/integrations/helics_integration.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} try: @@ -43,13 +29,16 @@ HAS_HELICS = False RuntimeError('HELICS must be installed before running this script ') -import os +from copy import deepcopy import logging -import gevent +import os import weakref + +import gevent + from volttron.platform.agent.base_simulation_integration.base_sim_integration import BaseSimIntegration from volttron.platform import jsonapi -from copy import deepcopy + _log = logging.getLogger(__name__) __version__ = '1.0' @@ -351,5 +340,3 @@ def stop_simulation(self, *args, **kwargs): h.helicsCloseLibrary() except h._helics.HelicsException as e: _log.exception("Error stopping HELICS federate {}".format(e)) - - diff --git a/pytest.ini b/pytest.ini index 0261b0897e..1830fef016 100644 --- a/pytest.ini +++ b/pytest.ini @@ -69,3 +69,4 @@ markers = # To support testing asyncio code with pytest (e.g. OpenADRVenAgent), we need to set this configuration option. # See documentation on this configuration option at https://pypi.org/project/pytest-asyncio/ asyncio_mode = auto + diff --git a/requirements.py b/requirements.py index bac0d08fcc..249d9b56ce 100644 --- a/requirements.py +++ b/requirements.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} # These need to be importable by bootstrap.py. If we put them in @@ -44,7 +30,7 @@ # wheel version 0.31 has removed metadata.json file # https://github.com/pypa/wheel/issues/195 # so sticking to 0.30 for now. Could upgrade to wheel 0.31 with code changes -option_requirements = [('wheel==0.30', []), ('pyzmq==22.2.1', ['--zmq=bundled'])] +option_requirements = [('pip==24.0', []), ('wheel==0.30', []), ('pyzmq==22.2.1', ['--zmq=bundled'])] install_requires = ['gevent==21.12.0', @@ -61,29 +47,31 @@ 'tzlocal==2.1', #'pyOpenSSL==19.0.0', 'cryptography==37.0.4', - 'watchdog-gevent==0.1.1'] + 'watchdog-gevent==0.1.1', + 'deprecated==1.2.14'] extras_require = {'crate': ['crate==0.27.1'], 'databases': ['mysql-connector-python==8.0.30', - 'pymongo==4.2.0', + 'pymongo==4.5.0', 'crate==0.27.1', 'influxdb==5.3.1', - 'psycopg2-binary==2.8.6'], + 'psycopg2-binary==2.9.7'], 'documentation': ['mock==4.0.3', 'docutils<0.18', 'sphinx-rtd-theme==1.0.0', 'sphinx==5.1.1', - 'm2r2==0.3.2'], + 'm2r2==0.3.2', + 'sphinxcontrib-mermaid'], 'drivers': ['pymodbus==2.5.3', 'bacpypes==0.16.7', 'modbus-tk==1.1.2', 'pyserial==3.5'], 'influxdb': ['influxdb==5.3.1'], 'market': ['numpy==1.23.1', 'transitions==0.8.11'], - 'mongo': ['pymongo==4.2.0'], + 'mongo': ['pymongo==4.5.0'], 'mysql': ['mysql-connector-python==8.0.30'], 'pandas': ['numpy==1.23.1', 'pandas==1.4.3'], - 'postgres': ['psycopg2-binary==2.8.6'], + 'postgres': ['psycopg2-binary==2.9.7'], # This is installed in bootstrap.py itself so we don't # include here, though we include the version number here # @@ -99,10 +87,13 @@ 'pytest_asyncio==0.19.0', 'pytest_timeout==2.1.0'], 'weather': ['Pint==0.19.2'], + 'yapf': ['yapf'], 'web': ['ws4py==0.5.1', 'PyJWT==1.7.1', 'Jinja2==3.1.2', 'passlib==1.7.4', 'argon2-cffi==21.3.0', 'Werkzeug==2.2.1', - 'treelib==1.6.1']} + 'treelib==1.6.1'], + 'dnp3': ['dnp3-python==0.2.3b3'], + 'openadr': ['openleadr==0.5.30']} diff --git a/scripts/bacnet/bacnet_scan.py b/scripts/bacnet/bacnet_scan.py index a19060f234..7f0bf3fb51 100644 --- a/scripts/bacnet/bacnet_scan.py +++ b/scripts/bacnet/bacnet_scan.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -245,7 +231,7 @@ def time_out(): stop() thread = threading.Thread(target=time_out) - thread.start() + thread.start() this_application.request(request) @@ -257,4 +243,3 @@ def time_out(): _log.debug("finally") if f is not None: f.close() - diff --git a/scripts/bacnet/grab_bacnet_config.py b/scripts/bacnet/grab_bacnet_config.py index ef49cbe6ba..9d41ce8402 100644 --- a/scripts/bacnet/grab_bacnet_config.py +++ b/scripts/bacnet/grab_bacnet_config.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys @@ -77,37 +63,37 @@ def __init__(self, *args): def confirmation(self, apdu): self.apdu = apdu stop() - + def indication(self, apdu): # We only care about indications if we sent out a who is request. if not isinstance(self._request, WhoIsRequest): _log.debug("Ignoring indication as we don't have an outstanding WhoIs") return - + # We only care about IAmRequest if not isinstance(apdu, IAmRequest): _log.debug("Ignoring indication as apdu is not IAm") return - + # Ignore IAmRequests that don't have the device id we care about. - if self.expected_device_id is not None: + if self.expected_device_id is not None: device_type, device_instance = apdu.iAmDeviceIdentifier - + if device_type != 'device': raise DecodingError("invalid object type") - + if device_instance != self.expected_device_id: _log.debug("Ignoring IAm. Expected ID: {} Received: {}".format( self.expected_device_id, device_instance)) return - + self.apdu = apdu stop() def make_request(self, request, expected_device_id=None): self.expected_device_id = expected_device_id self._request = request - + self.request(request) run() return self.apdu @@ -115,15 +101,15 @@ def make_request(self, request, expected_device_id=None): def get_iam(app, device_id, target_address = None): request = WhoIsRequest() - + request.deviceInstanceRangeLowLimit = device_id request.deviceInstanceRangeHighLimit = device_id - + if target_address is not None: request.pduDestination = Address(target_address) else: request.pduDestination = GlobalBroadcast() - + result = app.make_request(request, expected_device_id=device_id) return result @@ -135,12 +121,12 @@ def read_prop(app, address, obj_type, obj_inst, prop_id, index=None): propertyIdentifier=prop_id, propertyArrayIndex=index) request.pduDestination = address - + result = app.make_request(request) if not isinstance(result, ReadPropertyACK): result.debug_contents(file=sys.stderr) raise TypeError("Error reading property") - + # find the datatype datatype = get_datatype(obj_type, prop_id) if issubclass(datatype, Array) and (result.propertyArrayIndex is not None): @@ -149,21 +135,21 @@ def read_prop(app, address, obj_type, obj_inst, prop_id, index=None): else: value = result.propertyValue.cast_out(datatype.subtype) else: - value = result.propertyValue.cast_out(datatype) + value = result.propertyValue.cast_out(datatype) return value def process_object(app, address, obj_type, index, max_range_report, config_writer): _log.debug('obj_type = ' + repr(obj_type)) _log.debug('bacnet_index = ' + repr(index)) - + writable = 'FALSE' - + present_value_type = get_datatype(obj_type, 'presentValue') if present_value_type is None: _log.debug('This object type has no presentValue. Skipping.') return - + if not issubclass(present_value_type, (Enumerated, Unsigned, Boolean, @@ -189,22 +175,22 @@ def process_object(app, address, obj_type, index, max_range_report, config_write pass except Exception: _log.debug(traceback.format_exc()) - + object_units_details = '' - + if issubclass(present_value_type, Enumerated): object_units = 'Enum' values = list(present_value_type.enumerations.values()) min_value = min(values) max_value = max(values) - + vendor_range = '' if hasattr(present_value_type, 'vendor_range'): vendor_min, vendor_max = present_value_type.vendor_range vendor_range = ' (vendor {min}-{max})'.format(min=vendor_min, max=vendor_max) - + object_units_details = '{min}-{max}{vendor}'.format(min=min_value, max=max_value, vendor=vendor_range) - + if not obj_type.endswith('Input'): try: default_value = read_prop(app, address, obj_type, index, "relinquishDefault") @@ -217,21 +203,21 @@ def process_object(app, address, obj_type, index, max_range_report, config_write pass except Exception: _log.debug(traceback.format_exc()) - + if not object_notes: enum_strings = [] try: for name in Enumerated.keylist(present_value_type(0)): value = present_value_type.enumerations[name] enum_strings.append(str(value) + '=' + name) - + object_notes = present_value_type.__name__ + ': ' + ', '.join(enum_strings) except AttributeError: pass elif issubclass(present_value_type, Boolean): object_units = 'Boolean' - + elif get_datatype(obj_type, 'units') is None: if obj_type.startswith('multiState'): object_units = 'State' @@ -242,18 +228,18 @@ def process_object(app, address, obj_type, index, max_range_report, config_write pass except Exception: _log.debug(traceback.format_exc()) - + try: enum_strings = [] state_list = read_prop(app, address, obj_type, index, "stateText") for name in state_list[1:]: enum_strings.append(name) - + object_notes = ', '.join('{}={}'.format(x,y) for x,y in enumerate(enum_strings, start=1)) - + except TypeError: pass - + if obj_type != 'multiStateInput': try: default_value = read_prop(app, address, obj_type, index, "relinquishDefault") @@ -266,11 +252,11 @@ def process_object(app, address, obj_type, index, max_range_report, config_write pass except Exception: _log.debug(traceback.format_exc()) - + elif obj_type == 'loop': object_units = 'Loop' else: - object_units = 'UNKNOWN UNITS' + object_units = 'UNKNOWN UNITS' else: object_units = 'UNKNOWN UNITS' try: @@ -279,10 +265,10 @@ def process_object(app, address, obj_type, index, max_range_report, config_write pass except Exception: _log.debug(traceback.format_exc()) - + if isinstance(object_units, int): object_units = 'UNKNOWN UNIT ENUM VALUE: ' + str(object_units) - + if obj_type.startswith('analog') or obj_type in ('largeAnalogValue', 'integerValue', 'positiveIntegerValue'): # Value objects never have a resolution property in practice. if not object_notes and not obj_type.endswith('Value'): @@ -291,15 +277,15 @@ def process_object(app, address, obj_type, index, max_range_report, config_write object_notes = 'Resolution: {resolution:.6g}'.format(resolution=res_value) except TypeError: pass - - if obj_type not in ('largeAnalogValue', 'integerValue', 'positiveIntegerValue'): + + if obj_type not in ('largeAnalogValue', 'integerValue', 'positiveIntegerValue'): try: min_value = read_prop(app, address, obj_type, index, "minPresValue") max_value = read_prop(app, address, obj_type, index, "maxPresValue") has_min = (min_value is not None) and (min_value > -max_range_report) has_max = (max_value is not None) and (max_value < max_range_report) - + if has_min and has_max: object_units_details = '{min:.2f} to {max:.2f}'.format(min=min_value, max=max_value) elif has_min: @@ -313,7 +299,7 @@ def process_object(app, address, obj_type, index, max_range_report, config_write pass except Exception: _log.debug(traceback.format_exc()) - + if obj_type != 'analogInput': try: default_value = read_prop(app, address, obj_type, index, "relinquishDefault") @@ -326,11 +312,11 @@ def process_object(app, address, obj_type, index, max_range_report, config_write pass except Exception: _log.debug(traceback.format_exc()) - + _log.debug(' object units = ' + str(object_units)) _log.debug(' object units details = ' + str(object_units_details)) - _log.debug(' object notes = ' + object_notes) - + _log.debug(' object notes = ' + object_notes) + results = { 'Reference Point Name': object_name, 'Volttron Point Name': object_name, @@ -349,13 +335,13 @@ def process_object(app, address, obj_type, index, max_range_report, config_write def main(): # parse the command line arguments arg_parser = ConfigArgumentParser(description=__doc__) - + arg_parser.add_argument("device_id", type=int, help="Device ID of the target device") - + arg_parser.add_argument("--address", help="Address of target device, may be needed to help route initial request to device.") - + arg_parser.add_argument("--registry-out-file", type=argparse.FileType('w'), help="Output registry to CSV file", default=sys.stdout) @@ -363,12 +349,12 @@ def main(): arg_parser.add_argument("--driver-out-file", type=argparse.FileType('w'), help="Output driver configuration to JSON file.", default=sys.stdout) - + arg_parser.add_argument("--max-range-report", nargs='?', type=float, help='Affects how very large numbers are reported in the "Unit Details" column of the ' 'output. Does not affect driver behavior.', default=1.0e+20) - + args = arg_parser.parse_args() _log.debug("initialization") @@ -387,12 +373,12 @@ def main(): this_application = SynchronousApplication(this_device, args.ini.address) _log.debug("starting build") - + result = get_iam(this_application, args.device_id, args.address) target_address = result.pduSource device_id = result.iAmDeviceIdentifier[1] - + _log.debug('pduSource = ' + repr(result.pduSource)) _log.debug('iAmDeviceIdentifier = ' + str(result.iAmDeviceIdentifier)) _log.debug('maxAPDULengthAccepted = ' + str(result.maxAPDULengthAccepted)) @@ -409,19 +395,19 @@ def main(): } jsonapi.dump(config, args.driver_out_file, indent=4) - + try: device_name = read_prop(this_application, target_address, "device", device_id, "objectName") _log.debug('device_name = ' + str(device_name)) except TypeError: _log.debug('device missing objectName') - + try: device_description = read_prop(this_application, target_address, "device", device_id, "description") _log.debug('description = ' + str(device_description)) except TypeError: _log.debug('device missing description') - + config_writer = DictWriter(args.registry_out_file, ('Reference Point Name', 'Volttron Point Name', @@ -433,7 +419,7 @@ def main(): 'Index', 'Write Priority', 'Notes')) - + config_writer.writeheader() try: @@ -442,14 +428,14 @@ def main(): except TypeError: object_count = read_prop(this_application, target_address, "device", device_id, "structuredObjectList", index=0) list_property = "structuredObjectList" - + _log.debug('objectCount = ' + str(object_count)) - + for object_index in range(1, object_count + 1): _log.debug('object_device_index = ' + repr(object_index)) - + bac_object = read_prop(this_application, target_address, "device", device_id, list_property, index=object_index) - + obj_type, index = bac_object try: @@ -465,7 +451,3 @@ def main(): _log.exception("an error has occurred: %s", e) finally: _log.debug("finally") - - - - diff --git a/scripts/bacnet/grab_multiple_configs.py b/scripts/bacnet/grab_multiple_configs.py index df47033f5e..f5258d54ae 100644 --- a/scripts/bacnet/grab_multiple_configs.py +++ b/scripts/bacnet/grab_multiple_configs.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import argparse diff --git a/scripts/bacnet/proxy_bacnet_scan.py b/scripts/bacnet/proxy_bacnet_scan.py index f3d887f16d..be97c13d70 100644 --- a/scripts/bacnet/proxy_bacnet_scan.py +++ b/scripts/bacnet/proxy_bacnet_scan.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import argparse @@ -102,7 +88,7 @@ def main(): arg_parser.add_argument("--debug", action="store_true", help="Set the logger in debug mode") - + args = arg_parser.parse_args() core_logger = logging.getLogger("volttron.platform.vip.agent.core") diff --git a/scripts/bacnet/proxy_grab_bacnet_config.py b/scripts/bacnet/proxy_grab_bacnet_config.py index 7f0955f4b9..b2068fdf70 100644 --- a/scripts/bacnet/proxy_grab_bacnet_config.py +++ b/scripts/bacnet/proxy_grab_bacnet_config.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys @@ -180,7 +166,3 @@ def main(): _log.exception("an error has occurred: %s", e) finally: _log.debug("finally") - - - - diff --git a/scripts/dnp3/get_point_demo.py b/scripts/dnp3/get_point_demo.py new file mode 100644 index 0000000000..bb1e090383 --- /dev/null +++ b/scripts/dnp3/get_point_demo.py @@ -0,0 +1,41 @@ +""" +A demo to test dnp3-driver get_point method using rpc call. + +Pre-requisite: +- install platform-driver +- configure dnp3-driver +- a dnp3 outstation/server is up and running +- platform-driver is up and running +""" + +import random +from volttron.platform.vip.agent.utils import build_agent +from time import sleep +import datetime + + +def main(): + a = build_agent() + while True: + sleep(5) + print("============") + try: + rpc_method = "get_point" + device_name = "campus-vm/building-vm/Dnp3" + + reg_pt_name = "AnalogInput_index0" + rs = a.vip.rpc.call("platform.driver", rpc_method, + device_name, + reg_pt_name).get(timeout=10) + print(datetime.datetime.now(), "point_name: ", reg_pt_name, "value: ", rs) + reg_pt_name = "AnalogInput_index1" + rs = a.vip.rpc.call("platform.driver", rpc_method, + device_name, + reg_pt_name).get(timeout=10) + print(datetime.datetime.now(), "point_name: ", reg_pt_name, "value: ", rs) + except Exception as e: + print(e) + + +if __name__ == "__main__": + main() diff --git a/scripts/dnp3/set_point_demo.py b/scripts/dnp3/set_point_demo.py new file mode 100644 index 0000000000..4f8de9115f --- /dev/null +++ b/scripts/dnp3/set_point_demo.py @@ -0,0 +1,52 @@ +""" +A demo to test dnp3-driver set_point method using rpc call. + +Pre-requisite: +- install platform-driver +- configure dnp3-driver +- a dnp3 outstation/server is up and running +- platform-driver is up and running +""" + +import random +from volttron.platform.vip.agent.utils import build_agent +from time import sleep +import datetime + + +def main(): + a = build_agent() + while True: + sleep(5) + print("============") + try: + rpc_method = "set_point" + device_name = "campus-vm/building-vm/Dnp3" + + for i in range(3): + reg_pt_name = "AnalogOutput_index" + str(i) + val_to_set = random.random() + rs = a.vip.rpc.call("platform.driver", rpc_method, + device_name, + reg_pt_name, + val_to_set).get(timeout=10) + print(datetime.datetime.now(), "point_name: ", reg_pt_name, "response: ", rs) + + # verify + sleep(1) + + for i in range(3): + rpc_method = "get_point" + reg_pt_name = "AnalogOutput_index" + str(i) + # val_to_set = random.random() + rs = a.vip.rpc.call("platform.driver", rpc_method, + device_name, + reg_pt_name + ).get(timeout=10) + print(datetime.datetime.now(), "point_name: ", reg_pt_name, "response: ", rs) + except Exception as e: + print(e) + + +if __name__ == "__main__": + main() diff --git a/scripts/extract_config_store.py b/scripts/extract_config_store.py index 5e56afa817..b5f0bfc686 100644 --- a/scripts/extract_config_store.py +++ b/scripts/extract_config_store.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import gevent @@ -74,7 +60,7 @@ def get_configs(config_id, output_directory): event.wait() config_list = agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_list_configs', + 'list_configs', config_id).get(timeout=10) if not config_list: @@ -88,7 +74,7 @@ def get_configs(config_id, output_directory): for config in config_list: print("Retrieving configuration", config) raw_config = agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_get', + 'get_config', config_id, config, raw=True).get(timeout=10) diff --git a/scripts/get_versions.py b/scripts/get_versions.py index dc45ec4a49..b87cc88af8 100644 --- a/scripts/get_versions.py +++ b/scripts/get_versions.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """Gets the version numbers of all agents in the services, examples, and applications directories. @@ -112,4 +98,3 @@ def get_agent_version(agent_path): for agent_version in agent_versions: dict_writer.writerow({"Agent": agent_version[0], "Version": agent_version[1]}) - diff --git a/scripts/historian-scripts/install-dbs-ubuntu-2004.sh b/scripts/historian-scripts/install-dbs-ubuntu-2004.sh new file mode 100755 index 0000000000..91cbe97564 --- /dev/null +++ b/scripts/historian-scripts/install-dbs-ubuntu-2004.sh @@ -0,0 +1,110 @@ +#! /bin/bash + + # Utility script for installing mysql, mongodb, and postgresql on Ubuntu 22.04 and creates test data base and test + # db user for testing volttron agents that use these databases. Installs databases on a /databases + # folder and assumes the unix user running VOLTTRON is "volttron" + # You can use this as a reference, update database versions and user name as needed to install database environment for + # testing volttron agents + # To run provide execute permissions and pass one or more database names as input + # For example + # ./install-dbs-ubuntu-2204.sh mongodb mysql postgresql + # ./install-dbs-ubuntu-2204.sh mongodb + # ./install-dbs-ubuntu-2204.sh mysql + +function install_mongodb(){ + mkdir -p /databases/mongodb + cd /databases/mongodb + sudo apt-get install -y libcurl4 openssl liblzma5 + wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2004-7.0.1.tgz + tar -xvzf mongodb-linux-x86_64-ubuntu2004-7.0.1.tgz + ln -s mongodb-linux-x86_64-ubuntu2004-7.0.1 mongodb + mkdir data + mkdir log + chown -R volttron /databases/mongodb + export PATH=$PATH:/databases/mongodb/mongodb/bin + echo 'export PATH=$PATH:/databases/mongodb/mongodb/bin' >> /home/volttron/.bashrc + echo "alias start_mongo='mongod --dbpath /databases/mongodb/data --logpath /databases/mongodb/log/mongod.log --fork'" >> /home/volttron/.bash_aliases + echo "alias stop_mongo='mongod --dbpath /databases/mongodb/data --logpath /databases/mongodb/log/mongod.log --shutdown'" >> /home/volttron/.bash_aliases + su volttron -c "/databases/mongodb/mongodb/bin/mongod --dbpath /databases/mongodb/data --logpath /databases/mongodb/log/mongod.log --fork" + wget https://downloads.mongodb.com/compass/mongosh-1.10.6-linux-x64-openssl11.tgz + tar -xvzf mongosh-1.10.6-linux-x64-openssl11.tgz + mv mongosh-1.10.6-linux-x64-openssl11/bin/* /databases/mongodb/mongodb/bin + chmod a+x /databases/mongodb/mongodb/bin/mongosh + mongosh admin --eval 'db.createUser( {user: "admin", pwd: "volttron", roles: [ { role: "userAdminAnyDatabase", db: "admin" }]});' + mongosh test_historian -u admin -p volttron --authenticationDatabase admin --eval 'db.createUser( {user: "historian", pwd: "historian", roles: [ { role: "readWrite", db: "test_historian" }]});' + su volttron -c "/databases/mongodb/mongodb/bin/mongod --dbpath /databases/mongodb/data --logpath /databases/mongodb/log/mongod.log --shutdown" +} + + +function install_mysql(){ + apt-get install -y libaio1 libncurses5 libnuma1 + mkdir -p /databases/mysql + cd /databases/mysql + wget https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.25-linux-glibc2.12-x86_64.tar.xz + tar -xvf mysql-8.0.25-linux-glibc2.12-x86_64.tar.xz + ln -s mysql-8.0.25-linux-glibc2.12-x86_64 mysql + groupadd mysql + useradd -r -g mysql -s /bin/false mysql + mkdir mysql-files data etc log + chmod 750 mysql-files data etc log + echo "[mysqld]" > etc/my.cnf + echo "basedir=/databases/mysql/mysql" >> etc/my.cnf + echo "datadir=/databases/mysql/data" >> etc/my.cnf + echo "log-error=/databases/mysql/log/mysql.err" >> etc/my.cnf + cd /databases/mysql + cp mysql/support-files/mysql.server mysql/bin + chown -R mysql:mysql /databases/mysql + export PATH=/databases/mysql/mysql/bin:$PATH + echo 'export PATH=/databases/mysql/mysql/bin:$PATH' >> /root/.bashrc + echo 'export PATH=/databases/mysql/mysql/bin:$PATH' >> /home/volttron/.bashrc + echo "alias start_mysql='sudo /databases/mysql/mysql/bin/mysql.server start'" >> /home/volttron/.bash_aliases + echo "alias stop_mysql='sudo /databases/mysql/mysql/bin/mysql.server stop'" >> /home/volttron/.bash_aliases + mysqld --defaults-file=/databases/mysql/etc/my.cnf --initialize-insecure --user=mysql + sed -i 's/^basedir=/basedir=\/databases\/mysql\/mysql/' /databases/mysql/mysql/bin/mysql.server + sed -i 's/^datadir=/datadir=\/databases\/mysql\/data/' /databases/mysql/mysql/bin/mysql.server + mysql.server start + mysql -u root -e "CREATE DATABASE test_historian;" + mysql -u root -e "CREATE USER 'historian'@'localhost' IDENTIFIED BY 'historian';" + mysql -u root -e "GRANT SELECT, INSERT, DELETE, CREATE, INDEX, UPDATE, DROP ON test_historian.* TO 'historian'@'localhost';" + mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'volttron';" + mysql.server stop +} + + +function install_postgresql(){ + apt-get install -y libreadline8 libreadline-dev zlib1g-dev + mkdir -p /databases/postgresql + cd /databases/postgresql + wget https://ftp.postgresql.org/pub/source/v10.16/postgresql-10.16.tar.gz + tar -xvzf postgresql-10.16.tar.gz + ln -s postgresql-10.16 postgresql_source + cd postgresql_source + ./configure --prefix=/databases/postgresql/pgsql + make + make install + echo 'export LD_LIBRARY_PATH=/databases/postgresql/pgsql/lib' >> /home/volttron/.bashrc + export LD_LIBRARY_PATH=/databases/postgresql/pgsql/lib + echo 'export PATH=/databases/postgresql/pgsql/bin:$PATH' >> /home/volttron/.bashrc + export PATH=/databases/postgresql/pgsql/bin:$PATH + export LD_LIBRARY_PATH=/databases/postgresql/pgsql/lib + ln -s /databases/postgresql/pgsql/lib/libpq.so.5 /usr/lib/libpq.so.5 + adduser --disabled-password --gecos "" postgres + mkdir /databases/postgresql/pgsql/data + chown -R postgres /databases/postgresql + su postgres -c "/databases/postgresql/pgsql/bin/initdb -D /databases/postgresql/pgsql/data" + echo "alias start_postgres='sudo su postgres -c \"/databases/postgresql/pgsql/bin/pg_ctl -D /databases/postgresql/pgsql/data -l /databases/postgresql/logfile start\"'" >> /home/volttron/.bash_aliases + echo "alias stop_postgres='sudo su postgres -c \"/databases/postgresql/pgsql/bin/pg_ctl -D /databases/postgresql/pgsql/data -l /databases/postgresql/logfile stop\"'" >> /home/volttron/.bash_aliases + sudo su postgres -c "/databases/postgresql/pgsql/bin/pg_ctl -D /databases/postgresql/pgsql/data -l /databases/postgresql/logfile start" + psql -U postgres -c 'CREATE DATABASE test_historian;' + psql -U postgres -c "CREATE USER historian with encrypted password 'historian';" + psql -U postgres -c "GRANT ALL PRIVILEGES on database test_historian to historian;" + sudo su postgres -c "/databases/postgresql/pgsql/bin/pg_ctl -D /databases/postgresql/pgsql/data -l /databases/postgresql/logfile stop" +} + +echo "Configured to install dbs: $@" +v=( "$@" ) +for i in ${v[@]} +do + echo "Calling install_$i" + install_$i +done diff --git a/scripts/historian-scripts/install-dbs-ubuntu-2204.sh b/scripts/historian-scripts/install-dbs-ubuntu-2204.sh new file mode 100755 index 0000000000..694d5b7b6f --- /dev/null +++ b/scripts/historian-scripts/install-dbs-ubuntu-2204.sh @@ -0,0 +1,110 @@ +#! /bin/bash + + # Utility script for installing mysql, mongodb, and postgresql on Ubuntu 22.04 and creates test data base and test + # db user for testing volttron agents that use these databases. Installs databases on a /databases + # folder and assumes the unix user running VOLTTRON is "volttron" + # You can use this as a reference, update database versions and user name as needed to install database environment for + # testing volttron agents + # To run provide execute permissions and pass one or more database names as input + # For example + # ./install-dbs-ubuntu-2204.sh mongodb mysql postgresql + # ./install-dbs-ubuntu-2204.sh mongodb + # ./install-dbs-ubuntu-2204.sh mysql + +function install_mongodb(){ + mkdir -p /databases/mongodb + cd /databases/mongodb + sudo apt-get install -y libcurl4 libgssapi-krb5-2 libldap-2.5-0 libwrap0 libsasl2-2 libsasl2-modules libsasl2-modules-gssapi-mit openssl liblzma5 + wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2204-7.0.1.tgz + tar -xvzf mongodb-linux-x86_64-ubuntu2204-7.0.1.tgz + ln -s mongodb-linux-x86_64-ubuntu2204-7.0.1 mongodb + mkdir data + mkdir log + chown -R volttron /databases/mongodb + export PATH=$PATH:/databases/mongodb/mongodb/bin + echo 'export PATH=$PATH:/databases/mongodb/mongodb/bin' >> /home/volttron/.bashrc + echo "alias start_mongo='mongod --dbpath /databases/mongodb/data --logpath /databases/mongodb/log/mongod.log --fork'" >> /home/volttron/.bash_aliases + echo "alias stop_mongo='mongod --dbpath /databases/mongodb/data --logpath /databases/mongodb/log/mongod.log --shutdown'" >> /home/volttron/.bash_aliases + su volttron -c "/databases/mongodb/mongodb/bin/mongod --dbpath /databases/mongodb/data --logpath /databases/mongodb/log/mongod.log --fork" + wget https://downloads.mongodb.com/compass/mongosh-1.10.6-linux-x64-openssl3.tgz + tar -xvzf mongosh-1.10.6-linux-x64-openssl3.tgz + mv mongosh-1.10.6-linux-x64-openssl3/bin/* /databases/mongodb/mongodb/bin + chmod a+x /databases/mongodb/mongodb/bin/mongosh + mongosh admin --eval 'db.createUser( {user: "admin", pwd: "volttron", roles: [ { role: "userAdminAnyDatabase", db: "admin" }]});' + mongosh test_historian -u admin -p volttron --authenticationDatabase admin --eval 'db.createUser( {user: "historian", pwd: "historian", roles: [ { role: "readWrite", db: "test_historian" }]});' + su volttron -c "/databases/mongodb/mongodb/bin/mongod --dbpath /databases/mongodb/data --logpath /databases/mongodb/log/mongod.log --shutdown" +} + + +function install_mysql(){ + apt-get install -y libaio1 libncurses5 libnuma1 + mkdir -p /databases/mysql + cd /databases/mysql + wget https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.25-linux-glibc2.12-x86_64.tar.xz + tar -xvf mysql-8.0.25-linux-glibc2.12-x86_64.tar.xz + ln -s mysql-8.0.25-linux-glibc2.12-x86_64 mysql + groupadd mysql + useradd -r -g mysql -s /bin/false mysql + mkdir mysql-files data etc log + chmod 750 mysql-files data etc log + echo "[mysqld]" > etc/my.cnf + echo "basedir=/databases/mysql/mysql" >> etc/my.cnf + echo "datadir=/databases/mysql/data" >> etc/my.cnf + echo "log-error=/databases/mysql/log/mysql.err" >> etc/my.cnf + cd /databases/mysql + cp mysql/support-files/mysql.server mysql/bin + chown -R mysql:mysql /databases/mysql + export PATH=/databases/mysql/mysql/bin:$PATH + echo 'export PATH=/databases/mysql/mysql/bin:$PATH' >> /root/.bashrc + echo 'export PATH=/databases/mysql/mysql/bin:$PATH' >> /home/volttron/.bashrc + echo "alias start_mysql='sudo /databases/mysql/mysql/bin/mysql.server start'" >> /home/volttron/.bash_aliases + echo "alias stop_mysql='sudo /databases/mysql/mysql/bin/mysql.server stop'" >> /home/volttron/.bash_aliases + mysqld --defaults-file=/databases/mysql/etc/my.cnf --initialize-insecure --user=mysql + sed -i 's/^basedir=/basedir=\/databases\/mysql\/mysql/' /databases/mysql/mysql/bin/mysql.server + sed -i 's/^datadir=/datadir=\/databases\/mysql\/data/' /databases/mysql/mysql/bin/mysql.server + mysql.server start + mysql -u root -e "CREATE DATABASE test_historian;" + mysql -u root -e "CREATE USER 'historian'@'localhost' IDENTIFIED BY 'historian';" + mysql -u root -e "GRANT SELECT, INSERT, DELETE, CREATE, INDEX, UPDATE, DROP ON test_historian.* TO 'historian'@'localhost';" + mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'volttron';" + mysql.server stop +} + + +function install_postgresql(){ + apt-get install -y libreadline8 libreadline-dev zlib1g-dev + mkdir -p /databases/postgresql + cd /databases/postgresql + wget https://ftp.postgresql.org/pub/source/v10.16/postgresql-10.16.tar.gz + tar -xvzf postgresql-10.16.tar.gz + ln -s postgresql-10.16 postgresql_source + cd postgresql_source + ./configure --prefix=/databases/postgresql/pgsql + make + make install + echo 'export LD_LIBRARY_PATH=/databases/postgresql/pgsql/lib' >> /home/volttron/.bashrc + export LD_LIBRARY_PATH=/databases/postgresql/pgsql/lib + echo 'export PATH=/databases/postgresql/pgsql/bin:$PATH' >> /home/volttron/.bashrc + export PATH=/databases/postgresql/pgsql/bin:$PATH + export LD_LIBRARY_PATH=/databases/postgresql/pgsql/lib + ln -s /databases/postgresql/pgsql/lib/libpq.so.5 /usr/lib/libpq.so.5 + adduser --disabled-password --gecos "" postgres + mkdir /databases/postgresql/pgsql/data + chown -R postgres /databases/postgresql + su postgres -c "/databases/postgresql/pgsql/bin/initdb -D /databases/postgresql/pgsql/data" + echo "alias start_postgres='sudo su postgres -c \"/databases/postgresql/pgsql/bin/pg_ctl -D /databases/postgresql/pgsql/data -l /databases/postgresql/logfile start\"'" >> /home/volttron/.bash_aliases + echo "alias stop_postgres='sudo su postgres -c \"/databases/postgresql/pgsql/bin/pg_ctl -D /databases/postgresql/pgsql/data -l /databases/postgresql/logfile stop\"'" >> /home/volttron/.bash_aliases + sudo su postgres -c "/databases/postgresql/pgsql/bin/pg_ctl -D /databases/postgresql/pgsql/data -l /databases/postgresql/logfile start" + psql -U postgres -c 'CREATE DATABASE test_historian;' + psql -U postgres -c "CREATE USER historian with encrypted password 'historian';" + psql -U postgres -c "GRANT ALL PRIVILEGES on database test_historian to historian;" + sudo su postgres -c "/databases/postgresql/pgsql/bin/pg_ctl -D /databases/postgresql/pgsql/data -l /databases/postgresql/logfile stop" +} + +echo "Configured to install dbs: $@" +v=( "$@" ) +for i in ${v[@]} +do + echo "Calling install_$i" + install_$i +done diff --git a/scripts/historian-scripts/update_sqlite_historian_database.py b/scripts/historian-scripts/update_sqlite_historian_database.py index a682c9dad0..bffbcd39d2 100644 --- a/scripts/historian-scripts/update_sqlite_historian_database.py +++ b/scripts/historian-scripts/update_sqlite_historian_database.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from argparse import ArgumentParser diff --git a/scripts/install_platform_driver_configs.py b/scripts/install_platform_driver_configs.py index 9bdf02ed86..3653dd151a 100644 --- a/scripts/install_platform_driver_configs.py +++ b/scripts/install_platform_driver_configs.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -89,13 +75,13 @@ def install_configs(input_directory, keep=False): if not keep: print("Deleting old Platform Driver store") agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get(timeout=10) with open("config") as f: print("Storing main configuration") agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'config', f.read(), @@ -105,7 +91,7 @@ def install_configs(input_directory, keep=False): with open(name) as f: print("Storing configuration:", name) agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', PLATFORM_DRIVER, name, f.read(), @@ -117,7 +103,7 @@ def install_configs(input_directory, keep=False): with open(name) as f: print("Storing configuration:", name) agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', PLATFORM_DRIVER, name, f.read(), diff --git a/scripts/make_release_requirements.py b/scripts/make_release_requirements.py index fca7a91868..c1aa047364 100644 --- a/scripts/make_release_requirements.py +++ b/scripts/make_release_requirements.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -120,4 +106,3 @@ def freeze_version(replacement_map, value): if __name__ == "__main__": main() - diff --git a/scripts/obix/get_obix_driver_config.py b/scripts/obix/get_obix_driver_config.py index ac2afffc91..9c690fa33c 100644 --- a/scripts/obix/get_obix_driver_config.py +++ b/scripts/obix/get_obix_driver_config.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from xml.dom.minidom import parseString @@ -141,5 +127,3 @@ def get_csv_row(element): } jsonapi.dump(config, args.devicefile, indent=4) - - diff --git a/scripts/obix/get_obix_history_config.py b/scripts/obix/get_obix_history_config.py index 2a25d13b1e..a272008fc1 100644 --- a/scripts/obix/get_obix_history_config.py +++ b/scripts/obix/get_obix_history_config.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from xml.dom.minidom import parseString @@ -114,5 +100,3 @@ def get_csv_row(element): } jsonapi.dump(config, args.devicefile, indent=4) - - diff --git a/scripts/pycharm-launch.py b/scripts/pycharm-launch.py index a2a5694d5c..e2663799c6 100644 --- a/scripts/pycharm-launch.py +++ b/scripts/pycharm-launch.py @@ -17,12 +17,13 @@ input box put services/core/VolttronCentral/volttroncentral/agent.py. """ import argparse -import shutil -import string -import sys import os import runpy +import shutil +import string import subprocess +import sys + from volttron.platform import jsonapi __author__ = 'Craig Allwardt' @@ -31,16 +32,21 @@ parser = argparse.ArgumentParser() parser.add_argument("agent", help="Path to the agent file to be executed.") -parser.add_argument("-s", "--silence", const=True, dest="silence", nargs="?", +parser.add_argument("-s", + "--silence", + const=True, + dest="silence", + nargs="?", help="Silence the help message.") -parser.add_argument("-n", "--no-config", action="store_true", +parser.add_argument("-n", + "--no-config", + action="store_true", help="Don't include the default config in the agent directory.") parsed = parser.parse_args() mod_name = [os.path.basename(parsed.agent)] if not os.path.isfile(parsed.agent): - sys.stdout.write("Passed argument must be a python file! {}". - format(parsed.agent)) + sys.stdout.write("Passed argument must be a python file! {}".format(parsed.agent)) sys.exit() abspath = os.path.abspath(os.path.join(parsed.agent, os.pardir)) @@ -60,14 +66,12 @@ def write_required_statement(out=sys.stderr): - out.write( - """Required Environment Variables - AGENT_VIP_IDENTITY - Required + out.write("""Required Environment Variables + AGENT_VIP_IDENTITY - Required Optional Environmental Variables AGENT_CONFIG - Set to /config by default VOLTTRON_HOME - Set to ~/.volttron by default -""" - ) +""") sys.path.insert(0, abspath) @@ -89,9 +93,7 @@ def write_required_statement(out=sys.stderr): if not volttron_home: os.environ['VOLTTRON_HOME'] = os.path.abspath( - os.path.expandvars( - os.path.join( - os.path.expanduser("~"), '.volttron'))) + os.path.expandvars(os.path.join(os.path.expanduser("~"), '.volttron'))) volttron_home = os.environ.get('VOLTTRON_HOME') # Now register the @@ -101,7 +103,7 @@ def write_required_statement(out=sys.stderr): sys.stderr.write("AGENT_VIP_IDENTITY MUST be set in environment\n") sys.exit(10) -valid_chars = "_.%s%s" % (string.ascii_letters, string.digits) +valid_chars = "_.-%s%s" % (string.ascii_letters, string.digits) for c in agent_identity: if c not in valid_chars: @@ -111,48 +113,65 @@ def write_required_statement(out=sys.stderr): sys.exit(10) if agent_identity: - new_dir = os.path.join(volttron_home, 'keystores', agent_identity) - if not os.path.exists(new_dir): - os.makedirs(new_dir) + agent_keystore_dir = os.path.join(volttron_home, 'keystores', agent_identity) + if os.path.exists(agent_keystore_dir): + with open(agent_keystore_dir + '/keystore.json', 'r') as fin: + json_obj = jsonapi.loads(fin.read()) + pubkey = json_obj['public'] + secret = json_obj['secret'] + else: + os.makedirs(agent_keystore_dir) try: output = subprocess.check_output(['vctl', 'auth', 'keypair'], - env=os.environ.copy(), universal_newlines=True, stderr=subprocess.STDOUT) + env=os.environ.copy(), + universal_newlines=True, + stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - sys.stderr.write("Couldn't get key pair for identity: {}\n".format( - agent_identity - )) + sys.stderr.write("Couldn't get key pair for identity: {}\n".format(agent_identity)) sys.stderr.write("Call was:\n\tvctl auth keypair\n") sys.stderr.write("Output of command: {}".format(e.output)) sys.stderr.write("Your environment might not be setup correctly!") - os.rmdir(new_dir) + os.rmdir(agent_keystore_dir) write_required_statement() sys.exit(20) else: - keystore_file = os.path.join(new_dir, "keystore.json") + keystore_file = os.path.join(agent_keystore_dir, "keystore.json") json_obj = jsonapi.loads(output) with open(keystore_file, 'w') as fout: fout.write(output) pubkey = json_obj['public'] + secret = json_obj['secret'] try: - params = ['vctl', 'auth', 'add', - '--credentials', "{}".format(pubkey), '--user_id', agent_identity, - '--capabilities', "edit_config_store", - '--comments', "Added from pycharm-launch.py script." - ] - output = subprocess.check_output(params, env=os.environ.copy(), universal_newlines=True) + params = [ + 'vctl', 'auth', 'add', '--credentials', "{}".format(pubkey), '--user_id', + agent_identity, '--capabilities', "edit_config_store", '--comments', + "Added from pycharm-launch.py script." + ] + print(" ".join(params)) + output = subprocess.check_output(params, + env=os.environ.copy(), + universal_newlines=True) except subprocess.CalledProcessError as e: sys.stderr.write(str(e)) sys.stderr.write("Command returned following output: {}".format(e.output)) - shutil.rmtree(new_dir) - sys.stderr.write("Couldn't authenticate agent id: {}\n".format( - agent_identity - )) + shutil.rmtree(agent_keystore_dir) + sys.stderr.write("Couldn't authenticate agent id: {}\n".format(agent_identity)) sys.stderr.write("Call was: {}\n".format(params)) sys.stderr.write("Your environment might not be setup correctly!") write_required_statement() sys.exit(20) +if not pubkey or not secret: + raise ValueError(f"Missing publickey or secretkey for {agent_identity}") + +# Populate the serverkey +with open(os.path.join(volttron_home, "keystore"), 'r') as fin: + json_obj = jsonapi.loads(fin.read()) + os.environ['VOLTTRON_SERVERKEY'] = json_obj['public'] + +os.environ['AGENT_PUBLICKEY'] = pubkey +os.environ['AGENT_SECRETKEY'] = secret if not parsed.silence: sys.stdout.write("For your information (-s) to not print this message.") write_required_statement(sys.stdout) diff --git a/scripts/rabbit_dependencies.sh b/scripts/rabbit_dependencies.sh deleted file mode 100755 index c14508639c..0000000000 --- a/scripts/rabbit_dependencies.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env bash -set -e -ubuntu_list=(bionic focal) -list=(buster ) -list=("${ubuntu_list[@]}" "${debian_list[@]}") -declare -A ubuntu_versions -ubuntu_versions=( ["ubuntu-18.04"]="bionic" ["ubuntu-20.04"]="focal") - -function exit_on_error { - rc=$? - if [[ $rc != 0 ]] - then - printf "\n## Script could not complete successfully because of above error## \n" - exit $rc - fi - -} - -function print_usage { - echo " -Command Usage: -/rabbit_dependencies.sh or centos version> -Valid Debian distributions: ${list[@]} ${!ubuntu_versions[@]} -Valid centos versions: 8 -" - exit 0 - -} - - -function install_on_centos { - - if [[ "$DIST" != "8" ]]; then - printf "Invalid centos version. Centos 8 is the only compatible versions\n" - print_usage - fi - - repo="## In /etc/yum.repos.d/erlang.repo -[erlang-solutions] -name=CentOS $releasever - $basearch - Erlang Solutions -baseurl=https://packages.erlang-solutions.com/rpm/centos/\$releasever/\$basearch -gpgcheck=1 -gpgkey=https://packages.erlang-solutions.com/rpm/erlang_solutions.asc -enabled=1 -" - if [[ -f "/etc/yum.repos.d/erlang.repo" ]]; then - echo "\n/etc/yum.repos.d/erlang.repo exists. renaming current file to rlang.repo.old\n" - mv /etc/yum.repos.d/erlang.repo /etc/yum.repos.d/erlang.repo.old - exit_on_error - fi - echo "$repo" | ${prefix} tee -a /etc/yum.repos.d/erlang.repo - rpm --import https://packages.erlang-solutions.com/rpm/erlang_solutions.asc - ${prefix} yum install -y erlang-$erlang_package_version - exit_on_error -} - -function install_on_debian { - FOUND=0 - OS="" - for item in "${ubuntu_list[@]}"; do - if [[ "$DIST" == "$item" ]]; then - FOUND=1 - OS="ubuntu" - break - fi - done - - if [[ "$FOUND" != "1" ]]; then - for item in "${debian_list[@]}"; do - if [[ "$DIST" == "$item" ]]; then - FOUND=1 - OS="debian" - break - fi - done - fi - - if [[ "$FOUND" != "1" ]]; then - # check if ubuntu-version was passed if so map it to name - for ubuntu_version in "${!ubuntu_versions[@]}"; do - if [[ "$DIST" == "$ubuntu_version" ]]; then - FOUND=1 - DIST="${ubuntu_versions[$ubuntu_version]}" - OS="ubuntu" - break - fi - done - fi - - if [[ "$FOUND" != "1" ]]; then - echo "Invalid distribution found" - print_usage - fi - - echo "Installing ERLANG" - ${prefix} apt-get update - ${prefix} apt-get install -y gnupg apt-transport-https -y - ${prefix} apt-get purge -yf erlang-base - # Adds erlang repository entry - wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb - sudo dpkg -i erlang-solutions_2.0_all.deb - rm erlang-solutions_2.0_all.deb - if [[ -f "/etc/apt/sources.list.d/erlang.list" ]]; then - echo "\n/etc/apt/sources.list.d/erlang.list exists. renaming current file to erlang.list.old\n" - ${prefix} mv /etc/apt/sources.list.d/erlang.list /etc/apt/sources.list.d/erlang.list.old - exit_on_error - fi - version=${erlang_package_version} - to_install="\ - erlang-base=$version\ - erlang-asn1=$version \ - erlang-crypto=$version \ - erlang-eldap=$version \ - erlang-ftp=$version \ - erlang-inets=$version \ - erlang-mnesia=$version \ - erlang-os-mon=$version \ - erlang-parsetools=$version \ - erlang-public-key=$version \ - erlang-runtime-tools=$version \ - erlang-snmp=$version \ - erlang-ssl=$version \ - erlang-syntax-tools=$version \ - erlang-tools=$version \ - erlang-xmerl=$version \ - erlang-tftp=$version \ - " - - ${prefix} apt-get update - ${prefix} apt-get install -y --allow-downgrades ${to_install} -} - -os_name="$1" -DIST="$2" -user=`whoami` -if [[ ${user} == 'root' ]]; then - prefix="" -else - prefix="sudo" -fi -is_arm="FALSE" - -${prefix} pwd > /dev/null - -if [[ "$os_name" == "debian" ]]; then - erlang_package_version="1:24.1.7-1" - is_arm="FALSE" - install_on_debian -elif [[ "$os_name" == "centos" ]]; then - erlang_package_version="24.2-1.el8" - install_on_centos -else - printf "For operating system/distributions not supported by this script, please refer to https://www.rabbitmq.com/which-erlang.html#erlang-repositories\n" - print_usage -fi - -echo "Finished installing dependencies for rabbitmq" diff --git a/scripts/scalability-testing/agents/NullHistorian/null_historian/agent.py b/scripts/scalability-testing/agents/NullHistorian/null_historian/agent.py index 9ce7908b23..911590b089 100644 --- a/scripts/scalability-testing/agents/NullHistorian/null_historian/agent.py +++ b/scripts/scalability-testing/agents/NullHistorian/null_historian/agent.py @@ -1,48 +1,34 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging import sys -from volttron.platform.vip.agent import * from volttron.platform.agent.base_historian import BaseHistorian, add_timing_data_to_header from volttron.platform.agent import utils from volttron.platform.agent import math_utils +from volttron.platform.vip.agent.core import Core utils.setup_logging() _log = logging.getLogger(__name__) @@ -65,7 +51,7 @@ def __init__(self, **kwargs): @Core.receiver("onstart") def starting(self, sender, **kwargs): - + _log.debug('Null historian started.') def publish_to_historian(self, to_publish_list): diff --git a/scripts/scalability-testing/agents/NullHistorian/setup.py b/scripts/scalability-testing/agents/NullHistorian/setup.py index 3a654ad0db..37a90bb1d3 100644 --- a/scripts/scalability-testing/agents/NullHistorian/setup.py +++ b/scripts/scalability-testing/agents/NullHistorian/setup.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== # }}} #}}} @@ -57,4 +43,3 @@ ] } ) - diff --git a/scripts/scalability-testing/config_builder.py b/scripts/scalability-testing/config_builder.py index 4063c5c353..2ca990a474 100644 --- a/scripts/scalability-testing/config_builder.py +++ b/scripts/scalability-testing/config_builder.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -42,7 +28,7 @@ import abc import argparse from shutil import copy, rmtree -from test_settings import (virtual_device_host, device_types, config_dir, +from test_settings import (virtual_device_host, device_types, config_dir, volttron_install, platform_driver_file, host_config_location) from volttron.platform import jsonapi @@ -56,14 +42,14 @@ def __init__(self, host_address, instance_number, registry_config, interval=60, if heart_beat_point is not None: self.configuration["heart_beat_point"] = heart_beat_point - + self.configuration["driver_config"] = self.get_driver_config(host_address, instance_number) - + def __str__(self): return jsonapi.dumps(self.configuration, indent=4, separators=(',', ': ')) - + @abc.abstractmethod def device_type(self): pass @@ -72,21 +58,21 @@ def device_type(self): @abc.abstractmethod def get_driver_config(host_address, instance_number): pass - + @abc.abstractmethod def get_virtual_driver_commandline(self): pass class BACnetConfig(DeviceConfig): starting_port = 47808 - + def device_type(self): return "bacnet" - + @staticmethod def get_driver_config(host_address, instance_number): return {"device_address": host_address + ":" + str(BACnetConfig.starting_port + instance_number)} - + def get_virtual_driver_commandline(self): config_file = os.path.basename(self.configuration["registry_config"]) @@ -95,30 +81,30 @@ def get_virtual_driver_commandline(self): class ModbusConfig(DeviceConfig): starting_port = 50200 - + def device_type(self): return "modbus" - + @staticmethod def get_driver_config(host_address, instance_number): return {"device_address": host_address, "port": ModbusConfig.starting_port + instance_number} - + def get_virtual_driver_commandline(self): config_file = os.path.basename(self.configuration["registry_config"]) port = self.configuration["driver_config"]["port"] host_address = self.configuration["driver_config"]["device_address"] - return "modbus.py {config} {interface} --port={port}".format(config=config_file, - interface=host_address, + return "modbus.py {config} {interface} --port={port}".format(config=config_file, + interface=host_address, port=port) - -class FakeConfig(DeviceConfig): + +class FakeConfig(DeviceConfig): def device_type(self): return "fakedriver" - + @staticmethod def get_driver_config(host_address, instance_number): - return {} + return {} def get_virtual_driver_commandline(self): return "" @@ -135,20 +121,20 @@ def build_device_configs(device_type, host_address, count, reg_config_ref, confi os.makedirs(output_path) except os.error: pass - + klass = device_config_classes[device_type] for i in range(count): config_instance = klass(host_address, i, reg_config_ref, interval=interval) - + file_name = device_type + str(i) file_path = os.path.join(output_path, file_name) - + with open(file_path, 'w') as f: f.write(str(config_instance)+'\n') command_lines.append(config_instance.get_virtual_driver_commandline()) - + return command_lines def build_all_configs(device_type, host_address, count, reg_config, config_dir, @@ -156,7 +142,7 @@ def build_all_configs(device_type, host_address, count, reg_config, config_dir, publish_only_depth_all, interval, campus, building): '''For command line interface''' print(config_dir) - + config_dir = os.path.abspath(config_dir) registry_config_dir = os.path.join(config_dir, "registry_configs") @@ -172,19 +158,19 @@ def build_all_configs(device_type, host_address, count, reg_config, config_dir, os.makedirs(registry_config_dir) except os.error: pass - + copy(reg_config, registry_config_dir) reg_config_ref = "config://registry_configs/" + os.path.basename(reg_config) - + command_lines = build_device_configs(device_type, host_address, count, reg_config_ref, config_dir, interval, devices_dir) - + build_platform_config(config_dir, scalability_test, scalability_test_iterations, driver_scrape_interval, publish_only_depth_all) - - + + def build_platform_config(config_dir, scalability_test, scalability_test_iterations, driver_scrape_interval, publish_only_depth_all): @@ -198,63 +184,60 @@ def build_platform_config(config_dir, configuration["publish_breadth_first_all"] = False configuration["publish_depth_first"] = False configuration["publish_breadth_first"] = False - + config_str = jsonapi.dumps(configuration, indent=4, separators=(',', ': ')) - + agent_config = os.path.join(config_dir, "config") - + with open(agent_config, 'w') as f: f.write(config_str+'\n') - + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Create driver configuration files for scalability test.") - - parser.add_argument('--count', type=int, default=1, + + parser.add_argument('--count', type=int, default=1, help='number of devices to configure') - - parser.add_argument('--scalability-test', action='store_true', + + parser.add_argument('--scalability-test', action='store_true', help='Configure platform driver for a scalability test') - - parser.add_argument('--publish-only-depth-all', action='store_true', + + parser.add_argument('--publish-only-depth-all', action='store_true', help='Configure drivers to only publish depth first all.') - + parser.add_argument('--driver-scrape-interval', type=float, default=0.02, help='Configure interval between individual device publishes.') - - parser.add_argument('--scalability-test-iterations', type=int, default=5, + + parser.add_argument('--scalability-test-iterations', type=int, default=5, help='Scalability test iterations') - - parser.add_argument('device_type', choices=['bacnet', 'modbus', 'fake'], + + parser.add_argument('device_type', choices=['bacnet', 'modbus', 'fake'], help='type of device to use for testing') - - parser.add_argument('registry_config', + + parser.add_argument('registry_config', help='registry configuration to use for test devices') - - parser.add_argument('virtual_device_host', + + parser.add_argument('virtual_device_host', help='host of the test devices', default=virtual_device_host) - + parser.add_argument('--config-dir', help='output directory for configurations', default=config_dir) - + parser.add_argument('--interval', help='Scrape interval setting for all drivers', type=float, default=60.0) - - parser.add_argument('--campus', + + parser.add_argument('--campus', help='campus name used for testing', default='') - - parser.add_argument('--building', + + parser.add_argument('--building', help='building name used for testing', default='') - + args = parser.parse_args() build_all_configs(args.device_type, - args.virtual_device_host, args.count, args.registry_config, + args.virtual_device_host, args.count, args.registry_config, args.config_dir, args.scalability_test, args.scalability_test_iterations, args.driver_scrape_interval, args.publish_only_depth_all, args.interval, args.campus, args.building) - - - diff --git a/scripts/scalability-testing/fabfile.py b/scripts/scalability-testing/fabfile.py index 53604f101e..0f363a0dea 100644 --- a/scripts/scalability-testing/fabfile.py +++ b/scripts/scalability-testing/fabfile.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys @@ -42,7 +28,7 @@ from fabric.api import * import test_settings -import config_builder +import config_builder env.hosts = [test_settings.virtual_device_host] env.user='volttron' @@ -58,22 +44,22 @@ def build_configs(): config_full_path = os.path.abspath(test_settings.config_dir) for device_type, settings in test_settings.device_types.items(): count, reg_config = settings - + reg_path = os.path.abspath(reg_config) reg_config_files.append(reg_path) - - configs, commands = config_builder.build_device_configs(device_type, + + configs, commands = config_builder.build_device_configs(device_type, env.host, count, reg_path, config_full_path, 60, True) - - + + config_paths.extend(configs) command_lines.extend(commands) - + #config_builder.build_platform_config(test_settings.platform_driver_file, config_dir, config_paths) config_builder.build_platform_config(test_settings.platform_driver_file, config_full_path, @@ -86,14 +72,14 @@ def get_command_lines(): global command_lines if command_lines is None: build_configs() - + return command_lines - + def get_reg_configs(): global reg_config_files if reg_config_files is None: build_configs() - + return reg_config_files def get_remote_path(path): @@ -104,40 +90,40 @@ def get_remote_path(path): @task def deploy_virtual_devices(): - - + + volttron_path = 'python -c "import os; print(os.path.expanduser(\'' \ + test_settings.volttron_install + '\'))"' - + remote_volttron = get_remote_path(test_settings.volttron_install) # Get the remote config location to put the registry configs for the # virtual drivers to use. remote_device_configs = get_remote_path(test_settings.host_config_location) python_exe = os.path.join(remote_volttron, 'env/bin/python') - + # The volttron scalabiility-testing directory that is located on the # remote host in the remote volttron directory. scalability_dir = os.path.join(remote_volttron, 'scripts/scalability-testing') # location of the bacnet.py and modbus.py folders and the shutdown.py script virtual_driver_dir = os.path.join(scalability_dir, 'virtual-drivers') - - + + local_device_configs = os.path.abspath('device-configs') - + try: - # Remove remote directory + # Remove remote directory run('rm -rf {}'.format(remote_device_configs)) except: pass - + # Make remote directory for configs. run('mkdir -p {}'.format(remote_device_configs)) - + # move the files to the remote configuration directory. Only # move files in the top level and then all directories (though # none are currently used). put(local_device_configs+'/*', remote_device_configs) - + # Assume working from root volttron folder for cmd in get_command_lines(): print(cmd) @@ -149,21 +135,20 @@ def deploy_virtual_devices(): port = parts[3] reg_filename = os.path.join(remote_device_configs, reg_filename) script_name = os.path.join(virtual_driver_dir, script_name) - run_script = ' '.join([python_exe, - script_name, + run_script = ' '.join([python_exe, + script_name, reg_filename, - address, + address, port]) - + # Execute the virtual devices. result = run(run_script) print('result: {}'.format(result)) @task def stop_virtual_devices(): - + volttron = get_remote_path(test_settings.volttron_install) python_exe = os.path.join(volttron, 'env/bin/python') shutdown_script = os.path.join(volttron, 'scripts/scalability-testing/virtual-drivers/shutdown.py') run(python_exe + ' ' + shutdown_script) - diff --git a/scripts/scalability-testing/test_settings.py b/scripts/scalability-testing/test_settings.py index 304914b421..4bc087e145 100644 --- a/scripts/scalability-testing/test_settings.py +++ b/scripts/scalability-testing/test_settings.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #Change this to the IP of the machine that will host the virtual devices. @@ -59,4 +45,3 @@ #Directory will be created if it does not exist and will # have all config files removed prior to push out new configs. host_config_location = "~/scalability-confgurations" - diff --git a/scripts/scalability-testing/virtual-drivers/bacnet.py b/scripts/scalability-testing/virtual-drivers/bacnet.py index c2a21af55d..3a4458ad07 100644 --- a/scripts/scalability-testing/virtual-drivers/bacnet.py +++ b/scripts/scalability-testing/virtual-drivers/bacnet.py @@ -1,45 +1,31 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# # import the various server implementations -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# from bacpypes.debugging import bacpypes_debugging, ModuleLogger from bacpypes.consolelogging import ArgumentParser @@ -61,9 +47,9 @@ from utils import createDaemon -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# # configure the service logging -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# # some debugging _debug = 0 _log = ModuleLogger(globals()) @@ -86,7 +72,7 @@ def __init__(self, point_name, instance_number, object_type, property_name, read self.object_type = object_type self.instance_number = int(instance_number) self.point_name = point_name - + def get_register_type(self): '''Get (type, read_only) tuple''' return self.register_type, self.read_only @@ -97,33 +83,33 @@ def __init__(self, interface_str, config_file): self.build_register_map() self.parse_config(config_file) self.interface = interface_str - + def build_register_map(self): self.registers = {('byte',True):[], ('byte',False):[], ('bit',True):[], ('bit',False):[]} - - def insert_register(self, register): + + def insert_register(self, register): register_type = register.get_register_type() - self.registers[register_type].append(register) - + self.registers[register_type].append(register) + def parse_config(self, config_file): with open(config_file, 'rb') as f: configDict = DictReader(f) - - for regDef in configDict: + + for regDef in configDict: object_type = regDef['BACnet Object Type'] - read_only = regDef['Writable'].lower() != 'true' - index = int(regDef['Index']) - property = regDef['Property'] - point_name = regDef['Volttron Point Name'] - + read_only = regDef['Writable'].lower() != 'true' + index = int(regDef['Index']) + property = regDef['Property'] + point_name = regDef['Volttron Point Name'] + register = Register(point_name, index, object_type, property, read_only) - + self.insert_register(register) - - + + def get_server_application(self): if _debug: DeviceAbstraction._debug(" - creating application") # make a device object @@ -134,7 +120,7 @@ def get_server_application(self): segmentationSupported="segmentedBoth", vendorIdentifier=15 ) - + # build a bit string that knows about the bit names pss = ServicesSupported() pss['whoIs'] = 1 @@ -142,44 +128,44 @@ def get_server_application(self): pss['readProperty'] = 1 pss['readPropertyMultiple'] = 1 pss['writeProperty'] = 1 - + # set the property value to be just the bits - this_device.protocolServicesSupported = pss.value + this_device.protocolServicesSupported = pss.value # make a sample application this_application = ReadPropertyMultipleApplication(this_device, args.interface) - - + + registers= self.registers[('byte',True)] - - #Currently we don't actually enforce read only properties. + + #Currently we don't actually enforce read only properties. for register in registers: if _debug: DeviceAbstraction._debug(" - creating object of type: %s, %i", register.object_type, register.instance_number) klass = get_object_class(register.object_type) - ravo = klass(objectIdentifier=(register.object_type, register.instance_number), + ravo = klass(objectIdentifier=(register.object_type, register.instance_number), objectName=register.point_name) - + ravo.WriteProperty("presentValue", 0, direct=True) - + this_application.add_object(ravo) - - + + registers= self.registers[('byte',False)] - + for register in registers: if _debug: DeviceAbstraction._debug(" - creating object of type: %s, %i", register.object_type, register.instance_number) klass = get_object_class(register.object_type) - ravo = klass(objectIdentifier=(register.object_type, register.instance_number), + ravo = klass(objectIdentifier=(register.object_type, register.instance_number), objectName=register.point_name) - + ravo.WriteProperty("presentValue", 0, direct=True) - + this_application.add_object(ravo) - + return this_application -#Most of this stuff is copied from the example here: +#Most of this stuff is copied from the example here: #https://github.com/JoelBender/bacpypes/blob/master/samples/ReadPropertyMultipleServer.py @@ -369,11 +355,11 @@ def do_ReadPropertyMultipleRequest(self, apdu): try: abstraction = DeviceAbstraction(args.interface, args.config) - + #Create the deamon as soon as we've loaded the device configuration. if not args.no_daemon: createDaemon() - + application = abstraction.get_server_application() _log.debug("running") diff --git a/scripts/scalability-testing/virtual-drivers/modbus.py b/scripts/scalability-testing/virtual-drivers/modbus.py index e662eb348f..f974714329 100644 --- a/scripts/scalability-testing/virtual-drivers/modbus.py +++ b/scripts/scalability-testing/virtual-drivers/modbus.py @@ -1,48 +1,34 @@ #!python # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #This is based on example code from the pymodbus source. -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# # import the various server implementations -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# from pymodbus.server.sync import StartTcpServer from pymodbus.device import ModbusDeviceIdentification @@ -52,9 +38,9 @@ from csv import DictReader -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# # configure the service logging -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# import argparse @@ -85,13 +71,13 @@ def __init__(self, address, register_type, read_only, register_struct=''): self.read_only = read_only self.register_type = register_type self.address = address - + if register_type == "byte": self.parse_struct = struct.Struct(register_struct) self.register_count = self.parse_struct.size // MODBUS_REGISTER_SIZE else: self.register_count = 1 - + def get_register_type(self): '''Get (type, read_only) tuple''' return self.register_type, self.read_only @@ -137,61 +123,61 @@ def __init__(self, config_file): self.build_register_map() self.build_ranges_map() self.parse_config(config_file) - + def build_register_map(self): self.registers = {('byte',True):[], ('byte',False):[], ('bit',True):[], ('bit',False):[]} - + def build_ranges_map(self): self.register_ranges = {('byte',True):[None,None], ('byte',False):[None,None], ('bit',True):[None,None], ('bit',False):[None,None]} - - def insert_register(self, register): + + def insert_register(self, register): register_type = register.get_register_type() - self.registers[register_type].append(register) - + self.registers[register_type].append(register) + register_type = register.get_register_type() - - register_range = self.register_ranges[register_type] + + register_range = self.register_ranges[register_type] register_count = register.register_count - + start, end = register.address, register.address + register_count - 1 - + if register_range[0] is None: - register_range[:] = start, end + register_range[:] = start, end else: if register_range[0] > start: register_range[0] = start if register_range[1] < end: - register_range[1] = end - + register_range[1] = end + def parse_config(self, config_file): with open(config_file, 'rb') as f: configDict = DictReader(f) - - for regDef in configDict: + + for regDef in configDict: io_type = regDef['Modbus Register'] bit_register = io_type.lower() == 'bool' - read_only = regDef['Writable'].lower() != 'true' - address = int(regDef['Point Address']) - + read_only = regDef['Writable'].lower() != 'true' + address = int(regDef['Point Address']) + register_type = 'bit' if bit_register else 'byte' register = Register(address, register_type, read_only, io_type) - + self.insert_register(register) - - - def get_server_context(self): + + + def get_server_context(self): start, end = self.register_ranges[('bit',True)] if start is None: di = None else: count = end - start + 1 - + #See http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf # section 4.4 about this nonsense. start += 1 @@ -203,52 +189,52 @@ def get_server_context(self): co = None else: count = end - start + 1 - + #See http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf # section 4.4 about this nonsense. start += 1 log.debug("{} Read only: {} Address: {} Count: {}".format("bit", False, start, count)) co = CallbackSequentialDataBlock(log_callback, start, [0]*count) - + start, end = self.register_ranges[('byte',True)] if start is None: ir = None else: count = end - start + 1 - + #See http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf # section 4.4 about this nonsense. start += 1 log.debug("{} Read only: {} Address: {} Count: {}".format("byte", True, start, count)) ir = CallbackSequentialDataBlock(log_callback, start, [0]*count) - + start, end = self.register_ranges[('byte',False)] if start is None: hr = None else: count = end - start + 1 - + #See http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf # section 4.4 about this nonsense. start += 1 log.debug("{} Read only: {} Address: {} Count: {}".format("byte", False, start, count)) hr = CallbackSequentialDataBlock(log_callback, start, [0]*count) - + store = ModbusSlaveContext( di = di, co = co, hr = hr, ir = ir) context = ModbusServerContext(slaves=store, single=True) - - return context + + return context -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# # initialize the server information -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# # If you don't set this or any fields, they are defaulted to empty strings. -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# identity = ModbusDeviceIdentification() identity.VendorName = 'VOLTTRON' identity.ProductCode = 'VT' @@ -262,10 +248,10 @@ def get_server_context(self): #Create the deamon as soon as we've loaded the device configuration. if not args.no_daemon: createDaemon() - + context = abstraction.get_server_context() -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# # run the server you want -#---------------------------------------------------------------------------# +#---------------------------------------------------------------------------# StartTcpServer(context, identity=identity, address=(args.interface, args.port)) diff --git a/scripts/scalability-testing/virtual-drivers/shutdown.py b/scripts/scalability-testing/virtual-drivers/shutdown.py index 3899818556..82ceed91b7 100644 --- a/scripts/scalability-testing/virtual-drivers/shutdown.py +++ b/scripts/scalability-testing/virtual-drivers/shutdown.py @@ -1,41 +1,27 @@ #!python # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} ''' A simple shutdown script for shutting down all bacnet and modbus @@ -47,33 +33,33 @@ def stop_all(): '''Stop both modbus and bacnet devices.''' - + stop_modbus() stop_bacnet() def stop_modbus(): '''Stop all virtual modbus devices''' - + for pid in psutil.pids(): proc = psutil.Process(pid) - - for opt in proc.cmdline(): + + for opt in proc.cmdline(): if 'modbus' in opt: print('Killing:', opt) os.kill(pid, signal.SIGTERM) break - + def stop_bacnet(): '''Stop all virtual bacnet devices''' - + for pid in psutil.pids(): proc = psutil.Process(pid) - - for opt in proc.cmdline(): + + for opt in proc.cmdline(): if 'bacnet' in opt: print('Killing:', opt) os.kill(pid, signal.SIGTERM) break - + if __name__ == '__main__': stop_all() diff --git a/scripts/scalability-testing/virtual-drivers/utils.py b/scripts/scalability-testing/virtual-drivers/utils.py index a631c8f33e..2ce63c40c7 100644 --- a/scripts/scalability-testing/virtual-drivers/utils.py +++ b/scripts/scalability-testing/virtual-drivers/utils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #Adapted from http://code.activestate.com/recipes/278731-creating-a-daemon-the-python-way/ @@ -44,7 +30,7 @@ 1.) The current working directory set to the "/" directory. 2.) The current file creation mode mask set to 0. - 3.) Close all open files (1024). + 3.) Close all open files (1024). 4.) Redirect standard I/O streams to "/dev/null". A failed call to fork() now raises an exception. @@ -195,7 +181,7 @@ def createDaemon(): maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] if (maxfd == resource.RLIM_INFINITY): maxfd = MAXFD - + # Iterate through and close all file descriptors. for fd in range(0, maxfd): try: diff --git a/scripts/secure_user_permissions.sh b/scripts/secure_user_permissions.sh index faa7816e0d..ac614c57cd 100755 --- a/scripts/secure_user_permissions.sh +++ b/scripts/secure_user_permissions.sh @@ -265,6 +265,19 @@ while true; do fi done +# Get full path to python executable +while true; do + echo -n "Enter full path to python used for volttron:" + read python_path + valid=0 + version=`$python_path -V` + if [ $? -eq 0 ]; then + break + else + echo "Invalid python_path" + fi +done + echo "$volttron_user ALL= NOPASSWD: /usr/sbin/groupadd volttron_$name" | sudo EDITOR='tee -a' visudo -f /etc/sudoers.d/volttron_$name echo "$volttron_user ALL= NOPASSWD: /usr/sbin/usermod -a -G volttron_$name $USER" | sudo EDITOR='tee -a' visudo -f /etc/sudoers.d/volttron_$name echo "$volttron_user ALL= NOPASSWD: /usr/sbin/useradd volttron_[1-9]* -r -G volttron_$name" | sudo EDITOR='tee -a' visudo -f /etc/sudoers.d/volttron_$name @@ -273,6 +286,6 @@ echo "$volttron_user ALL= NOPASSWD: $source_dir/scripts/stop_agent_running_in_is # TODO want delete only users with pattern of particular group echo "$volttron_user ALL= NOPASSWD: /usr/sbin/userdel volttron_[1-9]*" | sudo EDITOR='tee -a' visudo -f /etc/sudoers.d/volttron_$name # allow user to run all non-sudo commands for all volttron agent users -echo "$volttron_user ALL=(%volttron_$name) NOPASSWD: ALL" | sudo EDITOR='tee -a' visudo -f /etc/sudoers.d/volttron_$name +echo "$volttron_user ALL=(%volttron_$name) NOPASSWD:SETENV: $python_path" | sudo EDITOR='tee -a' visudo -f /etc/sudoers.d/volttron_$name echo "Permissions set for $volttron_user" echo "Volttron agent isolation mode setup is complete" diff --git a/scripts/tagging_scripts/insert_id_and_ref_tags.py b/scripts/tagging_scripts/insert_id_and_ref_tags.py index 23c5738822..3c8a6ebb57 100644 --- a/scripts/tagging_scripts/insert_id_and_ref_tags.py +++ b/scripts/tagging_scripts/insert_id_and_ref_tags.py @@ -164,7 +164,7 @@ def mongo_insert(tags, execute_now=False): try: result = mongo_bulk.execute() if result['nInserted'] != mongo_batch_size: - print ("bulk execute result {}".format(result)) + print("bulk execute result {}".format(result)) errors = True except BulkWriteError as ex: print(str(ex.details)) diff --git a/scripts/update_curve_key.py b/scripts/update_curve_key.py index 8f3804762b..078371cda2 100644 --- a/scripts/update_curve_key.py +++ b/scripts/update_curve_key.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from argparse import ArgumentParser @@ -59,7 +45,7 @@ def update_curve_key(curve_key_path, no_warn=False): return keystore_path = os.path.join(os.path.dirname(curve_key_path), 'keystore') - + if os.path.exists(keystore_path) and not no_warn: response = input("{} already exists. " "Overwrite? [y/N]: ".format(keystore_path)) @@ -75,7 +61,7 @@ def update_curve_key(curve_key_path, no_warn=False): if __name__ == "__main__": parser = ArgumentParser(description="Update curve.key file (from " "VOLTTRON 3.5rc1) to key-store file (VOLTRON 4.0)") - + parser.add_argument('curve_key', metavar='curve-key-file', help='Path to curve.key file (usually $VOLTTRON_HOME/curve.key)') diff --git a/scripts/update_master_driver_config.py b/scripts/update_master_driver_config.py index 82c9ad5a2f..ecc8610d31 100644 --- a/scripts/update_master_driver_config.py +++ b/scripts/update_master_driver_config.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from volttron.platform.agent.utils import parse_json_config diff --git a/services/contrib/InfluxdbHistorian/influx/historian.py b/services/contrib/InfluxdbHistorian/influx/historian.py index 7a304abe21..3c1dbecc6f 100644 --- a/services/contrib/InfluxdbHistorian/influx/historian.py +++ b/services/contrib/InfluxdbHistorian/influx/historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/contrib/InfluxdbHistorian/setup.py b/services/contrib/InfluxdbHistorian/setup.py index b5b7604d05..ce3fdb17dd 100644 --- a/services/contrib/InfluxdbHistorian/setup.py +++ b/services/contrib/InfluxdbHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/contrib/InfluxdbHistorian/tests/test_influxdb_historian.py b/services/contrib/InfluxdbHistorian/tests/test_influxdb_historian.py index 0544ea39ed..fdff3458ad 100644 --- a/services/contrib/InfluxdbHistorian/tests/test_influxdb_historian.py +++ b/services/contrib/InfluxdbHistorian/tests/test_influxdb_historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import math @@ -42,12 +28,11 @@ import gevent import pytz import os -import json from pytest import approx from datetime import datetime, timedelta from dateutil import parser -from volttron.platform import get_services_core, jsonapi +from volttron.platform import jsonapi from volttron.platform.agent.utils import format_timestamp, parse_timestamp_string, get_aware_utc_now from volttron.platform.messaging import headers as headers_mod @@ -1333,7 +1318,7 @@ def test_update_config_store(volttron_instance, influxdb_client): publish_some_fake_data(publisher, 5) # Update config store - publisher.vip.rpc.call('config.store', 'manage_store', 'influxdb.historian', 'config', + publisher.vip.rpc.call('config.store', 'set_config', 'influxdb.historian', 'config', jsonapi.dumps(updated_influxdb_config), config_type="json").get(timeout=10) publish_some_fake_data(publisher, 5) diff --git a/services/contrib/KafkaAgent/Test/kafka_producer.py b/services/contrib/KafkaAgent/Test/kafka_producer.py index 00d9b4600f..eea5a02ade 100644 --- a/services/contrib/KafkaAgent/Test/kafka_producer.py +++ b/services/contrib/KafkaAgent/Test/kafka_producer.py @@ -2,7 +2,6 @@ from kafka import KafkaProducer -from kafka.errors import KafkaError from volttron.platform import jsonapi diff --git a/services/contrib/KafkaAgent/setup.py b/services/contrib/KafkaAgent/setup.py index cb5acdb326..86d2806539 100644 --- a/services/contrib/KafkaAgent/setup.py +++ b/services/contrib/KafkaAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/contrib/MarketServiceAgent/market_service/agent.py b/services/contrib/MarketServiceAgent/market_service/agent.py index 5803a07cc3..acb780fcca 100644 --- a/services/contrib/MarketServiceAgent/market_service/agent.py +++ b/services/contrib/MarketServiceAgent/market_service/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/services/contrib/MarketServiceAgent/market_service/director.py b/services/contrib/MarketServiceAgent/market_service/director.py index 70203db2ec..c7a837d6b7 100644 --- a/services/contrib/MarketServiceAgent/market_service/director.py +++ b/services/contrib/MarketServiceAgent/market_service/director.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/services/contrib/MarketServiceAgent/market_service/market.py b/services/contrib/MarketServiceAgent/market_service/market.py index 12843d0b69..ecf76b18f8 100644 --- a/services/contrib/MarketServiceAgent/market_service/market.py +++ b/services/contrib/MarketServiceAgent/market_service/market.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} ACCEPT_RESERVATIONS = 'market_accept_resevations' @@ -147,7 +133,7 @@ def make_offer(self, participant, curve): _log.debug("Make offer Market: {} {} entered in state {}".format(self.market_name, participant.buyer_seller, self.state)) - if (participant.buyer_seller == SELLER): + if participant.buyer_seller == SELLER: self.receive_sell_offer() else: self.receive_buy_offer() @@ -163,7 +149,7 @@ def make_offer(self, participant, curve): participant.buyer_seller, offer_count, curve.tuppleize())) self.offers.make_offer(participant.buyer_seller, curve) if self.all_satisfied(participant.buyer_seller): - if (participant.buyer_seller == SELLER): + if participant.buyer_seller == SELLER: self.last_sell_offer() else: self.last_buy_offer() @@ -199,25 +185,24 @@ def clear_market(self): error_code = None error_message = None aux = {} - if (self.state in [ACCEPT_ALL_OFFERS, ACCEPT_BUY_OFFERS, ACCEPT_SELL_OFFERS]): + if self.state in [ACCEPT_ALL_OFFERS, ACCEPT_BUY_OFFERS, ACCEPT_SELL_OFFERS]: error_code = SHORT_OFFERS error_message = 'The market {} failed to receive all the expected offers. ' \ 'The state is {}.'.format(self.market_name, self.state) - elif (self.state != MARKET_DONE): + elif self.state != MARKET_DONE: error_code = BAD_STATE error_message = 'Programming error in Market class. State of {} and clear market signal arrived. ' \ 'This represents a logic error.'.format(self.state) + elif not self.has_market_formed(): + error_code = NOT_FORMED + error_message = 'The market {} has not received a buy and a sell reservation.'.format(self.market_name) else: - if not self.has_market_formed(): - error_code = NOT_FORMED - error_message = 'The market {} has not received a buy and a sell reservation.'.format(self.market_name) - else: - quantity, price, aux = self.offers.settle() - _log.info("Clearing mixmarket: {} Price: {} Qty: {}".format(self.market_name, price, quantity)) - aux = {} - if price is None or quantity is None: - error_code = NO_INTERSECT - error_message = "Error: The supply and demand curves do not intersect. The market {} failed to clear.".format(self.market_name) + quantity, price, aux = self.offers.settle() + _log.info("Clearing mixmarket: {} Price: {} Qty: {}".format(self.market_name, price, quantity)) + aux = {} + if price is None or quantity is None: + error_code = NO_INTERSECT + error_message = "Error: The supply and demand curves do not intersect. The market {} failed to clear.".format(self.market_name) _log.info("Clearing price for Market: {} Price: {} Qty: {}".format(self.market_name, price, quantity)) timestamp = self._get_time() timestamp_string = utils.format_timestamp(timestamp) @@ -241,13 +226,12 @@ def log_market_failure(self, message): def all_satisfied(self, buyer_seller): are_satisfied = False - if (buyer_seller == BUYER): + if buyer_seller == BUYER: are_satisfied = self.reservations.buyer_count() == self.offers.buyer_count() - if (buyer_seller == SELLER): + if buyer_seller == SELLER: are_satisfied = self.reservations.seller_count() == self.offers.seller_count() return are_satisfied def _get_time(self): now = utils.get_aware_utc_now() return now - diff --git a/services/contrib/MarketServiceAgent/market_service/market_list.py b/services/contrib/MarketServiceAgent/market_service/market_list.py index 80dea6b272..d3f1dab478 100644 --- a/services/contrib/MarketServiceAgent/market_service/market_list.py +++ b/services/contrib/MarketServiceAgent/market_service/market_list.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/services/contrib/MarketServiceAgent/market_service/market_participant.py b/services/contrib/MarketServiceAgent/market_service/market_participant.py index 93b495ebed..4560d8e5dc 100644 --- a/services/contrib/MarketServiceAgent/market_service/market_participant.py +++ b/services/contrib/MarketServiceAgent/market_service/market_participant.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from volttron.platform.agent.base_market_agent.buy_sell import BUYER, SELLER @@ -51,4 +37,3 @@ def is_buyer(self): def is_seller(self): return self.buyer_seller == SELLER - diff --git a/services/contrib/MarketServiceAgent/market_service/market_state.py b/services/contrib/MarketServiceAgent/market_service/market_state.py index dcab7a6d79..875142b43e 100644 --- a/services/contrib/MarketServiceAgent/market_service/market_state.py +++ b/services/contrib/MarketServiceAgent/market_service/market_state.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} ACCEPT_RESERVATIONS = 0 diff --git a/services/contrib/MarketServiceAgent/market_service/offer_manager.py b/services/contrib/MarketServiceAgent/market_service/offer_manager.py index 41fff0eedb..705af29a18 100644 --- a/services/contrib/MarketServiceAgent/market_service/offer_manager.py +++ b/services/contrib/MarketServiceAgent/market_service/offer_manager.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -100,4 +86,3 @@ def buyer_count(self): def seller_count(self): return len(self._sell_offers) - diff --git a/services/contrib/MarketServiceAgent/market_service/reservation_manager.py b/services/contrib/MarketServiceAgent/market_service/reservation_manager.py index 23f18e282c..ff2ba2ab97 100644 --- a/services/contrib/MarketServiceAgent/market_service/reservation_manager.py +++ b/services/contrib/MarketServiceAgent/market_service/reservation_manager.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -49,7 +35,7 @@ def __init__(self): self._sell_reservations = {} def make_reservation(self, participant): - if (participant.is_buyer()): + if participant.is_buyer(): self._make_buy_reservation(participant.identity) else: self._make_sell_reservation(participant.identity) @@ -68,7 +54,7 @@ def _make_sell_reservation(self, owner): self._add_reservation(self._sell_reservations, owner, 'sell') def take_reservation(self, participant): - if (participant.is_buyer()): + if participant.is_buyer(): self._take_buy_reservation(participant.identity) else: self._take_sell_reservation(participant.identity) @@ -96,4 +82,3 @@ def buyer_count(self): def seller_count(self): return len(self._sell_reservations) - diff --git a/services/contrib/MarketServiceAgent/setup.py b/services/contrib/MarketServiceAgent/setup.py index 38bbd09f51..ad65abcf14 100644 --- a/services/contrib/MarketServiceAgent/setup.py +++ b/services/contrib/MarketServiceAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/contrib/MarketServiceAgent/tests/test_market.py b/services/contrib/MarketServiceAgent/tests/test_market.py index 429015f449..28ab112b27 100644 --- a/services/contrib/MarketServiceAgent/tests/test_market.py +++ b/services/contrib/MarketServiceAgent/tests/test_market.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest diff --git a/services/contrib/MarketServiceAgent/tests/test_market_list.py b/services/contrib/MarketServiceAgent/tests/test_market_list.py index 3255ef248d..014e747944 100644 --- a/services/contrib/MarketServiceAgent/tests/test_market_list.py +++ b/services/contrib/MarketServiceAgent/tests/test_market_list.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/services/contrib/MarketServiceAgent/tests/test_market_service_agent.py b/services/contrib/MarketServiceAgent/tests/test_market_service_agent.py index e97bbe10f4..b54e0d8b97 100644 --- a/services/contrib/MarketServiceAgent/tests/test_market_service_agent.py +++ b/services/contrib/MarketServiceAgent/tests/test_market_service_agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os diff --git a/services/contrib/MarketServiceAgent/tests/test_offer.py b/services/contrib/MarketServiceAgent/tests/test_offer.py index c51c29520d..e7248909ba 100644 --- a/services/contrib/MarketServiceAgent/tests/test_offer.py +++ b/services/contrib/MarketServiceAgent/tests/test_offer.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest diff --git a/services/contrib/MessageDebuggerAgent/messagedebugger/agent.py b/services/contrib/MessageDebuggerAgent/messagedebugger/agent.py index eb90ddbbe8..22aaa03590 100644 --- a/services/contrib/MessageDebuggerAgent/messagedebugger/agent.py +++ b/services/contrib/MessageDebuggerAgent/messagedebugger/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime @@ -53,7 +39,7 @@ from volttron.platform.agent import utils from volttron.platform import jsonapi -from volttron.platform.control import ControlConnection, KnownHostsStore, KeyStore +from volttron.platform.control import KnownHostsStore, KeyStore from volttron.platform.vip.agent import Agent, RPC, Core from volttron.platform.vip.router import ERROR, UNROUTABLE, INCOMING, OUTGOING diff --git a/services/contrib/MessageDebuggerAgent/messageviewer/viewer.py b/services/contrib/MessageDebuggerAgent/messageviewer/viewer.py index 1d1c1e787f..dcc82b4c24 100644 --- a/services/contrib/MessageDebuggerAgent/messageviewer/viewer.py +++ b/services/contrib/MessageDebuggerAgent/messageviewer/viewer.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from cmd import Cmd diff --git a/services/contrib/MessageDebuggerAgent/tests/test_message_debugging.py b/services/contrib/MessageDebuggerAgent/tests/test_message_debugging.py index 9d2dd3879f..a162082b75 100644 --- a/services/contrib/MessageDebuggerAgent/tests/test_message_debugging.py +++ b/services/contrib/MessageDebuggerAgent/tests/test_message_debugging.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime diff --git a/services/core/ActuatorAgent/actuator/agent.py b/services/core/ActuatorAgent/actuator/agent.py index 8a9547b67b..369489ed75 100644 --- a/services/core/ActuatorAgent/actuator/agent.py +++ b/services/core/ActuatorAgent/actuator/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -43,13 +29,13 @@ may request scheduled times, called Tasks, to interact with one or more devices. -Agents may interact with the ActuatorAgent via either PUB/SUB or RPC, +Agents may interact with the ActuatorAgent via either PUB/SUB or RPC, but it is recommended agents use RPC to interact with the ActuatorAgent. -The PUB/SUB interface remains primarily for VOLTTRON 2.0 agents. +The PUB/SUB interface remains primarily for VOLTTRON 2.0 agents. -The Actuator Agent also triggers the heart beat on devices whose -drivers are configured to do so. +The Actuator Agent also triggers the heart beat on devices whose +drivers are configured to do so. ActuatorAgent Configuration =========================== @@ -67,7 +53,7 @@ "heartbeat_interval" How often to send a heartbeat signal to all devices in seconds. Defaults to 60. - + Sample configuration file ------------------------- @@ -93,8 +79,8 @@ Scheduling a New Task ===================== -:py:meth:`RPC interface ` -:py:meth:`PUB/SUB interface ` +:py:meth:`RPC interface ` +:py:meth:`PUB/SUB interface ` Creating a Task requires four things: @@ -110,20 +96,20 @@ There are three valid prioirity levels: "HIGH" - This Task cannot be preempted under any circumstance. + This Task cannot be preempted under any circumstance. This Task may preempt other conflicting preemptable Tasks. "LOW" - This Task cannot be preempted **once it has started**. - A Task is considered started once the earliest time slot on any + This Task cannot be preempted **once it has started**. + A Task is considered started once the earliest time slot on any device has been reached. This Task may not preempt other Tasks. "LOW_PREEMPT" - This Task may be preempted at any time. - If the Task is preempted once it has begun running any current - time slots will be given a grace period (configurable in the - ActuatorAgent configuration file, defaults to 60 seconds) before + This Task may be preempted at any time. + If the Task is preempted once it has begun running any current + time slots will be given a grace period (configurable in the + ActuatorAgent configuration file, defaults to 60 seconds) before being revoked. This Task may not preempt other Tasks. - -Whenever a Task is preempted the Actuator Agent will publish a message to + +Whenever a Task is preempted the Actuator Agent will publish a message to ``devices/actuators/schedule/result`` indicating that the Task has been cancelled due to being preempted. See `Preemption Publishes`_ @@ -153,11 +139,11 @@ "2013-12-06 16:20:00"], #End of time slot. #etc... ] - -.. note:: + +.. note:: Points on Task Scheduling - + - Task id and requester id (agentid) should be a non empty value of type string - A Task schedule must have at least one time slot. @@ -174,7 +160,7 @@ conflict. For example, time\_slot1(device0, time1, **time2**) and time\_slot2(device0,\ **time2**, time3) are not considered a conflict - A request must not conflict with itself. - + New Task Response ----------------- @@ -188,7 +174,7 @@ 'info': , 'data': } - + The PUB/SUB interface will respond to requests on the ``devices/actuators/schedule/result`` topic. @@ -201,12 +187,12 @@ 'requesterID': , 'taskID': } - + Failure Reasons *************** In many cases the ActuatorAgent will try to give good feedback as to why -a request failed. The type of failure will populate "info" item as a +a request failed. The type of failure will populate "info" item as a string. @@ -244,18 +230,18 @@ the conflicts in this form: .. code-block:: python - + { - '': + '': { '': [ - ["campus/building/device1", - "2013-12-06 16:00:00", + ["campus/building/device1", + "2013-12-06 16:00:00", "2013-12-06 16:20:00"], - ["campus/building/device1", - "2013-12-06 18:00:00", - "2013-12-06 18:20:00"] + ["campus/building/device1", + "2013-12-06 18:00:00", + "2013-12-06 18:20:00"] ] '':[...] } @@ -268,40 +254,40 @@ Getting values -------------- -:py:meth:`RPC interface ` -:py:meth:`PUB/SUB interface ` +:py:meth:`RPC interface ` +:py:meth:`PUB/SUB interface ` -While a device driver for a device will periodically broadcast -the state of a device you may want an up to the moment value for +While a device driver for a device will periodically broadcast +the state of a device you may want an up to the moment value for point on a device. -As of VOLTTRON 3.5 it is no longer required to have the device +As of VOLTTRON 3.5 it is no longer required to have the device scheduled before you can use this interface. Setting Values -------------- -:py:meth:`RPC interface ` -:py:meth:`PUB/SUB interface ` +:py:meth:`RPC interface ` +:py:meth:`PUB/SUB interface ` Failure to schedule the device first will result in an error. Errors Setting Values ********************* -If there is an error the RPC interface will raise an exception -and the PUB/SUB interface will publish to +If there is an error the RPC interface will raise an exception +and the PUB/SUB interface will publish to ``devices/actuators/error//`` -The headder of the publish will take this form: +The headder of the publish will take this form: .. code-block:: python { 'requesterID': } - + and a message body in this form: .. code-block:: python @@ -310,7 +296,7 @@ 'type': 'value': } - + Common Error Types ****************** @@ -319,16 +305,16 @@ use a device. (Forgot to schedule, preempted and we did not handle  the preemption message correctly, ran out of time in time slot, etc...) ``ValueError`` - Message missing (PUB/SUB only) or is the wrong data type. + Message missing (PUB/SUB only) or is the wrong data type. Most other error types involve problems with communication between the -VOLTTRON device drivers and the device itself. +VOLTTRON device drivers and the device itself. Reverting Values and Devices to a Default State ----------------------------------------------- As of VOLTTRON 3.5 device drivers are now required to support -reverting to a default state. The exact mechanism used to +reverting to a default state. The exact mechanism used to accomplish this is driver specific. Failure to schedule the device first will result in a ``LockError``. @@ -338,12 +324,12 @@ :py:meth:`RPC revert device interface ` :py:meth:`PUB/SUB revert device interface ` - + Canceling a Task ================ -:py:meth:`RPC interface ` -:py:meth:`PUB/SUB interface ` +:py:meth:`RPC interface ` +:py:meth:`PUB/SUB interface ` Cancelling a Task requires two things: @@ -356,7 +342,7 @@ Both the RPC and PUB/SUB interface respond to requests with the result in the following format: - + .. code-block:: python { @@ -365,14 +351,14 @@ 'data': {} } -.. note:: +.. note:: There are some things to be aware of when canceling a schedule: - + - The taskID must match the original value from the original request header. - After a Tasks time has passed there is no need to cancel it. Doing so will result in a "TASK_ID_DOES_NOT_EXIST" error. - + If an attempt cancel a schedule fails than the "info" item will have any of the following values: @@ -383,11 +369,11 @@ "AGENT_ID_TASK_ID_MISMATCH" A different agent ID is being used when trying to cancel a Task. - + Preemption Publishes ==================== -If a Task is preempted it will publish the following to the +If a Task is preempted it will publish the following to the ``devices/actuators/schedule/result`` topic: .. code-block:: python @@ -400,7 +386,7 @@ 'taskID': } } - + Along with the following header: .. code-block:: python @@ -410,13 +396,13 @@ 'requesterID': , 'taskID': } - + .. note:: - Remember that if your "LOW_PREEMPT" Task has already started and + Remember that if your "LOW_PREEMPT" Task has already started and is preempted you have a grace period to do any clean up before losing access to the device. - + Schedule State Publishes ======================== @@ -490,11 +476,11 @@ class LockError(Exception): def actuator_agent(config_path, **kwargs): - """Parses the Actuator Agent configuration and returns an instance of + """Parses the Actuator Agent configuration and returns an instance of the agent created using that configuation. - - :param config_path: Path to a configuation file. - + + :param config_path: Path to a configuation file. + :type config_path: str :returns: Actuator Agent :rtype: ActuatorAgent @@ -528,18 +514,18 @@ class ActuatorAgent(Agent): The Actuator Agent regulates control of devices by other agents. Agents request a schedule and then issue commands to the device through this agent. - + The Actuator Agent also sends out the signal to drivers to trigger a device heartbeat. - - :param heartbeat_interval: Interval in seonds to send out a heartbeat - to devices. + + :param heartbeat_interval: Interval in seonds to send out a heartbeat + to devices. :param schedule_publish_interval: Interval in seonds to publish the - currently active schedules. + currently active schedules. :param schedule_state_file: Name of the file to save the current schedule - state to. This file is updated every time a schedule changes. + state to. This file is updated every time a schedule changes. :param preempt_grace_time: Time in seconds after a schedule is preemted - before it is actually cancelled. + before it is actually cancelled. :param driver_vip_identity: VIP identity of the Platform Driver Agent. :type heartbeat_interval: float @@ -786,26 +772,26 @@ def _handle_standard_error(self, ex, point, headers): def handle_get(self, peer, sender, bus, topic, headers, message): """ Requests up to date value of a point. - + To request a value publish a message to the following topic: ``devices/actuators/get//`` - + with the fallowing header: - + .. code-block:: python - + { 'requesterID': } - - The ActuatorAgent will reply on the **value** topic + + The ActuatorAgent will reply on the **value** topic for the actuator: ``devices/actuators/value//`` - + with the message set to the value the point. - + """ point = topic.replace(topics.ACTUATOR_GET() + '/', '', 1) requester = sender @@ -822,32 +808,32 @@ def handle_get(self, peer, sender, bus, topic, headers, message): def handle_set(self, peer, sender, bus, topic, headers, message): """ Set the value of a point. - + To set a value publish a message to the following topic: ``devices/actuators/set//`` - + with the fallowing header: - + .. code-block:: python - + { 'requesterID': } - - The ActuatorAgent will reply on the **value** topic + + The ActuatorAgent will reply on the **value** topic for the actuator: ``devices/actuators/value//`` - + with the message set to the value the point. - - Errors will be published on - + + Errors will be published on + ``devices/actuators/error//`` - + with the same header as the request. - + """ if sender == 'pubsub.compat': message = compat.unpack_legacy_message(headers, message) @@ -873,11 +859,11 @@ def handle_set(self, peer, sender, bus, topic, headers, message): def get_point(self, topic, point=None, **kwargs): """ RPC method - - Gets up to date value of a specific point on a device. - Does not require the device be scheduled. - - :param topic: The topic of the point to grab in the + + Gets up to date value of a specific point on a device. + Does not require the device be scheduled. + + :param topic: The topic of the point to grab in the format / Only the if point is specified. @@ -900,12 +886,12 @@ def get_point(self, topic, point=None, **kwargs): @RPC.export def set_point(self, requester_id, topic, value, point=None, **kwargs): """RPC method - - Sets the value of a specific point on a device. + + Sets the value of a specific point on a device. Requires the device be scheduled by the calling agent. - + :param requester_id: Ignored, VIP Identity used internally - :param topic: The topic of the point to set in the + :param topic: The topic of the point to set in the format / Only the if point is specified. :param value: Value to set point to. @@ -915,12 +901,12 @@ def set_point(self, requester_id, topic, value, point=None, **kwargs): :type requester_id: str :type value: any basic python type :type point: str - :returns: value point was actually set to. Usually invalid values + :returns: value point was actually set to. Usually invalid values cause an error but some drivers (MODBUS) will return a different value with what the value was actually set to. :rtype: any base python type - + .. warning:: Calling without previously scheduling a device and not within the time allotted will raise a LockError""" @@ -1062,34 +1048,34 @@ def set_multiple_points(self, requester_id, topics_values, **kwargs): results.update(r) return results - + def handle_revert_point(self, peer, sender, bus, topic, headers, message): """ Revert the value of a point. - + To revert a value publish a message to the following topic: ``actuators/revert/point//`` - + with the fallowing header: - + .. code-block:: python - + { 'requesterID': } - + The ActuatorAgent will reply on ``devices/actuators/reverted/point//`` - + This is to indicate that a point was reverted. - - Errors will be published on - + + Errors will be published on + ``devices/actuators/error//`` - + with the same header as the request. """ point = topic.replace(topics.ACTUATOR_REVERT_POINT() + '/', '', 1) @@ -1106,30 +1092,30 @@ def handle_revert_point(self, peer, sender, bus, topic, headers, message): def handle_revert_device(self, peer, sender, bus, topic, headers, message): """ Revert all the writable values on a device. - + To revert a device publish a message to the following topic: ``devices/actuators/revert/device/`` - + with the fallowing header: - + .. code-block:: python - + { 'requesterID': } - - The ActuatorAgent will reply on the **value** topic + + The ActuatorAgent will reply on the **value** topic for the actuator: ``devices/actuators/reverted/device/`` - + to indicate that a point was reverted. - - Errors will be published on - + + Errors will be published on + ``devices/actuators/error//`` - + with the same header as the request. """ point = topic.replace(topics.ACTUATOR_REVERT_DEVICE() + '/', '', 1) @@ -1147,17 +1133,17 @@ def handle_revert_device(self, peer, sender, bus, topic, headers, message): def revert_point(self, requester_id, topic, point=None, **kwargs): """ RPC method - - Reverts the value of a specific point on a device to a default state. + + Reverts the value of a specific point on a device to a default state. Requires the device be scheduled by the calling agent. - + :param requester_id: Ignored, VIP Identity used internally - :param topic: The topic of the point to revert in the + :param topic: The topic of the point to revert in the format / :param \*\*kwargs: Any driver specific parameters :type topic: str :type requester_id: str - + .. warning:: Calling without previously scheduling a device and not within the time allotted will raise a LockError""" @@ -1189,16 +1175,16 @@ def _revert_point(self, sender, topic, point=None, **kwargs): def revert_device(self, requester_id, topic, **kwargs): """ RPC method - - Reverts all points on a device to a default state. + + Reverts all points on a device to a default state. Requires the device be scheduled by the calling agent. - + :param requester_id: Ignored, VIP Identity used internally :param topic: The topic of the device to revert :param \*\*kwargs: Any driver specific parameters :type topic: str :type requester_id: str - + .. warning:: Calling without previously scheduling a device and not within the time allotted will raise a LockError""" @@ -1234,14 +1220,14 @@ def _check_lock(self, device, requester): def handle_schedule_request(self, peer, sender, bus, topic, headers, message): - """ + """ Schedule request pub/sub handler - + An agent can request a task schedule by publishing to the ``devices/actuators/schedule/request`` topic with the following header: - + .. code-block:: python - + { 'type': 'NEW_SCHEDULE', 'requesterID': , @@ -1250,21 +1236,21 @@ def handle_schedule_request(self, peer, sender, bus, topic, headers, 'priority': , #The desired task priority, must be 'HIGH', 'LOW', or 'LOW_PREEMPT' } - + The message must describe the blocks of time using the format described in `Device Schedule`_. - + A task may be canceled by publishing to the ``devices/actuators/schedule/request`` topic with the following header: - + .. code-block:: python - + { 'type': 'CANCEL_SCHEDULE', 'requesterID': , 'taskID': , #The task ID for the canceled Task. } - + requesterID The name of the requesting agent. Automatically replaced with VIP id. taskID @@ -1272,9 +1258,9 @@ def handle_schedule_request(self, peer, sender, bus, topic, headers, other scheduled tasks. priority The desired task priority, must be 'HIGH', 'LOW', or 'LOW_PREEMPT' - + No message is requires to cancel a schedule. - + """ if sender == 'pubsub.compat': message = compat.unpack_legacy_message(headers, message) @@ -1319,24 +1305,24 @@ def handle_schedule_request(self, peer, sender, bus, topic, headers, def request_new_schedule(self, requester_id, task_id, priority, requests): """ RPC method - + Requests one or more blocks on time on one or more device. - + :param requester_id: Ignored, VIP Identity used internally :param task_id: Task name. :param priority: Priority of the task. Must be either "HIGH", "LOW", or "LOW_PREEMPT" :param requests: A list of time slot requests in the format described in `Device Schedule`_. - + :type requester_id: str :type task_id: str :type priority: str :returns: Request result - :rtype: dict - + :rtype: dict + :Return Values: - + The return values are described in `New Task Response`_. """ rpc_peer = self.vip.rpc.context.vip_message.peer @@ -1426,21 +1412,21 @@ def _handle_unknown_schedule_error(self, ex, headers, message): @RPC.export def request_cancel_schedule(self, requester_id, task_id): """RPC method - + Requests the cancellation of the specified task id. - + :param requester_id: Ignored, VIP Identity used internally :param task_id: Task name. - + :type requester_id: str :type task_id: str :returns: Request result :rtype: dict - - :Return Values: + + :Return Values: The return values are described in `Cancel Task Response`_. - + """ rpc_peer = self.vip.rpc.context.vip_message.peer return self._request_cancel_schedule(rpc_peer, task_id, publish_result=False) diff --git a/services/core/ActuatorAgent/actuator/scheduler.py b/services/core/ActuatorAgent/actuator/scheduler.py index 3cebfe4d6d..c1190e5491 100644 --- a/services/core/ActuatorAgent/actuator/scheduler.py +++ b/services/core/ActuatorAgent/actuator/scheduler.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/ActuatorAgent/setup.py b/services/core/ActuatorAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/services/core/ActuatorAgent/setup.py +++ b/services/core/ActuatorAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/ActuatorAgent/tests/test_actuator_pubsub.py b/services/core/ActuatorAgent/tests/test_actuator_pubsub.py index d95bc4c470..60eb4fa94e 100644 --- a/services/core/ActuatorAgent/tests/test_actuator_pubsub.py +++ b/services/core/ActuatorAgent/tests/test_actuator_pubsub.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/ActuatorAgent/tests/test_actuator_rpc.py b/services/core/ActuatorAgent/tests/test_actuator_rpc.py index 17d45ac99f..af964bf8d0 100644 --- a/services/core/ActuatorAgent/tests/test_actuator_rpc.py +++ b/services/core/ActuatorAgent/tests/test_actuator_rpc.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -215,7 +201,7 @@ def test_request_new_schedule(publish_agent, cancel_schedules, taskid, expected_ :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_schedule_success ****") + print("\n**** test_schedule_success ****") # used by cancel_schedules agentid = TEST_AGENT cancel_schedules.append({'agentid': agentid, 'taskid': taskid}) @@ -460,7 +446,7 @@ def test_request_new_schedule_should_suceed_on_preempt_active_task(publish_agent :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_schedule_preempt_active_task ****") + print("\n**** test_schedule_preempt_active_task ****") # used by cancel_schedules agentid = 'new_agent' taskid = 'task_high_priority2' @@ -656,7 +642,7 @@ def test_request_new_schedule_should_return_failure_on_preempt_active_task(publi :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_schedule_preempt_error_active_task ****") + print("\n**** test_schedule_preempt_error_active_task ****") # used by cancel_schedules agentid = TEST_AGENT taskid = 'task_low_priority3' @@ -713,7 +699,7 @@ def test_request_new_schedule_should_succeed_on_preempt_future_task(publish_agen :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_schedule_preempt_future_task ****") + print("\n**** test_schedule_preempt_future_task ****") # used by cancel_schedules agentid = 'new_agent' taskid = 'task_high_priority4' @@ -789,7 +775,7 @@ def test_request_new_schedule_should_return_failure_on_conflicting_time_slots(pu :param publish_agent: fixture invoked to setup all agents necessary and returns an instance of Agent object used for publishing """ - print ("\n**** test_schedule_conflict_self ****") + print("\n**** test_schedule_conflict_self ****") # used by cancel_schedules taskid = 'task_self_conflict' start = str(datetime.now()) @@ -868,7 +854,7 @@ def test_request_new_schedule_should_succeed_on_overlap_time_slots(publish_agent :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_schedule_overlap_success ****") + print("\n**** test_schedule_overlap_success ****") # set agentid and task id for cancel_schedules fixture agentid = TEST_AGENT taskid = 'task_overlap' @@ -902,7 +888,7 @@ def test_request_cancel_schedule_should_succeed(publish_agent): :param publish_agent: fixture invoked to setup all agents necessary and returns an instance of Agent object used for publishing """ - print ("\n**** test_cancel_success ****") + print("\n**** test_cancel_success ****") start = str(datetime.now()) end = str(datetime.now() + timedelta(seconds=2)) @@ -940,7 +926,7 @@ def test_request_cancel_schedule_should_return_failure_on_invalid_taskid(publish returns an instance of Agent object used for publishing """ - print ("\n**** test_cancel_error_invalid_taskid ****") + print("\n**** test_cancel_error_invalid_taskid ****") result = publish_agent.vip.rpc.call( PLATFORM_ACTUATOR, REQUEST_CANCEL_SCHEDULE, @@ -963,7 +949,7 @@ def test_get_point_should_succeed(publish_agent): :param publish_agent: fixture invoked to setup all agents necessary and returns an instance of Agent object used for publishing """ - print ("\n**** test_get_default ****") + print("\n**** test_get_default ****") result = publish_agent.vip.rpc.call( PLATFORM_ACTUATOR, # Target agent @@ -1072,7 +1058,7 @@ def test_revert_point_should_succeed(publish_agent, cancel_schedules): :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_set_float_value ****") + print("\n**** test_set_float_value ****") taskid = 'test_revert_point' agentid = TEST_AGENT cancel_schedules.append({'agentid': agentid, 'taskid': taskid}) @@ -1136,7 +1122,7 @@ def test_revert_point_with_point_should_succeed(publish_agent, cancel_schedules) :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_set_float_value ****") + print("\n**** test_set_float_value ****") taskid = 'test_revert_point' agentid = TEST_AGENT cancel_schedules.append({'agentid': agentid, 'taskid': taskid}) @@ -1380,7 +1366,7 @@ def test_set_point_raises_value_error(publish_agent, cancel_schedules): :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_set_value_error ****") + print("\n**** test_set_value_error ****") agentid = TEST_AGENT taskid = 'task_set_value_error' cancel_schedules.append({'agentid': agentid, 'taskid': taskid}) @@ -1562,7 +1548,7 @@ def test_set_point_raises_remote_error_on_lock_failure(publish_agent, cancel_sch :param cancel_schedules: fixture used to cancel the schedule at the end of test so that other tests can use the same device and time slot """ - print ("\n**** test_set_float_value ****") + print("\n**** test_set_float_value ****") agentid = TEST_AGENT with pytest.raises(RemoteError): diff --git a/services/core/ActuatorAgent/tests/test_scheduler.py b/services/core/ActuatorAgent/tests/test_scheduler.py index 271f4da056..be2de1ec0f 100644 --- a/services/core/ActuatorAgent/tests/test_scheduler.py +++ b/services/core/ActuatorAgent/tests/test_scheduler.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os diff --git a/services/core/BACnetProxy/bacnet_proxy/agent.py b/services/core/BACnetProxy/bacnet_proxy/agent.py index 08caff938c..68d4cc4f1f 100644 --- a/services/core/BACnetProxy/bacnet_proxy/agent.py +++ b/services/core/BACnetProxy/bacnet_proxy/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/services/core/BACnetProxy/setup.py b/services/core/BACnetProxy/setup.py index 65bf2b0a14..e671e235b2 100644 --- a/services/core/BACnetProxy/setup.py +++ b/services/core/BACnetProxy/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from setuptools import setup, find_packages diff --git a/services/core/DNP3Agent/README.md b/services/core/DNP3Agent/README.md deleted file mode 100644 index 3cf6162e19..0000000000 --- a/services/core/DNP3Agent/README.md +++ /dev/null @@ -1,86 +0,0 @@ -DNP3Agent and MesaAgent, either of which can be built from this directory, -are VOLTTRON agents that handle DNP3 communications. -They implement a DNP3 outstation, communicating with a DNP3 master. - -For further information about these agents and DNP3 communications, please see the VOLTTRON -DNP3 and MESA specifications, located in VOLTTRON readthedocs -under http://volttron.readthedocs.io/en/develop/specifications/dnp3_agent.html -and http://volttron.readthedocs.io/en/develop/specifications/mesa_agent.html. - -These agents depend on the pydnp3 library, which must be installed in the VOLTTRON virtual environment: - - (volttron) $ pip install pydnp3 - -Installing MesaAgent --------------------- - -MesaAgent implements MESA-ESS, an enhanced version of the DNP3 protocol. - -MesaAgent can be installed by running the **install_mesa_agent.sh** -command-line script as follows: - - (volttron) $ export VOLTTRON_ROOT= - (volttron) $ source $VOLTTRON_ROOT/services/core/DNP3Agent/install_mesa_agent.sh - -The **install_mesa_agent.sh** script installs the agent: - - (volttron) $ export DNP3_ROOT=$VOLTTRON_ROOT/services/core/DNP3Agent - (volttron) $ export AGENT_MODULE=dnp3.mesa.agent - (volttron) $ cd $VOLTTRON_ROOT - (volttron) $ python scripts/install-agent.py -s $DNP3_ROOT -i mesaagent -c $DNP3_ROOT/mesaagent.config -t mesaagent -f - -(Note that $AGENT_MODULE directs the installer to use agent -source code residing in the "dnp3/mesa" subdirectory.) - -Then the script stores DNP3 point and MESA function definitions in the agent's config store: - - (volttron) $ cd $DNP3_ROOT - (volttron) $ python dnp3/mesa/conversion.py < dnp3/mesa/mesa_functions.yaml > dnp3/mesa/mesa_functions.config - (volttron) $ cd $VOLTTRON_ROOT - (volttron) $ vctl config store mesaagent mesa_points.config $DNP3_ROOT/dnp3/mesa_points.config - (volttron) $ vctl config store mesaagent mesa_functions.config $DNP3_ROOT/dnp3/mesa/mesa_functions.config - -Regression tests can be run from a command-line shell as follows: - - (volttron) $ pytest services/core/DNP3Agent/tests/test_mesa_agent.py - -Installing DNP3Agent --------------------- - -DNP3Agent implements the basic DNP3 protocol. - -DNP3Agent can be installed by running the **install_dnp3_agent.sh** -command-line script as follows: - - (volttron) $ export VOLTTRON_ROOT= - (volttron) $ source $VOLTTRON_ROOT/services/core/DNP3Agent/install_dnp3_agent.sh - -The **install_dnp3_agent.sh** script installs the agent: - - (volttron) $ export DNP3_ROOT=$VOLTTRON_ROOT/services/core/DNP3Agent - (volttron) $ export AGENT_MODULE=dnp3.agent - (volttron) $ cd $VOLTTRON_ROOT - (volttron) $ python scripts/install-agent.py -s $DNP3_ROOT -i dnp3agent -c $DNP3_ROOT/config -t dnp3agent -f - -(Note that $AGENT_MODULE directs the installer to use agent -source code residing in the "dnp3" directory.) - -Then the script stores DNP3 point (but not MESA function) definitions in the agent's config store: - - (volttron) $ vctl config store dnp3agent mesa_points.config $DNP3_ROOT/dnp3/mesa_points.config - -Regression tests can be run from a command-line shell as follows: - - (volttron) $ cd $VOLTTRON_ROOT - (volttron) $ pytest services/core/DNP3Agent/tests/test_dnp3_agent.py - -Maintaining mesa_points.config and mesa_functions.yaml ------------------------------------------------------- - -mesa_points.config is installed in $DNP3_ROOT/dnp3/mesa_points.config - -mesa_functions.yaml is installed in $DNP3_ROOT/dnp3/mesa/mesa_functions.yaml - -To update Mesa points and functions config files, please follow instructions for -[mesa_points.config](https://docs.google.com/document/d/1WgiGkNCtILLvNKSm0ZsNo0HrqY0akIQIiGQNZP1PBP0/edit#heading=h.5224t5rtcb0g) -and [mesa_functions.yaml](https://docs.google.com/document/d/1WgiGkNCtILLvNKSm0ZsNo0HrqY0akIQIiGQNZP1PBP0/edit#heading=h.qhuvbxq207n2) diff --git a/services/core/DNP3Agent/config b/services/core/DNP3Agent/config deleted file mode 100644 index fe60378e83..0000000000 --- a/services/core/DNP3Agent/config +++ /dev/null @@ -1,11 +0,0 @@ -{ - "points": "config://mesa_points.config", - "point_topic": "dnp3/point", - "outstation_status_topic": "dnp3/outstation_status", - "outstation_config": { - "database_sizes": 10000, - "log_levels": ["NORMAL"] - }, - "local_ip": "0.0.0.0", - "port": 20000 -} \ No newline at end of file diff --git a/services/core/DNP3Agent/conftest.py b/services/core/DNP3Agent/conftest.py deleted file mode 100644 index 74134a5b76..0000000000 --- a/services/core/DNP3Agent/conftest.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys - -from volttrontesting.fixtures.volttron_platform_fixtures import * - -collect_ignore = ["function_test.py", "tests/mesa_platform_test.py"] - -try: - import pydnp3 -except ImportError: - # pydnp3 library has not been installed -- all pytest modules would fail - collect_ignore.extend(["tests/test_dnp3_agent.py", - "tests/test_mesa_agent.py", - "tests/test_mesa_data.py"]) - -# Add system path of the agent's directory -sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) - -# Add system path of the agent's dnp3 subdirectory -sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/dnp3')) diff --git a/services/core/DNP3Agent/dnp3/__init__.py b/services/core/DNP3Agent/dnp3/__init__.py deleted file mode 100644 index d0525d5da5..0000000000 --- a/services/core/DNP3Agent/dnp3/__init__.py +++ /dev/null @@ -1,74 +0,0 @@ -from pydnp3 import opendnp3 - -DEFAULT_POINT_TOPIC = 'dnp3/point' -DEFAULT_OUTSTATION_STATUS_TOPIC = 'mesa/outstation_status' -DEFAULT_LOCAL_IP = "0.0.0.0" -DEFAULT_PORT = 20000 - -# StepDefinition.fcode values: -DIRECT_OPERATE = 'direct_operate' # This is actually DIRECT OPERATE / RESPONSE -SELECT = 'select' # This is actually SELECT / RESPONSE -OPERATE = 'operate' # This is actually OPERATE / RESPONSE -READ = 'read' -RESPONSE = 'response' - -# PointDefinition.action values: -PUBLISH = 'publish' -PUBLISH_AND_RESPOND = 'publish_and_respond' - -# Some PointDefinition.type values -POINT_TYPE_ARRAY = 'array' -POINT_TYPE_SELECTOR_BLOCK = 'selector_block' -POINT_TYPE_ENUMERATED = 'enumerated' -POINT_TYPES = [POINT_TYPE_ARRAY, POINT_TYPE_SELECTOR_BLOCK, POINT_TYPE_ENUMERATED] - -# Some PointDefinition.point_type values: -DATA_TYPE_ANALOG_INPUT = 'AI' -DATA_TYPE_ANALOG_OUTPUT = 'AO' -DATA_TYPE_BINARY_INPUT = 'BI' -DATA_TYPE_BINARY_OUTPUT = 'BO' - -# PointDefinition.group -DEFAULT_GROUP_BY_DATA_TYPE = { - DATA_TYPE_BINARY_INPUT: 1, - DATA_TYPE_BINARY_OUTPUT: 10, - DATA_TYPE_ANALOG_INPUT: 30, - DATA_TYPE_ANALOG_OUTPUT: 40 -} - -# variation = 1: 32 bit, variation = 2: 16 bit -DEFAULT_VARIATION = { - DATA_TYPE_BINARY_INPUT: {'evariation': opendnp3.EventBinaryVariation.Group2Var1, - 'svariation': opendnp3.StaticBinaryVariation.Group1Var2}, - DATA_TYPE_BINARY_OUTPUT: {'evariation': opendnp3.EventBinaryOutputStatusVariation.Group11Var1, - 'svariation': opendnp3.StaticBinaryOutputStatusVariation.Group10Var2}, - DATA_TYPE_ANALOG_INPUT: {'evariation': opendnp3.EventAnalogVariation.Group32Var1, - 'svariation': opendnp3.StaticAnalogVariation.Group30Var1}, - DATA_TYPE_ANALOG_OUTPUT: {'evariation': opendnp3.EventAnalogOutputStatusVariation.Group42Var1, - 'svariation': opendnp3.StaticAnalogOutputStatusVariation.Group40Var1} -} - -# PointDefinition.event_class -DEFAULT_EVENT_CLASS = 2 - -EVENT_CLASSES = { - 0: opendnp3.PointClass.Class0, - 1: opendnp3.PointClass.Class1, - 2: opendnp3.PointClass.Class2, - 3: opendnp3.PointClass.Class3 -} - -DATA_TYPES_BY_GROUP = { - # Single-Bit Binary: See DNP3 spec, Section A.2-A.5 and Table 11-17 - 1: DATA_TYPE_BINARY_INPUT, # Binary Input (static): Reporting the present value of a single-bit binary object - 2: DATA_TYPE_BINARY_INPUT, # Binary Input Event: Reporting single-bit binary input events and flag bit changes - # Binary Output: See DNP3 spec, Section A.6-A.9 and Table 11-12 - 10: DATA_TYPE_BINARY_OUTPUT, # Binary Output (static): Reporting the present output status - 11: DATA_TYPE_BINARY_OUTPUT, # Binary Output Event: Reporting changes to the output status or flag bits - # Analog Input: See DNP3 spec, Section A.14-A.18 and Table 11-9 - 30: DATA_TYPE_ANALOG_INPUT, # Analog Input (static): Reporting the present value - 32: DATA_TYPE_ANALOG_INPUT, # Analog Input Event: Reporting analog input events or changes to the flag bits - # Analog Output: See DNP3 spec, Section A.19-A.22 and Table 11-10 - 40: DATA_TYPE_ANALOG_OUTPUT, # Analog Output Status (static): Reporting present value of analog outputs - 42: DATA_TYPE_ANALOG_OUTPUT # Analog Output Event: Reporting changes to the analog output or flag bits -} diff --git a/services/core/DNP3Agent/dnp3/agent.py b/services/core/DNP3Agent/dnp3/agent.py deleted file mode 100644 index 8ecbc7cd24..0000000000 --- a/services/core/DNP3Agent/dnp3/agent.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, SLAC / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor SLAC, nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# SLAC, or Kisensum. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# }}} - -import logging -import sys - -from volttron.platform.agent import utils -from dnp3.base_dnp3_agent import BaseDNP3Agent - -utils.setup_logging() -_log = logging.getLogger(__name__) - -__version__ = '1.1' - - -class DNP3Agent(BaseDNP3Agent): - """ - DNP3Agent is a VOLTTRON agent that handles DNP3 outstation communications. - - DNP3Agent models a DNP3 outstation, communicating with a DNP3 master. - - For further information about this agent and DNP3 communications, please see the VOLTTRON - DNP3 specification, located in VOLTTRON readthedocs - under http://volttron.readthedocs.io/en/develop/specifications/dnp3_agent.html. - - This agent can be installed from a command-line shell as follows: - $ export VOLTTRON_ROOT= - $ cd $VOLTTRON_ROOT - $ source services/core/DNP3Agent/install_dnp3_agent.sh - """ - - def _process_point_value(self, point_value): - """DNP3Agent publishes each point value to the message bus as the value is received from the master.""" - point_val = super(DNP3Agent, self)._process_point_value(point_value) - if point_val: - self.publish_point_value(point_value) - - -def dnp3_agent(config_path, **kwargs): - """ - Parse the DNP3 Agent configuration. Return an agent instance created from that config. - - :param config_path: (str) Path to a configuration file. - :returns: (DNP3Agent) The DNP3 agent - """ - try: - config = utils.load_config(config_path) - except Exception: - config = {} - return DNP3Agent(points=config.get('points', None), - point_topic=config.get('point_topic', 'dnp3/point'), - local_ip=config.get('local_ip', '0.0.0.0'), - port=config.get('port', 20000), - outstation_config=config.get('outstation_config', {}), - **kwargs) - - -def main(): - """Main method called to start the agent.""" - utils.vip_main(dnp3_agent, identity='dnp3agent', version=__version__) - - -if __name__ == '__main__': - # Entry point for script - try: - sys.exit(main()) - except KeyboardInterrupt: - pass diff --git a/services/core/DNP3Agent/dnp3/base_dnp3_agent.py b/services/core/DNP3Agent/dnp3/base_dnp3_agent.py deleted file mode 100644 index 46eb97a4f8..0000000000 --- a/services/core/DNP3Agent/dnp3/base_dnp3_agent.py +++ /dev/null @@ -1,517 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, SLAC / 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared in part as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor SLAC, nor 8minutenergy, nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# SLAC, 8minutenergy, or Kisensum. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# }}} - -import logging -import numbers -import os - -from pydnp3 import opendnp3 - -from volttron.platform.vip.agent import RPC -from volttron.platform.agent import utils -from volttron.platform.messaging import headers -from volttron.platform.vip.agent import Agent - -from dnp3.outstation import DNP3Outstation -from dnp3 import DEFAULT_POINT_TOPIC, DEFAULT_OUTSTATION_STATUS_TOPIC -from dnp3 import DEFAULT_LOCAL_IP, DEFAULT_PORT -from dnp3 import DATA_TYPE_ANALOG_INPUT, DATA_TYPE_BINARY_INPUT -from dnp3 import PUBLISH_AND_RESPOND -from dnp3.points import PointDefinitions, PointDefinition, PointArray -from dnp3.points import DNP3Exception - -utils.setup_logging() -_log = logging.getLogger(__name__) - - -class BaseDNP3Agent(Agent): - """ - DNP3Agent is a VOLTTRON agent that handles DNP3 outstation communications. - - DNP3Agent models a DNP3 outstation, communicating with a DNP3 master. - - For further information about this agent and DNP3 communications, please see the VOLTTRON - DNP3 specification, located in VOLTTRON readthedocs - under http://volttron.readthedocs.io/en/develop/specifications/dnp3_agent.html. - - This agent can be installed from a command-line shell as follows: - export VOLTTRON_ROOT= - export DNP3_ROOT=$VOLTTRON_ROOT/services/core/DNP3Agent - cd $VOLTTRON_ROOT - python scripts/install-agent.py -s $DNP3_ROOT -i dnp3agent -c $DNP3_ROOT/config -t dnp3agent -f - """ - - def __init__(self, points=None, point_topic='', local_ip=None, port=None, - outstation_config=None, local_point_definitions_path=None, **kwargs): - """Initialize the DNP3 agent.""" - super(BaseDNP3Agent, self).__init__(**kwargs) - self.points = points - self.point_topic = point_topic - self.local_ip = local_ip - self.port = port - self.outstation_config = outstation_config - self.default_config = { - 'points': points, - 'point_topic': point_topic, - 'local_ip': local_ip, - 'port': port, - 'outstation_config': outstation_config, - } - self.application = None - self.volttron_points = None - - self.point_definitions = None - self._current_point_values = {} - self._current_array = None - self._local_point_definitions_path = local_point_definitions_path - - self.vip.config.set_default('config', self.default_config) - self.vip.config.subscribe(self._configure, actions=['NEW', 'UPDATE'], pattern='config') - - def _configure(self, config_name, action, contents): - """Initialize/Update the agent configuration.""" - self._configure_parameters(contents) - - def load_point_definitions(self): - """ - Load and cache a dictionary of PointDefinitions from a json list. - - Index the dictionary by point_type and point index. - """ - _log.debug('Loading DNP3 point definitions.') - try: - self.point_definitions = PointDefinitions() - self.point_definitions.load_points(self.points) - except (AttributeError, TypeError) as err: - if self._local_point_definitions_path: - _log.warning("Attempting to load point definitions from local path.") - self.point_definitions = PointDefinitions(point_definitions_path=self._local_point_definitions_path) - else: - raise DNP3Exception("Failed to load point definitions from config store: {}".format(err)) - - def start_outstation(self): - """Start the DNP3Outstation instance, kicking off communication with the DNP3 Master.""" - _log.info('Starting DNP3Outstation') - self.publish_outstation_status('starting') - self.application = DNP3Outstation(self.local_ip, self.port, self.outstation_config) - self.application.start() - self.publish_outstation_status('running') - - def stop_outstation(self): - """Shutdown the DNP3Outstation application.""" - _log.info('Stopping DNP3Outstation') - self.publish_outstation_status('stopping') - self.application.shutdown() - self.publish_outstation_status('stopped') - self.application = None - - def _configure_parameters(self, contents): - """ - Initialize/Update the DNP3 agent configuration. - - DNP3Agent configuration parameters (the MesaAgent subclass has some more): - - points: (string) A JSON structure of point definitions to be loaded. - point_topic: (string) Message bus topic to use when publishing DNP3 point values. - Default: mesa/point. - outstation_status_topic: (string) Message bus topic to use when publishing outstation status. - Default: mesa/outstation_status. - local_ip: (string) Outstation's host address (DNS resolved). - Default: 0.0.0.0. - port: (integer) Outstation's port number - the port that the remote endpoint (Master) is listening on. - Default: 20000. - outstation_config: (dictionary) Outstation configuration parameters. All are optional. - Parameters include: - database_sizes: (integer) Size of each DNP3 database buffer. - Default: 10000. - event_buffers: (integer) Size of the database event buffers. - Default: 10. - allow_unsolicited: (boolean) Whether to allow unsolicited requests. - Default: True. - link_local_addr: (integer) Link layer local address. - Default: 10. - link_remote_addr: (integer) Link layer remote address. - Default: 1. - log_levels: List of bit field names (OR'd together) that filter what gets logged by DNP3. - Default: [NORMAL]. - Possible values: ALL, ALL_APP_COMMS, ALL_COMMS, NORMAL, NOTHING. - threads_to_allocate: (integer) Threads to allocate in the manager's thread pool. - Default: 1. - """ - config = self.default_config.copy() - config.update(contents) - self.points = config.get('points', []) - self.point_topic = config.get('point_topic', DEFAULT_POINT_TOPIC) - self.outstation_status_topic = config.get('outstation_status_topic', DEFAULT_OUTSTATION_STATUS_TOPIC) - self.local_ip = config.get('local_ip', DEFAULT_LOCAL_IP) - self.port = int(config.get('port', DEFAULT_PORT)) - self.outstation_config = config.get('outstation_config', {}) - _log.debug('DNP3Agent configuration parameters:') - _log.debug('\tpoints type={}'.format(type(self.points))) - _log.debug('\tpoint_topic={}'.format(self.point_topic)) - _log.debug('\toutstation_status_topic={}'.format(self.outstation_status_topic)) - _log.debug('\tlocal_ip={}'.format(self.local_ip)) - _log.debug('\tport={}'.format(self.port)) - _log.debug('\toutstation_config={}'.format(self.outstation_config)) - self.load_point_definitions() - DNP3Outstation.set_agent(self) - - # Stop outstation if DNP3 config has been changed - if self.application and ( - self.application.local_ip, self.application.port, self.application.outstation_config) != ( - self.local_ip, self.port, self.outstation_config): - self.stop_outstation() - - # Start outstation if the DNP3 application has not started - if not self.application: - self.start_outstation() - - return config - - @RPC.export - def reset(self): - """Reset the agent's internal state, emptying point value caches. Used during iterative testing.""" - _log.info('Resetting agent state.') - self._current_point_values = {} - self._current_array = {} - - def get_current_point_value(self, data_type, index): - """Return the most-recently-received PointValue for a given PointDefinition.""" - if data_type not in self._current_point_values or index not in self._current_point_values[data_type]: - return None - else: - return self._current_point_values[data_type][index] - - def _set_point(self, point_name, value): - """ - (Internal) Set the value of a given input point (no debug trace). - - @param point_name: The VOLTTRON point name of a DNP3 PointDefinition. - @param value: The value to set. The value's data type must match the one in the DNP3 PointDefinition. - """ - point_properties = self.volttron_points.get(point_name, {}) - data_type = point_properties.get('data_type', None) - index = point_properties.get('index', None) - try: - if data_type == DATA_TYPE_ANALOG_INPUT: - wrapped_value = opendnp3.Analog(value) - elif data_type == DATA_TYPE_BINARY_INPUT: - wrapped_value = opendnp3.Binary(value) - else: - raise Exception('Unexpected data type for DNP3 point named {0}'.format(point_name)) - DNP3Outstation.apply_update(wrapped_value, index) - except Exception as e: - raise DNP3Exception(e) - - def process_point_value(self, command_type, command, index, op_type): - """ - A point value was received from the Master. Process its payload. - - @param command_type: Either 'Select' or 'Operate'. - @param command: A ControlRelayOutputBlock or else a wrapped data value (AnalogOutputInt16, etc.). - @param index: DNP3 index of the payload's data definition. - @param op_type: An OperateType, or None if command_type == 'Select'. - @return: A CommandStatus value. - """ - try: - point_value = self.point_definitions.point_value_for_command(command_type, command, index, op_type) - if point_value is None: - return opendnp3.CommandStatus.DOWNSTREAM_FAIL - except Exception as ex: - _log.error('No DNP3 PointDefinition for command with index {}'.format(index)) - return opendnp3.CommandStatus.DOWNSTREAM_FAIL - - try: - self._process_point_value(point_value) - except Exception as ex: - _log.error('Error processing DNP3 command: {}'.format(ex)) - # Delete a cached point value (typically occurs only if an error is being handled). - try: - self._current_point_values.get(point_value.point_def.data_type, {}).pop(int(point_value.index), None) - except Exception as err: - _log.error('Error discarding cached value {}'.format(point_value)) - return opendnp3.CommandStatus.DOWNSTREAM_FAIL - - return opendnp3.CommandStatus.SUCCESS - - def _process_point_value(self, point_value): - _log.info('Received DNP3 {}'.format(point_value)) - if point_value.command_type == 'Select': - # Perform any needed validation now, then wait for the subsequent Operate command. - return None - else: - # Update a dictionary that holds the most-recently-received value of each point. - self._current_point_values.setdefault(point_value.point_def.data_type, {})[ - int(point_value.index)] = point_value - return point_value - - def get_point_named(self, point_name): - return self.point_definitions.get_point_named(point_name) - - def update_array_for_point(self, point_value): - """A received point belongs to a PointArray. Update it.""" - if point_value.point_def.is_array_head_point: - self._current_array = PointArray(point_value.point_def) - elif self._current_array is None: - raise DNP3Exception('Array point received, but there is no current Array.') - elif not self._current_array.contains_index(point_value.index): - raise DNP3Exception('Received Array point outside of current Array.') - self._current_array.add_point_value(point_value) - - def update_input_point(self, point_def, value): - """ - Update an input point. This may send its PointValue to the Master. - - :param point_def: A PointDefinition. - :param value: A value to send (unwrapped simple data type, or else a list/array). - """ - if type(value) == list: - # It's an array. Break it down into its constituent points, and apply each one separately. - col_count = len(point_def.array_points) - cols_by_name = {pt['name']: col for col, pt in enumerate(point_def.array_points)} - for row_number, point_dict in enumerate(value): - for pt_name, pt_val in point_dict.items(): - pt_index = point_def.index + col_count * row_number + cols_by_name[pt_name] - array_point_def = self.point_definitions.get_point_named(point_def.name, index=pt_index) - self._apply_point_update(array_point_def, pt_index, pt_val) - else: - self._apply_point_update(point_def, point_def.index, value) - - @staticmethod - def _apply_point_update(point_def, point_index, value): - """ - Set an input point in the outstation database. This may send its PointValue to the Master. - - :param point_def: A PointDefinition. - :param point_index: A numeric index for the point. - :param value: A value to send (unwrapped, simple data type). - """ - data_type = point_def.data_type - if data_type == DATA_TYPE_ANALOG_INPUT: - wrapped_val = opendnp3.Analog(float(value)) - if isinstance(value, bool) or not isinstance(value, numbers.Number): - # Invalid data type - raise DNP3Exception('Received {} value for {}.'.format(type(value), point_def)) - elif data_type == DATA_TYPE_BINARY_INPUT: - wrapped_val = opendnp3.Binary(value) - if not isinstance(value, bool): - # Invalid data type - raise DNP3Exception('Received {} value for {}.'.format(type(value), point_def)) - else: - # The agent supports only DNP3's Analog and Binary point types at this time. - raise DNP3Exception('Unsupported point type {}'.format(data_type)) - if wrapped_val is not None: - DNP3Outstation.apply_update(wrapped_val, point_index) - _log.debug('Sent DNP3 point {}, value={}'.format(point_def, wrapped_val.value)) - - def publish_point_value(self, point_value): - """Publish a PointValue as it is received from the DNP3 Master.""" - _log.info('Publishing DNP3 {}'.format(point_value)) - msg = { - point_value.name: (point_value.unwrapped_value() if point_value else None) - } - - if point_value.point_def.action == PUBLISH_AND_RESPOND: - msg.update({ - 'response': point_value.point_def.response - }) - - self.publish_data(self.point_topic, msg) - - def publish_outstation_status(self, outstation_status): - """Publish outstation status.""" - _log.info('Publishing outstation status: {}'.format(outstation_status)) - self.publish_data(self.outstation_status_topic, outstation_status) - - def publish_data(self, topic, msg): - """Publish a payload to the message bus.""" - try: - self.vip.pubsub.publish(peer='pubsub', - topic=topic, - headers={headers.TIMESTAMP: utils.format_timestamp(utils.get_aware_utc_now())}, - message=msg) - except Exception as err: - if os.environ.get('UNITTEST', False): - _log.debug('Disregarding publish_data exception during unit test') - else: - raise DNP3Exception('Error publishing topic {}, message {}: {}'.format(topic, msg, err)) - - def dnp3_point_name(self, point_name): - """ - Return a point's DNP3 point name, mapped from its VOLTTRON point name if necessary. - - If VOLTTRON point names were configured (by the DNP device driver), map them to DNP3 point names. - """ - dnp3_point_name = self.volttron_points.get(point_name, '') if self.volttron_points else point_name - if not dnp3_point_name: - raise DNP3Exception('No configured point for {}'.format(point_name)) - return dnp3_point_name - - @RPC.export - def get_point(self, point_name): - """ - Look up the most-recently-received value for a given output point. - - @param point_name: The point name of a DNP3 PointDefinition. - @return: The (unwrapped) value of a received point. - """ - _log.info('Getting point value for {}'.format(point_name)) - try: - point_name = self.dnp3_point_name(point_name) - point_def = self.point_definitions.get_point_named(point_name) - point_value = self.get_current_point_value(point_def.data_type, point_def.index) - return point_value.unwrapped_value() if point_value else None - except Exception as e: - raise DNP3Exception(e) - - @RPC.export - def get_point_by_index(self, data_type, index): - """ - Look up the most-recently-received value for a given point. - - @param data_type: The data_type of a DNP3 point. - @param index: The index of a DNP3 point. - @return: The (unwrapped) value of a received point. - """ - _log.info('Getting point value for data_type {} and index {}'.format(data_type, index)) - try: - point_value = self.get_current_point_value(data_type, index) - return point_value.unwrapped_value() if point_value else None - except Exception as e: - raise DNP3Exception(e) - - @RPC.export - def get_points(self, point_list): - """ - Look up the most-recently-received value of each configured output point. - - @param point_list: A list of point names. - @return: A dictionary of point values, indexed by their point names. - """ - _log.info('Getting values for the following points: {}'.format(point_list)) - try: - return {name: self.get_point(name) for name in point_list} - except Exception as e: - raise DNP3Exception(e) - - @RPC.export - def get_configured_points(self): - """ - Look up the most-recently-received value of each configured point. - - @return: A dictionary of point values, indexed by their point names. - """ - if self.volttron_points is None: - raise DNP3Exception('DNP3 points have not been configured') - - _log.info('Getting all DNP3 configured point values') - try: - return {name: self.get_point(name) for name in self.volttron_points} - except Exception as e: - raise DNP3Exception(e) - - @RPC.export - def set_point(self, point_name, value): - """ - Set the value of a given input point. - - @param point_name: The point name of a DNP3 PointDefinition. - @param value: The value to set. The value's data type must match the one in the DNP3 PointDefinition. - """ - _log.info('Setting DNP3 {} point value = {}'.format(point_name, value)) - try: - self.update_input_point(self.get_point_named(self.dnp3_point_name(point_name)), value) - - except Exception as e: - raise DNP3Exception(e) - - @RPC.export - def set_points(self, point_dict): - """ - Set point values for a dictionary of points. - - @param point_dict: A dictionary of {point_name: value} for a list of DNP3 points to set. - """ - _log.info('Setting DNP3 point values: {}'.format(point_dict)) - try: - for point_name, value in point_dict.items(): - self.update_input_point(self.get_point_named(self.dnp3_point_name(point_name)), value) - except Exception as e: - raise DNP3Exception(e) - - @RPC.export - def config_points(self, point_map): - """ - For each of the agent's points, map its VOLTTRON point name to its DNP3 group and index. - - @param point_map: A dictionary that maps a point's VOLTTRON point name to its DNP3 group and index. - """ - _log.info('Configuring DNP3 points: {}'.format(point_map)) - self.volttron_points = point_map - - @RPC.export - def get_point_definitions(self, point_name_list): - """ - For each DNP3 point name in point_name_list, return a dictionary with each of the point definitions. - - The returned dictionary looks like this: - - { - "point_name1": { - "property1": "property1_value", - "property2": "property2_value", - ... - }, - "point_name2": { - "property1": "property1_value", - "property2": "property2_value", - ... - } - } - - If a definition cannot be found for a point name, it is omitted from the returned dictionary. - - :param point_name_list: A list of point names. - :return: A dictionary of point definitions. - """ - _log.info('Fetching a list of DNP3 point definitions for {}'.format(point_name_list)) - try: - response = {} - for name in point_name_list: - point_def = self.point_definitions.get_point_named(self.dnp3_point_name(name)) - if point_def is not None: - response[name] = point_def.as_json() - return response - except Exception as e: - raise DNP3Exception(e) diff --git a/services/core/DNP3Agent/dnp3/mesa/agent.py b/services/core/DNP3Agent/dnp3/mesa/agent.py deleted file mode 100644 index 4a0200a982..0000000000 --- a/services/core/DNP3Agent/dnp3/mesa/agent.py +++ /dev/null @@ -1,353 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} -import logging -import sys - -from volttron.platform.agent import utils -from volttron.platform.vip.agent import RPC - -from dnp3.base_dnp3_agent import BaseDNP3Agent - -from dnp3.points import DNP3Exception -from dnp3 import DEFAULT_LOCAL_IP, DEFAULT_PORT -from dnp3 import DEFAULT_POINT_TOPIC, DEFAULT_OUTSTATION_STATUS_TOPIC -from dnp3 import PUBLISH, PUBLISH_AND_RESPOND - -from dnp3.mesa.functions import DEFAULT_FUNCTION_TOPIC, ACTION_PUBLISH_AND_RESPOND -from dnp3.mesa.functions import FunctionDefinitions, Function, FunctionException - -__version__ = '1.1' - -utils.setup_logging() -_log = logging.getLogger(__name__) - - -class MesaAgent(BaseDNP3Agent): - """ - MesaAgent is a VOLTTRON agent that handles MESA-ESS DNP3 outstation communications. - - MesaAgent models a DNP3 outstation, communicating with a DNP3 master. - - For further information about this agent, MESA-ESS, and DNP3 communications, please - see the VOLTTRON MESA-ESS agent specification, which can be found in VOLTTRON readthedocs - at http://volttron.readthedocs.io/en/develop/specifications/mesa_agent.html. - - This agent can be installed from a command-line shell as follows: - $ export VOLTTRON_ROOT= - $ cd $VOLTTRON_ROOT - $ source services/core/DNP3Agent/install_mesa_agent.sh - That file specifies a default agent configuration, which can be overridden as needed. - """ - - def __init__(self, functions=None, function_topic='', outstation_status_topic='', - all_functions_supported_by_default=False, - local_function_definitions_path=None, function_validation=False, **kwargs): - """Initialize the MESA agent.""" - super(MesaAgent, self).__init__(**kwargs) - self.functions = functions - self.function_topic = function_topic - self.outstation_status_topic = outstation_status_topic - self.all_functions_supported_by_default = all_functions_supported_by_default - self.function_validation = function_validation - - # Update default config - self.default_config.update({ - 'functions': functions, - 'function_topic': function_topic, - 'outstation_status_topic': outstation_status_topic, - 'all_functions_supported_by_default': all_functions_supported_by_default, - 'function_validation': function_validation - }) - - # Update default config in config store. - self.vip.config.set_default('config', self.default_config) - - self.function_definitions = None - self._local_function_definitions_path = local_function_definitions_path - - self._current_functions = dict() # {function_id: Function} - self._current_block = dict() # {name: name, index: index} - self._selector_block = dict() # {selector_block_point_name: {selector_index: [Step]}} - self._edit_selectors = list() # [{name: name, index: index}] - - def _configure_parameters(self, contents): - """ - Initialize/Update the MesaAgent configuration. - - See also the superclass version of this method, which does most of the initialization. - MesaAgent configuration parameters: - - functions: (string) A JSON structure of function definitions to be loaded. - function_topic: (string) Message bus topic to use when publishing MESA-ESS functions. - Default: mesa/function. - all_functions_supported_by_default: (boolean) When deciding whether to reject points for unsupported - functions, ignore the values of their 'supported' points: simply treat all functions as - supported. - Default: False. - """ - config = super(MesaAgent, self)._configure_parameters(contents) - self.functions = config.get('functions', {}) - self.function_topic = config.get('function_topic', DEFAULT_FUNCTION_TOPIC) - self.all_functions_supported_by_default = config.get('all_functions_supported_by_default', False) - self.function_validation = config.get('function_validation', False) - _log.debug('MesaAgent configuration parameters:') - _log.debug('\tfunctions type={}'.format(type(self.functions))) - _log.debug('\tfunction_topic={}'.format(self.function_topic)) - _log.debug('\tall_functions_supported_by_default={}'.format(bool(self.all_functions_supported_by_default))) - _log.debug('\tfuntion_validation={}'.format(bool(self.function_validation))) - self.load_function_definitions() - self.supported_functions = [] - # Un-comment the next line to do more detailed validation and print definition statistics. - # validate_definitions(self.point_definitions, self.function_definitions) - - def load_function_definitions(self): - """Populate the FunctionDefinitions repository from JSON in the config store.""" - _log.debug('Loading MESA function definitions') - try: - self.function_definitions = FunctionDefinitions(self.point_definitions) - self.function_definitions.load_functions(self.functions['functions']) - except (AttributeError, TypeError) as err: - if self._local_function_definitions_path: - _log.warning("Attempting to load Function Definitions from local path.") - self.function_definitions = FunctionDefinitions( - self.point_definitions, - function_definitions_path=self._local_function_definitions_path) - else: - raise DNP3Exception("Failed to load Function Definitions from config store: {}".format(err)) - - @RPC.export - def reset(self): - """Reset the agent's internal state, emptying point value caches. Used during iterative testing.""" - super(MesaAgent, self).reset() - self._current_functions = dict() - self._current_block = dict() - self._selector_block = dict() - self._edit_selectors = list() - - @RPC.export - def get_selector_block(self, block_name, index): - try: - return {step.definition.name: step.as_json() for step in self._selector_block[block_name][index]} - except KeyError: - _log.debug('Have not received data for Selector Block {} at Edit Selector {}'.format(block_name, index)) - return None - - def _process_point_value(self, point_value): - """ - A PointValue was received from the Master. Process its payload. - - :param point_value: A PointValue. - """ - try: - point_val = super(MesaAgent, self)._process_point_value(point_value) - - if point_val: - if point_val.point_def.is_selector_block: - self._current_block = { - 'name': point_val.point_def.name, - 'index': float(point_val.value) - } - _log.debug('Starting to receive Selector Block {name} at Edit Selector {index}'.format( - **self._current_block - )) - - # Publish mesa/point if the point action is PUBLISH or PUBLISH_AND_RESPOND - if point_val.point_def.action in (PUBLISH, PUBLISH_AND_RESPOND): - self.publish_point_value(point_value) - - self.update_function_for_point_value(point_val) - - if self._current_functions: - for current_func_id, current_func in self._current_functions.items(): - # if step action is ACTION_ECHO or ACTION_ECHO_AND_PUBLISH - if current_func.has_input_point(): - self.update_input_point( - self.get_point_named(current_func.input_point_name()), - point_val.unwrapped_value() - ) - - # if step is the last curve or schedule step - if self._current_block and point_val.point_def == current_func.definition.last_step.point_def: - current_block_name = self._current_block['name'] - self._selector_block.setdefault(current_block_name, dict()) - self._selector_block[current_block_name][self._current_block['index']] = current_func.steps - - _log.debug('Saved Selector Block {} at Edit Selector {}: {}'.format( - self._current_block['name'], - self._current_block['index'], - self.get_selector_block(self._current_block['name'], self._current_block['index']) - )) - - self._current_block = dict() - - # if step reference to a curve or schedule function - func_ref = current_func.last_step.definition.func_ref - if func_ref: - block_name = self.function_definitions[func_ref].first_step.name - block_index = float(point_val.value) - if not self._selector_block.get(block_name, dict()).get(block_index, None): - error_msg = 'Have not received data for Selector Block {} at Edit Selector {}' - raise DNP3Exception(error_msg.format(block_name, block_index)) - current_edit_selector = { - 'name': block_name, - 'index': block_index - } - if current_edit_selector not in self._edit_selectors: - self._edit_selectors.append(current_edit_selector) - - # if step action is ACTION_PUBLISH, ACTION_ECHO_AND_PUBLISH, or ACTION_PUBLISH_AND_RESPOND - if current_func.publish_now(): - self.publish_function_step(current_func.last_step) - - # if current function is completed - if current_func.complete: - self._current_functions.pop(current_func_id) - self._edit_selectors = list() - - except (DNP3Exception, FunctionException) as err: - self._current_functions = dict() - self._edit_selectors = list() - if type(err) == DNP3Exception: - raise DNP3Exception('Error processing point value: {}'.format(err)) - - def update_function_for_point_value(self, point_value): - """Add point_value to the current Function if appropriate.""" - error_msg = None - current_functions = self.current_function_for(point_value.point_def) - if not current_functions: - return None - for function_id, current_function in current_functions.items(): - try: - if point_value.point_def.is_array_point: - self.update_array_for_point(point_value) - current_function.add_point_value(point_value, - current_array=self._current_array, - function_validation=self.function_validation) - except (DNP3Exception, FunctionException) as err: - current_functions.pop(function_id) - if type(err) == DNP3Exception: - error_msg = err - if error_msg and not current_functions: - raise DNP3Exception('Error updating function: {}'.format(error_msg)) - - def current_function_for(self, new_point_def): - """A point was received. Return the current Function, updating it if necessary.""" - new_point_function_def = self.function_definitions.get_fdef_for_pdef(new_point_def) - if new_point_function_def is None: - return None - if self._current_functions: - current_funcs = dict() - for func_def in new_point_function_def: - val = self._current_functions.pop(func_def.function_id, None) - if val: - current_funcs.update({func_def.function_id: val}) - self._current_functions = current_funcs - else: - for func_def in new_point_function_def: - if not self.all_functions_supported_by_default and not func_def.supported: - raise DNP3Exception('Received a point for unsupported {}'.format(func_def)) - self._current_functions[func_def.function_id] = Function(func_def) - return self._current_functions - - def update_input_point(self, point_def, value): - """ - Update an input point. This may send its PointValue to the Master. - - :param point_def: A PointDefinition. - :param value: A value to send (unwrapped simple data type, or else a list/array). - """ - super(MesaAgent, self).update_input_point(point_def, value) - if type(value) != list: - # Side-effect: If it's a Support point for a Function, update the Function's "supported" property. - func = self.function_definitions.support_point_names().get(point_def.name, None) - if func is not None and func.supported != value: - _log.debug('Updating supported property to {} in {}'.format(value, func)) - func.supported = value - - def publish_function_step(self, step_to_send): - """A Function Step was received from the DNP3 Master. Publish the Function.""" - function_to_send = step_to_send.function - - points = {step.definition.name: step.as_json() for step in function_to_send.steps} - for edit_selector in self._edit_selectors: - block_name = edit_selector['name'] - index = edit_selector['index'] - try: - points[block_name][index] = self.get_selector_block(block_name, index) - except (KeyError, TypeError): - points[block_name] = { - index: self.get_selector_block(block_name, index) - } - - msg = { - "function_id": function_to_send.definition.function_id, - "function_name": function_to_send.definition.name, - "points": points - } - if step_to_send.definition.action == ACTION_PUBLISH_AND_RESPOND: - msg["expected_response"] = step_to_send.definition.response - _log.info('Publishing MESA {} message {}'.format(function_to_send, msg)) - self.publish_data(self.function_topic, msg) - - -def mesa_agent(config_path, **kwargs): - """ - Parse the MesaAgent configuration. Return an agent instance created from that config. - - :param config_path: (str) Path to a configuration file. - :returns: (MesaAgent) The MESA agent - """ - try: - config = utils.load_config(config_path) - except Exception: - config = {} - return MesaAgent(points=config.get('points', []), - functions=config.get('functions', []), - point_topic=config.get('point_topic', DEFAULT_POINT_TOPIC), - function_topic=config.get('function_topic', DEFAULT_FUNCTION_TOPIC), - outstation_status_topic=config.get('outstation_status_topic', DEFAULT_OUTSTATION_STATUS_TOPIC), - local_ip=config.get('local_ip', DEFAULT_LOCAL_IP), - port=config.get('port', DEFAULT_PORT), - outstation_config=config.get('outstation_config', {}), - all_functions_supported_by_default=config.get('all_functions_supported_by_default', False), - function_validation=config.get('function_validation', False), - **kwargs) - - -def main(): - """Main method called to start the agent.""" - utils.vip_main(mesa_agent, identity='mesaagent', version=__version__) - - -if __name__ == '__main__': - # Entry point for script - try: - sys.exit(main()) - except KeyboardInterrupt: - pass diff --git a/services/core/DNP3Agent/dnp3/mesa/conversion.py b/services/core/DNP3Agent/dnp3/mesa/conversion.py deleted file mode 100644 index f78824791a..0000000000 --- a/services/core/DNP3Agent/dnp3/mesa/conversion.py +++ /dev/null @@ -1,4 +0,0 @@ -import sys, yaml, json - -y=yaml.load(sys.stdin.read()) -print(json.dumps(y)) \ No newline at end of file diff --git a/services/core/DNP3Agent/dnp3/mesa/functions.py b/services/core/DNP3Agent/dnp3/mesa/functions.py deleted file mode 100644 index f6e0cc4c27..0000000000 --- a/services/core/DNP3Agent/dnp3/mesa/functions.py +++ /dev/null @@ -1,570 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} -import argparse -import logging -import os -import collections.abc -import yaml - -from dnp3.points import PointDefinitions, PointDefinition, DNP3Exception - -DEFAULT_FUNCTION_TOPIC = 'mesa/function' - -# Values of StepDefinition.optional -OPTIONAL = 'O' -MANDATORY = 'M' -INITIALIZE = 'I' -ALL_OPTIONALITY = [OPTIONAL, MANDATORY, INITIALIZE] - -# Values of the elements of StepDefinition.fcodes: -DIRECT_OPERATE = 'direct_operate' # This is actually DIRECT OPERATE / RESPONSE -SELECT = 'select' # This is actually SELECT / RESPONSE -OPERATE = 'operate' # This is actually OPERATE / RESPONSE -READ = 'read' -RESPONSE = 'response' - -# Values of StepDefinition.action: -ACTION_ECHO = 'echo' -ACTION_PUBLISH = 'publish' -ACTION_ECHO_AND_PUBLISH = 'echo_and_publish' -ACTION_PUBLISH_AND_RESPOND = 'publish_and_respond' -ACTION_NONE = 'none' - -_log = logging.getLogger(__name__) - - -class FunctionDefinitions(collections.abc.Mapping): - """In-memory repository of FunctionDefinitions.""" - - def __init__(self, point_definitions, function_definitions_path=None): - """Data holder for all MESA-ESS functions.""" - self._point_definitions = point_definitions - self._functions = dict() # {function_id: FunctionDefinition} - self._pdef_function_map = dict() # {PointDefinition: [FunctionDefinition]} - if function_definitions_path: - file_path = os.path.expandvars(os.path.expanduser(function_definitions_path)) - self.load_functions_from_yaml_file(file_path) - - def __getitem__(self, function_id): - """Return the function associated with this function_id. Must be unique.""" - return self._functions[function_id] - - def __iter__(self): - return iter(self._functions) - - def __len__(self): - """Return the total number of functions from FunctionDefinitions.""" - return len(self._functions) - - @property - def all_function_ids(self): - """Return all function_id from FunctionDefinitions.""" - return self._functions.keys() - - @property - def function_def_lst(self): - """Return a list of all FunctionDefinition in the FunctionDefinitions.""" - return self._functions.values() - - def support_point_names(self): - """Return a dictionary of FunctionDefinitions keyed by their (non-null) support_point_names.""" - return {f.support_point_name: f - for f_id, f in self._functions.items() - if f.support_point_name is not None} - - def function_for_id(self, function_id): - """Return a specific function definition from (cached) dictionary of FunctionDefinitions.""" - return self._functions.get(function_id, None) - - def load_functions_from_yaml_file(self, function_definitions_path): - """Load and cache a YAML file of FunctionDefinitions. Index them by function name.""" - _log.debug('Loading MESA-ESS FunctionDefinitions from {}.'.format(function_definitions_path)) - if function_definitions_path: - fdef_path = os.path.expandvars(os.path.expanduser(function_definitions_path)) - self._functions = {} - try: - with open(fdef_path, 'r') as f: - self.load_functions(yaml.load(f)['functions']) - except Exception as err: - raise ValueError('Problem parsing {}. Error={}'.format(fdef_path, err)) - _log.debug('Loaded {} FunctionDefinitions'.format(len(self._functions.keys()))) - - def get_fdef_for_pdef(self, pdef): - """ - Return a list of FunctionDefinition that contains the PointDefinition or None otherwise. - - :param pdef: PointDefinition - """ - return self._pdef_function_map.get(pdef, None) - - def load_functions(self, function_definitions_json): - """ - Load and cache a JSON dictionary of FunctionDefinitions. Index them by function ID. - Check if function_id is unique and func_ref in steps are valid. - """ - self._functions = {} - try: - for function_def in function_definitions_json: - new_function = FunctionDefinition(self._point_definitions, function_def) - function_id = new_function.function_id - if self._functions.get(function_id, None): - raise ValueError('There are multiple functions for function id {}'.format(function_id)) - self._functions[function_id] = new_function - for pdef in new_function.all_point_defs(): - try: - self._pdef_function_map[pdef].append(new_function) - except KeyError: - self._pdef_function_map[pdef] = [new_function] - except Exception as err: - raise ValueError('Problem parsing FunctionDefinitions. Error={}'.format(err)) - - for fdef in self.function_def_lst: - for step in fdef.steps: - func_ref = step.func_ref - if func_ref and func_ref not in self.all_function_ids: - raise ValueError('Invalid Function Reference {} for Step {} in Function {}'. format( - func_ref, - step.step_number, - fdef.function_id - )) - - _log.debug('Loaded {} FunctionDefinitions'.format(len(self))) - - -class FunctionDefinition: - """A MESA-ESS FunctionDefinition (aka mode, command).""" - - def __init__(self, point_definitions, function_def_dict): - """ - Data holder for the definition of a MESA-ESS function. Including parsing data validation. - self._point_steps_map: dictionary mapping PointDefinition including all Array points to StepDefinition - self.steps: a list of all StepDefinition (not including array points) in the function - """ - self.function_id = function_def_dict.get('id', None) # Must be unique - self.name = function_def_dict.get('name', None) - self.mode_types = function_def_dict.get('mode_types', {}) - self.ref = function_def_dict.get('ref', None) - self.support_point_name = function_def_dict.get('support_point', None) - self._point_steps_map = {} - - # function_id and steps validation - if not self.function_id: - raise ValueError('Missing function ID') - json_steps = function_def_dict.get('steps', None) - if not json_steps: - raise ValueError('Missing steps for function {}'.format(self.function_id)) - - step_numbers = list() - try: - self.steps = [StepDefinition(point_definitions, self.function_id, step_def) for step_def in json_steps] - is_selector_block = self.is_selector_block - for step in self.steps: - step_number = step.step_number - - # Check if there are duplicated step number - if step_number in step_numbers: - raise ValueError('Duplicated step number {} for function {}'.format(step_number, self.function_id)) - step_numbers.append(step_number) - - # If function is selector block (curve or schedule), all steps must be mandatory or initialize - if is_selector_block and step.optional not in [INITIALIZE, MANDATORY]: - raise ValueError( - 'Function {} - Step {}: optionality must be either INITIALIZE or MANDATORY'.format( - self.function_id, step_number)) - - # Update self._point_steps_map - for pd in step.all_point_defs(): - self._point_steps_map[pd] = step - except AttributeError as err: - raise AttributeError('Error creating FunctionDefinition {}, err={}'.format(self.name, err)) - - # Check is there is missing steps - if set([i for i in range(1, len(self.steps) + 1)]) != set(step_numbers): - raise ValueError('There are missing steps for function {}'.format(self.function_id)) - - def __str__(self): - return 'Function {}'.format(self.name) - - def __contains__(self, point_def): - return point_def in self.all_point_defs() - - def __getitem__(self, point_def): - return self._point_steps_map[point_def] - - @property - def supported(self): - """ - Set supported to False if the Function has a defined support_point_name -- the Control Agent must set it. - To override this (support all functions), set config all_functions_supported_by_default = "True". - """ - return not self.support_point_name - - @property - def first_step(self): - """First step of the function. Mainly used for Selector Block.""" - for step in self.steps: - if step.step_number == 1: - return step - return None - - @property - def last_step(self): - """Last step of the function. Mainly used for Selector Block.""" - for step in self.steps: - if step.step_number == len(self.steps): - return step - return None - - @property - def is_selector_block(self): - return self.first_step.point_def and self.first_step.point_def.is_selector_block - - def instance(self): - """Return an instance of this FunctionDefinition.""" - return Function(self) - - def describe_function(self): - """Return a string describing a function: its name and all of its StepDefinitions.""" - return 'Function {}: {}'.format(self.name, [s.__str__() for s in self.steps]) - - def all_point_defs(self): - """Return all point definition including array points.""" - return self._point_steps_map.keys() - - def all_points(self): - """Return all point definition not including array points and None points.""" - return [step_def.point_def for step_def in self.steps if step_def] - - def is_mode(self): - """Return True if there is mode enable point in the function, False otherwise.""" - for point in self.all_points(): - if point and point.category == 'mode_enable': - return True - return False - - def get_mode_enable(self): - """Return a list of all mode enable points in the function.""" - return [point for point in self.all_points() if point and point.category == 'mode_enable'] - - -class StepDefinition: - """Step definition in a MESA-ESS FunctionDefinition.""" - - def __init__(self, point_definitions, function_id, step_def=None): - """ - Data holder for the definition of a step in a MESA-ESS FunctionDefinition. - - :param function_def: The FunctionDefinition to which the StepDefinition belongs. - :param step_def: A dictionary of data from which to create the StepDefinition. - """ - self.function_id = function_id - self.name = step_def.get('point_name', None) - self.point_def = point_definitions[self.name] - self.step_number = step_def.get('step_number', None) - self.optional = step_def.get('optional', OPTIONAL) - self.fcodes = step_def.get('fcodes', []) - self.action = step_def.get('action', None) - self.func_ref = step_def.get('func_ref', None) - self.description = step_def.get('description', None) - self.validate() - - try: - self.response = point_definitions[step_def.get('response', None)] - except Exception as err: - raise AttributeError('Response point in function {} step {} does not match point definition. Error={}'.format( - self.function_id, - self.step_number, - err - )) - - def __str__(self): - return '{} Step {}: {}'.format(self.function_id, self.step_number, self.name) - - def all_point_defs(self): - """Return a list of all PointDefinition including all Array points""" - all_defs = [self.point_def] - if self.point_def and self.point_def.is_array_head_point: - all_defs.extend(self.point_def.array_point_definitions) - return all_defs - - def validate(self): - if self.step_number is None: - raise AttributeError('Missing step number in function {}'.format(self.function_id)) - if not self.name: - raise AttributeError('Missing name in function {} step {}'.format(self.function_id, self.step_number)) - if self.optional not in ALL_OPTIONALITY: - raise AttributeError('Invalid optional value in function {} step {}: {}'.format(self.function_id, - self.step_number, - self.optional)) - if type(self.fcodes) != list: - raise AttributeError('Invalid fcodes in function {} step {}, type={}'.format(self.function_id, - self.step_number, - type(self.fcodes))) - for fc in self.fcodes: - if fc not in [DIRECT_OPERATE, SELECT, OPERATE, READ, RESPONSE]: - raise AttributeError('Invalid fcode in function {} step {}, fcode={}'.format(self.function_id, - self.step_number, - fc)) - if fc == READ and self.optional != OPTIONAL: - raise AttributeError('Invalid optionality in function {} step {}: must be OPTIONAL'.format( - self.function_id, - self.step_number - )) - - -class Step: - """A MESA-ESS Step that has been received by an outstation.""" - - def __init__(self, definition, func, value): - """ - Data holder for a received Step. - - :param definition: A StepDefinition. - :param value: A PointValue. - """ - self.definition = definition - self.function = func - self.value = value - - def __str__(self): - return '{}: {}'.format(self.definition, self.value) - - def as_json(self): - return self.value.as_json() if self.definition.point_def.is_array_head_point else self.value.unwrapped_value() - - def echoes_input(self): - return self.definition.action in [ACTION_ECHO, ACTION_ECHO_AND_PUBLISH] - - def publish(self): - return self.definition.action in [ACTION_PUBLISH, - ACTION_ECHO_AND_PUBLISH, - ACTION_PUBLISH_AND_RESPOND] - - -class FunctionException(Exception): - """ - Raise exceptions that are used for _process_point_value in Mesa agent. - Set the current function to None if the exception is raised. - """ - pass - - -class Function: - """A MESA-ESS Function that has been received by an outstation.""" - - def __init__(self, definition): - """ - Data holder for a Function received by an outstation. - - :param definition: A FunctionDefinition. - """ - self.definition = definition - self.steps = [] - - def __str__(self): - return 'Function {}'.format(self.definition.name) - - def __contains__(self, point_def): - if not isinstance(point_def, PointDefinition): - raise ValueError("Membership test only works for PointDefinition instance, not {}".format(point_def)) - return point_def in self.definition - - @property - def last_step(self): - """ - Return last received step of the function. - """ - return self.steps[-1] if self.steps else None - - @property - def complete(self): - """ - Return True if function is completed, False otherwise. - """ - if self.next_remaining_mandatory_step_number: - return False - return True - - @property - def next_remaining_mandatory_step_number(self): - """ - Return next remaining mandatory step number of the function if there is one existed, None otherwise. - """ - last_received_step_number = 0 if not self.last_step else self.last_step.definition.step_number - for step_def in self.definition.steps: - step_number = step_def.step_number - if step_number > last_received_step_number and step_def.optional in [MANDATORY, INITIALIZE]: - return step_number - return None - - def add_step(self, step_def, value, function_validation=False): - """ - Add a step to function if no mandatory step missing and return the step, raise exception otherwise. - - :param step_def: step definition to add to function - :param value: value of the point in step_def - :param function_validation: defaults to False. - When there is mandatory step missing, raise DNP3Exception if function_validation is True, - raise FunctionException otherwise. - FunctionException is used for _process_point_value in Mesa agent, if the FunctionException is raised, - reset current function to None and process the next point as the first step of a new function. - """ - # Check for missing mandatory steps up to the current step - if self.next_remaining_mandatory_step_number \ - and step_def.step_number > self.next_remaining_mandatory_step_number: - exception_message = '{} is missing Mandatory step number {}'.format( - self, - self.next_remaining_mandatory_step_number - ) - if function_validation: - raise DNP3Exception(exception_message) - raise FunctionException(exception_message) - # add current step to self.steps - step_value = Step(step_def, self, value) - self.steps.append(step_value) - return step_value - - def add_point_value(self, point_value, current_array=None, function_validation=False): - """ - Add a received PointValue as a Step in the current Function. Return the Step. - - :param point_value: point value - :param current_array: current array - :param function_validation: defaults to False. If function_validation is True, - raise DNP3Exception when getting an error while adding a new step to the current function. - If function_validation is False, reset current function to None if missing mandatory step, - set the adding step as the first step of the current function if step is not in order, - or replace the last step by the adding step if step is duplicated. - """ - step_def = self.definition[point_value.point_def] - step_number = step_def.step_number - if not self.last_step: - self.add_step(step_def, point_value, function_validation) - else: - last_received_step_number = self.last_step.definition.step_number - if step_number != last_received_step_number: - if step_number < last_received_step_number: - if self.next_remaining_mandatory_step_number: - if function_validation: - raise DNP3Exception('Step {} received after {}'.format(step_number, - last_received_step_number)) - # Since the old function was complete, treat this as the first step of a new function. - self.steps = [] - self.add_step(step_def, point_value, function_validation) - else: - if not point_value.point_def.is_array_point: - if function_validation: - raise DNP3Exception('Duplicate step number {} received'.format(step_number)) - self.steps.pop() - self.add_step(step_def, point_value, function_validation) - else: - # An array point was received for an existing step. Update the step's value. - self.last_step.value = current_array - - return self.last_step - - def has_input_point(self): - """Function has an input pont to be echoed following last step.""" - return self.last_step.echoes_input() if self.last_step else False - - def input_point_name(self): - """The name of the input point - - @todo This really should be a point_def - """ - return self.last_step.definition.response if self.last_step else '' - - def publish_now(self): - """The function has points to published following last step.""" - return self.last_step.publish() if self.last_step else False - - -def load_and_validate_definitions(): - """ - Standalone method, intended to be invoked from the command line. - - Load PointDefinition and FunctionDefinition files as specified in command line args, - and validate their contents. - """ - # Grab JSON and YAML definition file paths from the command line. - parser = argparse.ArgumentParser() - parser.add_argument('point_defs', help='path of the point definitions file (json)') - parser.add_argument('function_defs', help='path of the function definitions file (yaml)') - args = parser.parse_args() - - point_definitions = PointDefinitions(point_definitions_path=args.point_defs) - function_definitions = FunctionDefinitions(point_definitions, function_definitions_path=args.function_defs) - validate_definitions(point_definitions, function_definitions) - - -def validate_definitions(point_definitions, function_definitions): - """Validate PointDefinitions, Arrays, SelectorBlocks and FunctionDefinitions.""" - - print('\nValidating Point definitions...') - all_points = point_definitions.all_points() - print('\t{} point definitions'.format(len(all_points))) - - print('\nValidating Array definitions...') - array_head_points = [pt for pt in all_points if pt.is_array_head_point] - array_bounds = {pt: [pt.index, pt.array_last_index] for pt in array_head_points} - for pt in array_head_points: - # Print each array's definition. Also, check for overlapping array bounds. - print('\t{} ({}): indexes=({},{}), elements={}'.format(pt.name, - pt.data_type, - pt.index, - pt.array_last_index, - len(pt.array_points))) - for other_pt, other_bounds in array_bounds.iteritems(): - if pt.name != other_pt.name: - if other_bounds[0] <= pt.index <= other_bounds[1]: - print('\tERROR: Overlapping array definition in {} and {}'.format(pt, other_pt)) - if other_bounds[0] <= pt.array_last_index <= other_bounds[1]: - print('\tERROR: Overlapping array definition in {} and {}'.format(pt, other_pt)) - print('\t{} array definitions'.format(len(array_head_points))) - - print('\nValidating Selector Block definitions...') - selector_block_points = [pt for pt in all_points if pt.is_selector_block] - selector_block_bounds = {pt: [pt.selector_block_start, pt.selector_block_end] for pt in selector_block_points} - for pt in selector_block_points: - # Print each selector block's definition. Also, check for overlapping selector block bounds. - print('\t{} ({}): indexes=({},{})'.format(pt.name, - pt.data_type, - pt.selector_block_start, - pt.selector_block_end)) - for other_pt, other_bounds in selector_block_bounds.iteritems(): - if pt.name != other_pt.name: - if other_bounds[0] <= pt.selector_block_start <= other_bounds[1]: - print('\tERROR: Overlapping selector blocks in {} and {}'.format(pt, other_pt)) - if other_bounds[0] <= pt.selector_block_end <= other_bounds[1]: - print('\tERROR: Overlapping selector blocks in {} and {}'.format(pt, other_pt)) - # Check that each save_on_write point references a selector_block_point - print('\t{} selector block definitions'.format(len(selector_block_points))) - print('\nValidating Function definitions...') - functions = function_definitions.all_function_ids - print('\t{} function definitions'.format(len(functions))) diff --git a/services/core/DNP3Agent/dnp3/mesa/mesa_functions.yaml b/services/core/DNP3Agent/dnp3/mesa/mesa_functions.yaml deleted file mode 100644 index 500f52d3eb..0000000000 --- a/services/core/DNP3Agent/dnp3/mesa/mesa_functions.yaml +++ /dev/null @@ -1,2595 +0,0 @@ -functions: -- id: connect_and_disconnect - name: Connect and Disconnect - ref: AN2018 Spec section 2.4.4 Table 29 - steps: - - description: Set time window - fcodes: - - direct_operate - optional: I - point_name: DCTE.WinTms.AO16 - response: DCTE.WinTms.AI60 - step_number: 1 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DCTE.RvrtTms.AO17 - response: DCTE.RvrtTms.AI61 - step_number: 2 - - description: Retrieve status of switch - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.DEROpSt.off.BI23 - step_number: 3 - - action: publish - description: Issue switch control command and receive response - fcodes: - - select - - operate - optional: M - point_name: CSWI.Pos.BO5 - response: DSTO.DEROpSt.off.BI23 - step_number: 4 - - description: Detect if switch is moving - fcodes: - - read - - response - optional: O - point_name: n/a - response: CSWI.Pos.BI24 - step_number: 5 -- id: cease_to_energize_and_return_to_service - name: Cease to Energize and Return to Service - ref: AN2018 Spec section 2.4.5 Table 30 - steps: - - description: Set Cease to Energize Time Window - fcodes: - - direct_operate - optional: I - point_name: DCTE.WinTms.AO13 - response: DCTE.WinTms.AI57 - step_number: 1 - - description: Set Cease to Energize Ramp DownTime - fcodes: - - direct_operate - optional: I - point_name: DCTE.RmpTms.AO14 - response: DCTE.RmpTms.AI58 - step_number: 2 - - description: Set Cease to Energize Timeout Period - fcodes: - - direct_operate - optional: I - point_name: DCTE.RvrtTms.AO15 - response: DCTE.RvrtTms.AI59 - step_number: 3 - - description: Cause DER to Cease to Energize - fcodes: - - select - - operate - optional: M - point_name: DCTE.CeaEngzReq.BO2 - response: DSTO.DEROpSt.connectedandidle.BI14 - step_number: 4 - - description: Give DER Permission to Stop - fcodes: - - select - - operate - optional: M - point_name: DSTO.PrmDscon.BO4 - response: DSTO.PrmDscon.BI17 - step_number: 5 - - description: Confirm DER is Stopping - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.DEROpSt.stopping.BI13 - step_number: 6 - - description: Confirm DER has Ceased to Energize - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.DEROpSt.ceasedtoenergize.BI15 - step_number: 7 - - description: Set High Voltage Limit - fcodes: - - direct_operate - optional: I - point_name: DCTE.VHiLim.AO6 - response: DCTE.VHiLim.AI50 - step_number: 8 - - description: Set Low Voltage Limit - fcodes: - - direct_operate - optional: I - point_name: DCTE.VLoLim.AO7 - response: DCTE.VLoLim.AI51 - step_number: 9 - - description: Set High Frequency Limit - fcodes: - - direct_operate - optional: I - point_name: DCTE.HzHiLim.AO8 - response: DCTE.HzHiLim.AI52 - step_number: 10 - - description: Set Low Frequency Limit - fcodes: - - direct_operate - optional: I - point_name: DCTE.HzLoLim.AO9 - response: DCTE.HzLoLim.AI53 - step_number: 11 - - description: Set Delay Time - fcodes: - - direct_operate - optional: I - point_name: DCTE.RtnDlyTmms.AO10 - response: DCTE.RtnDlTmms.AI54 - step_number: 12 - - description: Set Return to Service Time Window - fcodes: - - direct_operate - optional: I - point_name: DCTE.WinTms.AO11 - response: DCTE.WinTms.AI55 - step_number: 13 - - description: Set Return to Service Ramp Up Time - fcodes: - - direct_operate - optional: I - point_name: DCTE.RtnRmpTmms.AO12 - response: DCTE.RtnRmpTmms.AI56 - step_number: 14 - - description: Cause DER to Return to Service - fcodes: - - select - - operate - optional: M - point_name: DCTE.RtnSrvReq.BO1 - response: DSTO.DEROpSt.startingandsynchronizing.BI12 - step_number: 15 - - action: publish - description: Give DER Permission to Start - fcodes: - - select - - operate - optional: M - point_name: DSTO.PrmConn.BO3 - response: DSTO.PrmConn.BI16 - step_number: 16 - - description: Confirm DER is Started - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.DEROpSt.connectedandidle.BI14 - step_number: 17 -- id: enable_low_high_voltage_ride-through_mode - mode_types: - curve: - - 9 - - 10 - - 11 - - 12 - schedule: - - 1 - - 2 - - 3 - - 4 - name: Enable Low/High Voltage Ride-Through Mode - ref: AN2018 Spec section 2.5.1 Table 33 - steps: - - description: Set the Reference Voltage if it is not already set - fcodes: - - direct_operate - optional: I - point_name: DECP.VRef.AO0 - response: DECP.VRef.AI29 - step_number: 1 - - description: Set the Reference Voltage Offset if it is not already set - fcodes: - - direct_operate - optional: I - point_name: DECP.VRefOfs.AO1 - response: DECP.VRefOfs.AI30 - step_number: 2 - - description: Identify the meter used to measure the voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DHVT.EcpRef.AO22 - response: DHVT.EcpRef.AI71 - step_number: 3 - - description: 'DGSMn.ModTyp.AO245 = <9> HVRT Must Trip: If the curve is a must - trip curve, identify the index of the curve which specifies trip points when - the voltage is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTOV.BlkRef.AO23 - response: PTOV.BlkRef.AI73 - step_number: 4 - - description: 'DGSMn.ModTyp.AO245 = <11> LVRT Must Trip: If the curve is a must - trip curve, identify the index of the curve which specifies trip points when - the voltage is low' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTUV.BlkRef.AO24 - response: PTUV.BlkRef.AI74 - step_number: 5 - - description: 'DGSMn.ModTyp.AO245 = <10> HVRT Momentary Cessation: If the curve - is a must trip curve, identify the index of the curve which specifies where - generation/discharging must stop when the voltage is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTOV.BlkRef.AO25 - response: PTOV.BlkRef.AI75 - step_number: 6 - - description: 'DGSMn.ModTyp.AO245 = <12> LVRT Momentary Cessation: If the curve - is a must trip curve, identify the index of the curve which specifies where - generation/discharging must stop when the voltage is low' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTUV.BlkRef.AO26 - response: PTUV.BlkRef.AI76 - step_number: 7 - - action: publish - description: Enable the Low/High Voltage Ride-Through Mode - fcodes: - - select - - operate - optional: M - point_name: DHVT.ModEna.BO12 - response: DHVT.ModEna.BI64 - step_number: 8 -- id: enable_low_high_frequency_ride-through_mode - mode_types: - curve: - - 13 - - 14 - - 15 - - 16 - schedule: - - 5 - - 6 - - 7 - - 8 - name: Enable Low/High Frequency Ride-Through Mode - ref: AN2018 Spec section 2.5.2 Table 35 - steps: - - description: Set the Nominal Grid Frequency if it is not already set - fcodes: - - direct_operate - optional: I - point_name: DECP.EcpNomHz.AO2 - response: DECP.EcpNomHz.AI31 - step_number: 1 - - description: Identify the meter used to measure the frequency. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DHFT.EcpRef.AO27 - response: DHFT.EcpRef.AI77 - step_number: 2 - - description: 'DGSMn.ModTyp.AO245 = <13> HFRT Must Trip: Identify the index of - the frequency ride through curve which specifies trip ponts when the frequency - is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTOF.BlkRef.AO28 - response: PTOF.BlkRef.AI79 - step_number: 3 - - description: 'DGSMn.ModTyp.AO245 = <15> LFRT Must Trip: Identify the index of - the frequency ride through curve which specifies trip ponts when the voltage - is low' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTUF.BlkRef.AO29 - response: PTUF.BlkRef.AI80 - step_number: 4 - - description: 'DGSMn.ModTyp.AO245 = <14> HFRT Mandatory Operation: Identify the - index of the frequency ride through curve which specifies where generation/discharging - must stop when the frequency is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTOF.BlkRef.AO30 - response: PTOF.BlkRef.AI81 - step_number: 5 - - description: 'DGSMn.ModTyp.AO245 = <16> LFRT Mandatory Operation: Identify the - index of the frequency ride through curve which specifies where generation/discharging - must stop when the frequency is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTUF.BlkRef.AO31 - response: PTUF.BlkRef.AI82 - step_number: 6 - - action: publish - description: Enable the Low/High Frequency Ride-Through Mode - fcodes: - - select - - operate - optional: M - point_name: DHFT.ModEna.BO13 - response: DHFT.ModEna.BI65 - step_number: 7 -- id: enable_frequency-watt_mode - name: Enable Frequency-Watt Mode - ref: AN2018 Spec section 2.5.3 Table 36 - mode_types: - schedule: - - 11 - steps: - - description: If not already established, set the Nominal Grid Frequency - fcodes: - - direct_operate - optional: I - point_name: DECP.EcpNomHz.AO2 - response: DECP.EcpNomHz.AI31 - step_number: 1 - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DHFW2.ModPrio.AO57 - response: DHFW2.ModPrio.AI115 - step_number: 2 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DHFW.WinTms.AO58 - response: DHFW.WinTms.AI116 - step_number: 3 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DHFW.RmpTms.AO59 - response: DHFW.RmpTms.AI117 - step_number: 4 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DHFW.RvrtTms.AO60 - response: DHFW.RvrtTms.AI118 - step_number: 5 - - description: Identify the meter used to measure the frequency. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DHFW.EcpRef.AO61 - response: DHFW2.EcpRef.AI119 - step_number: 6 - - description: Set the High Starting Frequency - fcodes: - - direct_operate - optional: I - point_name: DHFW.HzStr.AO62 - response: DHFW2.HzStr.AI121 - step_number: 7 - - description: Set the High Stopping Frequency - fcodes: - - direct_operate - optional: I - point_name: DHFW.HzStop.AO63 - response: DHFW2.HzStop.AI122 - step_number: 8 - - description: Set the High Discharging Gradient - fcodes: - - direct_operate - optional: I - point_name: DHFW.WGra.AO64 - response: DHFW.WGra.AI123 - step_number: 9 - - description: Set the High Charging Gradient - fcodes: - - direct_operate - optional: I - point_name: DHFW.WChaGra.AO65 - response: DHFW.WChaGra.AI124 - step_number: 10 - - description: Set the Low Starting Frequency - fcodes: - - direct_operate - optional: I - point_name: DLFW.HzStr.AO66 - response: DLFW2.HzStr.AI125 - step_number: 11 - - description: Set the Low Stopping Frequency - fcodes: - - direct_operate - optional: I - point_name: DLFW.HzStop.AO67 - response: DLFW2.HzStop.AI126 - step_number: 12 - - description: Set the Low Discharging Gradient - fcodes: - - direct_operate - optional: I - point_name: DLFW.WGra.AO68 - response: DLFW.WGra.AI127 - step_number: 13 - - description: Set the Low Charging Gradient - fcodes: - - direct_operate - optional: I - point_name: DLFW.WChaGra.AO69 - response: DLFW.WChaGra.AI128 - step_number: 14 - - description: Set the Start Delay - fcodes: - - direct_operate - optional: I - point_name: DHFW2.ActStrDlTmms.AO70 - response: DHFW2.ActStrDlTmms.AI129 - step_number: 15 - - description: Set the Stop Delay - fcodes: - - direct_operate - optional: I - point_name: DHFW2.ActStopDlTmms.AO71 - response: DHFW2.ActStopDlTmms.AI130 - step_number: 16 - - description: Set the Ramp Up Time Constant - fcodes: - - direct_operate - optional: I - point_name: DHFW.OpnLoop.AO72 - response: DLFW.OpnLoopMax.AI131 - step_number: 17 - - description: Set the Ramp Down Time Constant - fcodes: - - direct_operate - optional: I - point_name: DHFW.OpnLoop.AO73 - response: DHFW.OpnLoopMax.AI132 - step_number: 18 - - description: Set the Discharging Up Ramp Rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.DschRpuRte.AO74 - response: DHFW.RpuRte.AI133 - step_number: 19 - - description: Set the Discharging Down Ramp Rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.DschRpdRte.AO75 - response: DHFW.RpdRteMax.AI134 - step_number: 20 - - description: Set the Charging Up Ramp Rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.ChaRpuRte.AO76 - response: DHFW.RpuChaRte.AI135 - step_number: 21 - - description: Set the Charging Down Ramp Rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.ChaRpdRte.AO77 - response: DHFW.RpdChaRteMax.AI136 - step_number: 22 - - description: Set the Hight Return Gradient - fcodes: - - direct_operate - optional: I - point_name: DHFW.RtnRmpRte.AO78 - response: DHFW2.RtnRmpRte.AI137 - step_number: 23 - - description: Set the Low Return Gradient - fcodes: - - direct_operate - optional: I - point_name: DLFW.RtnRmpRte.AO79 - response: DLFW2.RtnRmpRte.AI138 - step_number: 24 - - description: Set the minium State of Charge to be used by this mode - fcodes: - - direct_operate - optional: I - point_name: DHFW.SocUseMin.AO80 - response: DAGC.SocUseMinPct.AI140 - step_number: 25 - - description: Set the maximum State of Charge to be used by this mode - fcodes: - - direct_operate - optional: I - point_name: DHFW.SocUseMax.AO81 - response: DAGC.SocUseMaxPct.AI141 - step_number: 26 - - description: Enable or Disable Hysteresis - fcodes: - - direct_operate - optional: I - point_name: DHFW.HysEna.BO34 - response: DHFW.HysEna.BI86 - step_number: 27 - - description: Enable or Disable Snapshot of Power - fcodes: - - direct_operate - optional: I - point_name: DHFW.SnptEna.BO35 - response: DHFW.SnptEna.BI87 - step_number: 28 - - action: publish - description: Enable Frequency-Watt Mode - fcodes: - - select - - operate - optional: M - point_name: DHFW.ModEna.BO16 - response: DHFW.ModEna.BI68 - step_number: 29 -- id: enable_dynamic_reactive_current_support_mode - name: Enable Dynamic Reactive Current Support Mode - ref: AN2018 Spec section 2.5.4 Table 37 - mode_types: - schedule: - - 9 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DRGS.ModPrio.AO32 - response: DRGS.ModPrio.AI83 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DRGS.WinTms.AO33 - response: DRGS.WinTms.AI84 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DRGS.RmpTms.AO34 - response: DRGS.RmpTms.AI85 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DRGS.RvrtTms.AO35 - response: DRGS.RvrtTms.AI86 - step_number: 4 - - description: Identify the meter used to measure the voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DRGS.EcpRef.AO36 - response: DRGS.EcpRef.AI87 - step_number: 5 - - description: Set the Gradient Mode to select the curve shape - fcodes: - - direct_operate - optional: M - point_name: DRGS.ArGraMod.AO37 - response: DRGS.ArGraMod.AI91 - step_number: 6 - - description: Set the Deadband Minimum Voltage - fcodes: - - direct_operate - optional: M - point_name: DRGS.DbVMin.AO38 - response: DRGS.DbVMin.AI92 - step_number: 7 - - description: Set the Deadband Maximum Voltage - fcodes: - - direct_operate - optional: M - point_name: DRGS.DbVMax.AO39 - response: DRGS.DbVMax.AI93 - step_number: 8 - - description: Set the Reactive Current Support Gradient for Sags - fcodes: - - direct_operate - optional: M - point_name: DRGS.ArGraSag.AO40 - response: DRGS.ArGraSag.AI94 - step_number: 9 - - description: Set the Reactive Current Support Gradient for Swells - fcodes: - - direct_operate - optional: M - point_name: DRGS.ArGraSwl.AO41 - response: DRGS.ArGraSwl.AI95 - step_number: 10 - - description: Set the Filter Time for the Moving Average Voltage in seconds - fcodes: - - direct_operate - optional: M - point_name: DRGS.FilTms.AO42 - response: DRGS.FilTms.AI96 - step_number: 11 - - description: Enable Event-Based Reactive Current Support if required. It shall - default to Disabled. - fcodes: - - direct_operate - optional: I - point_name: DRGS.ArGraMod.BO33 - response: DRGS.ModEna.BI85 - step_number: 12 - - description: Set the Hold Time in milliseconds if Event-Based Reactive Current - Support is required. - fcodes: - - direct_operate - optional: I - point_name: DRGS.HoldTmms.AO46 - response: DRGS.HoldTmms.AI100 - step_number: 13 - - description: Set the Block Zone Voltage if required. Otherwise it shall default - to zero. - fcodes: - - direct_operate - optional: I - point_name: DRGS.BlkZnV.AO43 - response: DRGS.BlkZnV.AI97 - step_number: 14 - - description: Set the Hysteresis Block Zone Voltage if required. Otherwise it - shall default to zero. - fcodes: - - direct_operate - optional: I - point_name: DRGS.HysBlkZnV.AO44 - response: DRGS.HysBlkZnV.AI98 - step_number: 15 - - description: Set the Block Zone Time in milliseconds if required. Otherwise it - shall default to zero. - fcodes: - - direct_operate - optional: I - point_name: DRGS.BlkZnTmms.AO45 - response: DRGS.BlkZnTmms.AI99 - step_number: 16 - - action: publish - description: Enable Dynamic Reactive Current Mode - fcodes: - - select - - operate - optional: M - point_name: DRGS.ModEna.BO14 - response: DRGS.ModEna.BI66 - step_number: 17 -- id: enable_volt-watt_mode - name: Enable Volt-Watt Mode - ref: AN2018 Spec section 2.5.5 Table 38 - steps: - - description: If not already established, set the Reference Voltage - fcodes: - - direct_operate - optional: I - point_name: DECP.VRef.AO0 - response: DECP.VRef.AI29 - step_number: 1 - - description: If not already established, set the Reference Voltage Offset - fcodes: - - direct_operate - optional: I - point_name: DECP.VRefOfs.AO1 - response: DECP.VRefOfs.AI30 - step_number: 2 - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DVWD.ModPrio.AO48 - response: DVWD.ModPrio.AI102 - step_number: 3 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DVWD.WinTms.AO49 - response: DVWD.WinTms.AI103 - step_number: 4 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DVWD.RmpTms.AO50 - response: DVWD.RmpTms.AI104 - step_number: 5 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DVWD.RvrtTms.AO51 - response: DVWD.RvrtTms.AI105 - step_number: 6 - - description: Identify the meter used to measure the voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DVWD2.EcpRef.AO52 - response: DVWD2.EcpRef.AI106 - step_number: 7 - - description: Set the Dynamic Volt-Watt Gradient - fcodes: - - direct_operate - optional: I - point_name: DVWD.DynVWGra.AO53 - response: DVWD.DynVWGra.AI110 - step_number: 8 - - description: Set the Dynamic Volt-Watt Filter Time - fcodes: - - direct_operate - optional: I - point_name: DVWD.VWFilTms.AO54 - response: DVWD.VWFilTms.AI111 - step_number: 9 - - description: Set the Dynamic Volt-Watt Lower Deadband - fcodes: - - direct_operate - optional: I - point_name: DVWD.DbVWLo.AO55 - response: DVWD.DbVWLo.AI112 - step_number: 10 - - description: Set the Dynamic Volt-Watt Upper Deadband - fcodes: - - direct_operate - optional: I - point_name: DVWD.DbVWHi.AO56 - response: DVWD.DbVWHi.AI113 - step_number: 11 - - action: publish - description: Enable Dynamic Volt-Watt mode - fcodes: - - select - - operate - optional: M - point_name: DVWD.ModEna.BO15 - response: DVWD.ModEna.BI67 - step_number: 12 -- id: enable_active_power_limit_mode - name: Enable Active Power Limit Mode - ref: AN2018 Spec section 2.6.1 Table 39 - mode_types: - schedule: - - 12 - - 13 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DWMX.ModPrio.AO82 - response: DWMX.ModPrio.AI142 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DWMX.WinTms.AO83 - response: DWMX.WinTms.AI143 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DWMX.RmpTms.AO84 - response: DWMX.RmpTms.AI144 - step_number: 3 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DWMX.RvrtTms.AO85 - response: DWMX.RvrtTms.AI145 - step_number: 4 - - description: Identify the meter used to measure the active power. By default - this is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DWMX.EcpRef.AO86 - response: DWMX.EcpRef.AI146 - step_number: 5 - - description: Retrieve Maximum Active Generation Power Capability - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.WMax.AI32 - step_number: 6 - - description: Retrieve Maximum Active Charging Power Capability - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.ChaWMax.AI33 - step_number: 7 - - description: Set maximum output in percent of nominal Watts (Charging) - fcodes: - - direct_operate - optional: M - point_name: DWMX.WLimPct.AO87 - response: DWMX.WLimPct.AI148 - step_number: 8 - - description: Set maximum output in percent of nominal Watts (Generating) - fcodes: - - direct_operate - optional: M - point_name: DWMN.WLimPct.AO88 - response: DWMN.WLimPct.AI149 - step_number: 9 - - action: publish - description: Enable Active Power Limit mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DWLM.ModEna.BO17 - response: DWLM.ModEna.BI69 - step_number: 10 -- id: enable_charge_discharge_storage_mode - name: Enable Charge/Discharge Storage Mode - ref: AN2018 Spec section 2.6.2 Table 41 - mode_types: - schedule: - - 14 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DWGC.ModPrio.AO89 - response: DWGC.ModPrio.AI150 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DWGC.WinTms.AO90 - response: DWGC.WinTms.AI151 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DWGC.RmpTms.AO91 - response: DWGC.RmpTms.AI152 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DWGC.RvrtTms.AO92 - response: DWGC.RvrtTms.AI153 - step_number: 4 - - description: Select whether to use Ramp Rates or Time Constants - fcodes: - - direct_operate - optional: I - point_name: DWGC.UseRmpRte.BO38 - response: DWGC.UseRmpRte.BI90 - step_number: 5 - - description: 'If DWGC.UseRmpRte = 0: Set Charge/Discharge Time Constant Ramp Up - Time' - fcodes: - - direct_operate - optional: O - point_name: DWGC.OpnLoop.AO94 - response: DWGC.OpnLoopMax.AI155 - step_number: 6 - - description: 'If DWGC.UseRmpRte = 0: Set Charge/Discharge Time Constant Ramp Down - Time' - fcodes: - - direct_operate - optional: O - point_name: DWGC.OpnLoop.AO95 - response: DWGC.OpnLoopMax.AI156 - step_number: 7 - - description: 'If DWGC.UseRmpRte = 1: Set Discharge Ramp Up Rate' - fcodes: - - direct_operate - optional: O - point_name: DWGC.DschRpuRte.AO96 - response: DWGC.RpuRte.AI157 - step_number: 8 - - description: 'If DWGC.UseRmpRte = 1: Set Discharge Ramp Down Rate' - fcodes: - - direct_operate - optional: O - point_name: DWGC.DschRpdRte.AO97 - response: DWGC.RpdRteMax.AI158 - step_number: 9 - - description: 'If DWGC.UseRmpRte = 1: Set Charge Ramp Up Rate' - fcodes: - - direct_operate - optional: O - point_name: DWGC.ChaRpuRte.AO98 - response: DWGC.RpuChaRte.AI159 - step_number: 10 - - description: 'If DWGC.UseRmpRte = 1: Set Charge Ramp Down Rate' - fcodes: - - direct_operate - optional: O - point_name: DWGC.ChaRpdRte.AO99 - response: DWGC.RpdChaRteMax.AI160 - step_number: 11 - - description: Set Minimum Reserve for Storage (percent of Battery Capacity Rating) - fcodes: - - direct_operate - optional: I - point_name: DWGC.SocUseMinPct.AO100 - response: DWGC.SocUseMinPct.AI161 - step_number: 12 - - description: Set Maximum Reserve for Storage (percent of Battery Capacity Rating) - fcodes: - - direct_operate - optional: I - point_name: DWGC.SocUseMaxPct.AO101 - response: DWGC.SocUseMaxPct.AI162 - step_number: 13 - - description: Set discharge/charge Active Power Target. Positive is discharging, - negative is charging. - fcodes: - - direct_operate - optional: M - point_name: DWGC.GnWPctSpt.AO93 - response: DWGC.GnWPctSpt.AI154 - step_number: 14 - - action: publish - description: Enable charge/discharge mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DWGC.ModEna.BO18 - response: DWGC.ModEna.BI70 - step_number: 15 -- id: enable_coordinated_charge_discharge_management_mode - name: Enable Coordinated Charge/Discharge Management Mode - ref: AN2018 Spec section 2.6.3 Table 42 - mode_types: - schedule: - - 15 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DTCD.ModPrio.AO102 - response: DTCD.ModPrio.AI163 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DTCD.WinTms.AO103 - response: DTCD.WinTms.AI164 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DTCD.RmpTms.AO104 - response: DTCD.RmpTms.AI165 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DTCD.RvrtTms.AO105 - response: DTCD.RvrtTms.AI166 - step_number: 4 - - description: Set the Target State of Charge, as a percentage of Usable Capacity - fcodes: - - direct_operate - optional: M - point_name: DTCD.SocUseTgtPct.AO106 - response: DTCD.SocUseTgtPct.AI167 - step_number: 5 - - description: Set the Target Date Charge Needed - fcodes: - - direct_operate - optional: M - point_name: DTCD.DateTgt.AO107 - response: DTCD.DateTgt.AI168 - step_number: 6 - - description: Set the Target Time Charge Needed (milliseconds since midnight) - fcodes: - - direct_operate - optional: M - point_name: DTCD.DateTgtTms.AO108 - response: DTCD.DateTgtTms.AI169 - step_number: 7 - - action: publish - description: Enable coordinated charge/discharge mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DWGC.ModEna.BO18 - response: DTCD.ModEna.BI71 - step_number: 8 -- id: enable_active_power_response_mode_1 - name: Enable Active Power Response Mode 1 - ref: AN2018 Spec section 2.6.4 Table 43 - mode_types: - schedule: - - 16 - steps: - - description: 'Set the priority of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.ModPrio.AO115 - response: DPKP.ModPrio.AI176 - step_number: 1 - - description: 'Set enabling time window of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.WinTms.AO116 - response: DPKP.WinTms.AI177 - step_number: 2 - - description: 'Set enabling ramp time of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.RmpTms.AO117 - response: DPKP.RmpTms.AI178 - step_number: 3 - - description: 'Set reversion timeout period of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.RvrtTms.AO118 - response: DPKP.RvrtTms.AI179 - step_number: 4 - - description: 'Identify the meter used to measure the Reference Power Input of - mode #1. By default this is the System Meter (ID = 0)' - fcodes: - - direct_operate - optional: I - point_name: DPKP.EcpRef.AO119 - response: DPKP.EcpRef.AI180 - step_number: 5 - - description: 'Set the power threshold for activating mode #1' - fcodes: - - direct_operate - optional: M - point_name: DPKP.PkPwrWLim.AO120 - response: DPKP.PkPwrWLim.AI182 - step_number: 6 - - description: 'Set the ratio used to calculate the output power from the measured - power of mode #1' - fcodes: - - direct_operate - optional: M - point_name: DPKP.PkPwrFolPct.AO121 - response: DPKP.PkPwrFolPct.AI183 - step_number: 7 - - description: 'Set the maximum ramp up rate of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.RpuRte.AO122 - response: DPKP.RpuRte.AI184 - step_number: 8 - - description: 'Set the maximum ramp down rate of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.RpdRte.AO123 - response: DPKP.RpdRte.AI185 - step_number: 9 - - action: publish - description: 'Enable the active response mode #1' - fcodes: - - select - - operate - optional: M - point_name: DPKP.ModEna.BO20 - response: DPKP.ModEna.BI72 - step_number: 10 -- id: enable_active_power_response_mode_2 - name: Enable Active Power Response Mode 2 - ref: AN2018 Spec section 2.6.4 Table 43 - mode_types: - schedule: - - 17 - steps: - - description: 'Set the priority of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.ModPrio.AO124 - response: DGFL.ModPrio.AI187 - step_number: 1 - - description: 'Set enabling time window of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.WinTms.AO125 - response: DGFL.WinTms.AI188 - step_number: 2 - - description: 'Set enabling ramp time of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.RmpTms.AO126 - response: DGFL.RmpTms.AI189 - step_number: 3 - - description: 'Set reversion timeout period of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.RvrtTms.AO127 - response: DGFL.RvrtTms.AI190 - step_number: 4 - - description: 'Identify the meter used to measure the Reference Power Input of - mode #2. By default this is the System Meter (ID = 0)' - fcodes: - - direct_operate - optional: I - point_name: DGFL.EcpRef.AO128 - response: DGFL.EcpRef.AI191 - step_number: 5 - - description: 'Set the power threshold for activating mode #2' - fcodes: - - direct_operate - optional: M - point_name: DGFL.PkPwrWLim.AO129 - response: DGFL.PkPwrWLim.AI193 - step_number: 6 - - description: 'Set the ratio used to calculate the output power from the measured - power of mode #2' - fcodes: - - direct_operate - optional: M - point_name: DGFL.PkPwrFolPct.AO130 - response: DGFL.PkPwrFolPct.AI194 - step_number: 7 - - description: 'Set the maximum ramp up rate of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.RpuRte.AO131 - response: DGFL.RpuRte.AI195 - step_number: 8 - - description: 'Set the maximum ramp down rate of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.RpdRte.AO132 - response: DGFL.RpdRte.AI196 - step_number: 9 - - action: publish - description: 'Enable the active response mode #2' - fcodes: - - select - - operate - optional: M - point_name: DGFL.ModEna.BO21 - response: DGFL.ModEna.BI73 - step_number: 10 -- id: enable_active_power_response_mode_3 - name: Enable Active Power Response Mode 3 - ref: AN2018 Spec section 2.6.4 Table 43 - mode_types: - schedule: - - 18 - steps: - - description: 'Set the priority of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.ModPrio.AO133 - response: DLFL.ModPrio.AI198 - step_number: 1 - - description: 'Set enabling time window of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.WinTms.AO134 - response: DLFL.WinTms.AI199 - step_number: 2 - - description: 'Set enabling ramp time of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.RmpTms.AO135 - response: DLFL.RmpTms.AI200 - step_number: 3 - - description: 'Set reversion timeout period of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.RvrtTms.AO136 - response: DLFL.RvrtTms.AI201 - step_number: 4 - - description: 'Identify the meter used to measure the Reference Power Input of - mode #3. By default this is the System Meter (ID = 0)' - fcodes: - - direct_operate - optional: I - point_name: DLFL.EcpRef.AO137 - response: DLFL.EcpRef.AI202 - step_number: 5 - - description: 'Set the power threshold for activating mode #3' - fcodes: - - direct_operate - optional: M - point_name: DLFL.PkPwrWLim.AO138 - response: DLFL.PkPwrWLim.AI204 - step_number: 6 - - description: 'Set the ratio used to calculate the output power from the measured - power of mode #3' - fcodes: - - direct_operate - optional: M - point_name: DLFL.PkPwrFolPct.AO139 - response: DLFL.PkPwrFolPct.AI205 - step_number: 7 - - description: 'Set the maximum ramp up rate of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.RpuRte.AO140 - response: DLFL.RpuRte.AI206 - step_number: 8 - - description: 'Set the maximum ramp down rate of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.RpdRte.AO141 - response: DLFL.RpdRte.AI207 - step_number: 9 - - action: publish - description: 'Enable the active response mode #3' - fcodes: - - select - - operate - optional: M - point_name: DLFL.ModEna.BO22 - response: DLFL.ModEna.BI74 - step_number: 10 -- id: perform_automatic_generation_control_mode - name: Perform Automatic Generation Control Mode - ref: AN2018 Spec section 2.6.5 Table 45 - mode_types: - schedule: - - 19 - steps: - - description: Set priority of the mode - fcodes: - - direct_operate - optional: I - point_name: DAGC.ModPrio.AO142 - response: DAGC.ModPrio.AI209 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DAGC.WinTms.AO143 - response: DAGC.WinTms.AI210 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DAGC.RmpTms.AO144 - response: DAGC.RmpTms.AI211 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DAGC.RvrtTms.AO145 - response: DAGC.RvrtTms.AI212 - step_number: 4 - - description: Select whether to use Ramp Rates or Time Constants - fcodes: - - direct_operate - optional: I - point_name: DAGC.UseRmpRte.BO39 - response: DAGC.UseRmpRte.BI91 - step_number: 5 - - description: 'If DAGC.UseRmpRte = 0: Set AGC Ramp Time Constant Up Time' - fcodes: - - direct_operate - optional: O - point_name: DAGC.OpnLoop.AO147 - response: DAGC.RmpUpTms.AI214 - step_number: 6 - - description: 'If DAGC.UseRmpRte = 0: Set AGC Ramp Time Constant Down Time' - fcodes: - - direct_operate - optional: O - point_name: DAGC.OpnLoop.AO148 - response: DAGC.RmpDnTms.AI215 - step_number: 7 - - description: 'If DAGC.UseRmpRte = 1: Set AGC Discharge Ramp Up Rate' - fcodes: - - direct_operate - optional: O - point_name: DAGC.DschRpuRte.AO149 - response: DAGC.RpuRte.AI216 - step_number: 8 - - description: 'If DAGC.UseRmpRte = 1: Set AGC Discharge Ramp Down Rate' - fcodes: - - direct_operate - optional: O - point_name: DAGC.DschRpdRte.AO150 - response: DAGC.RpdRte.AI217 - step_number: 9 - - description: 'If DAGC.UseRmpRte = 1: Set AGC Charge Ramp Up Rate' - fcodes: - - direct_operate - optional: O - point_name: DAGC.ChaRpuRte.AO151 - response: DAGC.RpuChaRte.AI218 - step_number: 10 - - description: 'If DAGC.UseRmpRte = 1: Set AGC Charge Ramp Down Rate' - fcodes: - - direct_operate - optional: O - point_name: DAGC.ChaRpdRte.AO152 - response: DAGC.RpdChaRte.AI219 - step_number: 11 - - description: Set Minimum Usable State of Charge (percent of Usable Capacity Rating) - fcodes: - - direct_operate - optional: I - point_name: DAGC.SocUseMinPct.AO153 - response: DAGC.SocUseMinPct.AI220 - step_number: 12 - - description: Set Maximum Usable State of Charge (percent of Usable Capacity Rating) - fcodes: - - direct_operate - optional: I - point_name: DAGC.SocUseMaxPct.AO154 - response: DAGC.SocUseMaxPct.AI221 - step_number: 13 - - description: Set the Active Power Target (in Watts) Positive is discharging, negative - is charging. - fcodes: - - direct_operate - optional: M - point_name: DAGC.GnWSpt.AO146 - response: DAGC.GnWSpt.AI213 - step_number: 14 - - description: Enable AGC mode and receive response. - fcodes: - - select - - operate - optional: M - point_name: DAGC.ModEna.BO23 - response: DAGC.ModEna.BI75 - step_number: 15 - - action: publish - description: Once the mode is enabled, periodically update the Active Power Target. - fcodes: - - direct_operate - optional: M - point_name: DAGC.GnWSpt.AO146 - response: DAGC.GnWSpt.AI213 - step_number: 16 - - description: Read the predicted State of Charge - fcodes: - - read - optional: O - point_name: n/a - response: DAGC.SocExpc.AI224 - step_number: 17 -- id: enable_active_power_smoothing - name: Enable Active Power Smoothing - ref: AN2018 Spec section 2.6.6 Table 46 - mode_types: - schedule: - - 20 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DWSM.ModPrio.AO155 - response: DWSM.ModPrio.AI227 - step_number: 1 - - description: Set time window - fcodes: - - direct_operate - optional: I - point_name: DWSM.WinTms.AO156 - response: DWSM.WinTms.AI228 - step_number: 2 - - description: Set ramp time - fcodes: - - direct_operate - optional: I - point_name: DWSM.RmpTms.AO157 - response: DWSM.RmpTms.AI229 - step_number: 3 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DWSM.RvrtTms.AO158 - response: DWSM.RvrtTms.AI230 - step_number: 4 - - description: Identify the meter used to measure the Reference Power Input. By - default this is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DWSM.EcpRef.AO159 - response: DWSM.EcpRef.AI231 - step_number: 5 - - description: Set the Active Power Smoothing Gradient - fcodes: - - direct_operate - optional: I - point_name: DWSM.WSmthGra.AO160 - response: DWSM.WSmthGra.AI233 - step_number: 6 - - description: Set the Active Power Smoothing Lower Limit - fcodes: - - direct_operate - optional: I - point_name: DWSM.WSmthLoLim.AO161 - response: DWSM.WSmthLoLim.AI234 - step_number: 7 - - description: Set the Active Power Smoothing Upper Limit - fcodes: - - direct_operate - optional: I - point_name: DWSM.WSmthHiLim.AO162 - response: DWSM.WSmthHiLim.AI235 - step_number: 8 - - description: Set the Active Power Smoothing Filter Time - fcodes: - - direct_operate - optional: I - point_name: DWSM.FilTms.AO163 - response: DWSM.FilTms.AI236 - step_number: 9 - - description: Set the Discharge Ramp Up Rate - fcodes: - - direct_operate - optional: I - point_name: DWSM.DschRpuRte.AO164 - response: DWSM.RpuRte.AI237 - step_number: 10 - - description: Set the Discharge Ramp Down Rate - fcodes: - - direct_operate - optional: I - point_name: DWSM.DschRpdRte.AO165 - response: DWSM.RpdRte.AI238 - step_number: 11 - - description: Set the Charge Ramp Up Rate - fcodes: - - direct_operate - optional: I - point_name: DWSM.ChaRpuRte.AO166 - response: DWSM.RpuChaRte.AI239 - step_number: 12 - - description: Set the Charge Ramp Down Rate - fcodes: - - direct_operate - optional: I - point_name: DWSM.ChaRpdRte.AO167 - response: DWSM.RpdChaRte.AI240 - step_number: 13 - - action: publish - description: Enable Active Power Smoothing Mode - fcodes: - - select - - operate - optional: M - point_name: DWSM.ModEna.BO24 - response: DWSM.ModEna.BI76 - step_number: 14 -- id: enable_volt-watt_curve - mode_types: - curve: - - 5 - schedule: - - 21 - name: Enable Volt-Watt Curve - ref: AN2018 Spec section 2.6.7 Table 47 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DVWC.ModPrio.AO168 - response: DVWC.ModPrio.AI242 - step_number: 1 - - description: Set time window - fcodes: - - direct_operate - optional: I - point_name: DVWC.WinTms.AO169 - response: DVWC.WinTms.AI243 - step_number: 2 - - description: Set ramp time - fcodes: - - direct_operate - optional: I - point_name: DVWC.RmpTms.AO170 - response: DVWC.RmpTms.AI244 - step_number: 3 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DVWC.RvrtTms.AO171 - response: DVWC.RvrtTms.AI245 - step_number: 4 - - description: Identify the meter used to measure the Voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DVWC.EcpRef.AO172 - response: DVWC.EcpRef.AI246 - step_number: 5 - - description: Set the reference voltage if it has not already been set - fcodes: - - direct_operate - optional: I - point_name: DECP.VRef.AO0 - response: DECP.VRef.AI29 - step_number: 6 - - description: Set the reference voltage offset if it has not already been set - fcodes: - - direct_operate - optional: I - point_name: DECP.VRefOfs.AO1 - response: DECP.VRefOfs.AI30 - step_number: 7 - - description: Identify the index of the curve being used - fcodes: - - direct_operate - func_ref: curve - optional: M - point_name: DVWC.VWCrv.AO173 - response: DVWC.VWCrv.AI248 - step_number: 8 - - action: publish - description: Enable the Volt-Watt Mode - fcodes: - - select - - operate - optional: M - point_name: DVWC.ModEna.BO25 - response: DVWC.ModEna.BI77 - step_number: 9 - - description: Read the maximum active power the outstation will attempt to generate - or absorb based on the voltage and the curve in use. - fcodes: - - read - optional: O - point_name: n/a - response: DVWC.ReqWLim.AI249 - step_number: 10 - - description: Read the actual active power produced or absorbed - fcodes: - - read - optional: O - point_name: n/a - response: MMXU.TotW.AI537 - step_number: 11 -- id: enable_frequency-watt_curve_mode - mode_types: - curve: - - 3 - schedule: - - 22 - - 23 - - 24 - name: Enable Frequency-Watt Curve Mode - ref: AN2018 Spec section 2.6.8 Table 48 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DHFW.ModPrio.AO181 - response: DHFW.ModPrio.AI257 - step_number: 1 - - description: Set time window - fcodes: - - direct_operate - optional: I - point_name: DHFW.WinTms.AO182 - response: DHFW.WinTms.AI258 - step_number: 2 - - description: Set ramp time - fcodes: - - direct_operate - optional: I - point_name: DHFW.RvrtTms.AO184 - response: DHFW.RmpTms.AI259 - step_number: 3 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DHFW.RmpTms.AO183 - response: DHFW.RvrtTms.AI260 - step_number: 4 - - description: Identify the meter used to measure the Frequency. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DHFW.EcpRef.AO185 - response: DHFW.EcpRef.AI261 - step_number: 5 - - description: Set the Nominal Grid Frequency if it is not already set - fcodes: - - direct_operate - optional: I - point_name: DECP.EcpNomHz.AO2 - response: DECP.EcpNomHz.AI31 - step_number: 6 - - description: Set the starting delays - fcodes: - - direct_operate - optional: I - point_name: DHFW.ActStrDlTmms.AO189 - response: DHFW.ActStrDlTmms.AI266 - step_number: 7 - - description: Set the stopping delays - fcodes: - - direct_operate - optional: I - point_name: DHFW.ActStopDlTmms.AO190 - response: DHFW.ActStopDlTmms.AI267 - step_number: 8 - - description: Set the frequency-watt curve ramp up time constant for the output - fcodes: - - direct_operate - optional: I - point_name: DHFW.OpnLoopMax.AO191 - response: DHFW.OpnLoopMax.AI268 - step_number: 9 - - description: Set the frequency-watt curve ramp down time constant for the output - fcodes: - - direct_operate - optional: I - point_name: DHFW.OpnLoopMax.AO192 - response: DHFW.OpnLoopMax.AI269 - step_number: 10 - - description: Set the frequency-watt curve discharge ramp up rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.RpuRte.AO193 - response: DHFW.RpuRte.AI270 - step_number: 11 - - description: Set the frequency-watt curve discharge ramp down rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.RpdRte.AO194 - response: DHFW.RpdRte.AI271 - step_number: 12 - - description: Set the frequency-watt curve charge ramp up rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.RpuChaRte.AO195 - response: DHFW.RpuChaRte.AI272 - step_number: 13 - - description: Set the frequency-watt curve charge ramp down rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.RpdChaRte.AO196 - response: DHFW.RpdChaRte.AI273 - step_number: 14 - - description: Identify the index of the main curve being used - fcodes: - - direct_operate - func_ref: curve - optional: I - point_name: DHFW.HzWCrv.AO186 - response: DHFW.HzWCrv.AI263 - step_number: 15 - - description: Identify the index of the high frequency hyteresis curve being used - fcodes: - - direct_operate - func_ref: curve - optional: I - point_name: DHFW.HysCrv.AO187 - response: DHFW.HysCrv.AI264 - step_number: 16 - - description: Identify the index of the low frequency hyteresis curve being used - fcodes: - - direct_operate - func_ref: curve - optional: I - point_name: DLFW.HysCrv.AO188 - response: DLFW.HysCrv.AI265 - step_number: 17 - - description: Set the minimum state of charge in which this mode shall operate - fcodes: - - direct_operate - optional: I - point_name: DHFW.SocUseMinPct.AO197 - response: DHFW.SocUseMinPct.AI275 - step_number: 18 - - description: Set the maximum state of charge in which this mode shall operate - fcodes: - - direct_operate - optional: I - point_name: DHFW.SocUseMaxPct.AO198 - response: DHFW.SocUseMaxPct.AI276 - step_number: 19 - - description: Choose whether to use hysteresis - fcodes: - - direct_operate - optional: I - point_name: DLFW.HysEna.BO36 - response: DLFW.HysEna.BI88 - step_number: 20 - - description: Choose whether to snapshot power - fcodes: - - direct_operate - optional: I - point_name: DLFW.SnptEna.BO37 - response: DLFW.SnptEna.BI89 - step_number: 21 - - action: publish - description: Enable the Frequency-Watt Curve Mode - fcodes: - - select - - operate - optional: M - point_name: DHFW.ModEna.BO26 - response: DHFW.ModEna.BI78 - step_number: 22 -- id: set_constant_var_output - name: Set Constant Var Output - ref: AN2018 Spec section 2.7.1 Table 50 - mode_types: - schedule: - - 25 - steps: - - description: Set the priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DVAR.ModPrio.AO199 - response: DVAR.ModPrio.AI277 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DVAR.WinTms.AO200 - response: DVAR.WinTms.AI278 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DVAR.RmpTms.AO201 - response: DVAR.RmpTms.AI279 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DVAR.RvrtTms.AO202 - response: DVAR.RvrtTms.AI280 - step_number: 4 - - description: Set the ramp up Time Constants - fcodes: - - direct_operate - optional: I - point_name: DVAR.OpnLoopMax.AO204 - response: DVAR.OpnLoopMax.AI282 - step_number: 5 - - description: Set the ramp down Time Constants - fcodes: - - direct_operate - optional: I - point_name: DVAR.OpnLoopMax.AO205 - response: DVAR.OpnLoopMax.AI283 - step_number: 6 - - description: Choose whether the time constants represent 3-Tau limits or Open - Loop Response Times - fcodes: - - direct_operate - optional: I - point_name: DSTO.OpnLoopTau.BO9 - response: DSTO.OpnLoopTau.BI28 - step_number: 7 - - description: If Open Loop Response Times are selected, choose the percentage of - final output represented by the time constant (e.g. 90% or 95%) - fcodes: - - direct_operate - optional: I - point_name: DSTO.OpnLoopPct.AO3 - response: DGEN.OpnLoopPct.AI40 - step_number: 8 - - description: Select the meaning of the Constant VArs Reactive Power Target - fcodes: - - direct_operate - optional: I - point_name: DSTO.VArRef.AO5 - response: DGEN.VArSetRef.AI42 - step_number: 9 - - description: 'If DSTO.VArRef = 1: Read percent of maximum active generation power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.WMax.AI32 - step_number: 10 - - description: 'If DSTO.VArRef = 1: Read percent of maximum active charging power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.ChaWMax.AI33 - step_number: 11 - - description: 'If DSTO.VArRef = 2: Read percent of maximum reactive injection power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.IvarMax.AI34 - step_number: 12 - - description: 'If DSTO.VArRef = 2: Read percent of maximum reactive absorption - power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.AvarMax.AI35 - step_number: 13 - - description: 'If DSTO.VArRef = 3: Read percent of system reactive injection power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.AvarAvl.AI45 - step_number: 14 - - description: 'If DSTO.VArRef = 3: Read percent of system reactive absorption power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.IvarAvl.AI46 - step_number: 15 - - description: Set the Constant VArs Reactive Power Target in percent - fcodes: - - direct_operate - optional: M - point_name: DVAR.VArTgtPct.AO203 - response: DVAR.VArTgtPct.AI281 - step_number: 16 - - action: publish - description: Enable Constant VArs mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DVAR.ModEna.BO27 - response: DVAR.ModEna.BI79 - step_number: 17 -- id: set_a_fixed_power_factor - name: Set a Fixed Power Factor - ref: AN2018 Spec section 2.7.2 Table 52 - mode_types: - schedule: - - 26 - steps: - - description: Set the priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DFPF.ModPrio.AO206 - response: DFPF.ModPrio.AI284 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DFPF.WinTms.AO207 - response: DFPF.WinTms.AI285 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DFPF.RmpTms.AO208 - response: DFPF.RmpTms.AI286 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DFPF.RvrtTms.AO209 - response: DFPF.RvrtTms.AI287 - step_number: 4 - - description: Set the requirement for whether to inject or absorb VARs (PFExt) - when discharging / generating - fcodes: - - direct_operate - optional: I - point_name: DFPF.PFGnExtSet.BO10 - response: DFPF.PFGnExtSet.BI29 - step_number: 5 - - description: Set the requirement for whether to inject or absorb VARs (PFExt) - when charging - fcodes: - - direct_operate - optional: I - point_name: DFPF.PFLodExtSet.BO11 - response: DFPF.PFLodExtSet.BI30 - step_number: 6 - - description: Set Fixed Power Factor Setpoint to use when generating / discharging - fcodes: - - direct_operate - optional: M - point_name: DFPF.PFGnTgt.AO210 - response: DFPF.PFGnTgt.AI288 - step_number: 7 - - description: Set Fixed Power Factor Setpoint to use when charging - fcodes: - - direct_operate - optional: M - point_name: DFPF.PFLodTgt.AO211 - response: DFPF.PFLodTgt.AI289 - step_number: 8 - - action: publish - description: Enable fixed power factor mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DFPF.ModEna.BO28 - response: DFPF.BI47 - step_number: 9 -- id: change_and_select_volt-var_control_mode - mode_types: - curve: - - 2 - schedule: - - 27 - name: Change and Select Volt-Var Control Mode - ref: AN2018 Spec section 2.7.3 Table 54 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DVVR.ModPrio.AO212 - response: DVVR.ModPrio.AI290 - step_number: 1 - - description: Set the enabling time window - fcodes: - - direct_operate - optional: I - point_name: DVVR.WinTms.AO213 - response: DVVR.WinTms.AI291 - step_number: 2 - - description: Set the enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DVVR.RmpTms.AO214 - response: DVVR.RmpTms.AI292 - step_number: 3 - - description: Set the enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DVVR.RvrtTms.AO215 - response: DVVR.RvrtTms.AI293 - step_number: 4 - - description: Identify the meter used to measure the voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DVVR.EcpRef.AO216 - response: DVVR.EcpRef.AI294 - step_number: 5 - - description: If using a fixed Voltage reference, set the reference voltage if - it has not already been set - fcodes: - - direct_operate - optional: O - point_name: DECP.VRef.AO0 - response: DECP.VRef.AI29 - step_number: 6 - - description: If using a fixed Voltage reference, set the reference voltage offset - if it has not already been set - fcodes: - - direct_operate - optional: O - point_name: DECP.VRefOfs.AO1 - response: DECP.VRefOfs.AI30 - step_number: 7 - - description: If autonomously adjusting the Voltage reference, set the time constant - for the lowpass filter - fcodes: - - direct_operate - optional: O - point_name: DVVR.VRefTmms.AO220 - response: DVVR.VRefTmms.AI300 - step_number: 8 - - description: If autonomously adjusting the Voltage reference, enable autonomous - adjustment - fcodes: - - direct_operate - optional: O - point_name: DVVR.VRefAdjEna.BO41 - response: DVVR.VRefAdjEna.BI93 - step_number: 9 - - description: Set the ramp up time constant for the output of the curve - fcodes: - - direct_operate - optional: I - point_name: DVVR.OpnLoopMax.AO218 - response: DVVR.OpnLoopMax.AI298 - step_number: 10 - - description: Set the ramp down time constant for the output of the curve - fcodes: - - direct_operate - optional: I - point_name: DVVR.OpnLoopMax.AO219 - response: DVVR.OpnLoopMax.AI299 - step_number: 11 - - description: Identify the index of the curve being used - fcodes: - - direct_operate - func_ref: curve - optional: M - point_name: DVVR.VVArCrv.AO217 - response: DVVR.VVArCrv.AI297 - step_number: 12 - - action: publish - description: Enable the Volt-VAr Control Mode - fcodes: - - select - - operate - optional: M - point_name: DVVC.ModEna.BO29 - response: DVVC.BI48 - step_number: 13 - - description: Read the adjusted reference voltage, if it is not fixed - fcodes: - - read - optional: O - point_name: n/a - response: DVVR.VRefSet.AI296 - step_number: 14 - - description: Read the measured Voltage - fcodes: - - read - optional: O - point_name: n/a - response: MMXN.Vol.AI295 - step_number: 15 - - description: Read the attempted VArs - fcodes: - - read - optional: O - point_name: n/a - response: DVVR.ReqVAr.AI301 - step_number: 16 - - description: Read the actual VArs (if using system meter) - fcodes: - - read - optional: O - point_name: n/a - response: MMXU.TotVAr.AI541 - step_number: 17 -- id: enable_watt-var_power_mode - mode_types: - curve: - - 4 - schedule: - - 28 - name: Enable Watt-Var Power Mode - ref: AN2018 Spec section 2.7.4 Table 55 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DWVR.ModPrio.AO221 - response: DWVR.ModPrio.AI302 - step_number: 1 - - description: Set the enabling time window - fcodes: - - direct_operate - optional: I - point_name: DWVR.WinTms.AO222 - response: DWVR.WinTms.AI303 - step_number: 2 - - description: Set the enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DWVR.RmpTms.AO223 - response: DWVR.RmpTms.AI304 - step_number: 3 - - description: Set the enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DWVR.RvrtTms.AO224 - response: DWVR.RvrtTms.AI305 - step_number: 4 - - description: Identify the meter used to measure the active power. By default - this is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DWVR.EcpRef.AO225 - response: DWVR.EcpRef.AI306 - step_number: 5 - - description: Read the maximum generation power used as the reference for percent - Watts - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.WMax.AI32 - step_number: 6 - - description: Read the maximum charging power used as the reference for percent - Watts - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.ChaWMax.AI33 - step_number: 7 - - description: Set the ramp up time constant for the output of the curve - fcodes: - - direct_operate - optional: I - point_name: DWVR.OpnLoopMax.AO227 - response: DWVR.OpnLoopMax.AI309 - step_number: 8 - - description: Set the ramp down time constant for the output of the curve - fcodes: - - direct_operate - optional: I - point_name: DWVR.OpnLoopMax.AO228 - response: DWVR.OpnLoopMax.AI310 - step_number: 9 - - description: Identify the index of the curve being used - fcodes: - - direct_operate - func_ref: curve - optional: M - point_name: DWVR.WVArCrv.AO226 - response: DWVR.WVArCrv.AI308 - step_number: 10 - - action: publish - description: Enable the Watt-VAr Power Mode - fcodes: - - select - - operate - optional: M - point_name: DWVR.ModEna.BO30 - response: DWVR.BI49 - step_number: 11 -- id: enable_power_factor_correction_mode - name: Enable Power Factor Correction Mode - ref: AN2018 Spec section 2.7.5 Table 56 - mode_types: - schedule: - - 29 - steps: - - description: Set the priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DPFC.ModPrio.AO229 - response: DPFC.ModPrio.AI312 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DPFC.WinTms.AO230 - response: DPFC.WinTms.AI313 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DPFC.RmpRte.AO231 - response: DPFC.RmpTms.AI314 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DPFC.RvrtTms.AO232 - response: DPFC.RvrtTms.AI315 - step_number: 4 - - description: Identify the meter used to measure the active power. By default - this is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DPFC.EcpRef.AO233 - response: DPFC.EcpRef.AI316 - step_number: 5 - - description: Set the requirement for whether to inject or absorb VARs (PFExt) - when discharging - fcodes: - - direct_operate - optional: I - point_name: DFPF.PFGnExtSet.BO10 - response: DFPF.PFGnExtSet.BI29 - step_number: 6 - - description: Set the requirement for whether to inject or absorb VARs (PFExt) - when charging - fcodes: - - direct_operate - optional: I - point_name: DFPF.PFLodExtSet.BO11 - response: DFPF.PFLodExtSet.BI30 - step_number: 7 - - description: Set the Average PF Target - fcodes: - - direct_operate - optional: M - point_name: DPFC.PFTrg.AO234 - response: MMXU.TotPF.AI317 - step_number: 8 - - description: Set the Lower PF Limit - fcodes: - - direct_operate - optional: M - point_name: DPFC.PFCorRef.rangeC.AO235 - response: DPFC.PFTrg.AI318 - step_number: 9 - - description: Set the Upper PF Limit - fcodes: - - direct_operate - optional: M - point_name: DPFC.PFCorRef.rangeC.AO236 - response: DPFC.PFCorRef.rangeC.AI319 - step_number: 10 - - action: publish - description: Enable Power Factor Correction Mode - fcodes: - - select - - operate - optional: M - point_name: DPFC.ModEna.BO31 - response: DPFC.ModEna.BI83 - step_number: 11 -- id: signal_a_price_change - name: Signal a Price Change - ref: AN2018 Spec section 2.8 Table 57 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DPRG.ModPrio.AO237 - response: DPRG.ModPrio.AI321 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DPRG.WinTms.AO238 - response: DPRG.WinTms.AI322 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DPRG.RmpTms.AO239 - response: DPRG.RmpTms.AI323 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DPRG.RvrtTms.AO240 - response: DPRG.RvrtTms.AI324 - step_number: 4 - - description: Set pricing mode time constant for ramping up - fcodes: - - direct_operate - optional: I - point_name: DPRG.OpnLoopMax.AO242 - response: DPRG.OpnLoopMax.AI326 - step_number: 5 - - description: Set pricing mode time constant for ramping down - fcodes: - - direct_operate - optional: I - point_name: DPRG.OpnLoopMax.AO243 - response: DPRG.OpnLoopMax.AI327 - step_number: 6 - - description: Set pricing signal and receive response - fcodes: - - select - - operate - optional: M - point_name: DPRG.PrcRef.AO241 - response: DPRG.PrcRef.AI325 - step_number: 7 - - action: publish - description: Enable pricing signal mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DPRG.ModEna.BO32 - response: DPRG.ModEna.BI84 - step_number: 8 -- id: enable_schedules - name: Enable Schedules - ref: AN2018 Spec section 2.9 Table 59 - steps: - - description: Enable the Schedule by changing its state to ready - fcodes: - - select - - operate - optional: M - point_name: FSCHxx.Mod.BO42 - response: FSCH.SchdSt.3.BI108 - step_number: 1 - - description: Select shedule index - fcodes: - - direct_operate - func_ref: schedule - optional: M - point_name: FSCC.Schd.AO461 - response: FSCC.Schd.AI570 - step_number: 2 - - description: Check that outstation validates the selected schedule - fcodes: - - read - optional: O - point_name: n/a - response: FSCH.SchdSt.2.BI109 - step_number: 3 - - description: Set selected schedule repeat weekly Sunday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO43 - response: FSCHxx.SchdReuse.BI110 - step_number: 4 - - description: Set selected schedule repeat weekly Monday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO44 - response: FSCHxx.SchdReuse.BI111 - step_number: 5 - - description: Set selected schedule repeat weekly Tuesday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO45 - response: FSCHxx.SchdReuse.BI112 - step_number: 6 - - description: Set selected schedule repeat weekly Wednesday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO46 - response: FSCHxx.SchdReuse.BI113 - step_number: 7 - - description: Set selected schedule repeat weekly Thursday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO47 - response: FSCHxx.SchdReuse.BI114 - step_number: 8 - - description: Set selected schedule repeat weekly Friday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO48 - response: FSCHxx.SchdReuse.BI115 - step_number: 9 - - action: publish - description: Set selected schedule repeat weekly Saturday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO49 - response: FSCHxx.SchdReuse.BI116 - step_number: 10 - - description: Be notified when the schedule is running - fcodes: - - read - optional: O - point_name: n/a - response: FSCH1.SchdSt.AI579 - step_number: 11 -- id: curve - name: Curve - ref: AN2018 Spec Curve Definition - steps: - - description: Select which curve to edit - fcodes: - - direct_operate - optional: M - point_name: DGSMn.InCrv.AO244 - response: DGSMn.InCrv.AI328 - step_number: 1 - - description: Specify the Curve Mode Type - fcodes: - - direct_operate - optional: M - point_name: DGSMn.ModTyp.AO245 - response: DGSMn.ModTyp.AI329 - step_number: 2 - - description: Specify that the Independent (X-Value) units for the curve - fcodes: - - direct_operate - optional: M - point_name: FMARn.IndpUnits.AO247 - response: FMARn.IndpUnits.AI331 - step_number: 3 - - description: Specify the Dependent (Y-Value) units for the curve - fcodes: - - direct_operate - optional: M - point_name: FMARn.DepRef.AO248 - response: FMARn.DepRef.AI332 - step_number: 4 - - description: Set X-Value and Y-Values pairs for the curve - fcodes: - - direct_operate - optional: M - point_name: FMARn.PairArr.CrvPts.AO249 - response: FMARn.PairArr.CrvPts.AI333 - step_number: 5 - - action: publish - description: Set number of points used for the curve - fcodes: - - direct_operate - optional: M - point_name: FMARn.PairArr.NumPts.AO246 - response: FMARn.PairArr.NumPts.AI330 - step_number: 6 -- id: schedule - name: Schedule - ref: AN2018 Spec Schedule Definition - steps: - - description: Select which schedule to edit. This is the index of the schedule, - not its identity. The indexes shall be the monotonically increasing integers - 12, 13, 14 .etc. while the curve identities may be any unique number. - fcodes: - - direct_operate - optional: M - point_name: FSCC.Schd.AO461 - response: FSCC.Schd.AI570 - step_number: 1 - - description: Set the identity of the schedule to a unique number - fcodes: - - direct_operate - optional: M - point_name: FSCC.Schd.AO462 - response: FSCC.Schd.AI571 - step_number: 2 - - description: Set the priority for the schedule - fcodes: - - direct_operate - optional: M - point_name: FSCH1.SchdPrio.AO463 - response: FSCH.SchdPrio.AI572 - step_number: 3 - - description: Set the meaning of the Y-values of the schedule, i.e. the schedule - type. Refer to Table 58. - fcodes: - - direct_operate - optional: M - point_name: FSCH.SchdVal.valEq.AO464 - response: AI573 - step_number: 4 - - description: Set the date for the schedule to start - fcodes: - - direct_operate - optional: M - point_name: FSCH.StrTm.AO465 - response: FSCH.StrTm.AI574 - step_number: 5 - - description: Set the time for the schedule to start - fcodes: - - direct_operate - optional: M - point_name: FSCH.StrTm.AO466 - response: FSCH.StrTm.AI575 - step_number: 6 - - description: Set the repetition interval - fcodes: - - direct_operate - optional: M - point_name: FSCH.NxtStrTm.AO467 - response: FSCH.NxtStrTm.AI576 - step_number: 7 - - description: Set the units of the repetition interval - fcodes: - - direct_operate - optional: M - point_name: FSCH.SchdReuse.AO468 - response: FSCH.SchdReuse.AI577 - step_number: 8 - - description: Set the Time Offset (X-Values) and Schedule Value (Y-Values) for - each schedule point - fcodes: - - direct_operate - optional: M - point_name: FSCHn.SchdEntr.AO470 - response: FSCHn.SchdEntr.AI581 - step_number: 9 - - action: publish - description: Set the number of points used for the schedule. - fcodes: - - direct_operate - optional: M - point_name: FSCH.NumEntr.AO469 - response: FSCH.NumEntr.AI580 - step_number: 10 \ No newline at end of file diff --git a/services/core/DNP3Agent/dnp3/mesa_points.config b/services/core/DNP3Agent/dnp3/mesa_points.config deleted file mode 100644 index a5561e411d..0000000000 --- a/services/core/DNP3Agent/dnp3/mesa_points.config +++ /dev/null @@ -1,10270 +0,0 @@ -[ - { - "index": 0, - "description": "Reference Voltage", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "minimum": 0, - "data_object": "VRef", - "name": "DECP.VRef.AO0" - }, - { - "index": 1, - "description": "Reference Voltage Offset", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "data_object": "VRefOfs", - "name": "DECP.VRefOfs.AO1" - }, - { - "index": 2, - "description": "Nominal Grid Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DECP", - "units": "Hz", - "minimum": 0, - "data_object": "EcpNomHz", - "name": "DECP.EcpNomHz.AO2" - }, - { - "index": 3, - "description": "Open Loop Response Time Percentage. Percent of target to reach within the open loop response time. Default is 90%.", - "data_type": "AO", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DSTO", - "units": "Percent", - "minimum": 0, - "data_object": "OpnLoopPct", - "name": "DSTO.OpnLoopPct.AO3" - }, - { - "index": 4, - "description": "Power Factor Sign convention", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 2, - "ln_class": "MMXU", - "units": "None", - "minimum": 1, - "data_object": "PFSign", - "allowed_values": { - "1": "IEC active power", - "2": "IEEE lead/lag" - }, - "type": "enumerated", - "name": "MMXU.PFSign.AO4" - }, - { - "index": 5, - "description": "Reference for Reactive Power Setpoints. Selects which setpoint is active. Default is <3>.", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 3, - "ln_class": "DSTO", - "units": "None (list)", - "minimum": 0, - "data_object": "VArRef", - "allowed_values": { - "0": "Not applicable / Unknown", - "1": "Percent of Maximum Active Power (WMax)", - "2": "Percent of Maximum Reactive Power (VArMax)", - "3": "Percent of Available Reactive Power (VArAval)" - }, - "type": "enumerated", - "name": "DSTO.VArRef.AO5" - }, - { - "index": 6, - "description": "DER Start (Return to Service) Voltage High Limit. Percent of Reference Voltage.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 20000, - "ln_class": "DCTE", - "units": "Percent", - "minimum": 0, - "data_object": "VHiLim", - "name": "DCTE.VHiLim.AO6" - }, - { - "index": 7, - "description": "DER Start (Return to Service) Voltage Low Limit. Percent of Reference Voltage.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 10000, - "ln_class": "DCTE", - "units": "Percent", - "minimum": 0, - "data_object": "VLoLim", - "name": "DCTE.VLoLim.AO7" - }, - { - "index": 8, - "description": "DER Start (Return to Service) Frequency High Limit", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DCTE", - "units": "Hz", - "minimum": 0, - "data_object": "HzHiLim", - "name": "DCTE.HzHiLim.AO8" - }, - { - "index": 9, - "description": "DER Start (Return to Service) Frequency Low Limit", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DCTE", - "units": "Hz", - "minimum": 0, - "data_object": "HzLoLim", - "name": "DCTE.HzLoLim.AO9" - }, - { - "index": 10, - "description": "DER Start (Return to Service) Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RtnDlyTmms", - "name": "DCTE.RtnDlyTmms.AO10" - }, - { - "index": 11, - "description": "DER Start (Return to Service) Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AO11" - }, - { - "index": 12, - "description": "DER Start (Return to Service) Ramp Up Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RtnRmpTmms", - "name": "DCTE.RtnRmpTmms.AO12" - }, - { - "index": 13, - "description": "DER Stop (Cease to Energize) Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AO13" - }, - { - "index": 14, - "description": "DER Stop (Cease to Energize) Ramp Down Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DCTE.RmpTms.AO14" - }, - { - "index": 15, - "description": "DER Stop (Cease to Energize) Reversion Timeout Period. Time to revert from the stopped state and return to service.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DCTE.RvrtTms.AO15" - }, - { - "index": 16, - "description": "Connect/Disconnect Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AO16" - }, - { - "index": 17, - "description": "Connect/Disconnect Reversion Timeout Period. Timeout (reversion time is for the Disconnect only).", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DCTE.RvrtTms.AO17" - }, - { - "index": 18, - "description": "Requested Settings Group", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "allowed_values": { - "0": "Not Used", - "1": "Unspecified / Autonomously Determined (see BO Enable Sensed Grid Config Detection)", - "2": "Factory Configuration", - "3": "Default Configuration / Comms Lost", - "4": "Normal Grid-Connected Configuration", - "5": "Islanded Condition 1 (small, local island)", - "6": "Islanded Condition 2 (larger, area island)", - "7": "Islanded Condition 3 (largest, regional island)", - "8": "1st Alternate Grid-Connected Configuration", - "9": "2nd Alternate Grid-Connected Configuration", - "10": "3rd Alternate Grid-Connected Configuration" - }, - "type": "enumerated", - "name": "DECP1.EcpIsldSt.AO18" - }, - { - "index": 19, - "description": "Settings Group Being Edited", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "DRCC", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "name": "DRCC1.EcpIsldSt.AO19" - }, - { - "index": 20, - "description": "Freeze Counter Interval. Interval between freeze counter operations after the initial occurrence. A zero value means the free counter operation is not repeated.", - "data_type": "AO", - "minimum": 0, - "name": "AO20" - }, - { - "index": 21, - "description": "Freeze Counter Interval Units. Units of the interval between freeze counter operations.", - "data_type": "AO", - "maximum": 9, - "minimum": 0, - "units": "None (list)", - "allowed_values": { - "0": "The outstation does not repeat the action, regardless of the Interval count.", - "1": "Milliseconds - In this case the interval is always counted relative to the Start Time and is constant regardless of the clock time set at the Outstation.", - "2": "Seconds - At the same millisecond within the second that is specified in the Start Time.", - "3": "Minutes - At the same second and millisecond within the minute that is specified in the Start Time.", - "4": "Hours - At the same minute,second and B7millisecond within the hour that is specified in the Start Time.", - "5": "Days - At the same time of day that is specified in the Start Time.", - "6": "Weeks - On the same day of the week at the same time of day that is specified in the Start Time", - "7": "Months - On the same day of each month at the same time of day that is specified in the Start Time. If the Start Time falls on the 29th or greater day of the month, the outstation shall not perform the action in months that do not have such a day.", - "8": "Months on Same Day of Week from Start of Month - At the same time of the day on the same day of the week after the beginning of the month as the day specified in the Start Time. For instance, if the Start Time specifies the second Tuesday of February and the Interval Count is 2, the next action shall occur on the second Tuesday of April. In the same example, if the Interval Count is set to 12, this is the same as specifying, Every year on the second Tuesday in February. If the specified day does not occur in a given month when an action was scheduled to occur, the outstation shall not perform the action that month but shall perform it at the next valid scheduled time.", - "9": "Months on Same Day of Week from End of Month - The outstation shall interpret this setting as in <8>, but the day of the week shall be measured from the end of the month, e.g., the second-last Tuesday in February." - }, - "type": "enumerated", - "name": "AO21" - }, - { - "index": 22, - "description": "Low/High Voltage Ride-Through Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DHVT", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHVT.EcpRef.AO22" - }, - { - "index": 23, - "description": "Low/High Voltage Ride-Through High Must Trip Curve Index. Index of the Voltage Ride-through curve which specifies trip points when the voltage is high.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTOV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOV.BlkRef.AO23" - }, - { - "index": 24, - "description": "Low/High Voltage Ride-Through Low Must Trip Curve Index. Index of the Voltage Ride-through curve which specifies trip points when the voltage is low.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTUV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUV.BlkRef.AO24" - }, - { - "index": 25, - "description": "Low/High Voltage Ride-Through High Momentary Cessation Curve Index. Index of the Voltage Ride-through curve which specifies where generation/discharging must stop when the voltage is high.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTOV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOV.BlkRef.AO25" - }, - { - "index": 26, - "description": "Low/High Voltage Ride-Through Low Momentary Cessation Curve Index. Index of the Voltage Ride-through curve which specifies where generation/discharging must stop when the voltage is low.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTUV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUV.BlkRef.AO26" - }, - { - "index": 27, - "description": "Low/High Frequency Ride-Through Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DHFT", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFT.EcpRef.AO27" - }, - { - "index": 28, - "description": "Low/High Frequency Ride-Through High Must Trip Curve Index. Index of the Frequency Ride-through curve which specifies trip points when the frequency is high.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTOF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOF.BlkRef.AO28" - }, - { - "index": 29, - "description": "Low/High Frequency Ride-Through Low Must Trip Curve Index. Index of the Frequency Ride-through curve which specifies trip points when the frequency is low.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTUF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUF.BlkRef.AO29" - }, - { - "index": 30, - "description": "Low/High Frequency Ride-Through High Momentary Cessation Curve Index. Index of the Frequency Ride-through curve which specifies where generation/discharging must stop when the frequency is high.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTOF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOF.BlkRef.AO30" - }, - { - "index": 31, - "description": "Low/High Frequency Ride-Through Low Momentary Cessation Curve Index. Index of the Frequency Ride-through curve which specifies where generation/discharging must stop when the frequency is low.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTUF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUF.BlkRef.AO31" - }, - { - "index": 32, - "description": "Dynamic Reactive Current Support Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "minimum": 0, - "data_object": "ModPrio", - "name": "DRGS.ModPrio.AO32" - }, - { - "index": 33, - "description": "Dynamic Reactive Current Support Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DRGS.WinTms.AO33" - }, - { - "index": 34, - "description": "Dynamic Reactive Current Support Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DRGS.RmpTms.AO34" - }, - { - "index": 35, - "description": "Dynamic Reactive Current Support Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DRGS.RvrtTms.AO35" - }, - { - "index": 36, - "description": "Dynamic Reactive Current Support Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DRGS", - "minimum": 0, - "data_object": "EcpRef", - "name": "DRGS.EcpRef.AO36" - }, - { - "index": 37, - "description": "Dynamic Reactive Current Support - Gradient Mode.", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 2, - "ln_class": "DRGS", - "units": "None (list)", - "minimum": 0, - "data_object": "ArGraMod", - "allowed_values": { - "0": "Undefined", - "1": "Gradients reach 0 at the moving average Voltage", - "2": "Gradients reach 0 at the Voltage deadbands" - }, - "type": "enumerated", - "name": "DRGS.ArGraMod.AO37" - }, - { - "index": 38, - "description": "Dynamic Reactive Current Support Deadband Minimum Voltage. Percentage of the nominal voltage (DRCT.Vref), measured from the moving average voltage (RDGS.VAv). Support is no longer applied when the voltage stays above this value for the length of the Hold Time.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 0, - "ln_class": "DRGS", - "units": "Percent", - "minimum": -10000, - "data_object": "DbVMin", - "name": "DRGS.DbVMin.AO38" - }, - { - "index": 39, - "description": "Dynamic Reactive Current Support Deadband Maximum Voltage. Percentage of the nominal voltage (DRCT.Vref), measured from the moving average voltage (RDGS.VAv). Support is no longer applied when the voltage stays below this value for the length of the Hold Time.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 10000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "DbVMax", - "name": "DRGS.DbVMax.AO39" - }, - { - "index": 40, - "description": "Dynamic Reactive Current Support Gradient for Sags. Percentage of the rated current (DRAT.ARtg) to apply capacitively per percentage of the negative deviation from the moving average voltage (RDGS.Av). It is a ratio of percent and is therefore unitless.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DRGS", - "units": "Percent current per percent voltage deviation", - "data_object": "ArGraSag", - "name": "DRGS.ArGraSag.AO40" - }, - { - "index": 41, - "description": "Dynamic Reactive Current Support Gradient for Swells. Percentage of the rated current (DRAT.ARtg) to apply inductively per percentage of the positive deviation from the moving average voltage (RDGS.Av). It is a ratio of percent and is therefore unitless.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DRGS", - "units": "Percent current per percent voltage deviation", - "data_object": "ArGraSwl", - "name": "DRGS.ArGraSwl.AO41" - }, - { - "index": 42, - "description": "Dynamic Reactive Current Support Filter Time for Moving Average Voltage (RDGS.VAv). Used to determine amount of dynamic reactive current support.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DRGS.FilTms.AO42" - }, - { - "index": 43, - "description": "Dynamic Reactive Current Support Block Zone Voltage. Percentage of the nominal voltage (DRCT.VRef) below which no reactive current support shall be applied.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "BlkZnV", - "name": "DRGS.BlkZnV.AO43" - }, - { - "index": 44, - "description": "Dynamic Reactive Current Support Hysteresis Block Zone Voltage. Percentage of the nominal voltage (DRCT.VRef). After being blocked, reactive current support shall not resume until the voltage has been above BlkZnV + HysBlkZnV.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "HysBlkZnV", - "name": "DRGS.HysBlkZnV.AO44" - }, - { - "index": 45, - "description": "Dynamic Reactive Current Support Block Zone Time. Time in milliseconds from the beginning of any \"sag\" event,before which dynamic reactive current support will always continue,regardless of how low voltage may sag.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "BlkZnTmms", - "name": "DRGS.BlkZnTmms.AO45" - }, - { - "index": 46, - "description": "Dynamic Reactive Current Support Start Hold Time. When the voltage exceeds the deadband limits for this length of time (measured in milliseconds),the \"sag\" or \"swell\" event begins and the DER may begin altering active power output.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "HoldTmms", - "name": "DRGS.HoldTmms.AO46" - }, - { - "index": 47, - "description": "Dynamic Reactive Current Support End Hold Time. When the voltage returns to within the deadband limits for this length of time (measured in milliseconds),the \"sag\" or \"swell\" event is considered to be over. Reactive current support ends,frozen values are unfrozen,and a new event can begin.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "HoldTmms", - "name": "DRGS.HoldTmms.AO47" - }, - { - "index": 48, - "description": "Dynamic Volt-Watt Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWD", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVWD.ModPrio.AO48" - }, - { - "index": 49, - "description": "Dynamic Volt-Watt Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVWD.WinTms.AO49" - }, - { - "index": 50, - "description": "Dynamic Volt-Watt Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVWD.RmpTms.AO50" - }, - { - "index": 51, - "description": "Dynamic Volt-Watt Reversion Timeout period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVWD.RvrtTms.AO51" - }, - { - "index": 52, - "description": "Dynamic Volt-Watt Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DVWD", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVWD2.EcpRef.AO52" - }, - { - "index": 53, - "description": "Dynamic Volt-Watt Gradient. Signed unit-less quantity that establishes the ratio of additional Watts supplied (expressed in terms of % DRCT.WMax) to the present difference from the moving average voltage (expressed as % DRCT.VRef).", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DVWD", - "units": "Percent watts per percent voltage difference", - "data_object": "DynVWGra", - "name": "DVWD.DynVWGra.AO53" - }, - { - "index": 54, - "description": "Dynamic Volt-Watt Filter Time. The time in seconds used to calculate the moving average voltage for dynamic Volt-Watt support.", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "VWFilTms", - "name": "DVWD.VWFilTms.AO54" - }, - { - "index": 55, - "description": "Dynamic Volt-Watt Lower Deadband. Percentage of the nominal voltage (DRCT.Vref) measured below the moving average voltage. If the present voltage is above this value, no additional Watts shall be supplied.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVWD", - "units": "Percent", - "minimum": 0, - "data_object": "DbVWLo", - "name": "DVWD.DbVWLo.AO55" - }, - { - "index": 56, - "description": "Dynamic Volt-Watt Upper Deadband. Percentage of the nominal voltage (DRCT.Vref) measured above the moving average voltage. If the present voltage is below this value,no additional Watts shall be supplied.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVWD", - "units": "Percent", - "minimum": 0, - "data_object": "DbVWHi", - "name": "DVWD.DbVWHi.AO56" - }, - { - "index": 57, - "description": "Frequency-Watt Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "ModPrio", - "name": "DHFW2.ModPrio.AO57" - }, - { - "index": 58, - "description": "Frequency-Watt Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DHFW.WinTms.AO58" - }, - { - "index": 59, - "description": "Frequency-Watt Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DHFW.RmpTms.AO59" - }, - { - "index": 60, - "description": "Frequency-Watt Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DHFW.RvrtTms.AO60" - }, - { - "index": 61, - "description": "Frequency-Watt Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFW.EcpRef.AO61" - }, - { - "index": 62, - "description": "Frequency-Watt High Starting Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DHFW", - "units": "Hz", - "minimum": 0, - "data_object": "HzStr", - "name": "DHFW.HzStr.AO62" - }, - { - "index": 63, - "description": "Frequency-Watt High Stopping Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DHFW", - "units": "Hz", - "minimum": 0, - "data_object": "HzStop", - "name": "DHFW.HzStop.AO63" - }, - { - "index": 64, - "description": "Frequency-Watt High Discharging/Generating Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WGra", - "name": "DHFW.WGra.AO64" - }, - { - "index": 65, - "description": "Frequency-Watt High Charging Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WChaGra", - "name": "DHFW.WChaGra.AO65" - }, - { - "index": 66, - "description": "Frequency-Watt Low Starting Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 0, - "ln_class": "DLFW", - "units": "Hz", - "minimum": -70000, - "data_object": "HzStr", - "name": "DLFW.HzStr.AO66" - }, - { - "index": 67, - "description": "Frequency-Watt Low Stopping Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 0, - "ln_class": "DLFW", - "units": "Hz", - "minimum": -70000, - "data_object": "HzStop", - "name": "DLFW.HzStop.AO67" - }, - { - "index": 68, - "description": "Frequency-Watt Low Discharging/Generating Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WGra", - "name": "DLFW.WGra.AO68" - }, - { - "index": 69, - "description": "Frequency-Watt Low Charging Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WChaGra", - "name": "DLFW.WChaGra.AO69" - }, - { - "index": 70, - "description": "Frequency-Watt Start Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStrDlTmms", - "name": "DHFW2.ActStrDlTmms.AO70" - }, - { - "index": 71, - "description": "Frequency-Watt Stop Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStopDlTmms", - "name": "DHFW2.ActStopDlTmms.AO71" - }, - { - "index": 72, - "description": "Frequency-Watt Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DHFW.OpnLoop.AO72" - }, - { - "index": 73, - "description": "Frequency-Watt Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DHFW.OpnLoop.AO73" - }, - { - "index": 74, - "description": "Frequency-Watt Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DHFW.DschRpuRte.AO74" - }, - { - "index": 75, - "description": "Frequency-Watt Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DHFW.DschRpdRte.AO75" - }, - { - "index": 76, - "description": "Frequency-Watt Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DHFW.ChaRpuRte.AO76" - }, - { - "index": 77, - "description": "Frequency-Watt Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DHFW.ChaRpdRte.AO77" - }, - { - "index": 78, - "description": "Frequency-Watt Hi Return Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "RtnRmpRte", - "name": "DHFW.RtnRmpRte.AO78" - }, - { - "index": 79, - "description": "Frequency-Watt Low Return Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "RtnRmpRte", - "name": "DLFW.RtnRmpRte.AO79" - }, - { - "index": 80, - "description": "Frequency-Watt Minimum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMin", - "name": "DHFW.SocUseMin.AO80" - }, - { - "index": 81, - "description": "Frequency-Watt Maximum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMax", - "name": "DHFW.SocUseMax.AO81" - }, - { - "index": 82, - "description": "Active Power Limit Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWMX", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWMX.ModPrio.AO82" - }, - { - "index": 83, - "description": "Active Power Limit Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWMX.WinTms.AO83" - }, - { - "index": 84, - "description": "Active Power Limit Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWMX.RmpTms.AO84" - }, - { - "index": 85, - "description": "Active Power Limit Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWMX.RvrtTms.AO85" - }, - { - "index": 86, - "description": "Active Power Limit Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DWMX", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWMX.EcpRef.AO86" - }, - { - "index": 87, - "description": "Active Power Limit Charge Setpoint. Maximum allowed Watts as a percentage of Maximum Active Power capability.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWMX", - "units": "Percent", - "minimum": 0, - "data_object": "WLimPct", - "name": "DWMX.WLimPct.AO87" - }, - { - "index": 88, - "description": "Active Power Limit Discharge Setpoint. Maximum allowed Watts as a percentage of Maximum Active Power capability.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWMN", - "units": "Percent", - "minimum": 0, - "data_object": "WLimPct", - "name": "DWMN.WLimPct.AO88" - }, - { - "index": 89, - "description": "Charge/Discharge Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWGC.ModPrio.AO89" - }, - { - "index": 90, - "description": "Charge/Discharge Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWGC.WinTms.AO90" - }, - { - "index": 91, - "description": "Charge/Discharge Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWGC.RmpTms.AO91" - }, - { - "index": 92, - "description": "Charge/Discharge Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWGC.RvrtTms.AO92" - }, - { - "index": 93, - "description": "Charge/Discharge Active Power Target. Percentage of maxmum active power.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "GnWPctSpt", - "name": "DWGC.GnWPctSpt.AO93" - }, - { - "index": 94, - "description": "Charge/Discharge Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DWGC.OpnLoop.AO94" - }, - { - "index": 95, - "description": "Charge/Discharge Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DWGC.OpnLoop.AO95" - }, - { - "index": 96, - "description": "Charge/Discharge Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DWGC.DschRpuRte.AO96" - }, - { - "index": 97, - "description": "Charge/Discharge Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DWGC.DschRpdRte.AO97" - }, - { - "index": 98, - "description": "Charge/Discharge Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DWGC.ChaRpuRte.AO98" - }, - { - "index": 99, - "description": "Charge/Discharge Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DWGC.ChaRpdRte.AO99" - }, - { - "index": 100, - "description": "Charge/Discharge Minimum Reserve for Storage. The minimum level to which the storage system may be discharged,expressed as a percentage of the total usable storage.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "SocUseMinPct", - "name": "DWGC.SocUseMinPct.AO100" - }, - { - "index": 101, - "description": "Charge/Discharge Maximum Reserve for Storage. The maximum level to which the storage system may be discharged,expressed as a percentage of the total usable storage.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "SocUseMaxPct", - "name": "DWGC.SocUseMaxPct.AO101" - }, - { - "index": 102, - "description": "Coordinated Charge/Discharge Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "minimum": 0, - "data_object": "ModPrio", - "name": "DTCD.ModPrio.AO102" - }, - { - "index": 103, - "description": "Coordinated Charge/Discharge Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DTCD.WinTms.AO103" - }, - { - "index": 104, - "description": "Coordinated Charge/Discharge Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DTCD.RmpTms.AO104" - }, - { - "index": 105, - "description": "Coordinated Charge/Discharge Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DTCD.RvrtTms.AO105" - }, - { - "index": 106, - "description": "Coordinated Charge/Discharge Target State of Charge. Charge that the system is expected to achieve,as a percentage of the usable capacity.", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DTCD", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseTgtPct", - "name": "DTCD.SocUseTgtPct.AO106" - }, - { - "index": 107, - "description": "Coordinated Charge/Discharge Target Date. Date by which the storage system must reach the target SOC. Expressed as number of days since January 1, 1970, UTC.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Days", - "minimum": 0, - "data_object": "DateTgt", - "name": "DTCD.DateTgt.AO107" - }, - { - "index": 108, - "description": "Coordinated Charge/Discharge Target Time. Time by which storage system must reach the target SOC. Expressed as number of milliseconds since the start of Target Date.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "DateTgtTms", - "name": "DTCD.DateTgtTms.AO108" - }, - { - "index": 109, - "description": "Coordinated Charge/Discharge Energy Request", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Watt-hours", - "minimum": 0, - "data_object": "SocWReq", - "name": "DTCD.SocWReq.AO109" - }, - { - "index": 110, - "description": "Coordinated Charge/Discharge Minimum Charging Duration", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "ChaDurTms", - "name": "DTCD.ChaDurTms.AO110" - }, - { - "index": 111, - "description": "Coordinated Charge/Discharge Date of Reference", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Days", - "minimum": 0, - "data_object": "DateTgt", - "name": "DTCD.DateTgt.AO111" - }, - { - "index": 112, - "description": "Coordinated Charge/Discharge Time of Reference", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "SocDateTms", - "name": "DTCD.SocDateTms.AO112" - }, - { - "index": 113, - "description": "Coordinated Charge/Discharge Duration at Maximum Charge Rate", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "ChaDurMax", - "name": "DTCD.ChaDurMax.AO113" - }, - { - "index": 114, - "description": "Coordinated Charge/Discharge Duration at Maximum Discharge Rate", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "DschDurMax", - "name": "DTCD.DschDurMax.AO114" - }, - { - "index": 115, - "description": "Active Power Response Mode #1 Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPKP", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPKP.ModPrio.AO115" - }, - { - "index": 116, - "description": "Active Power Response Mode #1 Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPKP.WinTms.AO116" - }, - { - "index": 117, - "description": "Active Power Response Mode #1 Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPKP.RmpTms.AO117" - }, - { - "index": 118, - "description": "Active Power Response Mode #1 Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPKP.RvrtTms.AO118" - }, - { - "index": 119, - "description": "Active Power Response Mode #1 Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DPKP", - "minimum": 0, - "data_object": "EcpRef", - "name": "DPKP.EcpRef.AO119" - }, - { - "index": 120, - "description": "Active Power Response Mode #1 Power Threshold", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DPKP", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DPKP.PkPwrWLim.AO120" - }, - { - "index": 121, - "description": "Active Power Response Mode #1 Ratio", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DPKP", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DPKP.PkPwrFolPct.AO121" - }, - { - "index": 122, - "description": "Active Power Response Mode #1 Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DPKP", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DPKP.RpuRte.AO122" - }, - { - "index": 123, - "description": "Active Power Response Mode #1 Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DPKP", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DPKP.RpdRte.AO123" - }, - { - "index": 124, - "description": "Active Power Response Mode #2 Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DGFL", - "minimum": 0, - "data_object": "ModPrio", - "name": "DGFL.ModPrio.AO124" - }, - { - "index": 125, - "description": "Active Power Response Mode #2 Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DGFL.WinTms.AO125" - }, - { - "index": 126, - "description": "Active Power Response Mode #2 Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DGFL.RmpTms.AO126" - }, - { - "index": 127, - "description": "Active Power Response Mode #2 Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DGFL.RvrtTms.AO127" - }, - { - "index": 128, - "description": "Active Power Response Mode #2 Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DGFL", - "minimum": 0, - "data_object": "EcpRef", - "name": "DGFL.EcpRef.AO128" - }, - { - "index": 129, - "description": "Active Power Response Mode #2 Power Threshold", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DGFL", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DGFL.PkPwrWLim.AO129" - }, - { - "index": 130, - "description": "Active Power Response Mode #2 Ratio", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DGFL", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DGFL.PkPwrFolPct.AO130" - }, - { - "index": 131, - "description": "Active Power Response Mode #2 Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DGFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DGFL.RpuRte.AO131" - }, - { - "index": 132, - "description": "Active Power Response Mode #2 Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DGFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DGFL.RpdRte.AO132" - }, - { - "index": 133, - "description": "Active Power Response Mode #3 Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DLFL", - "minimum": 0, - "data_object": "ModPrio", - "name": "DLFL.ModPrio.AO133" - }, - { - "index": 134, - "description": "Active Power Response Mode #3 Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DLFL.WinTms.AO134" - }, - { - "index": 135, - "description": "Active Power Response Mode #3 Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DLFL.RmpTms.AO135" - }, - { - "index": 136, - "description": "Active Power Response Mode #3 Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DLFL.RvrtTms.AO136" - }, - { - "index": 137, - "description": "Active Power Response Mode #3 Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DLFL", - "minimum": 0, - "data_object": "EcpRef", - "name": "DLFL.EcpRef.AO137" - }, - { - "index": 138, - "description": "Active Power Response Mode #3 Power Threshold", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DLFL", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DLFL.PkPwrWLim.AO138" - }, - { - "index": 139, - "description": "Active Power Response Mode #3 Ratio", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DLFL", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DLFL.PkPwrFolPct.AO139" - }, - { - "index": 140, - "description": "Active Power Response Mode #3 Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DLFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DLFL.RpuRte.AO140" - }, - { - "index": 141, - "description": "Active Power Response Mode #3 Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DLFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DLFL.RpdRte.AO141" - }, - { - "index": 142, - "description": "AGC Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DAGC.ModPrio.AO142" - }, - { - "index": 143, - "description": "AGC Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DAGC.WinTms.AO143" - }, - { - "index": 144, - "description": "AGC Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DAGC.RmpTms.AO144" - }, - { - "index": 145, - "description": "AGC Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DAGC.RvrtTms.AO145" - }, - { - "index": 146, - "description": "AGC Active Power Target", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DAGC", - "units": "Watts", - "data_object": "GnWSpt", - "name": "DAGC.GnWSpt.AO146" - }, - { - "index": 147, - "description": "AGC Ramp Time Constant Up Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DAGC.OpnLoop.AO147" - }, - { - "index": 148, - "description": "AGC Ramp Time Constant Down Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DAGC.OpnLoop.AO148" - }, - { - "index": 149, - "description": "AGC Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DAGC.DschRpuRte.AO149" - }, - { - "index": 150, - "description": "AGC Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DAGC.DschRpdRte.AO150" - }, - { - "index": 151, - "description": "AGC Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DAGC.ChaRpuRte.AO151" - }, - { - "index": 152, - "description": "AGC Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DAGC.ChaRpdRte.AO152" - }, - { - "index": 153, - "description": "AGC Minimum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DAGC.SocUseMinPct.AO153" - }, - { - "index": 154, - "description": "AGC Maximum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DAGC.SocUseMaxPct.AO154" - }, - { - "index": 155, - "description": "Active Power Smoothing Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWSM.ModPrio.AO155" - }, - { - "index": 156, - "description": "Active Power Smoothing Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWSM.WinTms.AO156" - }, - { - "index": 157, - "description": "Active Power Smoothing Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWSM.RmpTms.AO157" - }, - { - "index": 158, - "description": "Active Power Smoothing Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWSM.RvrtTms.AO158" - }, - { - "index": 159, - "description": "Active Power Smoothing Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DWSM", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWSM.EcpRef.AO159" - }, - { - "index": 160, - "description": "Active Power Smoothing Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DWSM", - "units": "Watts per delta-watt", - "data_object": "WSmthGra", - "name": "DWSM.WSmthGra.AO160" - }, - { - "index": 161, - "description": "Active Power Smoothing Lower Limit. Difference in Watts from the moving average of the reference power (MMXN1.Watt) above which no smoothing shall be applied.", - "data_type": "AO", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DWSM", - "units": "Watts", - "data_object": "WSmthLoLim", - "name": "DWSM.WSmthLoLim.AO161" - }, - { - "index": 162, - "description": "Active Power Smoothing Upper Limit. Difference in Watts from the moving average of the reference power (MMXN.Watt) below which no smoothing shall be applied.", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DWSM", - "units": "Watts", - "minimum": 0, - "data_object": "WSmthHiLim", - "name": "DWSM.WSmthHiLim.AO162" - }, - { - "index": 163, - "description": "Active Power Smoothing Filter Time (Seconds). Time in seconds used to calculate the moving average of the reference load or generation (MMXN1.Watt) being smoothed.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DWSM.FilTms.AO163" - }, - { - "index": 164, - "description": "Active Power Smoothing Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DWSM.DschRpuRte.AO164" - }, - { - "index": 165, - "description": "Active Power Smoothing Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DWSM.DschRpdRte.AO165" - }, - { - "index": 166, - "description": "Active Power Smoothing Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DWSM.ChaRpuRte.AO166" - }, - { - "index": 167, - "description": "Active Power Smoothing Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DWSM.ChaRpdRte.AO167" - }, - { - "index": 168, - "description": "Volt-Watt Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVWC.ModPrio.AO168" - }, - { - "index": 169, - "description": "Volt-Watt Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVWC.WinTms.AO169" - }, - { - "index": 170, - "description": "Volt-Watt Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVWC.RmpTms.AO170" - }, - { - "index": 171, - "description": "Volt-Watt Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVWC.RvrtTms.AO171" - }, - { - "index": 172, - "description": "Volt-Watt Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVWC.EcpRef.AO172" - }, - { - "index": 173, - "description": "Volt-Watt Curve Index", - "data_type": "AO", - "common_data_class": "CSG", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "VWCrv", - "name": "DVWC.VWCrv.AO173" - }, - { - "index": 174, - "description": "Volt-Watt Filter Time (Seconds)", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DVWC.FilTms.AO174" - }, - { - "index": 175, - "description": "Volt-Watt Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DVWC.OpnLoop.AO175" - }, - { - "index": 176, - "description": "Volt-Watt Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DVWC.OpnLoop.AO176" - }, - { - "index": 177, - "description": "Volt-Watt Discharging Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DVWC.DschRpuRte.AO177" - }, - { - "index": 178, - "description": "Volt-Watt Discharging Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DVWC.DschRpdRte.AO178" - }, - { - "index": 179, - "description": "Volt-Watt Charging Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DVWC.ChaRpuRte.AO179" - }, - { - "index": 180, - "description": "Volt-Watt Charging Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DVWC.ChaRpdRte.AO180" - }, - { - "index": 181, - "description": "Frequency-Watt Curve Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "ModPrio", - "name": "DHFW.ModPrio.AO181" - }, - { - "index": 182, - "description": "Frequency-Watt Curve Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DHFW.WinTms.AO182" - }, - { - "index": 183, - "description": "Frequency-Watt Curve Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DHFW.RmpTms.AO183" - }, - { - "index": 184, - "description": "Frequency-Watt Curve Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DHFW.RvrtTms.AO184" - }, - { - "index": 185, - "description": "Frequency-Watt Curve Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFW.EcpRef.AO185" - }, - { - "index": 186, - "description": "Frequency-Watt Curve - Curve Index", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "HzWCrv", - "name": "DHFW.HzWCrv.AO186" - }, - { - "index": 187, - "description": "Frequency-Watt Curve - High Frequency Hysteresis Curve Index", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "HysCrv", - "name": "DHFW.HysCrv.AO187" - }, - { - "index": 188, - "description": "Frequency-Watt Curve - Low Frequency Hysteresis Curve Index", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DLFW", - "minimum": 0, - "data_object": "HysCrv", - "name": "DLFW.HysCrv.AO188" - }, - { - "index": 189, - "description": "Frequency-Watt Curve Start Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStrDlTmms", - "name": "DHFW.ActStrDlTmms.AO189" - }, - { - "index": 190, - "description": "Frequency-Watt Curve Stop Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStopDlTmms", - "name": "DHFW.ActStopDlTmms.AO190" - }, - { - "index": 191, - "description": "Frequency-Watt Curve Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AO191" - }, - { - "index": 192, - "description": "Frequency-Watt Curve Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AO192" - }, - { - "index": 193, - "description": "Frequency-Watt Curve Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DHFW.RpuRte.AO193" - }, - { - "index": 194, - "description": "Frequency-Watt Curve Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DHFW.RpdRte.AO194" - }, - { - "index": 195, - "description": "Frequency-Watt Curve Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DHFW.RpuChaRte.AO195" - }, - { - "index": 196, - "description": "Frequency-Watt Curve Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DHFW.RpdChaRte.AO196" - }, - { - "index": 197, - "description": "Frequency-Watt Curve Minimum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DHFW.SocUseMinPct.AO197" - }, - { - "index": 198, - "description": "Frequency-Watt Curve Maximum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DHFW.SocUseMaxPct.AO198" - }, - { - "index": 199, - "description": "Constant VArs Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVAR.ModPrio.AO199" - }, - { - "index": 200, - "description": "Constant VArs Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVAR.WinTms.AO200" - }, - { - "index": 201, - "description": "Constant VArs Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVAR.RmpTms.AO201" - }, - { - "index": 202, - "description": "Constant VArs Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVAR.RvrtTms.AO202" - }, - { - "index": 203, - "description": "Constant VArs Reactive Power Target. Percentage of maxmum reactive power.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVAR", - "units": "Percent", - "minimum": -1000, - "data_object": "VArTgtPct", - "name": "DVAR.VArTgtPct.AO203" - }, - { - "index": 204, - "description": "Constant VArs Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVAR.OpnLoopMax.AO204" - }, - { - "index": 205, - "description": "Constant VArs Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVAR.OpnLoopMax.AO205" - }, - { - "index": 206, - "description": "Fixed Power Factor Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DFPF", - "minimum": 0, - "data_object": "ModPrio", - "name": "DFPF.ModPrio.AO206" - }, - { - "index": 207, - "description": "Fixed Power Factor Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DFPF.WinTms.AO207" - }, - { - "index": 208, - "description": "Fixed Power Factor Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DFPF.RmpTms.AO208" - }, - { - "index": 209, - "description": "Fixed Power Factor Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DFPF.RvrtTms.AO209" - }, - { - "index": 210, - "description": "Fixed Power Factor Setpoint - Generation/Discharging", - "data_type": "AO", - "common_data_class": "APC", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DFPF", - "units": "None", - "minimum": 0, - "data_object": "PFGnTgt", - "name": "DFPF.PFGnTgt.AO210" - }, - { - "index": 211, - "description": "Fixed Power Factor Setpoint - Charging", - "data_type": "AO", - "common_data_class": "APC", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DFPF", - "units": "None", - "minimum": 0, - "data_object": "PFLodTgt", - "name": "DFPF.PFLodTgt.AO211" - }, - { - "index": 212, - "description": "Volt-VAr Control Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVVR.ModPrio.AO212" - }, - { - "index": 213, - "description": "Volt-VAr Control Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVVR.WinTms.AO213" - }, - { - "index": 214, - "description": "Volt-VAr Control Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVVR.RmpTms.AO214" - }, - { - "index": 215, - "description": "Volt-VAr Control Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVVR.RvrtTms.AO215" - }, - { - "index": 216, - "description": "Volt-VAr Control Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVVR.EcpRef.AO216" - }, - { - "index": 217, - "description": "Volt-VAr Curve Index", - "data_type": "AO", - "common_data_class": "CSG", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "VVArCrv", - "name": "DVVR.VVArCrv.AO217" - }, - { - "index": 218, - "description": "Volt-VAr Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVVR.OpnLoopMax.AO218" - }, - { - "index": 219, - "description": "Volt-VAr Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVVR.OpnLoopMax.AO219" - }, - { - "index": 220, - "description": "Volt-VAr Autonomous Voltage Reference Adjustment Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "VRefTmms", - "name": "DVVR.VRefTmms.AO220" - }, - { - "index": 221, - "description": "Watt-VAr Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWVR.ModPrio.AO221" - }, - { - "index": 222, - "description": "Watt-VAr Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWVR.WinTms.AO222" - }, - { - "index": 223, - "description": "Watt-VAr Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWVR.RmpTms.AO223" - }, - { - "index": 224, - "description": "Watt-VAr Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWVR.RvrtTms.AO224" - }, - { - "index": 225, - "description": "Watt-VAr Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWVR.EcpRef.AO225" - }, - { - "index": 226, - "description": "Watt-VAr Curve Index", - "data_type": "AO", - "common_data_class": "CSG", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "WVArCrv", - "name": "DWVR.WVArCrv.AO226" - }, - { - "index": 227, - "description": "Watt-VAr Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWVR.OpnLoopMax.AO227" - }, - { - "index": 228, - "description": "Watt-VAr Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWVR.OpnLoopMax.AO228" - }, - { - "index": 229, - "description": "Power Factor Correction Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPFC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPFC.ModPrio.AO229" - }, - { - "index": 230, - "description": "Power Factor Correction Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPFC.WinTms.AO230" - }, - { - "index": 231, - "description": "Power Factor Correction Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpRte", - "name": "DPFC.RmpRte.AO231" - }, - { - "index": 232, - "description": "Power Factor Correction Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPFC.RvrtTms.AO232" - }, - { - "index": 233, - "description": "Power Factor Correction Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DPFC", - "minimum": 0, - "data_object": "EcpRef", - "name": "DPFC.EcpRef.AO233" - }, - { - "index": 234, - "description": "Power Factor Correction Average PF Target", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFTrg", - "name": "DPFC.PFTrg.AO234" - }, - { - "index": 235, - "description": "Power Factor Correction Lower PF Limit", - "data_type": "AO", - "common_data_class": "Int", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFCorRef.rangeC", - "name": "DPFC.PFCorRef.rangeC.AO235" - }, - { - "index": 236, - "description": "Power Factor Correction Upper PF Limit", - "data_type": "AO", - "common_data_class": "Int", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFCorRef.rangeC", - "name": "DPFC.PFCorRef.rangeC.AO236" - }, - { - "index": 237, - "description": "Pricing Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "None", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPRG.ModPrio.AO237" - }, - { - "index": 238, - "description": "Pricing Mode Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPRG.WinTms.AO238" - }, - { - "index": 239, - "description": "Pricing Mode Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPRG.RmpTms.AO239" - }, - { - "index": 240, - "description": "Pricing Mode Reversion Timeout period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPRG.RvrtTms.AO240" - }, - { - "index": 241, - "description": "Pricing Mode Setpoint. Hundredths of local currency per Kilowatt-Hr.", - "data_type": "AO", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "ln_class": "DPRG", - "units": "100ths of local currency", - "data_object": "PrcRef", - "name": "DPRG.PrcRef.AO241" - }, - { - "index": 242, - "description": "Pricing Mode Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DPRG.OpnLoopMax.AO242" - }, - { - "index": 243, - "description": "Pricing Mode Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DPRG.OpnLoopMax.AO243" - }, - { - "index": 244, - "description": "Curve Edit Selector. Writing to this point selects which of the curves can currently be viewed and changed.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DGSM", - "minimum": 1, - "data_object": "InCrv", - "name": "DGSMn.InCrv.AO244", - "type": "selector_block", - "selector_block_start": 244, - "selector_block_end": 448 - }, - { - "index": 245, - "description": "Curve Mode Type", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 20, - "ln_class": "DGSM", - "units": "None (list)", - "minimum": 0, - "data_object": "ModTyp", - "allowed_values": { - "0": "Curve disabled", - "1": "Not applicable / Unknown", - "2": "Volt-Var modes VV11-VV12", - "3": "Frequency-Watt mode FW22", - "4": "Watt-VAr mode WP42", - "5": "Voltage-Watt modes VW51-VW52", - "6": "Remain Connected", - "7": "Temperature mode", - "8": "Pricing signal mode", - "9": "HVRT Must Trip", - "10": "HVRT Momentary Cessation", - "11": "LVRT Must Trip", - "12": "LVRT Momentary Cessation", - "13": "HFRT Must Trip", - "14": "HFRT Momentary Cessation", - "15": "LFRT Must Trip", - "16": "LFRT Mandatory Operation" - }, - "type": "enumerated", - "name": "DGSMn.ModTyp.AO245" - }, - { - "index": 246, - "description": "Curve Number of Points", - "data_type": "AO", - "common_data_class": "CSG", - "maximum": 100, - "ln_class": "FMAR", - "minimum": 0, - "data_object": "PairArr.NumPts", - "name": "FMARn.PairArr.NumPts.AO246" - }, - { - "index": 247, - "description": "Independent (X-Value) Units for Curve", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "FMAR", - "units": "None (list)", - "minimum": 0, - "data_object": "IndpUnits", - "allowed_values": { - "0": "Curve disabled", - "1": "Not applicable / Unknown", - "4": "Time", - "23": "Celsius Temperature", - "29": "Voltage", - "33": "Frequency", - "38": "Watts", - "100": "Price in hundredths of local currency", - "129": "Percent Voltage", - "133": "Percent Frequency", - "138": "Percent Watts", - "233": "Frequency Deviation" - }, - "type": "enumerated", - "name": "FMARn.IndpUnits.AO247" - }, - { - "index": 248, - "description": "Dependent (Y-Value) Units for Curve", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "FMAR", - "units": "None (list)", - "minimum": 0, - "data_object": "DepRef", - "allowed_values": { - "0": "Curve disabled", - "1": "Not applicable / unknown", - "2": "VArs as percent of max VArs (VARMax)", - "3": "VArs as percent of max available VArs (VArAval)", - "4": "Vars as percent of max Watts (Wmax) not used", - "5": "Watts as percent of max Watts (Wmax)", - "6": "Watts as percent of frozen active power (DeptSnptRef)", - "7": "Power Factor in EEI notation", - "8": "Volts as a percent of the nominal voltage (VRef)", - "9": "Frequency as a percent of the nominal grid frequency (ECPNomHz)" - }, - "type": "enumerated", - "name": "FMARn.DepRef.AO248" - }, - { - "index": 249, - "description": "Curve X-Value and Y-Value pairs for curve points 1 - 100", - "data_type": "AO", - "common_data_class": "CSG", - "ln_class": "FMAR", - "units": "Varies", - "data_object": "PairArr.CrvPts", - "name": "FMARn.PairArr.CrvPts.AO249", - "type": "array", - "array_times_repeated": 100, - "array_points": [ - { - "name": "FMARn.PairArr.CrvPts.AO249.xVal" - }, - { - "name": "FMARn.PairArr.CrvPts.AO249.yVal" - } - ] - }, - { - "index": 449, - "description": "System Meter Active Power - High Threshold", - "data_type": "AO", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW.rangeC.hLim", - "name": "MMXU.TotW.rangeC.hLim.AO449" - }, - { - "index": 450, - "description": "System Meter Active Power - Low Threshold", - "data_type": "AO", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW.rangeC.lLim", - "name": "MMXU.TotW.rangeC.lLim.AO450" - }, - { - "index": 451, - "description": "System Meter Reactive Power - High Threshold", - "data_type": "AO", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "minimum": 0, - "data_object": "TotVAr.rangeC.hLim", - "name": "MMXU.TotVAr.rangeC.hLim.AO451" - }, - { - "index": 452, - "description": "System Meter at Reactive Power - Low Threshold", - "data_type": "AO", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "minimum": 0, - "data_object": "TotVAr.rangeC.lLim", - "name": "MMXU.TotVAr.rangeC.lLim.AO452" - }, - { - "index": 453, - "description": "System Meter at Power Factor - High Threshold", - "data_type": "AO", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF.rangeC.hLim", - "name": "MMXU.TotPF.rangeC.hLim.AO453" - }, - { - "index": 454, - "description": "System Meter at Power Factor - Low Threshold", - "data_type": "AO", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF.rangeC.lLim", - "name": "MMXU.TotPF.rangeC.lLim.AO454" - }, - { - "index": 455, - "description": "System Meter Phase A Volts - High Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.rangeC.hLim", - "name": "MMXU.PhV.phsA.rangeC.hLim.AO455" - }, - { - "index": 456, - "description": "System Meter Phase A Volts - Low Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.rangeC.lLim", - "name": "MMXU.PhV.phsA.rangeC.lLim.AO456" - }, - { - "index": 457, - "description": "System Meter Phase B Volts High Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.rangeC.hLim", - "name": "MMXU.PhV.phsB.rangeC.hLim.AO457" - }, - { - "index": 458, - "description": "System Meter Phase B Volts - Low Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.rangeC.lLim", - "name": "MMXU.PhV.phsB.rangeC.lLim.AO458" - }, - { - "index": 459, - "description": "System Meter Phase C Volts - High Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.rangeC.hLim", - "name": "MMXU.PhV.phsC.rangeC.hLim.AO459" - }, - { - "index": 460, - "description": "System Meter Phase C Volts - Low Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.rangeC.lLim", - "name": "MMXU.PhV.phsC.rangeC.lLim.AO460" - }, - { - "index": 461, - "description": "Schedule to Edit Selector. Selects which of the schedules can be currently viewed and changed.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "Schd", - "name": "FSCC.Schd.AO461", - "type": "selector_block", - "selector_block_start": 461, - "selector_block_end": 669 - - }, - { - "index": 462, - "description": "Selected Schedule Identity", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "Schd", - "name": "FSCC.Schd.AO462" - }, - { - "index": 463, - "description": "Selected Schedule Priority. Priority of the schedule relative to other running schedules. Lower values have higher priority over higher values.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "FSCH", - "minimum": 0, - "data_object": "SchdPrio", - "name": "FSCH1.SchdPrio.AO463" - }, - { - "index": 464, - "description": "Selected Schedule Type", - "data_type": "AO", - "common_data_class": "SCR", - "maximum": 30, - "ln_class": "FSCH", - "units": "None (list)", - "minimum": 0, - "data_object": "SchdVal.valEq", - "allowed_values": { - "1": "Low/High Voltage Ride-Through - Hi Must Trip", - "2": "Low/High Voltage Ride-Through - Low Must Trip", - "3": "Low/High Voltage Ride-Through - Hi Momentary", - "4": "Low/High Voltage Ride-Through - Lo Momentary", - "5": "Low/High Frequency Ride-Through - Hi Must Trip", - "6": "Low/High Frequency Ride-Through - Lo Must Trip", - "7": "Low/High Frequency Ride-Through - Hi Momentary", - "8": "Low/High Frequency Ride-Through - Low Momentary", - "9": "Dynamic Reactive Current Support - On/Off", - "10": "Dynamic Volt-Watt - On/Off", - "11": "Frequency-Watt - On/Off", - "12": "Active Power Limit - Charging", - "13": "Active Power Limit - Generating", - "14": "Charge/Discharge - Percent of Maximum", - "15": "Coordinated Charge/Discharge - SOC Target", - "16": "Active Power Response #1 - On/Off", - "17": "Active Power Response #2 - On/Off", - "18": "Active Power Response #3 - On/Off", - "19": "AGC - Watts", - "20": "Active Power Smoothing - On/Off", - "21": "Volt-Watt - Curve Index", - "22": "Frequency-Watt Curve - Curve Index", - "23": "Frequency-Watt Curve - High Hysteresis", - "24": "Frequency-Watt Curve - Low Hysteresis", - "25": "Constant VArs - Percent of Maximum", - "26": "Fixed Power Factor - Power Factor", - "27": "Volt-VAr - Curve Index", - "28": "Watt-VAr - Curve Index", - "29": "Power Factor Correction - On/Off", - "30": "Reserved - For pricing mode" - }, - "type": "enumerated", - "name": "FSCH.SchdVal.valEq.AO464" - }, - { - "index": 465, - "description": "Selected Schedule Start Date. Number of days since January 1, 1970, UTC.", - "data_type": "AO", - "common_data_class": "TSG", - "ln_class": "FSCH", - "units": "Days", - "minimum": 0, - "data_object": "StrTm", - "name": "FSCH.StrTm.AO465" - }, - { - "index": 466, - "description": "Selected Schedule Start Time. Milliseconds since the start of Schedule Start Date.", - "data_type": "AO", - "common_data_class": "TSG", - "maximum": 86400000, - "ln_class": "FSCH", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "StrTm", - "name": "FSCH.StrTm.AO466" - }, - { - "index": 467, - "description": "Selected Schedule Repeat Interval. Interval between actions after the initial occurrence. A zero value means the schedule is not repeated.", - "data_type": "AO", - "common_data_class": "TCS", - "ln_class": "FSCH", - "minimum": 0, - "data_object": "NxtStrTm", - "name": "FSCH.NxtStrTm.AO467" - }, - { - "index": 468, - "description": "Selected Schedule Repeat Interval Units", - "data_type": "AO", - "common_data_class": "SPG", - "maximum": 8, - "ln_class": "FSCH", - "units": "None (list)", - "minimum": 0, - "data_object": "SchdReuse", - "allowed_values": { - "0": "No Repeat", - "1": "Seconds", - "2": "Minutes", - "3": "Hours", - "4": "Days", - "5": "Weeks", - "6": "Months", - "7": "Months on Same Day of Week", - "8": "Months on Same Day of Week from End" - }, - "type": "enumerated", - "name": "FSCH.SchdReuse.AO468" - }, - { - "index": 469, - "description": "Selected Schedule Number of Points", - "data_type": "AO", - "common_data_class": "ING", - "maximum": 100, - "ln_class": "FSCH", - "minimum": 0, - "data_object": "NumEntr", - "name": "FSCH.NumEntr.AO469" - }, - { - "index": 470, - "description": "Select schedule time offset and value pairs for points 1 - 100", - "data_type": "AO", - "minimum": 0, - "name": "FSCHn.SchdEntr.AO470", - "type": "array", - "array_times_repeated": 100, - "array_points": [ - { - "name": "FSCHn.SchdEntr.AO470.time", - "description": "Number of seconds from the start of the schedule when this point becomes active", - "units": "Seconds" - }, - { - "name": "FSCHn.SchdEntr.AO470.val", - "ln_class": "FSCH", - "data_object": "SchdEntr" - } - ] - }, - { - "index": 0, - "description": "DER Profile Version Number. Always the number 1.00 for this specification.", - "data_type": "AI", - "scaling_multiplier": 0.01, - "maximum": 100, - "minimum": 100, - "event_class": 3, - "name": "AI0" - }, - { - "index": 1, - "description": "DER Profile Implementation Level. 1, 2 or 3 to indicate support for Level 1, Level 2 or Level 3 respectively.", - "data_type": "AI", - "maximum": 3, - "minimum": 1, - "event_class": 3, - "name": "AI1" - }, - { - "index": 2, - "description": "Nameplate Minimum Voltage Rating", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DGEN", - "units": "Volts", - "minimum": 0, - "data_object": "VMinRtg", - "event_class": 3, - "name": "DGEN.VMinRtg.AI2" - }, - { - "index": 3, - "description": "Nameplate Maximum Voltage Rating", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DGEN", - "units": "Volts", - "minimum": 0, - "data_object": "VMaxRtg", - "event_class": 3, - "name": "DGEN.VMaxRtg.AI3" - }, - { - "index": 4, - "description": "Nameplate Active Generation Power Rating at Unity Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Watts", - "minimum": 0, - "data_object": "WMaxRtg", - "event_class": 3, - "name": "DGEN.WMaxRtg.AI4" - }, - { - "index": 5, - "description": "Nameplate Active Charging Power Rating at Unity Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "Watts", - "data_object": "ChaWMaxRtg", - "event_class": 3, - "name": "DSTO.ChaWMaxRtg.AI5" - }, - { - "index": 6, - "description": "Nameplate Active Generation Power Rating at Specified Over-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Watts", - "minimum": 0, - "data_object": "WOvPFRtg", - "event_class": 3, - "name": "DGEN.WOvPFRtg.AI6" - }, - { - "index": 7, - "description": "Nameplate Active Charging Power Rating at Specified Over-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "Watts", - "data_object": "ChaWOvPFRtg", - "event_class": 3, - "name": "DSTO.ChaWOvPFRtg.AI7" - }, - { - "index": 8, - "description": "Specified Over-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DGEN", - "units": "None", - "minimum": -100, - "data_object": "OvPFRtg", - "event_class": 3, - "name": "DGEN.OvPFRtg.AI8" - }, - { - "index": 9, - "description": "Nameplate Active Generation Power Rating at Specified Under-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Watts", - "minimum": 0, - "data_object": "WUnPFRtg", - "event_class": 3, - "name": "DGEN.WUnPFRtg.AI9" - }, - { - "index": 10, - "description": "Nameplate Active Charging Power Rating at Specified Under-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "Watts", - "data_object": "ChaWUnPFRtg", - "event_class": 3, - "name": "DSTO.ChaWUnPFRtg.AI10" - }, - { - "index": 11, - "description": "Specified Under-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DGEN", - "units": "None", - "minimum": -100, - "data_object": "UnPFRtg", - "event_class": 3, - "name": "DGEN.UnPFRtg.AI11" - }, - { - "index": 12, - "description": "Nameplate Reactive Supply (Injection) Power Rating", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "VARs", - "minimum": 0, - "data_object": "IvarMaxRtg", - "event_class": 3, - "name": "DGEN.IvarMaxRtg.AI12" - }, - { - "index": 13, - "description": "Nameplate Reactive Absorption Power Rating", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DGEN", - "units": "VARs", - "data_object": "AvarMaxRtg", - "event_class": 3, - "name": "DGEN.AvarMaxRtg.AI13" - }, - { - "index": 14, - "description": "Nameplate Apparent Generation Power Rating", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "VAs", - "minimum": 0, - "data_object": "VAMaxRtg", - "event_class": 3, - "name": "DGEN.VAMaxRtg.AI14" - }, - { - "index": 15, - "description": "Nameplate Apparent Charging Power Rating", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "VAs", - "data_object": "ChaVAMaxRtg", - "event_class": 3, - "name": "DSTO.ChaVAMaxRtg.AI15" - }, - { - "index": 16, - "description": "Nameplate Storage Actual Energy Capacity. Nameplate (original) actual total energy capacity of the storage system expressed in Storage Capacity Units.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DSTO", - "units": "Amp-hrs or Watt-hrs", - "minimum": 0, - "data_object": "WhRtg", - "event_class": 3, - "name": "DSTO.WhRtg.AI16" - }, - { - "index": 17, - "description": "Storage Effective Actual Energy Capacity. Present actual total energy capacity of the storage system expressed in Storage Capacity Units.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DSTO", - "units": "Amp-hrs or Watt-hrs", - "minimum": 0, - "data_object": "EffWh", - "event_class": 3, - "name": "DSTO.EffWh.AI17" - }, - { - "index": 18, - "description": "Storage Usable Energy Capacity. Usable energy capacity of the storage system expressed in Storage Capacity Units.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DSTO", - "units": "Amp-hrs or Watt-hrs", - "minimum": 0, - "data_object": "UseWh", - "event_class": 3, - "name": "DSTO.UseWh.AI18" - }, - { - "index": 19, - "description": "Nameplate AC Current Maximum Generation Rating", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DGEN", - "units": "Amps", - "minimum": 0, - "data_object": "AMaxRtg", - "event_class": 3, - "name": "DGEN.AMaxRtg.AI19" - }, - { - "index": 20, - "description": "Nameplate AC Current Maximum Charging Rating", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 0, - "ln_class": "DSTO", - "units": "Amps", - "data_object": "ChaAMaxRtg", - "event_class": 3, - "name": "DSTO.ChaAMaxRtg.AI20" - }, - { - "index": 21, - "description": "Remaining Reactive Susceptance", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Siemens", - "data_object": "SuscRtg", - "event_class": 3, - "name": "DGEN.SuscRtg.AI21" - }, - { - "index": 22, - "description": "IEEE 1547 Normal Operating Performance Category.", - "data_type": "AI", - "maximum": 2, - "minimum": 0, - "units": "None (list)", - "event_class": 3, - "allowed_values": { - "0": "unknown", - "1": "Category A", - "2": "Category B" - }, - "type": "enumerated", - "name": "AI22" - }, - { - "index": 23, - "description": "IEEE 1547 Abnormal Operating Performance Category.", - "data_type": "AI", - "maximum": 3, - "minimum": 0, - "units": "None (list)", - "event_class": 3, - "allowed_values": { - "0": "unknown", - "1": "Category I", - "2": "Category II", - "3": "Category III" - }, - "type": "enumerated", - "name": "AI23" - }, - { - "index": 24, - "description": "Number of System Schedules", - "data_type": "AI", - "minimum": 0, - "units": "None", - "event_class": 3, - "name": "AI24" - }, - { - "index": 25, - "description": "Number of Meters", - "data_type": "AI", - "minimum": 0, - "units": "None", - "event_class": 3, - "name": "AI25" - }, - { - "index": 26, - "description": "Number of Inverters", - "data_type": "AI", - "minimum": 0, - "units": "None", - "event_class": 3, - "name": "AI26" - }, - { - "index": 27, - "description": "Number of Batteries", - "data_type": "AI", - "minimum": 0, - "units": "None", - "event_class": 3, - "name": "AI27" - }, - { - "index": 28, - "description": "Number of DER units connected to controller", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DSTO", - "units": "None", - "minimum": 0, - "data_object": "InclDER", - "event_class": 3, - "name": "DSTO.InclDER.AI28" - }, - { - "index": 29, - "description": "Reference Voltage", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "minimum": 0, - "data_object": "VRef", - "name": "DECP.VRef.AI29" - }, - { - "index": 30, - "description": "Reference Voltage Offset", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "data_object": "VRefOfs", - "name": "DECP.VRefOfs.AI30" - }, - { - "index": 31, - "description": "Nominal Grid Frequency", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DECP", - "units": "Hz", - "minimum": 0, - "data_object": "EcpNomHz", - "name": "DECP.EcpNomHz.AI31" - }, - { - "index": 32, - "description": "Maximum Active Generation Power", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Watts", - "minimum": 0, - "data_object": "WMax", - "name": "DGEN.WMax.AI32" - }, - { - "index": 33, - "description": "Maximum Active Charging Power", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "Watts", - "data_object": "ChaWMax", - "name": "DSTO.ChaWMax.AI33" - }, - { - "index": 34, - "description": "Maximum Reactive Injection Power", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "VARs", - "minimum": 0, - "data_object": "IvarMax", - "name": "DGEN.IvarMax.AI34" - }, - { - "index": 35, - "description": "Maximum Reactive Absorption Power", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DGEN", - "units": "VARs", - "data_object": "AvarMax", - "name": "DGEN.AvarMax.AI35" - }, - { - "index": 36, - "description": "Maximum Apparent Generation Power", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "VA", - "minimum": 0, - "data_object": "VAMax", - "name": "DGEN.VAMax.AI36" - }, - { - "index": 37, - "description": "Maximum Apparent Charging Power", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "VA", - "data_object": "ChaVAMax", - "name": "DSTO.ChaVAMax.AI37" - }, - { - "index": 38, - "description": "Minimum Voltage", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "minimum": 0, - "data_object": "VMin", - "name": "DECP.VMin.AI38" - }, - { - "index": 39, - "description": "Maximum Voltage", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "minimum": 0, - "data_object": "VMax", - "name": "DECP.VMax.AI39" - }, - { - "index": 40, - "description": "Open Loop Response Time Percentage. Percent of target to reach within the open loop response time. Default is 90%.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DGEN", - "units": "Percent", - "minimum": 0, - "data_object": "OpnLoopPct", - "name": "DGEN.OpnLoopPct.AI40" - }, - { - "index": 41, - "description": "Power Factor Sign Convention.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 2, - "ln_class": "MMXU", - "units": "None", - "minimum": 1, - "data_object": "PFSign", - "allowed_values": { - "1": "IEC active power", - "2": "IEEE lead/lag" - }, - "type": "enumerated", - "name": "MMXU.PFSign.AI41" - }, - { - "index": 42, - "description": "Reference for Reactive Power Setpoints. Selects which setpoint is active. Default is <3>.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 3, - "ln_class": "DGEN", - "units": "None (list)", - "minimum": 0, - "data_object": "VArSetRef", - "allowed_values": { - "0": "Not applicable / Unknown", - "1": "Percent of Maximum Active Power (WMax)", - "2": "Percent of Maximum Reactive Power (VArMax)", - "3": "Percent of Available Reactive Power (VArAvl)" - }, - "type": "enumerated", - "name": "DGEN.VArSetRef.AI42" - }, - { - "index": 43, - "description": "System Available Active Generation Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW", - "name": "MMXU.TotW.AI43" - }, - { - "index": 44, - "description": "System Available Active Charging Power", - "data_type": "AI", - "common_data_class": "MV", - "maximum": 0, - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotChaW", - "name": "MMXU.TotChaW.AI44" - }, - { - "index": 45, - "description": "System Available Reactive Injection Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DGEN", - "units": "VARs", - "minimum": 0, - "data_object": "AvarAvl", - "name": "DGEN.AvarAvl.AI45" - }, - { - "index": 46, - "description": "System Available Reactive Absorption Power", - "data_type": "AI", - "common_data_class": "MV", - "maximum": 0, - "ln_class": "DGEN", - "units": "VARs", - "data_object": "IvarAvl", - "name": "DGEN.IvarAvl.AI46" - }, - { - "index": 47, - "description": "System Available Actual State of Charge - Present energy in the DER as a percentage of Storage Effective Actual Capacity", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DSTO", - "units": "Percent", - "minimum": 0, - "data_object": "SocPct", - "name": "DSTO.SocPct.AI47" - }, - { - "index": 48, - "description": "System Usable State of Charge - Present usable energy in the DER as a percentage of Nameplate Storage Usable Capacity", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DSTO", - "units": "Percent", - "minimum": 0, - "data_object": "UseSocPct", - "name": "DSTO.UseSocPct.AI48" - }, - { - "index": 49, - "description": "System Start-up Status", - "data_type": "AI", - "common_data_class": "ENS", - "maximum": 99, - "ln_class": "DGEN", - "units": "None (list)", - "minimum": -1, - "data_object": "DEROpSt", - "name": "DGEN.DEROpSt.AI49" - }, - { - "index": 50, - "description": "DER Start (Return to Service) Voltage High Limit. Percent of Reference Voltage.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 20000, - "ln_class": "DCTE", - "units": "Percent", - "minimum": 0, - "data_object": "VHiLim", - "name": "DCTE.VHiLim.AI50" - }, - { - "index": 51, - "description": "DER Start (Return to Service) Voltage Low Limit. Percent of Reference Voltage.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 10000, - "ln_class": "DCTE", - "units": "Percent", - "minimum": 0, - "data_object": "VLoLim", - "name": "DCTE.VLoLim.AI51" - }, - { - "index": 52, - "description": "DER Start (Return to Service) Frequency High Limit", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DCTE", - "units": "Hz", - "minimum": 0, - "data_object": "HzHiLim", - "name": "DCTE.HzHiLim.AI52" - }, - { - "index": 53, - "description": "DER Start (Return to Service) Frequency Low Limit", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DCTE", - "units": "Hz", - "minimum": 0, - "data_object": "HzLoLim", - "name": "DCTE.HzLoLim.AI53" - }, - { - "index": 54, - "description": "DER Start (Return to Service) Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RtnDlTmms", - "name": "DCTE.RtnDlTmms.AI54" - }, - { - "index": 55, - "description": "DER Start (Return to Service) Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AI55" - }, - { - "index": 56, - "description": "DER Start (Return to Service) Ramp Up Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RtnRmpTmms", - "name": "DCTE.RtnRmpTmms.AI56" - }, - { - "index": 57, - "description": "DER Stop (Cease to Energize) Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AI57" - }, - { - "index": 58, - "description": "DER Stop (Cease to Energize) Ramp Down Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DCTE.RmpTms.AI58" - }, - { - "index": 59, - "description": "DER Stop (Cease to Energize) Reversion Timeout Period. Time to revert from the stopped state and return to service.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DCTE.RvrtTms.AI59" - }, - { - "index": 60, - "description": "Connect/Disconnect Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AI60" - }, - { - "index": 61, - "description": "Connect/Disconnect Reversion Timeout Period. Timeout (reversion time is for the Disconnect only).", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DCTE.RvrtTms.AI61" - }, - { - "index": 62, - "description": "Maximum Generation Ramp Up Rate. The maximum generation ramp up rate expressed as a percentage of the Maximum Generation Rate (WMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DCTE", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRteMax", - "name": "DCTE.RpuRteMax.AI62" - }, - { - "index": 63, - "description": "Maximum Generation Ramp Down Rate. The maximum generation ramp down rate expressed as a percentage of the Maximum Generation Rate (WMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DCTE", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRteMax", - "name": "DCTE.RpdRteMax.AI63" - }, - { - "index": 64, - "description": "Maximum Charging Ramp Up Rate. The maximum charging ramp up rate expressed as a percentage of the Maximum Charging Rate (WChaMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DCTE", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRteMax", - "name": "DCTE.RpuChaRteMax.AI64" - }, - { - "index": 65, - "description": "Maximum Charging Ramp Down Rate. The maximum charging ramp down rate expressed as a percentage of the Maximum Charnging Rate (WChaMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DCTE", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRteMax", - "name": "DCTE.RpdChaRteMax.AI65" - }, - { - "index": 66, - "description": "Requested Settings Group.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "allowed_values": { - "0": "Not Used", - "1": "Unspecified / Autonomously Determined (see BO Enable Sensed Grid Config Detection)", - "2": "Factory Configuration", - "3": "Default Configuration / Comms Lost", - "4": "Normal Grid-Connected Configuration", - "5": "Islanded Condition 1 (small, local island)", - "6": "Islanded Condition 2 (larger, area island)", - "7": "Islanded Condition 3 (largest, regional island)", - "8": "1st Alternate Grid-Connected Configuration", - "9": "2nd Alternate Grid-Connected Configuration", - "10": "3rd Alternate Grid-Connected Configuration" - }, - "type": "enumerated", - "name": "DECP.EcpIsldSt.AI66" - }, - { - "index": 67, - "description": "Settings Group Being Edited.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "allowed_values": { - "0": "Not Used", - "1": "Unspecified / Autonomously Determined (see BO Enable Sensed Grid Config Detection)", - "2": "Factory Configuration", - "3": "Default Configuration / Comms Lost", - "4": "Normal Grid-Connected Configuration", - "5": "Islanded Condition 1 (small, local island)", - "6": "Islanded Condition 2 (larger, area island)", - "7": "Islanded Condition 3 (largest, regional island)", - "8": "1st Alternate Grid-Connected Configuration", - "9": "2nd Alternate Grid-Connected Configuration", - "10": "3rd Alternate Grid-Connected Configuration" - }, - "type": "enumerated", - "name": "DECP.EcpIsldSt.AI67" - }, - { - "index": 68, - "description": "Active Settings Group. Note this may differ from the Requested Settings Group or Settings Group Being Edited analog outputs depending on whether communications has been lost and how the Enable Sensed Grid Config Detection binary output is set.", - "data_type": "AI", - "common_data_class": "ENS", - "maximum": 255, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "allowed_values": { - "0": "Not Used", - "1": "Unspecified / Autonomously Determined (see BO42)", - "2": "Factory Configuration", - "3": "Default Configuration / Comms Lost", - "4": "Normal Grid-Connected Configuration", - "5": "Islanded Condition 1 (small, local island)", - "6": "Islanded Condition 2 (larger, area island)", - "7": "Islanded Condition 3 (largest, regional island)", - "8": "1st Alternate Grid-Connected Configuration", - "9": "2nd Alternate Grid-Connected Configuration", - "10": "3rd Alternate Grid-Connected Configuration" - }, - "type": "enumerated", - "name": "DECP.EcpIsldSt.AI68" - }, - { - "index": 69, - "description": "Freeze Counter Interval. interval between freeze counter operations after the initial occurrence. A zero value means the free counter operation is not repeated.", - "data_type": "AI", - "minimum": 0, - "name": "AI69" - }, - { - "index": 70, - "description": "Freeze Counter Interval Units. Units of the interval between freeze counter operations.", - "data_type": "AI", - "maximum": 9, - "minimum": 0, - "units": "None (list)", - "allowed_values": { - "0": "The outstation does not repeat the action,regardless of the Interval count.", - "1": "Milliseconds - In this case the interval is always counted relative to the Start Time and is constant regardless of the clock time set at the Outstation.", - "2": "Seconds - At the same millisecond within the second that is specified in the Start Time.", - "3": "Minutes - At the same second and millisecond within the minute that is specified in the Start Time.", - "4": "Hours - At the same minute,second and B7millisecond within the hour that is specified in the Start Time.", - "5": "Days - At the same time of day that is specified in the Start Time.", - "6": "Weeks - On the same day of the week at the same time of day that is specified in the Start Time", - "7": "Months - On the same day of each month at the same time of day that is specified in the Start Time. If the Start Time falls on the 29th or greater day of the month,the outstation shall not perform the action in months that do not have such a day", - "8": "Months on Same Day of Week from Start of Month - At the same timeof day on the same day of the week after the beginning of the month as the day specified in the Start Time. For instance,if the Start Time specifies the second Tuesday of February and the Interval Count is 2,the next action shall occur on the second Tuesday of April. In the same example,if the Interval Count is set to 12,this is the same as specifying,Every year on the second Tuesday in February. If the specified day does not occur in a given month when an action was scheduled to occur,the outstation shall not perform the action that month but shall perform it at the next valid scheduled time.", - "9": "Months on Same Day of Week from End of Month - The outstation shall interpret this setting as in <8>,but the day of the week shall be measured from the end of the month,e.g.,the second-last Tuesday in February." - }, - "type": "enumerated", - "name": "AI70" - }, - { - "index": 71, - "description": "Low/High Voltage Ride-Through Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DHVT", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHVT.EcpRef.AI71" - }, - { - "index": 72, - "description": "Low/High Voltage Ride-Through Voltage Reference Input. Active voltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN.Vol.AI72" - }, - { - "index": 73, - "description": "Low/High Voltage Ride-Through High Must Trip Curve Index. Index of the Voltage Ride-through curve which specifies trip points when the voltage is high.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTOV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOV.BlkRef.AI73" - }, - { - "index": 74, - "description": "Low/High Voltage Ride-Through Low Must Trip Curve Index. Index of the Voltage Ride-through curve which specifies trip points when the voltage is low.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTUV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUV.BlkRef.AI74" - }, - { - "index": 75, - "description": "Low/High Voltage Ride-Through High Momentary Cessation Curve Index. Index of the Voltage Ride-through curve which specifies where generation/discharging must stop when the voltage is high.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTOV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOV.BlkRef.AI75" - }, - { - "index": 76, - "description": "Low/High Voltage Ride-Through Low Momentary Cessation Curve Index. Index of the Voltage Ride-through curve which specifies where generation/discharging must stop when the voltage is low.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTUV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUV.BlkRef.AI76" - }, - { - "index": 77, - "description": "Low/High Frequency Ride-Through Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DHFT", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFT.EcpRef.AI77" - }, - { - "index": 78, - "description": "Low/High Frequency Ride-Through Frequency Reference Input. Active frequency measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "Hz", - "name": "MMXU.Hz.AI78" - }, - { - "index": 79, - "description": "Low/High Frequency Ride-Through High Must Trip Curve Index. Index of the Frequency Ride-through curve which specifies trip points when the frequency is high.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTOF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOF.BlkRef.AI79" - }, - { - "index": 80, - "description": "Low/High Frequency Ride-Through Low Must Trip Curve Index. Index of the Frequency Ride-through curve which specifies trip points when the frequency is low.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTUF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUF.BlkRef.AI80" - }, - { - "index": 81, - "description": "Low/High Frequency Ride-Through High Momentary Cessation Curve Index. Index of the Frequency Ride-through curve which specifies where generation/discharging must stop when the frequency is high.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTOF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOF.BlkRef.AI81" - }, - { - "index": 82, - "description": "Low/High Frequency Ride-Through Low Momentary Cessation Curve Index. Index of the Frequency Ride-through curve which specifies where generation/discharging must stop when the frequency is low.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTUF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUF.BlkRef.AI82" - }, - { - "index": 83, - "description": "Dynamic Reactive Current Support Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "minimum": 0, - "data_object": "ModPrio", - "name": "DRGS.ModPrio.AI83" - }, - { - "index": 84, - "description": "Dynamic Reactive Current Support Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DRGS.WinTms.AI84" - }, - { - "index": 85, - "description": "Dynamic Reactive Current Support Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DRGS.RmpTms.AI85" - }, - { - "index": 86, - "description": "Dynamic Reactive Current Support Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DRGS.RvrtTms.AI86" - }, - { - "index": 87, - "description": "Dynamic Reactive Current Support Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DRGS", - "minimum": 0, - "data_object": "EcpRef", - "name": "DRGS.EcpRef.AI87" - }, - { - "index": 88, - "description": "Dynamic Reactive Current Support Voltage Reference Input. Votltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN2.Vol.AI88" - }, - { - "index": 89, - "description": "Dynamic Reactive Current Support Moving Average Voltage", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DRGS", - "units": "Volts", - "minimum": 0, - "data_object": "VAv", - "name": "DRGS.VAv.AI89" - }, - { - "index": 90, - "description": "Dynamic Reactive Current Support Present Delta Voltage. Difference in Volts between the present measured Voltage and the Moving Average Voltage (RDGS.Vav) as a percentage of the reference voltage (VRef).", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 10000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": -10000, - "data_object": "DelV", - "name": "DRGS.DelV.AI90" - }, - { - "index": 91, - "description": "Dynamic Reactive Current Support - Gradient Mode.", - "data_type": "AI", - "common_data_class": "SPG", - "maximum": 2, - "ln_class": "DRGS", - "units": "None (list)", - "minimum": 0, - "data_object": "ArGraMod", - "allowed_values": { - "0": "Undefined", - "1": "Gradients reach 0 at the moving average Voltage", - "2": "Gradients reach 0 at the Voltage deadbands" - }, - "type": "enumerated", - "name": "DRGS.ArGraMod.AI91" - }, - { - "index": 92, - "description": "Dynamic Reactive Current Support Deadband Minimum Voltage. Percentage of the nominal voltage (DRCT.Vref), measured from the moving average voltage (RDGS.VAv). Support is no longer applied when the voltage stays above this value for the length of the Hold Time.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 0, - "ln_class": "DRGS", - "units": "Percent", - "minimum": -10000, - "data_object": "DbVMin", - "name": "DRGS.DbVMin.AI92" - }, - { - "index": 93, - "description": "Dynamic Reactive Current Support Deadband Maximum Voltage. Percentage of the nominal voltage (DRCT.Vref), measured from the moving average voltage (RDGS.VAv). Support is no longer applied when the voltage stays below this value for the length of the Hold Time.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 10000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "DbVMax", - "name": "DRGS.DbVMax.AI93" - }, - { - "index": 94, - "description": "Dynamic Reactive Current Support Gradient for Sags. Percentage of the rated current (DRAT.ARtg) to apply capacitively per percentage of the negative deviation from the moving average voltage (RDGS.Av). It is a ratio of percent and is therefore unitless.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DRGS", - "units": "Percent current per percent voltage deviation", - "data_object": "ArGraSag", - "name": "DRGS.ArGraSag.AI94" - }, - { - "index": 95, - "description": "Dynamic Reactive Current Support Gradient for Swells. Percentage of the rated current (DRAT.ARtg) to apply inductively per percentage of the positive deviation from the moving average voltage (RDGS.Av). It is a ratio of percent and is therefore unitless.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DRGS", - "units": "Percent current per percent voltage deviation", - "data_object": "ArGraSwl", - "name": "DRGS.ArGraSwl.AI95" - }, - { - "index": 96, - "description": "Dynamic Reactive Current Support Filter Time for Moving Average Voltage (RDGS.VAv). Used to determine amount of dynamic reactive current support.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DRGS.FilTms.AI96" - }, - { - "index": 97, - "description": "Dynamic Reactive Current Support Block Zone Voltage. Percentage of the nominal voltage (DRCT.VRef) below which no reactive current support shall be applied.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "BlkZnV", - "name": "DRGS.BlkZnV.AI97" - }, - { - "index": 98, - "description": "Dynamic Reactive Current Support Hysteresis Block Zone Voltage. Percentage of the nominal voltage (DRCT.VRef). After being blocked,reactive current support shall not resume until the voltage has been above BlkZnV + HysBlkZnV.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "HysBlkZnV", - "name": "DRGS.HysBlkZnV.AI98" - }, - { - "index": 99, - "description": "Dynamic Reactive Current Support Block Zone Time. Time in milliseconds from the beginning of any \"sag\" event, before which dynamic reactive current support will always continue, regardless of how low voltage may sag.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "BlkZnTmms", - "name": "DRGS.BlkZnTmms.AI99" - }, - { - "index": 100, - "description": "Dynamic Reactive Current Support Hold Time. When the voltage returns to within the deadband limits (RDGS.dbVMin annd RDGS.dbVMax) for this length of time (measured in milliseconds), the \"sag\" or \"swell\" event is considered to be over. Reactive current support ends, frozen values are unfrozen, and a new event can begin.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "HoldTmms", - "name": "DRGS.HoldTmms.AI100" - }, - { - "index": 101, - "description": "Dynamic Reactive Current Attempted Output. Current output that the mode is attempting to achieve based on the Voltage input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DRGS", - "units": "Amps", - "minimum": 0, - "data_object": "ReqA", - "name": "DRGS.ReqA.AI101" - }, - { - "index": 102, - "description": "Dynamic Volt-Watt Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWD", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVWD.ModPrio.AI102" - }, - { - "index": 103, - "description": "Dynamic Volt-Watt Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVWD.WinTms.AI103" - }, - { - "index": 104, - "description": "Dynamic Volt-Watt Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVWD.RmpTms.AI104" - }, - { - "index": 105, - "description": "Dynamic Volt-Watt Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVWD.RvrtTms.AI105" - }, - { - "index": 106, - "description": "Dynamic Volt-Watt Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DVWD", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVWD2.EcpRef.AI106" - }, - { - "index": 107, - "description": "Dynamic Volt-Watt Voltage Reference Input. Votltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN2.Vol.AI107" - }, - { - "index": 108, - "description": "Dynamic Volt-Watt Moving Average Voltage", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DVWD", - "units": "Volts", - "minimum": 0, - "data_object": "VAv", - "name": "DVWD2.VAv.AI108" - }, - { - "index": 109, - "description": "Dynamic Volt-Watt Present Delta Voltage", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DVWD", - "units": "Volts", - "minimum": 0, - "data_object": "DelV", - "name": "DVWD2.DelV.AI109" - }, - { - "index": 110, - "description": "Dynamic Volt-Watt Gradient. Signed quantity that establishes the ratio of additional Watts supplied (expressed in terms of % DRCT.WMax) to the present difference from the moving average voltage (expressed as % DRCT.VRef).", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DVWD", - "units": "Percent watts per percent voltage difference", - "data_object": "DynVWGra", - "name": "DVWD.DynVWGra.AI110" - }, - { - "index": 111, - "description": "Dynamic Volt-Watt Filter Time. The time in seconds used to calculate the moving average voltage for dynamic Volt-Watt support.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "VWFilTms", - "name": "DVWD.VWFilTms.AI111" - }, - { - "index": 112, - "description": "Dynamic Volt-Watt Lower Deadband. Percentage of the nominal voltage (DRCT.Vref) measured below the moving average voltage. If the present voltage is above this value,no additional Watts shall be supplied.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 0, - "ln_class": "DVWD", - "units": "Percent", - "minimum": -1000, - "data_object": "DbVWLo", - "name": "DVWD.DbVWLo.AI112" - }, - { - "index": 113, - "description": "Dynamic Volt-Watt Upper Deadband. Percentage of the nominal voltage (DRCT.Vref) measured above the moving average voltage. If the present voltage is below this value, no additional Watts shall be supplied.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVWD", - "units": "Percent", - "minimum": 0, - "data_object": "DbVWHi", - "name": "DVWD.DbVWHi.AI113" - }, - { - "index": 114, - "description": "Dynamic Volt-Watt Attempted Output. Watt output that the mode is attempting to achieve based on the Voltage input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DVWD", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DVWD.ReqWSet.AI114" - }, - { - "index": 115, - "description": "Frequency-Watt Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "ModPrio", - "name": "DHFW2.ModPrio.AI115" - }, - { - "index": 116, - "description": "Frequency-Watt Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DHFW.WinTms.AI116" - }, - { - "index": 117, - "description": "Frequency-Watt Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DHFW.RmpTms.AI117" - }, - { - "index": 118, - "description": "Frequency-Watt Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DHFW.RvrtTms.AI118" - }, - { - "index": 119, - "description": "Frequency-Watt Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFW2.EcpRef.AI119" - }, - { - "index": 120, - "description": "Frequency-Watt Frequency Reference Input. Frequency measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "MMXU", - "units": "Hz", - "minimum": 0, - "data_object": "Hz", - "name": "MMXU2.Hz.AI120" - }, - { - "index": 121, - "description": "Frequency-Watt High Starting Frequency. Delta frequency between start frequency and nominal grid frequency for high frequency events.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DHFW", - "units": "Hz", - "minimum": 0, - "data_object": "HzStr", - "name": "DHFW2.HzStr.AI121" - }, - { - "index": 122, - "description": "Frequency-Watt High Stopping Frequency. Delta frequency between stop frequency and nominal grid frequency for high frequency events.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DHFW", - "units": "Hz", - "minimum": 0, - "data_object": "HzStop", - "name": "DHFW2.HzStop.AI122" - }, - { - "index": 123, - "description": "Frequency-Watt High Discharging/Generating Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WGra", - "name": "DHFW.WGra.AI123" - }, - { - "index": 124, - "description": "Frequency-Watt High Charging Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WChaGra", - "name": "DHFW.WChaGra.AI124" - }, - { - "index": 125, - "description": "Frequency-Watt Low Starting Frequency. Delta frequency between start frequency and nominal grid frequency for low frequency events.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 0, - "ln_class": "DLFW", - "units": "Hz", - "minimum": -70000, - "data_object": "HzStr", - "name": "DLFW2.HzStr.AI125" - }, - { - "index": 126, - "description": "Frequency-Watt Low Stopping Frequency. Delta frequency between stop frequency and nominal grid frequency for low frequency events.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 0, - "ln_class": "DLFW", - "units": "Hz", - "minimum": -70000, - "data_object": "HzStop", - "name": "DLFW2.HzStop.AI126" - }, - { - "index": 127, - "description": "Frequency-Watt Low Discharging/Generating Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WGra", - "name": "DLFW.WGra.AI127" - }, - { - "index": 128, - "description": "Frequency-Watt Low Charging Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WChaGra", - "name": "DLFW.WChaGra.AI128" - }, - { - "index": 129, - "description": "Frequency-Watt Start Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStrDlTmms", - "name": "DHFW2.ActStrDlTmms.AI129" - }, - { - "index": 130, - "description": "Frequency-Watt Stop Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStopDlTmms", - "name": "DHFW2.ActStopDlTmms.AI130" - }, - { - "index": 131, - "description": "Frequency-Watt Ramp Up Time Constant. Time constant or open loop response time for moving from the current active power target to a higher active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DLFW.OpnLoopMax.AI131" - }, - { - "index": 132, - "description": "Frequency-Watt Ramp Down Time Constant. Time constant or open loop response time for moving from the current active power target to a lower active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AI132" - }, - { - "index": 133, - "description": "Frequency-Watt Discharge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DHFW.RpuRte.AI133" - }, - { - "index": 134, - "description": "Frequency-Watt Discharge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRteMax", - "name": "DHFW.RpdRteMax.AI134" - }, - { - "index": 135, - "description": "Frequency-Watt Charge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DHFW.RpuChaRte.AI135" - }, - { - "index": 136, - "description": "Frequency-Watt Charge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRteMax", - "name": "DHFW.RpdChaRteMax.AI136" - }, - { - "index": 137, - "description": "Frequency-Watt High Return Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "minimum": 0, - "data_object": "RtnRmpRte", - "name": "DHFW2.RtnRmpRte.AI137" - }, - { - "index": 138, - "description": "Frequency-Watt Low Return Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "minimum": 0, - "data_object": "RtnRmpRte", - "name": "DLFW2.RtnRmpRte.AI138" - }, - { - "index": 139, - "description": "Frequency-Watt Attempted Output. Watt output that the mode is attempting to achieve based on the Frequency input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DHFW", - "units": "Watts", - "data_object": "ReqWLim", - "name": "DHFW.ReqWLim.AI139" - }, - { - "index": 140, - "description": "Frequency-Watt Minimum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DAGC.SocUseMinPct.AI140" - }, - { - "index": 141, - "description": "Frequency-Watt Maximum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DAGC.SocUseMaxPct.AI141" - }, - { - "index": 142, - "description": "Active Power Limit Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWMX", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWMX.ModPrio.AI142" - }, - { - "index": 143, - "description": "Active Power Limit Enabling Time Window. Time window (in seconds) within which to randomly execute a command. If the time window is zero, the command will be executed immediately.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWMX.WinTms.AI143" - }, - { - "index": 144, - "description": "Active Power Limit Enabling Ramp Time. Ramp time, in seconds, for moving from current operational mode settings to new operational mode settings.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWMX.RmpTms.AI144" - }, - { - "index": 145, - "description": "Active Power Limit Reversion Timeout Period. Reversion Timeout Period (in seconds), after which the device will revert to its default status, such as closing the switch to reconnect to the grid or allowing maximum watts output, in case communications are lost or mitigating messages are not received.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWMX.RvrtTms.AI145" - }, - { - "index": 146, - "description": "Active Power Limit Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DWMX", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWMX.EcpRef.AI146" - }, - { - "index": 147, - "description": "Active Power Limit Reference Input. Active Power measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "name": "MMXU.TotW.AI147" - }, - { - "index": 148, - "description": "Active Power Limit Charge Setpoint", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWMX", - "units": "Percent", - "minimum": 0, - "data_object": "WLimPct", - "name": "DWMX.WLimPct.AI148" - }, - { - "index": 149, - "description": "Active Power Limit Generation Setpoint", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWMN", - "units": "Percent", - "minimum": 0, - "data_object": "WLimPct", - "name": "DWMN.WLimPct.AI149" - }, - { - "index": 150, - "description": "Charge/Discharge Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWGC.ModPrio.AI150" - }, - { - "index": 151, - "description": "Charge/Discharge Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWGC.WinTms.AI151" - }, - { - "index": 152, - "description": "Charge/Discharge Enabling Ramp Time. Ramp time, in seconds, for moving from current operational mode settings to new operational mode settings.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWGC.RmpTms.AI152" - }, - { - "index": 153, - "description": "Charge/Discharge Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWGC.RvrtTms.AI153" - }, - { - "index": 154, - "description": "Charge/Discharge Active Power Target. Percentage of maximum active power.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "GnWPctSpt", - "name": "DWGC.GnWPctSpt.AI154" - }, - { - "index": 155, - "description": "Charge/Discharge Ramp Up Time Constant. Ramp time, in seconds, for moving from the current active power target to a higher active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWGC.OpnLoopMax.AI155" - }, - { - "index": 156, - "description": "Charge/Discharge Ramp Down Time Constant. Ramp time, in seconds, for moving from the current active power target to a lower active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWGC.OpnLoopMax.AI156" - }, - { - "index": 157, - "description": "Charge/Discharge Discharge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DWGC.RpuRte.AI157" - }, - { - "index": 158, - "description": "Charge/Discharge Discharge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRteMax", - "name": "DWGC.RpdRteMax.AI158" - }, - { - "index": 159, - "description": "Charge/Discharge Charge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DWGC.RpuChaRte.AI159" - }, - { - "index": 160, - "description": "Charge/Discharge Charge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRteMax", - "name": "DWGC.RpdChaRteMax.AI160" - }, - { - "index": 161, - "description": "Charge/Discharge Minimum Reserve for Storage. The reserve level below which the storage system may be only be discharged in emergency situations, expressed as a percentage of the usable capacity.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "SocUseMinPct", - "name": "DWGC.SocUseMinPct.AI161" - }, - { - "index": 162, - "description": "Charge/Discharge Maximum Reserve for Storage. The reserve level above which the storage system may be only be charged in emergency situations, expressed as a percentage of the usable capacity.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "SocUseMaxPct", - "name": "DWGC.SocUseMaxPct.AI162" - }, - { - "index": 163, - "description": "Coordinated Charge/Discharge Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "minimum": 0, - "data_object": "ModPrio", - "name": "DTCD.ModPrio.AI163" - }, - { - "index": 164, - "description": "Coordinated Charge/Discharge Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DTCD.WinTms.AI164" - }, - { - "index": 165, - "description": "Coordinated Charge/Discharge Enabling Ramp Time. Ramp time, in seconds, for moving from current operational mode settings to new operational mode settings", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DTCD.RmpTms.AI165" - }, - { - "index": 166, - "description": "Coordinated Charge/Discharge Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DTCD.RvrtTms.AI166" - }, - { - "index": 167, - "description": "Coordinated Charge/Discharge Target State of Charge. Charge that the system is expected to achieve, as a percentage of the usable capacity.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DTCD", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseTgtPct", - "name": "DTCD.SocUseTgtPct.AI167" - }, - { - "index": 168, - "description": "Coordinated Charge/Discharge Target Date. Date by which the storage system must reach the target SOC. Days since January 1, 1970, UTC.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Days", - "minimum": 0, - "data_object": "DateTgt", - "name": "DTCD.DateTgt.AI168" - }, - { - "index": 169, - "description": "Coordinated Charge/Discharge Target Time. Time by when the storage system must reach the target SOC. Expressed as the number of seconds since the start of Target Date.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Milliseconds", - "minimum": 0, - "data_object": "DateTgtTms", - "name": "DTCD.DateTgtTms.AI169" - }, - { - "index": 170, - "description": "Coordinated Charge/Discharge Energy Request. Amount of energy that must be transferred from the grid to the charger to move the SOC from the value at the specific time of reference to the target SOC.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Watt-hours", - "minimum": 0, - "data_object": "SocWReq", - "name": "DTCD.SocWReq.AI170" - }, - { - "index": 171, - "description": "Coordinated Charge/Discharge Minimum Charging Duration. Minimum duration to move from the SOC at the time of reference to the target SOC.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "ChaDurTms", - "name": "DTCD.ChaDurTms.AI171" - }, - { - "index": 172, - "description": "Coordinated Charge/Discharge Date of Reference. Date that the SOC is measured or computed by the storage system and is the basis for the Energy Request, Minimum Charging Duration, and other parameters.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Days", - "minimum": 0, - "data_object": "DateTgt", - "name": "DTCD.DateTgt.AI172" - }, - { - "index": 173, - "description": "Coordinated Charge/Discharge Time of Reference. Time that the SOC is measured or computed by the storage system and is the basis for the Energy Request, Minimum Charging Duration, and other parameters.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Milliseconds", - "minimum": 0, - "data_object": "SocDateTms", - "name": "DTCD.SocDateTms.AI173" - }, - { - "index": 174, - "description": "Coordinated Charge/Discharge Duration at Maximum Charge Rate. Duration that energy can be stored at the Maximum Charge Rate.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "ChaDurMax", - "name": "DTCD.ChaDurMax.AI174" - }, - { - "index": 175, - "description": "Coordinated Charge/Discharge Duration Maximum Discharge Rate. Duration that energy can be delivered at the Maximum Discharge Rate.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "DschDurMax", - "name": "DTCD.DschDurMax.AI175" - }, - { - "index": 176, - "description": "Active Power Response Mode #1 Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPKP", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPKP.ModPrio.AI176" - }, - { - "index": 177, - "description": "Active Power Response Mode #1 Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPKP.WinTms.AI177" - }, - { - "index": 178, - "description": "Active Power Response Mode #1 Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPKP.RmpTms.AI178" - }, - { - "index": 179, - "description": "Active Power Response Mode #1 Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPKP.RvrtTms.AI179" - }, - { - "index": 180, - "description": "Active Power Response Mode #1 Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DPKP", - "minimum": 0, - "data_object": "EcpRef", - "name": "DPKP.EcpRef.AI180" - }, - { - "index": 181, - "description": "Active Power Response Mode #1 Reference Power Measured", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "name": "MMXU.TotW.AI181" - }, - { - "index": 182, - "description": "Active Power Response Mode #1 Power Threshold", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DPKP", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DPKP.PkPwrWLim.AI182" - }, - { - "index": 183, - "description": "Active Power Response Mode #1 Ratio", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DPKP", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DPKP.PkPwrFolPct.AI183" - }, - { - "index": 184, - "description": "Active Power Response Mode #1 Ramp Up Rate. Maximum ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DPKP", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DPKP.RpuRte.AI184" - }, - { - "index": 185, - "description": "Active Power Response Mode #1 Ramp Down Rate. Maximum ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DPKP", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DPKP.RpdRte.AI185" - }, - { - "index": 186, - "description": "Active Power Response Mode #1 Attempted Output. Watt output that the mode is attempting to achieve based on the Watts input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DPKP", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DPKP.ReqWSet.AI186" - }, - { - "index": 187, - "description": "Active Power Response Mode #2 Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DGFL", - "minimum": 0, - "data_object": "ModPrio", - "name": "DGFL.ModPrio.AI187" - }, - { - "index": 188, - "description": "Active Power Response Mode #2 Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DGFL.WinTms.AI188" - }, - { - "index": 189, - "description": "Active Power Response Mode #2 Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DGFL.RmpTms.AI189" - }, - { - "index": 190, - "description": "Active Power Response Mode #2 Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DGFL.RvrtTms.AI190" - }, - { - "index": 191, - "description": "Active Power Response Mode #2 Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DGFL", - "minimum": 0, - "data_object": "EcpRef", - "name": "DGFL.EcpRef.AI191" - }, - { - "index": 192, - "description": "Active Power Response Mode #2 Reference Power Measured", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "name": "MMXU.TotW.AI192" - }, - { - "index": 193, - "description": "Active Power Response Mode #2 Power Threshold", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGFL", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DGFL.PkPwrWLim.AI193" - }, - { - "index": 194, - "description": "Active Power Response Mode #2 Ratio", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DGFL", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DGFL.PkPwrFolPct.AI194" - }, - { - "index": 195, - "description": "Active Power Response Mode #2 Ramp Up Rate. Maximum ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DGFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DGFL.RpuRte.AI195" - }, - { - "index": 196, - "description": "Active Power Response Mode #2 Ramp Down Rate. Maximum ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DGFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DGFL.RpdRte.AI196" - }, - { - "index": 197, - "description": "Active Power Response Mode #2 Attempted Output. Watt output that the mode is attempting to achieve based on the Watts input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DGFL", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DGFL.ReqWSet.AI197" - }, - { - "index": 198, - "description": "Active Power Response Mode #3 Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFL", - "minimum": 0, - "data_object": "ModPrio", - "name": "DLFL.ModPrio.AI198" - }, - { - "index": 199, - "description": "Active Power Response Mode #3 Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DLFL.WinTms.AI199" - }, - { - "index": 200, - "description": "Active Power Response Mode #3 Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DLFL.RmpTms.AI200" - }, - { - "index": 201, - "description": "Active Power Response Mode #3 Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DLFL.RvrtTms.AI201" - }, - { - "index": 202, - "description": "Active Power Response Mode #3 Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DLFL", - "minimum": 0, - "data_object": "EcpRef", - "name": "DLFL.EcpRef.AI202" - }, - { - "index": 203, - "description": "Active Power Response Mode #3 Reference Power Measured", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "name": "MMXU.TotW.AI203" - }, - { - "index": 204, - "description": "Active Power Response Mode #3 Power Threshold", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DLFL", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DLFL.PkPwrWLim.AI204" - }, - { - "index": 205, - "description": "Active Power Response Mode #3 Ratio", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DLFL", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DLFL.PkPwrFolPct.AI205" - }, - { - "index": 206, - "description": "Active Power Response Mode #3 Ramp Up Rate. Maximum ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DLFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DLFL.RpuRte.AI206" - }, - { - "index": 207, - "description": "Active Power Response Mode #3 Ramp Down Rate. Maximum ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DLFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DLFL.RpdRte.AI207" - }, - { - "index": 208, - "description": "Active Power Response Mode #3 Attempted Output. Watt output that the mode is attempting to achieve based on the Watts input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DLFL", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DLFL.ReqWSet.AI208" - }, - { - "index": 209, - "description": "AGC Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DAGC.ModPrio.AI209" - }, - { - "index": 210, - "description": "AGC Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DAGC.WinTms.AI210" - }, - { - "index": 211, - "description": "AGC Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DAGC.RmpTms.AI211" - }, - { - "index": 212, - "description": "AGC Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DAGC.RvrtTms.AI212" - }, - { - "index": 213, - "description": "AGC Active Power Target", - "data_type": "AI", - "common_data_class": "APC", - "ln_class": "DAGC", - "units": "Watts", - "data_object": "GnWSpt", - "name": "DAGC.GnWSpt.AI213" - }, - { - "index": 214, - "description": "AGC Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpUpTms", - "name": "DAGC.RmpUpTms.AI214" - }, - { - "index": 215, - "description": "AGC Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpDnTms", - "name": "DAGC.RmpDnTms.AI215" - }, - { - "index": 216, - "description": "AGC Discharge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DAGC.RpuRte.AI216" - }, - { - "index": 217, - "description": "AGC Discharge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DAGC.RpdRte.AI217" - }, - { - "index": 218, - "description": "AGC Charge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DAGC.RpuChaRte.AI218" - }, - { - "index": 219, - "description": "AGC Charge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DAGC.RpdChaRte.AI219" - }, - { - "index": 220, - "description": "AGC Minimum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DAGC.SocUseMinPct.AI220" - }, - { - "index": 221, - "description": "AGC Maximum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DAGC.SocUseMaxPct.AI221" - }, - { - "index": 222, - "description": "AGC Maximum Watts Available", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DAGC", - "units": "Watts", - "data_object": "WMaxAvl", - "name": "DAGC.WMaxAvl.AI222" - }, - { - "index": 223, - "description": "AGC Minimum Watts Available", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DAGC", - "units": "Watts", - "data_object": "WMinAvl", - "name": "DAGC.WMinAvl.AI223" - }, - { - "index": 224, - "description": "AGC Expected State of Charge", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocExpc", - "name": "DAGC.SocExpc.AI224" - }, - { - "index": 225, - "description": "AGC Expected State of Energy", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SoeExpc", - "name": "DAGC.SoeExpc.AI225" - }, - { - "index": 226, - "description": "AGC Expected State of Charge Time Interval", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "SocExpcTms", - "name": "DAGC.SocExpcTms.AI226" - }, - { - "index": 227, - "description": "Active Power Smoothing Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWSM.ModPrio.AI227" - }, - { - "index": 228, - "description": "Active Power Smoothing Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWSM.WinTms.AI228" - }, - { - "index": 229, - "description": "Active Power Smoothing Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWSM.RmpTms.AI229" - }, - { - "index": 230, - "description": "Active Power Smoothing Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWSM.RvrtTms.AI230" - }, - { - "index": 231, - "description": "Active Power Smoothing Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DWSM", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWSM.EcpRef.AI231" - }, - { - "index": 232, - "description": "Active Power Smoothing Reference Power Input. Active Power measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "minimum": 0, - "data_object": "TotW", - "name": "MMXU.TotW.AI232" - }, - { - "index": 233, - "description": "Active Power Smoothing Gradient. Signed quantity that establishes the ratio of additional smoothing Watts provided to the present delta-watts of the reference load or generation. Delta Watts is the difference between the moving average and the present value of the reference power. Positive values of this gradient are for following load (increased reference load results in a dynamic increase in DER output), and negative values are for following generation (increased reference generation results in a dynamic decrease in DER output).", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DWSM", - "units": "Watts per Delta-watt", - "data_object": "WSmthGra", - "name": "DWSM.WSmthGra.AI233" - }, - { - "index": 234, - "description": "Active Power Smoothing Lower Limit. Difference in Watts from the moving average of the reference power above which no smoothing shall be applied.", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DWSM", - "units": "Watts", - "data_object": "WSmthLoLim", - "name": "DWSM.WSmthLoLim.AI234" - }, - { - "index": 235, - "description": "Active Power Smoothing Upper Limit. Difference in Watts from the moving average of the reference power below which no smoothing shall be applied.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DWSM", - "units": "Watts", - "minimum": 0, - "data_object": "WSmthHiLim", - "name": "DWSM.WSmthHiLim.AI235" - }, - { - "index": 236, - "description": "Active Power Smoothing Filter Time (Seconds). Time in seconds used to calculate the moving average of the reference load or generation being smoothed.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DWSM.FilTms.AI236" - }, - { - "index": 237, - "description": "Active Power Smoothing Discharge Ramp Up Rate. The maximum generation ramp up rate expressed as a percentage of the Maximum Generation Rate (WMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DWSM.RpuRte.AI237" - }, - { - "index": 238, - "description": "Active Power Smoothing Discharge Ramp Down Rate. The maximum generation ramp down rate expressed as a percentage of the Maximum Generation Rate (WMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DWSM.RpdRte.AI238" - }, - { - "index": 239, - "description": "Active Power Smoothing Charge Ramp Up Rate. The maximum charging ramp up rate expressed as a percentage of the Maximum Charging Rate (WChaMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DWSM.RpuChaRte.AI239" - }, - { - "index": 240, - "description": "Active Power Smoothing Charge Ramp Down Rate. The maximum charging ramp down rate expressed as a percentage of the Maximum Charnging Rate (WChaMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DWSM.RpdChaRte.AI240" - }, - { - "index": 241, - "description": "Active Power Smoothing Attempted Output. Watt output that the mode is attempting to achieve based on the Watt input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DWSM", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DWSM.ReqWSet.AI241" - }, - { - "index": 242, - "description": "Volt-Watt Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVWC.ModPrio.AI242" - }, - { - "index": 243, - "description": "Volt-Watt Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVWC.WinTms.AI243" - }, - { - "index": 244, - "description": "Volt-Watt Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVWC.RmpTms.AI244" - }, - { - "index": 245, - "description": "Volt-Watt Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVWC.RvrtTms.AI245" - }, - { - "index": 246, - "description": "Volt-Watt Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVWC.EcpRef.AI246" - }, - { - "index": 247, - "description": "Volt-Watt Reference Voltage Input. Voltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN.Vol.AI247" - }, - { - "index": 248, - "description": "Volt-Watt Curve Index. Index of the Volt-Watt curve that should be used by the mode.", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "VWCrv", - "name": "DVWC.VWCrv.AI248" - }, - { - "index": 249, - "description": "Volt-Watt Attempted Output. Maximum active power the outstation will attempt to generate or absorb based on the Voltage input and selected curve.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DVWC", - "units": "Watts", - "data_object": "ReqWLim", - "name": "DVWC.ReqWLim.AI249" - }, - { - "index": 250, - "description": "Volt-Watt Filter Time (Seconds)", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DVWC.FilTms.AI250" - }, - { - "index": 251, - "description": "Volt-Watt Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVWC.OpnLoopMax.AI251" - }, - { - "index": 252, - "description": "Volt-Watt Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVWC.OpnLoopMax.AI252" - }, - { - "index": 253, - "description": "Volt-Watt Discharging Ramp Up Rate. Maximum ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DVWC.RpuRte.AI253" - }, - { - "index": 254, - "description": "Volt-Watt Discharging Ramp Down Rate. Maximum ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DVWC.RpdRte.AI254" - }, - { - "index": 255, - "description": "Volt-Watt Charging Ramp Up Rate. Maximum charging ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DVWC.RpuChaRte.AI255" - }, - { - "index": 256, - "description": "Volt-Watt Charging Ramp Down Rate. Maximum charging ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DVWC.RpdChaRte.AI256" - }, - { - "index": 257, - "description": "Frequency-Watt Curve Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "ModPrio", - "name": "DHFW.ModPrio.AI257" - }, - { - "index": 258, - "description": "Frequency-Watt Curve Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DHFW.WinTms.AI258" - }, - { - "index": 259, - "description": "Frequency-Watt Curve Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DHFW.RmpTms.AI259" - }, - { - "index": 260, - "description": "Frequency-Watt Curve Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DHFW.RvrtTms.AI260" - }, - { - "index": 261, - "description": "Frequency-Watt Curve Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFW.EcpRef.AI261" - }, - { - "index": 262, - "description": "Frequency-Watt Curve Frequency Reference Input. Frequency measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "MMXU", - "units": "Hz", - "minimum": 0, - "data_object": "Hz", - "name": "MMXU.Hz.AI262" - }, - { - "index": 263, - "description": "Frequency-Watt Curve - Curve Index. Index of the Frequency-Watt curve that should be used by the mode.", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "HzWCrv", - "name": "DHFW.HzWCrv.AI263" - }, - { - "index": 264, - "description": "Frequency-Watt Curve - High Frequency Hysteresis Curve Index", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "HysCrv", - "name": "DHFW.HysCrv.AI264" - }, - { - "index": 265, - "description": "Frequency-Watt Curve - Low Frequency Hysteresis Curve Index", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DLFW", - "minimum": 0, - "data_object": "HysCrv", - "name": "DLFW.HysCrv.AI265" - }, - { - "index": 266, - "description": "Frequency-Watt Curve Start Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStrDlTmms", - "name": "DHFW.ActStrDlTmms.AI266" - }, - { - "index": 267, - "description": "Frequency-Watt Curve Stop Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStopDlTmms", - "name": "DHFW.ActStopDlTmms.AI267" - }, - { - "index": 268, - "description": "Frequency-Watt Curve Ramp Up Time Constant. Time constant or open loop response time for moving from the current active power target to a higher active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AI268" - }, - { - "index": 269, - "description": "Frequency-Watt Curve Ramp Down Time Constant. Time constant or open loop response time for moving from the current active power target to a lower active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AI269" - }, - { - "index": 270, - "description": "Frequency-Watt Curve Discharge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DHFW.RpuRte.AI270" - }, - { - "index": 271, - "description": "Frequency-Watt Curve Discharge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DHFW.RpdRte.AI271" - }, - { - "index": 272, - "description": "Frequency-Watt Curve Charge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DHFW.RpuChaRte.AI272" - }, - { - "index": 273, - "description": "Frequency-Watt Curve Charge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DHFW.RpdChaRte.AI273" - }, - { - "index": 274, - "description": "Frequency-Watt Attempted Output. Watt output that the mode is attempting to achieve based on the Frequency input and selected curve. If Snapshot of Power is not enabled,this is the maximum active power the outstation will attempt to generate or absorb.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DHFW", - "units": "Watts", - "data_object": "ReqWLim", - "name": "DHFW.ReqWLim.AI274" - }, - { - "index": 275, - "description": "Frequency-Watt Curve Minimum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DHFW.SocUseMinPct.AI275" - }, - { - "index": 276, - "description": "Frequency-Watt Curve Maximum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DHFW.SocUseMaxPct.AI276" - }, - { - "index": 277, - "description": "Constant VArs Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVAR.ModPrio.AI277" - }, - { - "index": 278, - "description": "Constant VArs Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVAR.WinTms.AI278" - }, - { - "index": 279, - "description": "Constant VArs Enabling Ramp Time. Ramp time, in seconds, for moving from current operational mode settings to new operational mode settings.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVAR.RmpTms.AI279" - }, - { - "index": 280, - "description": "Constant VArs Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVAR.RvrtTms.AI280" - }, - { - "index": 281, - "description": "Constant VArs Reactive Power Target. Percentage of maximum reactive power.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVAR", - "units": "Percent", - "minimum": -1000, - "data_object": "VArTgtPct", - "name": "DVAR.VArTgtPct.AI281" - }, - { - "index": 282, - "description": "Constant VArs Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVAR.OpnLoopMax.AI282" - }, - { - "index": 283, - "description": "Constant VArs Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVAR.OpnLoopMax.AI283" - }, - { - "index": 284, - "description": "Fixed Power Factor Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DFPF", - "minimum": 0, - "data_object": "ModPrio", - "name": "DFPF.ModPrio.AI284" - }, - { - "index": 285, - "description": "Fixed Power Factor Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DFPF.WinTms.AI285" - }, - { - "index": 286, - "description": "Fixed Power Factor Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DFPF.RmpTms.AI286" - }, - { - "index": 287, - "description": "Fixed Power Factor Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DFPF.RvrtTms.AI287" - }, - { - "index": 288, - "description": "Fixed Power Factor Setpoint - Generation/Discharging", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DFPF", - "units": "None", - "minimum": 0, - "data_object": "PFGnTgt", - "name": "DFPF.PFGnTgt.AI288" - }, - { - "index": 289, - "description": "Fixed Power Factor Setpoint - Charging", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DFPF", - "units": "None", - "minimum": 0, - "data_object": "PFLodTgt", - "name": "DFPF.PFLodTgt.AI289" - }, - { - "index": 290, - "description": "Volt-Var Control Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVVR.ModPrio.AI290" - }, - { - "index": 291, - "description": "Volt-VAr Control Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVVR.WinTms.AI291" - }, - { - "index": 292, - "description": "Volt-VAr Control Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVVR.RmpTms.AI292" - }, - { - "index": 293, - "description": "Volt-VAr Control Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVVR.RvrtTms.AI293" - }, - { - "index": 294, - "description": "Volt-VAr Control Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVVR.EcpRef.AI294" - }, - { - "index": 295, - "description": "Volt-VAr Control Voltage Input. Voltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN.Vol.AI295" - }, - { - "index": 296, - "description": "Volt-VAr Control Adjusted Voltage Reference. The Voltage used as reference for Volt-VAr control. If Autonomous Voltage Reference Adjustment is disabled,this is the same fixed value as the Reference Voltage.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DVVR", - "units": "Volts", - "minimum": 0, - "data_object": "VRefSet", - "name": "DVVR.VRefSet.AI296" - }, - { - "index": 297, - "description": "Volt-VAr Curve Index. Index of the Volt-VAr curve that should be used by the mode.", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "VVArCrv", - "name": "DVVR.VVArCrv.AI297" - }, - { - "index": 298, - "description": "Volt-VAr Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVVR.OpnLoopMax.AI298" - }, - { - "index": 299, - "description": "Volt-VAr Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVVR.OpnLoopMax.AI299" - }, - { - "index": 300, - "description": "Volt-VAr Autonomous Voltage Reference Adjustment Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "VRefTmms", - "name": "DVVR.VRefTmms.AI300" - }, - { - "index": 301, - "description": "Volt-VAr Attempted Output. VAr output that the mode is attempting to achieve based on the Voltage input and selected curve.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DVVR", - "units": "VARs", - "data_object": "ReqVAr", - "name": "DVVR.ReqVAr.AI301" - }, - { - "index": 302, - "description": "Watt-VAr Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWVR.ModPrio.AI302" - }, - { - "index": 303, - "description": "Watt-VAr Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWVR.WinTms.AI303" - }, - { - "index": 304, - "description": "Watt-VAr Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWVR.RmpTms.AI304" - }, - { - "index": 305, - "description": "Watt-VAr Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWVR.RvrtTms.AI305" - }, - { - "index": 306, - "description": "Watt-VAr Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWVR.EcpRef.AI306" - }, - { - "index": 307, - "description": "Watt-VAr Reference Power Input. Power measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW", - "name": "MMXU.TotW.AI307" - }, - { - "index": 308, - "description": "Watt-VAr Curve Index. Index of the Watt-VAr curve that should be used by the mode.", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "WVArCrv", - "name": "DWVR.WVArCrv.AI308" - }, - { - "index": 309, - "description": "Watt-VAr Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWVR.OpnLoopMax.AI309" - }, - { - "index": 310, - "description": "Watt-VAr Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWVR.OpnLoopMax.AI310" - }, - { - "index": 311, - "description": "Watt-VAr Attempted Output. VAr output that the mode is attempting to achieve based on the Watt input and selected curve.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DWVR", - "units": "VARs", - "data_object": "ReqVAr", - "name": "DWVR.ReqVAr.AI311" - }, - { - "index": 312, - "description": "Power Factor Correction Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPFC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPFC.ModPrio.AI312" - }, - { - "index": 313, - "description": "Power Factor Correction Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPFC.WinTms.AI313" - }, - { - "index": 314, - "description": "Power Factor Correction Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPFC.RmpTms.AI314" - }, - { - "index": 315, - "description": "Power Factor Correction Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPFC.RvrtTms.AI315" - }, - { - "index": 316, - "description": "Power Factor Correction Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DPFC", - "minimum": 0, - "data_object": "EcpRef", - "name": "DPFC.EcpRef.AI316" - }, - { - "index": 317, - "description": "Power Factor Correction Reference Power Factor Input. Power factor measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF", - "name": "MMXU.TotPF.AI317" - }, - { - "index": 318, - "description": "Power Factor Correction Average PF Target", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFTrg", - "name": "DPFC.PFTrg.AI318" - }, - { - "index": 319, - "description": "Power Factor Correction Lower PF Limit", - "data_type": "AI", - "common_data_class": "Int", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFCorRef.rangeC", - "name": "DPFC.PFCorRef.rangeC.AI319" - }, - { - "index": 320, - "description": "Power Factor Correction Upper PF Limit", - "data_type": "AI", - "common_data_class": "Int", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFCorRef.rangeC", - "name": "DPFC.PFCorRef.rangeC.AI320" - }, - { - "index": 321, - "description": "Pricing Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPRG", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPRG.ModPrio.AI321" - }, - { - "index": 322, - "description": "Pricing Mode Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPRG.WinTms.AI322" - }, - { - "index": 323, - "description": "Pricing Mode Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPRG.RmpTms.AI323" - }, - { - "index": 324, - "description": "Pricing Mode Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPRG.RvrtTms.AI324" - }, - { - "index": 325, - "description": "Pricing Mode Setpoint: Hundredths of local currency per Kilowatt-Hr.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "ln_class": "DPRG", - "units": "100ths of local currency", - "data_object": "PrcRef", - "name": "DPRG.PrcRef.AI325" - }, - { - "index": 326, - "description": "Pricing Mode Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DPRG.OpnLoopMax.AI326" - }, - { - "index": 327, - "description": "Pricing Mode Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DPRG.OpnLoopMax.AI327" - }, - { - "index": 328, - "description": "Curve Edit Selector Index of the curve which is currently being viewed and/or changed", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DGSM", - "minimum": 1, - "data_object": "InCrv", - "name": "DGSMn.InCrv.AI328", - "type": "selector_block", - "selector_block_start": 328, - "selector_block_end": 532 - - }, - { - "index": 329, - "description": "Curve Mode Type", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 20, - "ln_class": "DGSM", - "units": "None (list)", - "minimum": 0, - "data_object": "ModTyp", - "allowed_values": { - "0": "Curve is not defined", - "1": "None, dimensionless", - "2": "Volt-Var modes VV11-VV12", - "3": "Frequency-Watt mode FW22", - "4": "Watt-VAr mode WP42", - "5": "Voltage-Watt modes VW51-VW52", - "6": "Remain Connected", - "7": "Temperature mode", - "8": "Pricing signal mode", - "9": "HVRT Must Trip", - "10": "HVRT Momentary Cessation", - "11": "LVRT Must Trip", - "12": "LVRT Momentary Cessation", - "13": "HFRT Must Trip", - "14": "HFRT Momentary Cessation", - "15": "LFRT Must Trip", - "16": "LFRT Momentary Cessation" - }, - "type": "enumerated", - "name": "DGSMn.ModTyp.AI329" - }, - { - "index": 330, - "description": "Curve Number of Points", - "data_type": "AI", - "common_data_class": "CSG", - "maximum": 100, - "ln_class": "FMAR", - "minimum": 0, - "data_object": "PairArr.NumPts", - "name": "FMARn.PairArr.NumPts.AI330" - }, - { - "index": 331, - "description": "Independent (X-Value) Units for Curve", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "FMAR", - "units": "None (list)", - "allowed_values": { - "0": "Curve is not defined", - "1": "Not applicable / Unknown", - "4": "Time", - "23": "Celsius Temperature", - "29": "Voltage", - "33": "Frequency", - "38": "Watts", - "100": "Price in hundredths of local currency", - "129": "Percent Voltage", - "133": "Percent Frequency", - "138": "Percent Watts", - "233": "Frequency Deviation" - }, - "type": "enumerated", - "minimum": 0, - "data_object": "IndpUnits", - "name": "FMARn.IndpUnits.AI331" - }, - { - "index": 332, - "description": "Dependent (Y-Value) Units for Curve", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "FMAR", - "units": "None (list)", - "minimum": 0, - "data_object": "DepRef", - "allowed_values": { - "0": "Curve is not defined", - "1": "Not applicable / unknown", - "2": "VArs as percent of max VArs (VARMax)", - "3": "VArs as percent of max available VArs (VArAval)", - "4": "Vars as percent of max Watts (Wmax) - not used", - "5": "Watts as percent of max Watts (Wmax)", - "6": "Watts as percent of frozen active power (DeptSnptRef)", - "7": "Power Factor in EEI notation", - "8": "Volts as a percent of the nominal voltage (VRef)", - "9": "Frequency as a percentage of the Nominal Grid Frequency (ECPNomHz)" - }, - "type": "enumerated", - "name": "FMARn.DepRef.AI332" - }, - { - "index": 333, - "description": "Curve X-Value and Y-Value pairs for curve points 1 - 100", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "FMAR", - "units": "Varies", - "data_object": "PairArr.CrvPts", - "name": "FMARn.PairArr.CrvPts.AI333", - "type": "array", - "array_times_repeated": 100, - "array_points": [ - { - "name": "FMARn.PairArr.CrvPts.AI333.xVal" - }, - { - "name": "FMARn.PairArr.CrvPts.AI333.yVal" - } - ] - }, - { - "index": 533, - "description": "System Meter Type of Connection Point", - "data_type": "AI", - "common_data_class": "ENS", - "maximum": 99, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpConnType", - "event_class": 3, - "allowed_values": { - "0": "unknown", - "1": "DER to local EPS", - "2": "Internal to DER", - "3": "local EPS with load to area EPS (PCC with load)", - "4": "local EPS w/o load to area EPS (PCC without load)", - "5": "Load to local EPS", - "6": "External to DER beyond the PCC", - "7": "External to DER within the local EPS", - "8": "Auxiliary DER Load", - "9": "Group of DERs to the area EPS", - "99": "Other" - }, - "type": "enumerated", - "name": "DECP.EcpConnType.AI533" - }, - { - "index": 534, - "description": "System Meter Type of Circuit Phases", - "data_type": "AI", - "common_data_class": "ENS", - "maximum": 8, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "PhsConnTyp", - "event_class": 3, - "allowed_values": { - "0": "unknown", - "1": "Single phase", - "2": "Split phase", - "3": "2-phase", - "4": "3-phase delta", - "5": "3-phase wye", - "6": "3-phase wye grounded", - "7": "3-phase / 3-wire (inverter type)", - "8": "3-phase / 4-wire (inverter type)" - }, - "type": "enumerated", - "name": "DECP.PhsConnTyp.AI534" - }, - { - "index": 535, - "description": "System Meter Apparent Power Calculation Method. Calculation method for total apparent power calculation.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 2, - "ln_class": "MMXU", - "units": "None (list)", - "minimum": 0, - "data_object": "ClcTotVA", - "allowed_values": { - "0": "unknown", - "1": "vector", - "2": "arithmetic" - }, - "type": "enumerated", - "name": "MMXU.ClcTotVA.AI535" - }, - { - "index": 536, - "description": "System Meter Frequency", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "MMXU", - "units": "Hz", - "minimum": 0, - "data_object": "Hz", - "event_class": 3, - "name": "MMXU.Hz.AI536" - }, - { - "index": 537, - "description": "System Meter Active Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "event_class": 3, - "name": "MMXU.TotW.AI537" - }, - { - "index": 538, - "description": "System Meter Active Power A", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "W.phsA.mag", - "event_class": 1, - "name": "MMXU.W.phsA.mag.AI538" - }, - { - "index": 539, - "description": "System Meter Active Power B", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "W.phsB.mag", - "event_class": 1, - "name": "MMXU.W.phsB.mag.AI539" - }, - { - "index": 540, - "description": "System Meter Active Power C", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "W.phsC.mag", - "event_class": 1, - "name": "MMXU.W.phsC.mag.AI540" - }, - { - "index": 541, - "description": "System Meter Reactive Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "data_object": "TotVAr", - "event_class": 3, - "name": "MMXU.TotVAr.AI541" - }, - { - "index": 542, - "description": "System Meter Reactive Power A", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "VAr", - "data_object": "VAr.phsA.mag", - "event_class": 1, - "name": "MMXU.VAr.phsA.mag.AI542" - }, - { - "index": 543, - "description": "System Meter Reactive Power B", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "VAr", - "data_object": "VAr.phsB.mag", - "event_class": 1, - "name": "MMXU.VAr.phsB.mag.AI543" - }, - { - "index": 544, - "description": "System Meter Reactive Power C", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "VAr", - "data_object": "VAr.phsC.mag", - "event_class": 1, - "name": "MMXU.VAr.phsC.mag.AI544" - }, - { - "index": 545, - "description": "System Meter Power Factor", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF", - "event_class": 3, - "name": "MMXU.TotPF.AI545" - }, - { - "index": 546, - "description": "System Meter Apparent Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VA", - "data_object": "TotVA", - "event_class": 3, - "name": "MMXU.TotVA.AI546" - }, - { - "index": 547, - "description": "System Meter Phase A Volts", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.mag", - "event_class": 3, - "name": "MMXU.PhV.phsA.mag.AI547" - }, - { - "index": 548, - "description": "System Meter Phase A Angle", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "maximum": 3600, - "ln_class": "MMXU", - "units": "Degrees", - "minimum": 0, - "data_object": "PhV.phsA.ang", - "event_class": 3, - "name": "MMXU.PhV.phsA.ang.AI548" - }, - { - "index": 549, - "description": "System Meter Phase B Volts", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.mag", - "event_class": 3, - "name": "MMXU.PhV.phsB.mag.AI549" - }, - { - "index": 550, - "description": "System Meter Phase B Angle", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "maximum": 3600, - "ln_class": "MMXU", - "units": "Degrees", - "minimum": 0, - "data_object": "PhV.phsB.ang", - "event_class": 3, - "name": "MMXU.PhV.phsB.ang.AI550" - }, - { - "index": 551, - "description": "System Meter Phase C Volts", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.mag", - "event_class": 3, - "name": "MMXU.PhV.phsC.mag.AI551" - }, - { - "index": 552, - "description": "System Meter Phase C Angle", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "maximum": 3600, - "ln_class": "MMXU", - "units": "Degrees", - "minimum": 0, - "data_object": "PhV.phsC.ang", - "event_class": 3, - "name": "MMXU.PhV.phsC.ang.AI552" - }, - { - "index": 553, - "description": "System Meter Average Line to Line Voltage", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "AvPPVPhs", - "event_class": 1, - "name": "MMXU.AvPPVPhs.AI553" - }, - { - "index": 554, - "description": "System Meter Current A", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Amps", - "data_object": "A.phsA.mag", - "event_class": 1, - "name": "MMXU.A.phsA.mag.AI554" - }, - { - "index": 555, - "description": "System Meter Current B", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Amps", - "data_object": "A.phsB.mag", - "event_class": 1, - "name": "MMXU.A.phsB.mag.AI555" - }, - { - "index": 556, - "description": "System Meter Current C", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Amps", - "data_object": "A.phsC.mag", - "event_class": 1, - "name": "MMXU.A.phsC.mag.AI556" - }, - { - "index": 557, - "description": "System Meter Active Power - High Threshold", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW.rangeC.hLim", - "event_class": 3, - "name": "MMXU.TotW.rangeC.hLim.AI557" - }, - { - "index": 558, - "description": "System Meter Active Power - Low Threshold", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW.rangeC.lLim", - "event_class": 3, - "name": "MMXU.TotW.rangeC.lLim.AI558" - }, - { - "index": 559, - "description": "System Meter Reactive Power - High Threshold", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "minimum": 0, - "data_object": "TotVAr.rangeC.hLim", - "event_class": 3, - "name": "MMXU.TotVAr.rangeC.hLim.AI559" - }, - { - "index": 560, - "description": "System Meter Reactive Power - Low Threshold", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "minimum": 0, - "data_object": "TotVAr.rangeC.lLim", - "event_class": 3, - "name": "MMXU.TotVAr.rangeC.lLim.AI560" - }, - { - "index": 561, - "description": "System Meter Power Factor - High Threshold", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF.rangeC.hLim", - "event_class": 3, - "name": "MMXU.TotPF.rangeC.hLim.AI561" - }, - { - "index": 562, - "description": "System Meter Power Factor - Low Threshold", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF.rangeC.lLim", - "event_class": 3, - "name": "MMXU.TotPF.rangeC.lLim.AI562" - }, - { - "index": 563, - "description": "System Meter Phase A Volts - High Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.rangeC.hLim", - "event_class": 3, - "name": "MMXU.PhV.phsA.rangeC.hLim.AI563" - }, - { - "index": 564, - "description": "System Meter Phase A Volts - Low Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.rangeC.lLim", - "event_class": 3, - "name": "MMXU.PhV.phsA.rangeC.lLim.AI564" - }, - { - "index": 565, - "description": "System Meter Phase B Volts - High Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.rangeC.hLim", - "event_class": 3, - "name": "MMXU.PhV.phsB.rangeC.hLim.AI565" - }, - { - "index": 566, - "description": "System Meter Phase B Volts - Low Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.rangeC.lLim", - "event_class": 3, - "name": "MMXU.PhV.phsB.rangeC.lLim.AI566" - }, - { - "index": 567, - "description": "System Meter Phase C Volts - High Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.rangeC.hLim", - "event_class": 3, - "name": "MMXU.PhV.phsC.rangeC.hLim.AI567" - }, - { - "index": 568, - "description": "System Meter Phase C Volts - Low Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.rangeC.lLim", - "event_class": 3, - "name": "MMXU.PhV.phsC.rangeC.lLim.AI568" - }, - { - "index": 569, - "description": "Running Schedule Index. Index of the highest priority schedule that is currently running or 0 if no schedule is currently running.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "ActSchdRef", - "name": "FSCC1.ActSchdRef.AI569" - }, - { - "index": 570, - "description": "Schedule to Edit Selector", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "Schd", - "event_class": 3, - "name": "FSCC.Schd.AI570", - "type": "selector_block", - "selector_block_start": 570, - "selector_block_end": 780 - - }, - { - "index": 571, - "description": "Selected Schedule Identity", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "Schd", - "event_class": 3, - "name": "FSCC.Schd.AI571" - }, - { - "index": 572, - "description": "Selected Schedule Priority. Priority of the schedule relative to other running schedules. Lower values have higher priority over higher values.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "FSCH", - "minimum": 1, - "data_object": "SchdPrio", - "event_class": 3, - "name": "FSCH.SchdPrio.AI572" - }, - { - "index": 573, - "description": "Selected Schedule Type.", - "data_type": "AI", - "maximum": 21, - "minimum": 0, - "units": "None (list)", - "event_class": 3, - "allowed_values": { - "1": "Low/High Voltage Ride-Through Hi Must Trip", - "2": "Low/High Voltage Ride-Through Low Must Trip", - "3": "Low/High Voltage Ride-Through Hi Momentary", - "4": "Low/High Voltage Ride-Through Lo Momentary", - "5": "Low/High Frequency Ride-Through Hi Must Trip", - "6": "Low/High Frequency Ride-Through Lo Must Trip", - "7": "Low/High Frequency Ride-Through Hi Momentary", - "8": "Low/High Frequency Ride-Through Low Momentary", - "9": "Dynamic Reactive Current Support - On/Off", - "10": "Dynamic Volt-Watt - On/Off", - "11": "Frequency-Watt - On/Off", - "12": "Active Power Limit - Charging", - "13": "Active Power Limit - Generating", - "14": "Charge/Discharge - Percent of Maximum", - "15": "Coordinated Charge/Discharge - SOC Target", - "16": "Active Power Response #1 - On/Off", - "17": "Active Power Response #2 - On/Off", - "18": "Active Power Response #3 - On/Off", - "19": "AGC Watts", - "20": "Active Power Smoothing - On/Off", - "21": "Volt-Watt Curve Index", - "22": "Frequency-Watt Curve Curve Index", - "23": "Frequency-Watt Curve High Hysteresis", - "24": "Frequency-Watt Curve Low Hysteresis", - "25": "Constant VArs - Percent of Maximum", - "26": "Fixed Power Factor - Power Factor", - "27": "Volt-VAr Curve Index", - "28": "Watt-VAr Curve Index", - "29": "Power Factor Correction - On/Off", - "30": "Reserved - For pricing mode" - }, - "type": "enumerated", - "name": "AI573" - }, - { - "index": 574, - "description": "Selected Schedule Start Date. Number of days since January 1, 1970, UTC.", - "data_type": "AI", - "common_data_class": "TSG", - "ln_class": "FSCH", - "units": "Days", - "minimum": 0, - "data_object": "StrTm", - "event_class": 3, - "name": "FSCH.StrTm.AI574" - }, - { - "index": 575, - "description": "Selected Schedule Start Time. Milliseconds since the start of Schedule Start Date.", - "data_type": "AI", - "common_data_class": "TSG", - "maximum": 86400000, - "ln_class": "FSCH", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "StrTm", - "event_class": 3, - "name": "FSCH.StrTm.AI575" - }, - { - "index": 576, - "description": "Selected Schedule Repeat Interval. Interval between actions after the initial occurrence. A zero value means the schedule is not repeated.", - "data_type": "AI", - "common_data_class": "TCS", - "ln_class": "FSCH", - "units": "Varies", - "minimum": 0, - "data_object": "NxtStrTm", - "event_class": 3, - "name": "FSCH.NxtStrTm.AI576" - }, - { - "index": 577, - "description": "Selected Schedule Repeat Interval Units", - "data_type": "AI", - "common_data_class": "SPG", - "maximum": 8, - "ln_class": "FSCH", - "minimum": 0, - "data_object": "SchdReuse", - "event_class": 3, - "allowed_values": { - "0": "No Repeat", - "1": "sec", - "2": "Minutes", - "3": "Hours", - "4": "Days", - "5": "Weeks", - "6": "Months", - "7": "Months on Same Day of Week", - "8": "Months on Same Day of Week from End" - }, - "type": "enumerated", - "name": "FSCH.SchdReuse.AI577" - }, - { - "index": 578, - "description": "Selected Schedule Validation Status", - "data_type": "AI", - "common_data_class": "ENSScheduleState", - "maximum": 4, - "ln_class": "FSCH", - "minimum": 0, - "data_object": "SchdSt", - "event_class": 3, - "name": "FSCH1.SchdSt.AI578" - }, - { - "index": 579, - "description": "Selected Schedule Status", - "data_type": "AI", - "common_data_class": "ENSScheduleState", - "maximum": 4, - "ln_class": "FSCH", - "units": "None (list)", - "minimum": 0, - "data_object": "SchdSt", - "allowed_values": { - "0": "unknown", - "1": "Not available", - "2": "Inactive", - "3": "Ready-to-Run", - "4": "Running" - }, - "type": "enumerated", - "name": "FSCH1.SchdSt.AI579" - }, - { - "index": 580, - "description": "Selected Schedule Number of Points", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "FSCH", - "minimum": 0, - "data_object": "NumEntr", - "event_class": 3, - "name": "FSCH.NumEntr.AI580" - }, - { - "index": 581, - "description": "Select schedule time offset and value pairs for points 1 - 100", - "data_type": "AI", - "minimum": 0, - "name": "FSCHn.SchdEntr.AI581", - "type": "array", - "array_times_repeated": 100, - "array_points": [ - { - "name": "FSCHn.SchdEntr.AI581.time", - "units": "Seconds" - }, - { - "name": "FSCHn.SchdEntr.AI581.val", - "ln_class": "FSCH", - "data_object": "SchdEntr" - } - ] - }, - { - "index": 781, - "description": "Schedule 1 Status", - "data_type": "AI", - "common_data_class": "ENSScheduleState", - "maximum": 4, - "ln_class": "FSCH", - "units": "None (list)", - "minimum": 0, - "data_object": "SchdSt", - "allowed_values": { - "0": "unknown", - "1": "Not available", - "2": "Inactive", - "3": "Ready-to-Run", - "4": "Running" - }, - "type": "enumerated", - "name": "FSCH1.SchdSt.AI781" - }, - { - "index": 782, - "description": "Schedule 1 Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "FSCH", - "minimum": 1, - "data_object": "SchdPrio", - "name": "FSCH.SchdPrio.AI782" - }, - { - "index": 783, - "description": "Schedule 1 Active Time Value. This is the index of the time value entry the schedule is currently running. First entry is 1. Zero if the schedule is not running.", - "data_type": "AI", - "common_data_class": "INS", - "maximum": 10, - "ln_class": "FSCH", - "minimum": 0, - "data_object": "ActStrTm", - "name": "FSCH1.ActStrTm.AI783" - }, - { - "category": "alarm", - "index": 0, - "description": "System Communication Error", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "LCCH", - "data_object": "ChLiv", - "allowed_values": { - "0": "Normal", - "1": "Alarm: Communications error exists in the ESS" - }, - "event_class": 1, - "name": "LCCH.ChLiv.BI0" - }, - { - "category": "alarm", - "index": 1, - "description": "System Has Priority 1 Alarms", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "CALH", - "data_object": "GrAlm", - "allowed_values": { - "0": "No P1 Alarms Active", - "1": "Alarm: One or More P1 Alarms Active" - }, - "event_class": 1, - "name": "CALH.GrAlm.BI1" - }, - { - "category": "alarm", - "index": 2, - "description": "System Has Priority 2 Alarms", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "CALH", - "data_object": "GrWrn", - "allowed_values": { - "0": "No P2 Alarms Active", - "1": "Alarm: One or More P2 Alarms Active" - }, - "event_class": 1, - "name": "CALH.GrWrn.BI2" - }, - { - "category": "alarm", - "index": 3, - "description": "System Has Priority 3 Alarms", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "CALH", - "data_object": "GrInd", - "allowed_values": { - "0": "No P3 Alarms Active", - "1": "Alarm: One or More P3 Alarms Active" - }, - "event_class": 1, - "name": "CALH.GrInd.BI3" - }, - { - "category": "alarm", - "index": 4, - "description": "Storage State of Charge at Maximum. Maximum Usable State of Charge Reached.", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DSTO", - "data_object": "SocHiWrn", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DSTO.SocHiWrn.BI4" - }, - { - "category": "alarm", - "index": 5, - "description": "Storage State of Charge is Too High. Maximum Reserve Percentage (of usable capacity) reached.", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DSTO", - "data_object": "SocHiAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DSTO.SocHiAlm.BI5" - }, - { - "category": "alarm", - "index": 6, - "description": "Storage State of Charge is Too Low. Minimum Reserve Percentage (of usable capacity) reached.", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DSTO", - "data_object": "SocLoAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DSTO.SocLoAlm.BI6" - }, - { - "category": "alarm", - "index": 7, - "description": "Storage State of Charge is Depleted. Minimum Usable State of Charge Reached.", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DSTO", - "data_object": "SohLoAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DSTO.SohLoAlm.BI7" - }, - { - "category": "alarm", - "index": 8, - "description": "Storage Internal Temperature is Too High", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DBAT", - "data_object": "IntnTmpHiAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DBAT.IntnTmpHiAlm.BI8" - }, - { - "category": "alarm", - "index": 9, - "description": "Storage External (Ambient) Temperature is Too High", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DBAT", - "data_object": "ExtTmpHiAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DBAT.ExtTmpHiAlm.BI9" - }, - { - "index": 10, - "description": "System Is In Local State. System has been locked by a local operator which prevents other operators from executing commands. Note: Local State is also sometimes referred to as Maintenance State. Local State overrides Lockout State.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and in maintenance", - "allowed_values": { - "0": "System not in local state", - "1": "System in local state" - }, - "name": "DSTO.DEROpSt.disconnectedandinmaintenance.BI10" - }, - { - "index": 11, - "description": "System Is In Lockout State. System has been locked by an operator such that other operators may not execute commands. Lockout State is also sometimes referred to as Blocked State.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and blocked", - "allowed_values": { - "0": "System not locked out", - "1": "System locked out" - }, - "name": "DSTO.DEROpSt.disconnectedandblocked.BI11" - }, - { - "index": 12, - "description": "System Is Starting Up. Set to 1 when a BO \"System Initiate Start-up Sequence\" command has been received.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.starting and synchronizing", - "allowed_values": { - "0": "Not Starting Up", - "1": "Start command has been received." - }, - "name": "DSTO.DEROpSt.startingandsynchronizing.BI12" - }, - { - "index": 13, - "description": "System Is Stopping. Set to 1 when an B0 \"System Execute Stop\" command has been received.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.stopping", - "allowed_values": { - "0": "Not Stopping", - "1": "Emergency stop command has been received." - }, - "name": "DSTO.DEROpSt.stopping.BI13" - }, - { - "index": 14, - "description": "System is Started (Return to Service). If any of the DER Units are started,then true. DER Units in the maintenance operational state are excluded.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.connected and idle", - "allowed_values": { - "0": "Null", - "1": "Started" - }, - "name": "DSTO.DEROpSt.connectedandidle.BI14" - }, - { - "index": 15, - "description": "System is Stopped (Cease to Energize). If all of the DER Units are stopped, then true. DER Units in the maintenance operational state are excluded.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.ceased to energize", - "allowed_values": { - "0": "Null", - "1": "Stopped" - }, - "name": "DSTO.DEROpSt.ceasedtoenergize.BI15" - }, - { - "index": 16, - "description": "System Permission to Start Status", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DSTO", - "data_object": "PrmConn", - "allowed_values": { - "0": "Start Permission Not Granted", - "1": "Start Permission Granted" - }, - "name": "DSTO.PrmConn.BI16" - }, - { - "index": 17, - "description": "System Permission to Stop Status", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DSTO", - "data_object": "PrmDscon", - "allowed_values": { - "0": "Stop Permission Not Granted", - "1": "Stop Permission Granted" - }, - "name": "DSTO.PrmDscon.BI17" - }, - { - "index": 18, - "description": "DER is Connected and Idle", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.connected and idle", - "allowed_values": { - "0": "Null", - "1": "Idle-Connected" - }, - "name": "DSTO.DEROpSt.connectedandidle.BI18" - }, - { - "index": 19, - "description": "DER is Connected and Generating", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.connected and generating", - "allowed_values": { - "0": "Null", - "1": "On-Connected" - }, - "name": "DSTO.DEROpSt.connectedandgenerating.BI19" - }, - { - "index": 20, - "description": "DER is Connected and Charging", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.connected and consuming", - "allowed_values": { - "0": "Null", - "1": "On-Charging-Connected" - }, - "name": "DSTO.DEROpSt.connectedandconsuming.BI20" - }, - { - "index": 21, - "description": "DER is Off but Available to Start", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and available", - "allowed_values": { - "0": "Null", - "1": "Off-Available" - }, - "name": "DSTO.DEROpSt.disconnectedandavailable.BI21" - }, - { - "index": 22, - "description": "DER is Off and Not Available to Start", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and stand-by", - "allowed_values": { - "0": "Null", - "1": "Off-Not-Available" - }, - "name": "DSTO.DEROpSt.disconnectedandstand-by.BI22" - }, - { - "index": 23, - "description": "DER Connect/Disconnect Switch Closed Status", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.off", - "allowed_values": { - "0": "Open", - "1": "Closed" - }, - "name": "DSTO.DEROpSt.off.BI23" - }, - { - "index": 24, - "description": "DER Connect/Disconnect Switch Movement Status", - "data_type": "BI", - "common_data_class": "DPC", - "ln_class": "CSWI", - "data_object": "Pos", - "allowed_values": { - "0": "Not Moving", - "1": "Moving" - }, - "name": "CSWI.Pos.BI24" - }, - { - "index": 25, - "description": "Islanded Mode. Determines how the DER behaves when in an Islanded configuration.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DSTO", - "data_object": "IsldCtlFol", - "allowed_values": { - "0": "Isochronous Mode. DER attempts to control voltage and frequency independent of configured curves and settings up to the limits of the machine's capabilities in order to achieve the AO Reference Voltage and AO nominal frequency.", - "1": "Droop Mode. DER acts as a follower using Volt/VAR and Freq/Watt curves." - }, - "event_class": 3, - "name": "DSTO.IsldCtlFol.BI25" - }, - { - "index": 26, - "description": "Sensed Grid Config Detection Enabled. If Enabled, the DER may independently change its Active Settings Group based on locally observed grid conditions.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DECP", - "data_object": "ECPIsldAuto", - "allowed_values": { - "0": "No Autonomous Detection.", - "1": "Autonomous Detection. Inverter's Active Settings Group may differ from the Requested Settings Group" - }, - "event_class": 3, - "name": "DECP.ECPIsldAuto.BI26" - }, - { - "index": 27, - "description": "Storage Capacity Units. Determines whether energy storage values are expressed in units of Amp-hrs or Watt-hrs.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DSTO", - "data_object": "AGra", - "allowed_values": { - "0": "Amp-hrs (default)", - "1": "Watt-hrs" - }, - "event_class": 3, - "name": "DSTO.AGra.BI27" - }, - { - "index": 28, - "description": "Time Constant Mode. Indicates whether Time Constant Ramp parameters are interpreted as Open Loop Response times or 3Tau values.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DSTO", - "data_object": "OpnLoopTau", - "allowed_values": { - "0": "Open Loop Response Time", - "1": "3Tau Value" - }, - "event_class": 3, - "name": "DSTO.OpnLoopTau.BI28" - }, - { - "index": 29, - "description": "Power Factor Excitation When Discharging/Generating", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DFPF", - "data_object": "PFGnExtSet", - "allowed_values": { - "0": "Injecting VARs - Q1", - "1": "Absorbing VARs - Q4" - }, - "name": "DFPF.PFGnExtSet.BI29" - }, - { - "index": 30, - "description": "Power Factor Excitation When Charging", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DFPF", - "data_object": "PFLodExtSet", - "allowed_values": { - "0": "Injecting VARs - Q2", - "1": "Absorbing VARs - Q3" - }, - "name": "DFPF.PFLodExtSet.BI30" - }, - { - "index": 31, - "description": "Supports Low/High Voltage Ride-Through Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DHVT", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DHVT.BI31" - }, - { - "index": 32, - "description": "Supports Low/High Frequency Ride-Through Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DHFT", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DHFT.BI32" - }, - { - "index": 33, - "description": "Supports Dynamic Reactive Current Support Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DRGS", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DRGS.BI33" - }, - { - "index": 34, - "description": "Supports Dynamic Volt-Watt Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DVWD", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DVWD.BI34" - }, - { - "index": 35, - "description": "Supports Frequency-Watt Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DHFW", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DHFW.BI35" - }, - { - "index": 36, - "description": "Supports Active Power Limit Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DWLM", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DWLM.BI36" - }, - { - "index": 37, - "description": "Supports Charge/Discharge Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DWGC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DWGC.BI37" - }, - { - "index": 38, - "description": "Supports Coordinated Charge/Discharge Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DTCD", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DTCD.BI38" - }, - { - "index": 39, - "description": "Supports Active Power Response Mode #1", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DLFL", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DLFL.BI39" - }, - { - "index": 40, - "description": "Supports Active Power Response Mode #2", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DGFL", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DGFL.BI40" - }, - { - "index": 41, - "description": "Supports Active Power Response Mode #3", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DGFL", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DGFL.BI41" - }, - { - "index": 42, - "description": "Supports Automatic Generation Control Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DAGC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DAGC.BI42" - }, - { - "index": 43, - "description": "Supports Active Power Smoothing Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DWSM", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DWSM.BI43" - }, - { - "index": 44, - "description": "Supports Volt-Watt Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DVWC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DVWC.BI44" - }, - { - "index": 45, - "description": "Supports Frequency-Watt Curve Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DFWC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DFWC.BI45" - }, - { - "index": 46, - "description": "Supports Constant VArs Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DVAR", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DVAR.BI46" - }, - { - "index": 47, - "description": "Supports Fixed Power Factor Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DFPF", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DFPF.BI47" - }, - { - "index": 48, - "description": "Supports Volt-VAr Control Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DVVC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DVVC.BI48" - }, - { - "index": 49, - "description": "Supports Watt-VAr Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DWVR", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DWVR.BI49" - }, - { - "index": 50, - "description": "Supports Power Factor Correction Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DPFC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DPFC.BI50" - }, - { - "index": 51, - "description": "Supports Pricing Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DPRG", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DPRG.BI51" - }, - { - "index": 52, - "description": "Overvoltage Disconnect Protection Blocked", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "PTOV", - "data_object": "Blk", - "allowed_values": { - "0": "Not Blocked", - "1": "Blocked (Disabled)" - }, - "event_class": 1, - "name": "PTOV.Blk.BI52" - }, - { - "index": 53, - "description": "Overvoltage Disconnect Protection Started", - "data_type": "BI", - "common_data_class": "ACD", - "ln_class": "PTOV", - "data_object": "Str.general", - "allowed_values": { - "0": "Not Started", - "1": "Started (Evaluating)" - }, - "event_class": 1, - "name": "PTOV.Str.general.BI53" - }, - { - "index": 54, - "description": "Overvoltage Disconnect Protection Operated", - "data_type": "BI", - "common_data_class": "ACT", - "ln_class": "PTOV", - "data_object": "Op.general", - "allowed_values": { - "0": "Not Operated", - "1": "Operated (Disconnected)" - }, - "event_class": 1, - "name": "PTOV.Op.general.BI54" - }, - { - "index": 55, - "description": "Undervoltage Disconnect Protection Blocked", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "PTUV", - "data_object": "Blk", - "allowed_values": { - "0": "Not Blocked", - "1": "Blocked (Disabled)" - }, - "event_class": 1, - "name": "PTUV.Blk.BI55" - }, - { - "index": 56, - "description": "Undervoltage Disconnect Protection Started", - "data_type": "BI", - "common_data_class": "ACD", - "ln_class": "PTUV", - "data_object": "Str.general", - "allowed_values": { - "0": "Not Started", - "1": "Started (Evaluating)" - }, - "event_class": 1, - "name": "PTUV.Str.general.BI56" - }, - { - "index": 57, - "description": "Undervoltage Disconnect Protection Operated", - "data_type": "BI", - "common_data_class": "ACT", - "ln_class": "PTUV", - "data_object": "Op.general", - "allowed_values": { - "0": "Not Operated", - "1": "Operated (Disconnected)" - }, - "event_class": 1, - "name": "PTUV.Op.general.BI57" - }, - { - "index": 58, - "description": "Over Frequency Disconnect Protection Blocked", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "PTOV", - "data_object": "Blk", - "allowed_values": { - "0": "Not Blocked", - "1": "Blocked (Disabled)" - }, - "event_class": 1, - "name": "PTOV.Blk.BI58" - }, - { - "index": 59, - "description": "Over Frequency Disconnect Protection Started", - "data_type": "BI", - "common_data_class": "ACD", - "ln_class": "PTOV", - "data_object": "Str.general", - "allowed_values": { - "0": "Not Started", - "1": "Started (Evaluating)" - }, - "event_class": 1, - "name": "PTOV.Str.general.BI59" - }, - { - "index": 60, - "description": "Over Frequency Disconnect Protection Operated", - "data_type": "BI", - "common_data_class": "ACT", - "ln_class": "PTOV", - "data_object": "Op.general", - "allowed_values": { - "0": "Not Operated", - "1": "Operated (Disconnected)" - }, - "event_class": 1, - "name": "PTOV.Op.general.BI60" - }, - { - "index": 61, - "description": "Under Frequency Disconnect Protection Blocked", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "PTUV", - "data_object": "Blk", - "allowed_values": { - "0": "Not Blocked", - "1": "Blocked (Disabled)" - }, - "event_class": 1, - "name": "PTUV.Blk.BI61" - }, - { - "index": 62, - "description": "Under Frequency Disconnect Protection Started", - "data_type": "BI", - "common_data_class": "ACD", - "ln_class": "PTUV", - "data_object": "Str.general", - "allowed_values": { - "0": "Not Started", - "1": "Started (Evaluating)" - }, - "event_class": 1, - "name": "PTUV.Str.general.BI62" - }, - { - "index": 63, - "description": "Under Frequency Disconnect Protection Operated", - "data_type": "BI", - "common_data_class": "ACT", - "ln_class": "PTUV", - "data_object": "Op.general", - "allowed_values": { - "0": "Not Operated", - "1": "Operated (Disconnected)" - }, - "event_class": 1, - "name": "PTUV.Op.general.BI63" - }, - { - "category": "mode_enable", - "index": 64, - "description": "Operating Mode - Low/High Voltage Ride-Through", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DHVT", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHVT.ModEna.BI64" - }, - { - "category": "mode_enable", - "index": 65, - "description": "Operating Mode - Low/High Frequency Ride-Through", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DHFT", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHFT.ModEna.BI65" - }, - { - "category": "mode_enable", - "index": 66, - "description": "Operating Mode - Dynamic Reactive Current Support Enabled", - "data_type": "BI", - "common_data_class": "ENC", - "ln_class": "DRGS", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DRGS.ModEna.BI66" - }, - { - "category": "mode_enable", - "index": 67, - "description": "Operating Mode - Dynamic Volt-Watt Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DVWD", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVWD.ModEna.BI67" - }, - { - "category": "mode_enable", - "index": 68, - "description": "Operating Mode - Frequency-Watt Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DHFW", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHFW.ModEna.BI68" - }, - { - "category": "mode_enable", - "index": 69, - "description": "Operating Mode - Active Power Limit Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DWLM", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DWLM.ModEna.BI69" - }, - { - "category": "mode_enable", - "index": 70, - "description": "Operating Mode - Charge/Discharge Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DWGC", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DWGC.ModEna.BI70" - }, - { - "category": "mode_enable", - "index": 71, - "description": "Operating Mode - Coordinated Charge/Discharge Management Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DTCD", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DTCD.ModEna.BI71" - }, - { - "category": "mode_enable", - "index": 72, - "description": "Operating Mode - Active Power Response Mode #1 Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DPKP", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DPKP.ModEna.BI72" - }, - { - "category": "mode_enable", - "index": 73, - "description": "Operating Mode - Active Power Response Mode #2 Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DGFL", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DGFL.ModEna.BI73" - }, - { - "category": "mode_enable", - "index": 74, - "description": "Operating Mode - Active Power Response Mode #3 Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DLFL", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DLFL.ModEna.BI74" - }, - { - "category": "mode_enable", - "index": 75, - "description": "Operating Mode - Automatic Generation Control Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DAGC", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DAGC.ModEna.BI75" - }, - { - "category": "mode_enable", - "index": 76, - "description": "Operating Mode - Active Power Smoothing Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DWSM", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DWSM.ModEna.BI76" - }, - { - "category": "mode_enable", - "index": 77, - "description": "Operating Mode - Volt-Watt Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DVWC", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVWC.ModEna.BI77" - }, - { - "category": "mode_enable", - "index": 78, - "description": "Operating Mode - Frequency-Watt Curve Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DHFW", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHFW.ModEna.BI78" - }, - { - "category": "mode_enable", - "index": 79, - "description": "Operating Mode - Constant VArs Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DVAR", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVAR.ModEna.BI79" - }, - { - "category": "mode_enable", - "index": 80, - "description": "Operating Mode - Fixed Power Factor Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DFPF", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DFPF.ModEna.BI80" - }, - { - "category": "mode_enable", - "index": 81, - "description": "Operating Mode - Volt-VAR Control Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DVVR", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVVR.ModEna.BI81" - }, - { - "category": "mode_enable", - "index": 82, - "description": "Operating Mode - Watt-VAr Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DWVR", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DWVR.ModEna.BI82" - }, - { - "category": "mode_enable", - "index": 83, - "description": "Operating Mode - Power Factor Correction Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DPFC", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DPFC.ModEna.BI83" - }, - { - "category": "mode_enable", - "index": 84, - "description": "Operating Mode - Pricing Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DPRG", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DPRG.ModEna.BI84" - }, - { - "category": "mode_enable", - "index": 85, - "description": "Operating Mode - Event-Based Reactive Current Support Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DRGS", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DRGS.ModEna.BI85" - }, - { - "index": 86, - "description": "Frequency-Watt Mode - Use Hysteresis", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DHFW", - "data_object": "HysEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHFW.HysEna.BI86" - }, - { - "index": 87, - "description": "Frequency-Watt Mode - Snapshot of Power", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DHFW", - "data_object": "SnptEna", - "allowed_values": { - "0": "Not Active", - "1": "Active" - }, - "name": "DHFW.SnptEna.BI87" - }, - { - "index": 88, - "description": "Frequency-Watt Curve Mode - Use Hysteresis", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DLFW", - "data_object": "HysEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DLFW.HysEna.BI88" - }, - { - "index": 89, - "description": "Frequency-Watt Curve Mode - Snapshot of Power", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DLFW", - "data_object": "SnptEna", - "allowed_values": { - "0": "Not Active", - "1": "Active" - }, - "name": "DLFW.SnptEna.BI89" - }, - { - "index": 90, - "description": "Charge/Discharge Mode - Use Ramp Rates. Indicates whether or not Charge/Discharge should use specified ramp rates or ramp times.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DWGC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constants", - "1": "Use Ramp Rates" - }, - "name": "DWGC.UseRmpRte.BI90" - }, - { - "index": 91, - "description": "AGC Mode - Use Ramp Rates. Indicates whether or not charge/discharge should use specified ramp rates or ramp times.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DAGC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constants", - "1": "Use Ramp Rates" - }, - "name": "DAGC.UseRmpRte.BI91" - }, - { - "index": 92, - "description": "Volt-Watt - Use Ramp Rates and Time Constants", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DVWC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constants", - "1": "Use Ramp Rates AND Time Constants" - }, - "name": "DVWC.UseRmpRte.BI92" - }, - { - "index": 93, - "description": "Volt-VAr Enable Autonomous Voltage Reference Adjustment", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DVVR", - "data_object": "VRefAdjEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVVR.VRefAdjEna.BI93" - }, - { - "category": "alarm", - "index": 94, - "description": "System Meter Active Power is Too High", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotW.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotW.range.BI94" - }, - { - "category": "alarm", - "index": 95, - "description": "System Meter Active Power is Too Low", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotW.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotW.range.BI95" - }, - { - "category": "alarm", - "index": 96, - "description": "System Meter Reactive Power is Too High", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotVAr.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotVAr.range.BI96" - }, - { - "category": "alarm", - "index": 97, - "description": "System Meter Reactive Power is Too Low", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotVAr.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotVAr.range.BI97" - }, - { - "category": "alarm", - "index": 98, - "description": "System Meter Power Factor is Too High", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotPF.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotPF.range.BI98" - }, - { - "category": "alarm", - "index": 99, - "description": "System Meter Power Factor is Too Low", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotPF.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotPF.range.BI99" - }, - { - "category": "alarm", - "index": 100, - "description": "System Meter Phase A Voltage is Too High", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsA.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsA.range.BI100" - }, - { - "category": "alarm", - "index": 101, - "description": "System Meter Phase A Voltage is Too Low", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsA.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsA.range.BI101" - }, - { - "category": "alarm", - "index": 102, - "description": "System Meter Phase B Voltage is Too High", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsB.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsB.range.BI102" - }, - { - "category": "alarm", - "index": 103, - "description": "System Meter Phase B Voltage is Too Low", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsB.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsB.range.BI103" - }, - { - "category": "alarm", - "index": 104, - "description": "System Meter Phase C Voltage is Too High", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsC.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsC.range.BI104" - }, - { - "category": "alarm", - "index": 105, - "description": "System Meter Phase C Voltage is Too Low", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsC.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsC.range.BI105" - }, - { - "category": "alarm", - "index": 106, - "description": "System Meter Communication Error", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "LCCH", - "data_object": "ChLiv", - "allowed_values": { - "0": "Normal: No Active Communications Error", - "1": "Alarm: Active Communications Error" - }, - "event_class": 1, - "name": "LCCH.ChLiv.BI106" - }, - { - "index": 107, - "description": "Selected Curve is Referenced by a Mode", - "data_type": "BI", - "allowed_values": { - "0": "Curve is not Referenced", - "1": "Curve is Referenced" - }, - "event_class": 1, - "name": "BI107" - }, - { - "index": 108, - "description": "Selected Schedule Is Ready", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "FSCH", - "data_object": "SchdSt.3", - "allowed_values": { - "0": "Not Ready", - "1": "Ready" - }, - "name": "FSCH.SchdSt.3.BI108" - }, - { - "index": 109, - "description": "Selected Schedule is Validated", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "FSCH", - "data_object": "SchdSt.2", - "allowed_values": { - "0": "Not validated", - "1": "Validated" - }, - "name": "FSCH.SchdSt.2.BI109" - }, - { - "index": 110, - "description": "Selected Schedule Repeat Weekly Sunday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI110" - }, - { - "index": 111, - "description": "Selected Schedule Repeat Weekly Monday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI111" - }, - { - "index": 112, - "description": "Selected Schedule Repeat Weekly Tuesday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI112" - }, - { - "index": 113, - "description": "Selected Schedule Repeat Weekly Wednesday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI113" - }, - { - "index": 114, - "description": "Selected Schedule Repeat Weekly Thursday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI114" - }, - { - "index": 115, - "description": "Selected Schedule Repeat Weekly Friday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI115" - }, - { - "index": 116, - "description": "Selected Schedule Repeat Weekly Saturday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI116" - }, - { - "index": 0, - "description": "System Set Lockout State", - "data_type": "BO", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and blocked", - "allowed_values": { - "0": "Not Locked Out", - "1": "Lock Out" - }, - "name": "DSTO.DEROpSt.disconnectedandblocked.BO0" - }, - { - "index": 1, - "description": "System Initiate Start-up Sequence (Return to Service). Setting this to 1 does the following: - Sets BI \"System Is Starting Up\" to 1 indicating that the system is starting up. Additional start-up status can be found in AI \"System Start-up Status\". - Instructs all batteries to connect. - Once each battery has reported that it has connect successfully, instructs corresponding DER Unit to start. System can be shut down by executing B0 \"Emergency Stop\" command. This operation is the same as California Rule 21 \"Soft Start\".", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DCTE", - "data_object": "RtnSrvReq", - "allowed_values": { - "0": "No Change", - "1": "Initiate Start-up" - }, - "name": "DCTE.RtnSrvReq.BO1" - }, - { - "index": 2, - "description": "System Execute Stop (Cease to Energize). Setting this to 1 does the following: - Sets BI \"System Is Emergency Stopping\" to 1 indicating that an emergency stop is in progress. - Ensures that any executing operating modes are shut down (disabled). - Ensures that any executing schedules are shut down (disabled). - Instructs all inverters to shut down. - Instructs all batteries to disconnect. System can be started again by executing BO \"Initiate Start-up Sequence\" command.", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DCTE", - "data_object": "CeaEngzReq", - "allowed_values": { - "0": "No Change", - "1": "Stop (Emergency)" - }, - "name": "DCTE.CeaEngzReq.BO2" - }, - { - "index": 3, - "description": "System Permission to Start", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DSTO", - "data_object": "PrmConn", - "allowed_values": { - "0": "DCTE", - "1": "Start Permission Granted" - }, - "name": "DSTO.PrmConn.BO3" - }, - { - "index": 4, - "description": "System Permission to Stop", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DSTO", - "data_object": "PrmDscon", - "allowed_values": { - "0": "DCTE", - "1": "Stop Permission Granted" - }, - "name": "DSTO.PrmDscon.BO4" - }, - { - "index": 5, - "description": "DER Connect/Disconnect Switch", - "data_type": "BO", - "common_data_class": "DPC", - "ln_class": "CSWI", - "data_object": "Pos", - "allowed_values": { - "0": "Open Switch", - "1": "Close Switch" - }, - "name": "CSWI.Pos.BO5" - }, - { - "index": 6, - "description": "Islanded Mode. Determines how the DER behaves when in an Islanded configuration.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DGEN", - "data_object": "IsldCtlFol", - "allowed_values": { - "0": "Isochronous Mode. DER attempts to control voltage and frequency independent of configured curves and settings up to the limits of the machine's capabilities in order to achieve AO reference voltage and AO nominal frequency.", - "1": "Droop Mode. DER acts as a follower using Volt/VAR and Freq/Watt curves." - }, - "name": "DGEN.IsldCtlFol.BO6" - }, - { - "index": 7, - "description": "Enable Sensed Grid Config Detection. If Enabled, the DER may independently change its Active Settings Group based on locally observed grid conditions.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DECP", - "data_object": "ECPIsldAuto", - "allowed_values": { - "0": "No Autonomous Detection.", - "1": "Autonomous Detection. Inverter's Active Settings Group may differ from the Requested Settings Group" - }, - "name": "DECP.ECPIsldAuto.BO7" - }, - { - "index": 8, - "description": "Storage Capacity Units. Determines whether the energy storage values are expressed in Amp-hrs or Watt-hrs.", - "data_type": "BO", - "common_data_class": "ASG", - "ln_class": "DSTO", - "data_object": "AGra", - "allowed_values": { - "0": "Amp-hrs (default)", - "1": "Watt-hrs" - }, - "name": "DSTO.AGra.BO8" - }, - { - "index": 9, - "description": "Time Constant Mode. Indicates whether Time Constant Ramp parameters are interpreted as Open Loop Response times or 3Tau values.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DSTO", - "data_object": "OpnLoopTau", - "allowed_values": { - "0": "Open Loop Response Time", - "1": "3Tau Value" - }, - "name": "DSTO.OpnLoopTau.BO9" - }, - { - "index": 10, - "description": "Power Factor Excitation When Discharging/Generating", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DFPF", - "data_object": "PFGnExtSet", - "allowed_values": { - "0": "Producing VARs - Q1", - "1": "Absorbing VARs - Q4" - }, - "name": "DFPF.PFGnExtSet.BO10" - }, - { - "index": 11, - "description": "Power Factor Excitation When Charging", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DFPF", - "data_object": "PFLodExtSet", - "allowed_values": { - "0": "Producing VARs - Q2", - "1": "Absorbing VARs - Q3" - }, - "name": "DFPF.PFLodExtSet.BO11" - }, - { - "category": "mode_enable", - "index": 12, - "description": "Enable Low/High Voltage Ride-Through Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DHVT", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DHVT.ModEna.BI64", - "name": "DHVT.ModEna.BO12" - }, - { - "category": "mode_enable", - "index": 13, - "description": "Enable Low/High Frequency Ride-Through Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DHFT", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DHFT.ModEna.BI65", - "name": "DHFT.ModEna.BO13" - }, - { - "category": "mode_enable", - "index": 14, - "description": "Enable Dynamic Reactive Current Support Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DRGS", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DRGS.ModEna.BI66", - "name": "DRGS.ModEna.BO14" - }, - { - "category": "mode_enable", - "index": 15, - "description": "Enable Dynamic Volt-Watt Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DVWD", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DVWD.ModEna.BI67", - "name": "DVWD.ModEna.BO15" - }, - { - "category": "mode_enable", - "index": 16, - "description": "Enable Frequency-Watt Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DHFW", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DHFW.ModEna.BI68", - "name": "DHFW.ModEna.BO16" - }, - { - "category": "mode_enable", - "index": 17, - "description": "Enable Active Power Limit Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DWLM", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DWLM.ModEna.BI69", - "name": "DWLM.ModEna.BO17" - }, - { - "category": "mode_enable", - "index": 18, - "description": "Enable Charge/Discharge Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DWGC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DTCD.ModEna.BI71", - "name": "DWGC.ModEna.BO18" - }, - { - "category": "mode_enable", - "index": 19, - "description": "Enable Coordinated Charge/Discharge Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DTCD", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DTCD.ModEna.BO19" - }, - { - "category": "mode_enable", - "index": 20, - "description": "Enable Active Power Response Mode #1", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DPKP", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DPKP.ModEna.BI72", - "name": "DPKP.ModEna.BO20" - }, - { - "category": "mode_enable", - "index": 21, - "description": "Enable Active Power Response Mode #2", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DGFL", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DGFL.ModEna.BI73", - "name": "DGFL.ModEna.BO21" - }, - { - "category": "mode_enable", - "index": 22, - "description": "Enable Active Power Response Mode #3", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DLFL", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DLFL.ModEna.BI74", - "name": "DLFL.ModEna.BO22" - }, - { - "category": "mode_enable", - "index": 23, - "description": "Enable Automatic Generation Control Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DAGC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DAGC.ModEna.BI75", - "name": "DAGC.ModEna.BO23" - }, - { - "category": "mode_enable", - "index": 24, - "description": "Enable Active Power Smoothing Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DWSM", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DWSM.ModEna.BI76", - "name": "DWSM.ModEna.BO24" - }, - { - "category": "mode_enable", - "index": 25, - "description": "Enable Volt-Watt Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DVWC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DVWC.ModEna.BI77", - "name": "DVWC.ModEna.BO25" - }, - { - "category": "mode_enable", - "index": 26, - "description": "Enable Frequency-Watt Curve Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DHFW", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DHFW.ModEna.BI78", - "name": "DHFW.ModEna.BO26" - }, - { - "category": "mode_enable", - "index": 27, - "description": "Enable Constant VArs Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DVAR", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DVAR.ModEna.BI79", - "name": "DVAR.ModEna.BO27" - }, - { - "category": "mode_enable", - "index": 28, - "description": "Enable Fixed Power Factor Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DFPF", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DFPF.BI47", - "name": "DFPF.ModEna.BO28" - }, - { - "category": "mode_enable", - "index": 29, - "description": "Enable Volt-VAR Control Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DVVC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DVVC.BI48", - "name": "DVVC.ModEna.BO29" - }, - { - "category": "mode_enable", - "index": 30, - "description": "Enable Watt-VAr Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DWVR", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DWVR.BI49", - "name": "DWVR.ModEna.BO30" - }, - { - "category": "mode_enable", - "index": 31, - "description": "Enable Power Factor Correction Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DPFC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DPFC.ModEna.BI83", - "name": "DPFC.ModEna.BO31" - }, - { - "category": "mode_enable", - "index": 32, - "description": "Enable Pricing Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DPRG", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DPRG.ModEna.BI84", - "name": "DPRG.ModEna.BO32" - }, - { - "index": 33, - "description": "Enable Event-Based Reactive Current Support Mode, in which the moving average voltage and the base reactive current are frozen until after the voltage has returned to within the deadband for a specified hold time. Dynamic Reactive Current Support mode must be Enable for this setting to apply.", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DRGS", - "data_object": "ArGraMod", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DRGS.ArGraMod.BO33" - }, - { - "index": 34, - "description": "Frequency-Watt Mode - Use Hysteresis", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DHFW", - "data_object": "HysEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DHFW.HysEna.BO34" - }, - { - "index": 35, - "description": "Frequency-Watt Mode - Snapshot of Power", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DHFW", - "data_object": "SnptEna", - "allowed_values": { - "0": "Not Active", - "1": "Active" - }, - "name": "DHFW.SnptEna.BO35" - }, - { - "index": 36, - "description": "Frequency-Watt Curve Mode - Use Hysteresis", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DLFW", - "data_object": "HysEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DLFW.HysEna.BO36" - }, - { - "index": 37, - "description": "Frequency-Watt Curve Mode - Snapshot of Power", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DLFW", - "data_object": "SnptEna", - "allowed_values": { - "0": "Not Active", - "1": "Active" - }, - "name": "DLFW.SnptEna.BO37" - }, - { - "index": 38, - "description": "Charge/Discharge Mode - Use Ramp Rates. Indicates whether or not Charge/Discharge should use specified ramp rates or time constants.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DWGC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constatnts", - "1": "Use Ramp Rates" - }, - "name": "DWGC.UseRmpRte.BO38" - }, - { - "index": 39, - "description": "AGC Mode - Use Ramp Rates. Indicates whether or not AGC mode should use specified ramp rates or time constants.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DAGC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constatnts", - "1": "Use Ramp Rates" - }, - "name": "DAGC.UseRmpRte.BO39" - }, - { - "index": 40, - "description": "Volt-Watt - Use Ramp Rates and Time Constants. Indicates whether Volt-Watt mode should use only Time Constants,or both Time Constants and Ramp Rates", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DVWC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constatnts", - "1": "Use Ramp Rates AND Time Constants" - }, - "name": "DVWC.UseRmpRte.BO40" - }, - { - "index": 41, - "description": "Volt-VAr Enable Autonomous Voltage Reference Adjustment", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DVVR", - "data_object": "VRefAdjEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DVVR.VRefAdjEna.BO41" - }, - { - "index": 42, - "description": "Set Selected Scheduled Ready", - "data_type": "BO", - "common_data_class": "ENC", - "ln_class": "FSCH", - "data_object": "Mod", - "allowed_values": { - "0": "Not Ready", - "1": "Ready" - }, - "name": "FSCHxx.Mod.BO42" - }, - { - "index": 43, - "description": "Set Selected Schedule Repeat Weekly Sunday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO43" - }, - { - "index": 44, - "description": "Set Selected Schedule Repeat Weekly Monday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO44" - }, - { - "index": 45, - "description": "Set Selected Schedule Repeat Weekly Tuesday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO45" - }, - { - "index": 46, - "description": "Set Selected Schedule Repeat Weekly Wednesday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO46" - }, - { - "index": 47, - "description": "Set Selected Schedule Repeat Weekly Thursday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO47" - }, - { - "index": 48, - "description": "Set Selected Schedule Repeat Weekly Friday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO48" - }, - { - "index": 49, - "description": "Set Selected Schedule Repeat Weekly Saturday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO49" - } -] \ No newline at end of file diff --git a/services/core/DNP3Agent/dnp3/outstation.py b/services/core/DNP3Agent/dnp3/outstation.py deleted file mode 100644 index 142eec388d..0000000000 --- a/services/core/DNP3Agent/dnp3/outstation.py +++ /dev/null @@ -1,420 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, SLAC / 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared in part as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor SLAC, nor 8minutenergy, nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# SLAC, 8minutenergy, or Kisensum. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# }}} - -import os -import logging - -from pydnp3 import opendnp3, openpal, asiopal, asiodnp3 - -# from volttron.platform.agent import utils - -# utils.setup_logging() -_log = logging.getLogger(__name__) - - -class DNP3Outstation(opendnp3.IOutstationApplication): - """ - Model the Application Layer of a DNP3 outstation. - - This class models the interface for all outstation callback info except for control requests. - - DNP3 spec section 5.1.6.2: - The Application Layer provides the following services for the DNP3 User Layer in an outstation: - - Notifies the DNP3 User Layer when action requests, such as control output, - analog output, freeze and file operations, arrive from a master. - - Requests data and information from the outstation that is wanted by a master - and formats the responses returned to a master. - - Assures that event data is successfully conveyed to a master (using - Application Layer confirmation). - - Sends notifications to the master when the outstation restarts, has queued events, - and requires time synchronization. - - DNP spec section 5.1.6.3: - The Application Layer requires specific services from the layers beneath it. - - Partitioning of fragments into smaller portions for transport reliability. - - Knowledge of which device(s) were the source of received messages. - - Transmission of messages to specific devices or to all devices. - - Message integrity (i.e., error-free reception and transmission of messages). - - Knowledge of the time when messages arrive. - - Either precise times of transmission or the ability to set time values - into outgoing messages. - """ - - outstation = None - outstation_config = {} - agent = None - - def __init__(self, local_ip, port, outstation_config): - """ - Initialize the outstation's Application Layer. - - @param local_ip: Host name (DNS resolved) or IP address of remote endpoint. Default: 0.0.0.0. - @param port: Port remote endpoint is listening on. Default: 20000. - @param outstation_config: A dictionary of configuration parameters. All are optional. Parameters include: - database_sizes: (integer) Size of the Outstation's point database, by point type. Default: 10000. - event_buffers: (integer) Size of the database event buffers. Default: 10. - allow_unsolicited: (boolean) Whether to allow unsolicited requests. Default: True. - link_local_addr: (integer) Link layer local address. Default: 10. - link_remote_addr: (integer) Link layer remote address. Default: 1. - log_levels: List of bit field names (OR'd together) that filter what gets logged by DNP3. Default: [NORMAL]. - Possible values: ALL, ALL_APP_COMMS, ALL_COMMS, NORMAL, NOTHING - threads_to_allocate: (integer) Threads to allocate in the manager's thread pool. Default: 1. - """ - super(DNP3Outstation, self).__init__() - self.local_ip = local_ip - self.port = port - self.set_outstation_config(outstation_config) - # The following variables are initialized after start() is called. - self.stack_config = None - self.log_handler = None - self.manager = None - self.retry_parameters = None - self.listener = None - self.channel = None - self.command_handler = None - - def start(self): - _log.debug('Configuring the DNP3 stack.') - self.stack_config = asiodnp3.OutstationStackConfig(opendnp3.DatabaseSizes.AllTypes(self.outstation_config.get('database_sizes', 10000))) - self.stack_config.outstation.eventBufferConfig = opendnp3.EventBufferConfig.AllTypes(self.outstation_config.get('event_buffers', 10)) - self.stack_config.outstation.params.allowUnsolicited = self.outstation_config.get('allow_unsolicited', True) - self.stack_config.link.LocalAddr = self.outstation_config.get('link_local_addr', 10) - self.stack_config.link.RemoteAddr = self.outstation_config.get('link_remote_addr', 1) - self.stack_config.link.KeepAliveTimeout = openpal.TimeDuration().Max() - - # Configure the outstation database of points based on the contents of the data dictionary. - _log.debug('Configuring the DNP3 Outstation database.') - db_config = self.stack_config.dbConfig - for point in self.get_agent().point_definitions.all_points(): - if point.data_type == 'Analog Input': - cfg = db_config.analog[int(point.index)] - elif point.data_type == 'Binary Input': - cfg = db_config.binary[int(point.index)] - else: - # This database's point configuration is limited to Binary and Analog data types. - cfg = None - if cfg: - # cfg.vIndex = virtual index of the point - cfg.clazz = point.eclass - # cfg.svariation and cfg.evariation are static const: cannot modify - - _log.debug('Creating a DNP3Manager.') - threads_to_allocate = self.outstation_config.get('threads_to_allocate', 1) - # self.log_handler = asiodnp3.ConsoleLogger().Create() # (or use this during regression testing) - # self.log_handler = MyLogger().Create() - self.log_handler = MyLogger() - self.manager = asiodnp3.DNP3Manager(threads_to_allocate, self.log_handler) - - _log.debug('Creating the DNP3 channel, a TCP server.') - self.retry_parameters = asiopal.ChannelRetry().Default() - # self.listener = asiodnp3.PrintingChannelListener().Create() # (or use this during regression testing) - self.listener = AppChannelListener() - self.channel = self.manager.AddTCPServer("server", - self.dnp3_log_level(), - self.retry_parameters, - self.local_ip, - self.port, - self.listener) - - _log.debug('Adding the DNP3 Outstation to the channel.') - # self.command_handler = opendnp3.SuccessCommandHandler().Create() # (or use this during regression testing) - self.command_handler = OutstationCommandHandler() - self.outstation = self.channel.AddOutstation("outstation", self.command_handler, self, self.stack_config) - - # Set the singleton instance that communicates with the Master. - self.set_outstation(self.outstation) - - _log.info('Enabling the DNP3 Outstation. Traffic can now start to flow.') - self.outstation.Enable() - - def reload_parameters(self, local_ip, port, outstation_config): - _log.debug('In reload_parameters') - self.local_ip = local_ip - self.port = port - self.outstation_config = outstation_config - - @classmethod - def get_agent(cls): - """Return the singleton DNP3Agent or MesaAgent instance.""" - agt = cls.agent - if agt is None: - raise ValueError('Outstation has no configured agent') - return agt - - @classmethod - def set_agent(cls, agent): - """Set the singleton DNP3Agent or MesaAgent instance.""" - cls.agent = agent - - @classmethod - def get_outstation(cls): - """Get the singleton instance of IOutstation.""" - outst = cls.outstation - if outst is None: - raise AttributeError('IOutstation is not yet enabled') - return outst - - @classmethod - def set_outstation(cls, outstn): - """ - Set the singleton instance of IOutstation, as returned from the channel's AddOutstation call. - - Making IOutstation available as a singleton allows other classes - to send commands to it -- see apply_update(). - """ - cls.outstation = outstn - - @classmethod - def get_outstation_config(cls): - """Get the outstation_config, a dictionary of configuration parameters.""" - return cls.outstation_config - - @classmethod - def set_outstation_config(cls, outstn_cfg): - """ - Set the outstation_config. - - It's managed as a class variable so that it can be examined by the class method apply_update(). - - :param outstn_cfg: A dictionary of configuration parameters. - """ - cls.outstation_config = outstn_cfg - - def dnp3_log_level(self): - """ - Return a bit-encoded integer that indicates the level of DNP3 logging. - - If a list of level names is specified in the Outstation config, - use a union of those names to construct the integer. Otherwise return the default log level. - """ - log_level_list = self.outstation_config.get('log_levels', ['NORMAL']) - # log_level_list should be a list of strings. If it's not (e.g., if it's a simple string), fail. - if not isinstance(log_level_list, list): - raise TypeError('log_levels should be configured as a list of strings, not as {}'.format(log_level_list)) - log_level_list = [s.upper() for s in log_level_list] - - name_to_bitmasks = { - 'ALL': opendnp3.levels.ALL, - 'ALL_APP_COMMS': opendnp3.levels.ALL_APP_COMMS, - 'ALL_COMMS': opendnp3.levels.ALL_COMMS, - 'NORMAL': opendnp3.levels.NORMAL, - 'NOTHING': opendnp3.levels.NOTHING - } - log_level = 0 - for name in log_level_list: - log_level = log_level | name_to_bitmasks.get(name, 0) - - _log.debug('Setting DNP3 log level={} ({})'.format(log_level, log_level_list)) - return log_level - - # Overridden method - def ColdRestartSupport(self): - """Return a RestartMode enumerated type value indicating whether cold restart is supported.""" - _log.debug('In DNP3 ColdRestartSupport') - return opendnp3.RestartMode.UNSUPPORTED - - # Overridden method - def GetApplicationIIN(self): - """Return the application-controlled IIN field.""" - application_iin = opendnp3.ApplicationIIN() - application_iin.configCorrupt = False - application_iin.deviceTrouble = False - application_iin.localControl = False - application_iin.needTime = False - iin_field = application_iin.ToIIN() - # Experiment with setting iin_field to an error value, e.g. configCorrupt to indicate that - # a point couldn't be found in the Outstation's database. - # Other interesting IIN values might be PARAM_ERROR, ALREADY_EXECUTING, FUNC_NOT_SUPPORTED. - if iin_field.LSB != 0 or iin_field.MSB != 0: - status_string = 'IINField LSB={}, MSB={}'.format(iin_field.LSB, iin_field.MSB) - DNP3Outstation.get_agent().publish_outstation_status(status_string) - return application_iin - - # Overridden method - def SupportsAssignClass(self): - _log.debug('In DNP3 SupportsAssignClass') - return False - - # Overridden method - def SupportsWriteAbsoluteTime(self): - _log.debug('In DNP3 SupportsWriteAbsoluteTime') - return False - - # Overridden method - def SupportsWriteTimeAndInterval(self): - _log.debug('In DNP3 SupportsWriteTimeAndInterval') - return False - - # Overridden method - def WarmRestartSupport(self): - """Return a RestartMode enumerated value indicating whether a warm restart is supported.""" - _log.debug('In DNP3 WarmRestartSupport') - return opendnp3.RestartMode.UNSUPPORTED - - @classmethod - def apply_update(cls, value, index): - """ - Record an opendnp3 data value (Analog, Binary, etc.) in the outstation's database. - - The data value gets sent to the Master as a side-effect. - - :param value: An instance of Analog, Binary, or another opendnp3 data value. - :param index: (integer) Index of the data definition in the opendnp3 database. - """ - _log.debug('Recording DNP3 {} measurement, index={}, value={}'.format(type(value).__name__, index, value.value)) - max_index = cls.get_outstation_config().get('database_sizes', 10000) - if index > max_index: - raise ValueError('Attempt to set a value for index {} which exceeds database size {}'.format(index, - max_index)) - builder = asiodnp3.UpdateBuilder() - builder.Update(value, index) - update = builder.Build() - try: - cls.get_outstation().Apply(update) - except AttributeError as err: - if not os.environ.get('UNITTEST', False): - raise err - - def shutdown(self): - """ - Execute an orderly shutdown of the Outstation. - - The debug messages may be helpful if errors occur during shutdown. - """ - _log.debug('Exiting DNP3 Outstation module...') - self.manager.Shutdown() - _log.debug('Garbage collecting DNP3 Outstation...') - self.set_outstation(None) - _log.debug('Garbage collecting DNP3 stack config...') - self.stack_config = None - _log.debug('Garbage collecting DNP3 channel...') - self.channel = None - _log.debug('Garbage collecting DNP3Manager...') - self.manager = None - - -class OutstationCommandHandler(opendnp3.ICommandHandler): - """ - ICommandHandler implements the Outstation's handling of Select and Operate, - which relay commands and data from the Master to the Outstation. - """ - - def Start(self): - # This debug line is too chatty... - # _log.debug('In DNP3 OutstationCommandHandler.Start') - pass - - def End(self): - # This debug line is too chatty... - # _log.debug('In DNP3 OutstationCommandHandler.End') - pass - - def Select(self, command, index): - """ - The Master sent a Select command to the Outstation. Handle it. - - :param command: ControlRelayOutputBlock, - AnalogOutputInt16, AnalogOutputInt32, AnalogOutputFloat32, or AnalogOutputDouble64. - :param index: int - :return: CommandStatus - """ - return DNP3Outstation.get_agent().process_point_value('Select', command, index, None) - - def Operate(self, command, index, op_type): - """ - The Master sent an Operate command to the Outstation. Handle it. - - :param command: ControlRelayOutputBlock, - AnalogOutputInt16, AnalogOutputInt32, AnalogOutputFloat32, or AnalogOutputDouble64. - :param index: int - :param op_type: OperateType - :return: CommandStatus - """ - return DNP3Outstation.get_agent().process_point_value('Operate', command, index, op_type) - - -class AppChannelListener(asiodnp3.IChannelListener): - """ - IChannelListener has been overridden to implement application-specific channel behavior. - """ - - def __init__(self): - super(AppChannelListener, self).__init__() - - def OnStateChange(self, state): - """ - There has been an outstation state change. Publish the new state to the message bus. - - :param state: A ChannelState. - """ - DNP3Outstation.get_agent().publish_outstation_status(str(state)) - - -# class MyLogger(asiodnp3.ConsoleLogger): -class MyLogger(openpal.ILogHandler): - """ - ILogHandler has been overridden to implement application-specific logging behavior. - """ - - def __init__(self): - super(MyLogger, self).__init__() - self.tcp_client = None - - def Log(self, entry): - """Write a DNP3 log entry to the logger (debug level).""" - location = entry.location.rsplit('/')[-1] if entry.location else '' - filters = entry.filters.GetBitfield() - message = entry.message - - if "Accepted connection from" in message: - self.tcp_client = message.split(": ")[1] - - _log.debug('DNP3Log {0}\t(filters={1}) {2}'.format(location, filters, message)) - # This is here as an example of how to send a specific log entry to the message bus as outstation status. - # if 'Accepted connection' in message or 'Listening on' in message: - # DNP3Outstation.get_agent().publish_outstation_status(str(message)) - - -def main(): - """The Outstation has been started from the command line. Execute ad-hoc tests if desired.""" - dnp3_outstation = DNP3Outstation('0.0.0.0', 20000, {}) - dnp3_outstation.start() - _log.debug('DNP3 initialization complete. In command loop.') - # Ad-hoc tests can be performed at this point if desired. - dnp3_outstation.shutdown() - _log.debug('DNP3 Outstation exiting.') - exit() - -if __name__ == '__main__': - main() diff --git a/services/core/DNP3Agent/dnp3/points.py b/services/core/DNP3Agent/dnp3/points.py deleted file mode 100644 index eec4f3431a..0000000000 --- a/services/core/DNP3Agent/dnp3/points.py +++ /dev/null @@ -1,615 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, SLAC / 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared in part as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor SLAC, nor 8minutenergy, nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# SLAC, 8minutenergy, or Kisensum. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# }}} - -from datetime import datetime -import logging -import os -import pytz -import re - -from volttron.platform import jsonapi -from pydnp3 import opendnp3 -from dnp3 import POINT_TYPES, POINT_TYPE_SELECTOR_BLOCK, POINT_TYPE_ENUMERATED, POINT_TYPE_ARRAY -from dnp3 import DATA_TYPE_ANALOG_INPUT, DATA_TYPE_ANALOG_OUTPUT, DATA_TYPE_BINARY_INPUT, DATA_TYPE_BINARY_OUTPUT -from dnp3 import EVENT_CLASSES, DATA_TYPES_BY_GROUP -from dnp3 import DEFAULT_GROUP_BY_DATA_TYPE, DEFAULT_EVENT_CLASS -from dnp3 import PUBLISH_AND_RESPOND - -_log = logging.getLogger(__name__) - - -class DNP3Exception(Exception): - """Raise exceptions that are specific to the DNP3 agent. No special exception behavior is needed at this time.""" - pass - - -class PointDefinitions: - """In-memory repository of PointDefinitions.""" - - def __init__(self, point_definitions_path=None): - self._points = {} # {data_type: {point_index: PointDefinition}} - self._point_name_dict = {} # {point_name: [PointDefinition]} - if point_definitions_path: - file_path = os.path.expandvars(os.path.expanduser(point_definitions_path)) - self.load_points_from_json_file(file_path) - - def __getitem__(self, name): - """Return the PointDefinition associated with this name. Must be unique.""" - if name in [None, 'n/a']: - return None - return self.get_point_named(name) - - def load_points_from_json_file(self, point_definitions_path): - """Load and cache a dictionary of PointDefinitions, indexed by point_type and point index.""" - if point_definitions_path: - try: - file_path = os.path.expandvars(os.path.expanduser(point_definitions_path)) - _log.debug('Loading DNP3 point definitions from {}.'.format(file_path)) - with open(file_path, 'r') as f: - # Filter comments out of the file's contents before loading it as jsonapi. - self.load_points(jsonapi.loads(self.strip_comments(f.read()))) - except Exception as err: - raise ValueError('Problem parsing {}. Error={}'.format(point_definitions_path, err)) - else: - _log.debug('No point_definitions_path specified, loading no points') - - def strip_comments(self, raw_string): - """ - Return a string with comments stripped. - - Both JavaScript-style comments (//... and /*...*/) and hash (#...) comments are removed. - Thanks to VOLTTRON volttron/platform/agent/utils.py/strip_comments() for this logic. - """ - def _repl(match): - return match.group(1) or '' - - _comment_re = re.compile(r'((["\'])(?:\\?.)*?\2)|(/\*.*?\*/)|((?:#|//).*?(?=\n|$))', re.MULTILINE | re.DOTALL) - return _comment_re.sub(_repl, raw_string) - - def load_points(self, point_definitions_json): - """Load and cache a dictionary of PointDefinitions, indexed by point_type and point index.""" - try: - self._points = {} # If they're already loaded, force a reload. - for element in point_definitions_json: - # Load a PointDefinition (or subclass) from JSON, and add it to the dictionary of points. - # If the point defines an array, load additional definitions for each interior point in the array. - try: - if element.get('type', None) != POINT_TYPE_ARRAY: - point_def = PointDefinition(element) - self.update_point(point_def) - else: - point_def = ArrayHeadPointDefinition(element) - self.update_point(point_def) - # Load a separate ArrayPointDefinition for each interior point in the array. - for pt in point_def.create_array_point_definitions(element): - self.update_point(pt) - except ValueError as err: - raise DNP3Exception('Validation error for point with json: {}: {}'.format(element, err)) - except Exception as err: - raise ValueError('Problem parsing PointDefinitions. Error={}'.format(err)) - _log.debug('Loaded {} PointDefinitions'.format(len(self.all_points()))) - - def update_point(self, point_def): - """Add a PointDefinition to self._points and self._point_name_dict.""" - data_type, name, index = point_def.data_type, point_def.name, point_def.index - data_type_dict = self._points.setdefault(data_type, {}) - name_lst = self._point_name_dict.setdefault(name, []) - if index in data_type_dict: - raise ValueError('Duplicate index {} for data type {}'.format(index, data_type)) - if name_lst and point_def.type != 'array': - raise ValueError('Duplicated point name {}'.format(name)) - data_type_dict[index] = point_def - name_lst.append(point_def) - - def for_group_and_index(self, group, index): - """Return a PointDefinition for given group and index""" - data_type = DATA_TYPES_BY_GROUP.get(group, None) - if not data_type: - _log.error('No DNP3 point type found for group {}'.format(group)) - return self._points.get(data_type, {}).get(index, None) - - def point_value_for_command(self, command_type, command, index, op_type): - """ - A DNP3 Select or Operate was received from the master. Create and return a PointValue for its data. - - :param command_type: Either 'Select' or 'Operate'. - :param command: A ControlRelayOutputBlock or else a wrapped data value (AnalogOutputInt16, etc.). - :param index: DNP3 index of the payload's data definition. - :param op_type: An OperateType, or None if command_type == 'Select'. - :return: An instance of PointValue - """ - function_code = command.functionCode if type(command) == opendnp3.ControlRelayOutputBlock else None - data_type = DATA_TYPE_BINARY_OUTPUT if function_code else DATA_TYPE_ANALOG_OUTPUT - point_def = self.for_data_type_and_index(data_type, index) - if not point_def: - raise DNP3Exception('No DNP3 PointDefinition found for point type {} and index {}'.format(data_type, index)) - point_value = PointValue(command_type, - function_code, - command.value if not function_code else None, - point_def, - index, - op_type) - _log.debug('Received DNP3 {}'.format(point_value)) - return point_value - - def for_data_type_and_index(self, data_type, index): - """ - Return a PointDefinition for given data type and index. - - @param data_type: A data type (string). - @param index: Unique integer index of the PointDefinition to be looked up. - """ - return self._points.get(data_type, {}).get(index, None) - - def point_named(self, name, index=None): - """ - Return the PointDefinition with the indicated name and (optionally) index, or None if no match. - - :param name: (string) The point's name. - :param index: (integer) An optional index value. If supplied, search for an array point at this DNP3 index. - """ - point_def_list = self._point_name_dict.get(name, None) - if point_def_list is None: - return None # No points with that name - - if index is not None: - # Return the PointDefinition with a matching index. - for pt in point_def_list: - if pt.index == index: - return pt - return None - - # In multi-element lists, give preference to the ArrayHeadPointDefinition. - for pt in point_def_list: - if pt.is_array_head_point: - return pt - return point_def_list[0] - - def get_point_named(self, name, index=None): - """ - Return the PointDefinition with the indicated name and (optionally) index. - Raise an exception if none found. - - :param name: (string) The point's name. - :param index: (integer) An optional index value. If supplied, search for an array point at this DNP3 index. - :return A PointDefinition. - """ - point_def = self.point_named(name, index=index) - if point_def is None: - if index is not None: - raise DNP3Exception('No point named {} with index {}'.format(name, index)) - else: - raise DNP3Exception('No point named {}'.format(name)) - return point_def - - def all_points(self): - """Return a flat list of all PointDefinitions.""" - point_list = [] - for inner_dict in self._points.values(): - point_list.extend(inner_dict.values()) - return point_list - - -class BasePointDefinition: - """Abstract superclass for PointDefinition data holders.""" - - def __init__(self, element_def): - """Initialize an instance of the PointDefinition from a dictionary of point attributes.""" - self.name = str(element_def.get('name', '')) - self.data_type = element_def.get('data_type', None) - self.index = element_def.get('index', None) - self.type = element_def.get('type', None) - self.description = element_def.get('description', '') - self.scaling_multiplier = element_def.get('scaling_multiplier', 1) # Only used for Analog data_type - self.units = element_def.get('units', '') - self.event_class = element_def.get('event_class', DEFAULT_EVENT_CLASS) - self.selector_block_start = element_def.get('selector_block_start', None) - self.selector_block_end = element_def.get('selector_block_end', None) - self.action = element_def.get('action', None) - self.response = element_def.get('response', None) - self.category = element_def.get('category', None) - self.ln_class = element_def.get('ln_class', None) - self.data_object = element_def.get('data_object', None) - self.common_data_class = element_def.get('common_data_class', None) - self.minimum = element_def.get('minimum', -2147483648) # Only used for Analog data_type - self.maximum = element_def.get('maximum', 2147483647) # Only used for Analog data_type - self.scaling_offset = element_def.get('scaling_offset', 0) # Only used for Analog data_type - self.allowed_values = self.convert_allowed_values(element_def.get('allowed_values', None)) - - @property - def is_enumerated(self): - return self.type == POINT_TYPE_ENUMERATED - - @property - def is_array_point(self): - return False - - @property - def is_array_head_point(self): - return False - - @property - def is_array(self): - return self.is_array_point or self.is_array_head_point - - def convert_allowed_values(self, allowed_values): - if allowed_values: - return {int(str_val): description for str_val, description in allowed_values.items()} - return None - - def validate_point(self): - """A PointDefinition has been created. Perform a variety of validations on it.""" - if not self.name: - raise ValueError('Missing point name') - if self.index is None: - raise ValueError('Missing index for point {}'.format(self.name)) - if not self.data_type: - raise ValueError('Missing data type for point {}'.format(self.name)) - if self.data_type not in DEFAULT_GROUP_BY_DATA_TYPE: - raise ValueError('Invalid data type {} for point {}'.format(self.data_type, self.name)) - if not self.eclass: - raise ValueError('Invalid event class {} for point {}'.format(self.event_class, self.name)) - if self.type and self.type not in POINT_TYPES: - raise ValueError('Invalid type {} for point {}'.format(self.type, self.name)) - if self.action == PUBLISH_AND_RESPOND and not self.response: - raise ValueError('Missing response point name for point {}'.format(self.name)) - if self.is_enumerated and not self.allowed_values: - raise ValueError('Missing allowed values mapping for point {}'.format(self.name)) - if self.is_selector_block: - if self.selector_block_start is None: - raise ValueError('Missing selector_block_start for block named {}'.format(self.name)) - if self.selector_block_end is None: - raise ValueError('Missing selector_block_end for block named {}'.format(self.name)) - if self.selector_block_start > self.selector_block_end: - raise ValueError('Selector block end index < start index for block named {}'.format(self.name)) - else: - if self.selector_block_start is not None: - raise ValueError('selector_block_start defined for non-selector-block point {}'.format(self.name)) - if self.selector_block_end is not None: - raise ValueError('selector_block_end defined for non-selector-block point {}'.format(self.name)) - - def as_json(self): - """Return a json description of the PointDefinition.""" - point_json = { - "name": self.name, - "data_type": self.data_type, - "index": self.index, - "group": self.group, - "event_class": self.event_class - } - if self.type: - point_json["type"] = self.type - if self.description: - point_json["description"] = self.description - if self.units: - point_json["units"] = self.units - if self.selector_block_start is not None: - point_json["selector_block_start"] = self.selector_block_start - if self.selector_block_end is not None: - point_json["selector_block_end"] = self.selector_block_end - if self.allowed_values: - point_json["allowed_values"] = self.allowed_values - if self.action: - point_json["action"] = self.action - if self.response: - point_json["response"] = self.response - if self.category: - point_json["category"] = self.category - if self.ln_class: - point_json["ln_class"] = self.ln_class - if self.data_object: - point_json["data_object"] = self.data_object - if self.common_data_class: - point_json["common_data_class"] = self.common_data_class - if self.data_type in [DATA_TYPE_ANALOG_INPUT, DATA_TYPE_ANALOG_OUTPUT]: - point_json.update({ - "scaling_multiplier": self.scaling_multiplier, - "scaling_offset": self.scaling_offset, - "minimum": self.minimum, - "maximum": self.maximum - }) - - return point_json - - def __str__(self): - """Return a string description of the PointDefinition.""" - try: - return '{0} {1} (event_class={2}, index={3}, type={4})'.format( - self.__class__.__name__, - self.name, - self.event_class, - self.index, - self.data_type - ) - except UnicodeEncodeError as err: - _log.error('Unable to convert point definition to string, err = {}'.format(err)) - return '' - - @property - def group(self): - return DEFAULT_GROUP_BY_DATA_TYPE.get(self.data_type, None) - - @property - def is_input(self): - """Return True if the PointDefinition is a Binary or Analog input point (i.e., sent by the Outstation).""" - return self.data_type in [DATA_TYPE_ANALOG_INPUT, DATA_TYPE_BINARY_INPUT] - - @property - def is_output(self): - """Return True if the PointDefinition is a Binary or Analog output point (i.e., sent by the Master).""" - return self.data_type in [DATA_TYPE_ANALOG_OUTPUT, DATA_TYPE_BINARY_OUTPUT] - - @property - def is_selector_block(self): - return self.type == POINT_TYPE_SELECTOR_BLOCK - - @property - def eclass(self): - """Return the PointDefinition's event class, or the default (2) if no event class was defined for the point.""" - return EVENT_CLASSES.get(self.event_class, None) - - -class PointDefinition(BasePointDefinition): - """Data holder for an OpenDNP3 data element.""" - - def __init__(self, element_def): - """Initialize an instance of the PointDefinition from a dictionary of point attributes.""" - super(PointDefinition, self).__init__(element_def) - self.validate_point() - - def validate_point(self): - """A PointDefinition has been created. Perform a variety of validations on it.""" - super(PointDefinition, self).validate_point() - if self.type and self.type not in ['selector_block', 'enumerated']: - raise ValueError('Invalid type for {}: {}'.format(self.name, self.type)) - - -class ArrayHeadPointDefinition(BasePointDefinition): - """Data holder for an OpenDNP3 data element that is the head point in an array.""" - - def __init__(self, json_element): - """ - Initialize an ArrayPointDefinition instance. - An ArrayPointDefinition defines an interior point (not the head point) in an array. - - :param json_element: A JSON dictionary of point attributes. - """ - super(ArrayHeadPointDefinition, self).__init__(json_element) - self.array_points = json_element.get('array_points', None) - self.array_times_repeated = json_element.get('array_times_repeated', None) - self.array_point_definitions = [] # Holds all ArrayPointDefinitions belonging to this array. - self.validate_point() - - def validate_point(self): - """An ArrayHeadPointDefinition has been created. Perform a variety of validations on it.""" - super(ArrayHeadPointDefinition, self).validate_point() - if self.type != 'array': - raise ValueError('Invalid type {} for array named {}'.format(self.type, self.name)) - if self.array_points is None: - raise ValueError('Missing array_points for array named {}'.format(self.name)) - if self.array_times_repeated is None: - raise ValueError('Missing array_times_repeated for array named {}'.format(self.name)) - - @property - def is_array_point(self): - return True - - @property - def is_array_head_point(self): - return True - - def as_json(self): - """Return a json description of the ArrayHeadPointDefinition.""" - point_json = super(ArrayHeadPointDefinition, self).as_json() - # array_points has been excluded because it's not a simple data type. Is it needed in the json? - # if self.array_points is not None: - # point_json["array_points"] = self.array_points - if self.array_times_repeated is not None: - point_json["array_times_repeated"] = self.array_times_repeated - return point_json - - @property - def array_last_index(self): - """Calculate and return the array's last index value.""" - if self.is_array_head_point: - return self.index + self.array_times_repeated * len(self.array_points) - 1 - else: - return None - - def create_array_point_definitions(self, element): - """Create a separate ArrayPointDefinition for each interior point in the array.""" - for row_number in range(self.array_times_repeated): - for column_number, pt in enumerate(self.array_points): - # The ArrayHeadPointDefinition is already defined -- don't create a redundant definition. - if row_number > 0 or column_number > 0: - array_pt_def = ArrayPointDefinition(element, self, row_number, column_number, pt['name']) - self.array_point_definitions.append(array_pt_def) - return self.array_point_definitions - - -class ArrayPointDefinition(BasePointDefinition): - """Data holder for an OpenDNP3 data element that is interior to an array.""" - - def __init__(self, json_element, base_point_def, row, column, array_element_name): - """ - Initialize an ArrayPointDefinition instance. - An ArrayPointDefinition defines an interior point (not the head point) in an array. - - :param json_element: A JSON dictionary of point attributes. - :param base_point_def: The PointDefinition of the head point in the array. - :param row: The point's row number in the array. - :param column: The point's column number in the array. - :param array_element_name: The point's column name in the array. - """ - super(ArrayPointDefinition, self).__init__(json_element) - self.base_point_def = base_point_def - self.row = row - self.column = column - self.index = self.base_point_def.index + row * len(self.base_point_def.array_points) + column - self.array_element_name = array_element_name - self.validate_point() - - def validate_point(self): - """An ArrayPointDefinition has been created. Perform a variety of validations on it.""" - super(ArrayPointDefinition, self).validate_point() - if self.type != 'array': - raise ValueError('Invalid type {} for array named {}'.format(self.type, self.name)) - if self.base_point_def is None: - raise ValueError('Missing base point definition for array point named {}'.format(self.name)) - if self.row is None: - raise ValueError('Missing row number for array point named {}'.format(self.name)) - if self.column is None: - raise ValueError('Missing column number for array point named {}'.format(self.name)) - if self.index is None: - raise ValueError('Missing index value for array point named {}'.format(self.name)) - if self.array_element_name is None: - raise ValueError('Missing array element name for array point named {}'.format(self.name)) - - @property - def is_array_point(self): - return True - - @property - def is_array_head_point(self): - return False - - def as_json(self): - """Return a json description of the ArrayPointDefinition.""" - point_json = super(ArrayPointDefinition, self).as_json() - if self.row is not None: - point_json["row"] = self.row - if self.row is not None: - point_json["column"] = self.column - if self.row is not None: - point_json["array_element_name"] = self.array_element_name - return point_json - - -class PointValue: - """Data holder for a point value (DNP3 measurement or command) received by an outstation.""" - - def __init__(self, command_type, function_code, value, point_def, index, op_type): - """Initialize an instance of the PointValue.""" - # Don't rely on VOLTTRON utils in this code, which may run outside of VOLTTRON - # self.when_received = utils.get_aware_utc_now() - self.when_received = pytz.UTC.localize(datetime.utcnow()) - self.command_type = command_type - self.function_code = function_code - self.value = value - self.point_def = point_def - self.index = index # MESA Array point indexes can differ from the indexes of their PointDefinitions. - self.op_type = op_type - - def __str__(self): - """Return a string description of the PointValue.""" - str_desc = 'Point value {0} ({1}, {2}.{3}, {4})' - return str_desc.format(self.value or self.function_code, - self.name, - self.point_def.event_class, - self.index, - self.command_type) - - @property - def name(self): - """Return the name of the PointDefinition.""" - return self.point_def.name - - def unwrapped_value(self): - """Unwrap the point's value, returning the sample data type (e.g. an integer, binary, etc. instance).""" - if self.value is None: - # For binary commands, send True if function_code is LATCH_ON, False otherwise - return self.function_code == opendnp3.ControlCode.LATCH_ON - else: - return self.value - - -class PointArray: - """Data holder for a MESA-ESS Array.""" - - def __init__(self, point_def): - """ - The "points" variable is a dictionary of dictionaries: - 0: { - 0: PointValue, - 1: PointValue - }, - 1: { - 0: PointValue, - 1: PointValue - } - (etc.) - It's stored as dictionaries indexed by index numbers, not as lists, - because there's no guarantee that array elements will arrive in order. - - :param point_def: The PointDefinition of the array's head point. - """ - _log.debug('New Array {} starting at {} with bounds ({}, {})'.format(point_def.name, - point_def.index, - point_def.index, - point_def.array_last_index)) - self.point_def = point_def - self.points = {} - - def __str__(self): - return 'Array, points = {}'.format(self.points) - - def as_json(self): - """ - Return a JSON representation of the PointArray: - - [ - {name1: val1a, name2: val2a, ...}, - {name1: val1b, name2: val2b, ...}, - ... - ] - """ - names = [d['name'] for d in self.point_def.array_points] - json_array = [] - for pt_dict_key in sorted(self.points): - pt_dict = self.points[pt_dict_key] - json_array.append({name: (pt_dict[i].value if i in pt_dict else None) for i, name in enumerate(names)}) - return json_array - - def contains_index(self, index): - """Answer whether this Array contains the point index.""" - return self.point_def.index <= index <= self.point_def.array_last_index - - def add_point_value(self, point_value): - """Add point_value to the Array's "points" dictionary.""" - point_def = point_value.point_def - row = 0 if point_def.is_array_head_point else point_def.row - col = 0 if point_def.is_array_head_point else point_def.column - if row not in self.points: - self.points[row] = {} - self.points[row][col] = point_value diff --git a/services/core/DNP3Agent/dnp3_master.py b/services/core/DNP3Agent/dnp3_master.py deleted file mode 100644 index 166026959f..0000000000 --- a/services/core/DNP3Agent/dnp3_master.py +++ /dev/null @@ -1,517 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - -import logging - -from pydnp3 import opendnp3, openpal, asiopal, asiodnp3 - -_log = logging.getLogger(__name__) - - -class DNP3Master: - """ - Interface for all master application callback info except for measurement values. - """ - - def __init__(self, - log_levels=opendnp3.levels.NORMAL | opendnp3.levels.ALL_APP_COMMS, - host_ip="127.0.0.1", # presumably outstation - local_ip="0.0.0.0", - port=20000, - log_handler=asiodnp3.ConsoleLogger().Create(), - channel_listener=asiodnp3.PrintingChannelListener().Create(), - soe_handler=asiodnp3.PrintingSOEHandler().Create(), - platform_application=asiodnp3.DefaultMasterApplication().Create(), - stack_config=None): - - self.log_levels = log_levels - self.host_ip = host_ip - self.local_ip = local_ip - self.port = port - self.log_handler = log_handler - self.channel_listener = channel_listener - self.soe_handler = soe_handler - self.platform_application = platform_application - - self.stackConfig = stack_config - if not self.stackConfig: - # The master config object for a master. - self.stackConfig = asiodnp3.MasterStackConfig() - self.stackConfig.master.responseTimeout = openpal.TimeDuration().Seconds(2) - self.stackConfig.link.RemoteAddr = 10 - - self.manager = None - self.channel = None - self.master = None - - def connect(self): - """Connect to an outstation, add an master to the channel, and start the communications.""" - - # Root DNP3 object used to create channels and sessions - if not self.manager: - self.manager = asiodnp3.DNP3Manager(1, self.log_handler) - - # Connect via a TCPClient socket to a outstation - self.channel = self.manager.AddTCPClient("tcpclient", - self.log_levels, - asiopal.ChannelRetry(), - self.host_ip, - self.local_ip, - self.port, - self.channel_listener) - - # Create a new master on a previously declared port, with a name, log level, command acceptor, and config info. - # This returns a thread-safe interface used for sending commands. - self.master = self.channel.AddMaster("master", - self.soe_handler, - self.platform_application, - self.stackConfig) - - # Enable the master. This will start communications. - self.master.Enable() - - def reconnect(self, host_ip, port): - """Reconnect master to a different host and port and start the communications.""" - if self.master: - self.master.Disable() - - if self.channel: - self.channel.Shutdown() - - self.host_ip = host_ip - self.port = port - self.connect() - - def send_read_command(self, group, variation, index): - """ - Request to read a point data from outstation - - :param group: group of the point data - :param variation: variation of the point data - :param index: index of the point data - :param data_type: 'analog' or 'binary' - """ - self.master.PerformFunction('READ', - opendnp3.FunctionCode.READ, - [opendnp3.Header().Range16(group, variation, index, index + 1)]) - - def send_unsolicited_response_command(self, group, variation, index): - """ - Unsolicited response that was not prompted by an explicit request - - :param group: group of the point data - :param variation: variation of the point data - :param index: index of the point data - :param data_type: 'analog' or 'binary' - """ - self.master.PerformFunction('UNSOLICITED_RESPONSE', - opendnp3.FunctionCode.UNSOLICITED_RESPONSE, - [opendnp3.Header().Range16(group, variation, index, index + 1)]) - - def send_direct_operate_command(self, command, index, callback=asiodnp3.PrintingCommandCallback.Get(), - config=opendnp3.TaskConfig().Default()): - """ - Direct operate a single command - - :param command: command to operate - :param index: index of the command - :param callback: callback that will be invoked upon completion or failure - :param config: optional configuration that controls normal callbacks and allows the user to be specified for SA - """ - self.master.DirectOperate(command, index, callback, config) - - def send_direct_operate_command_set(self, command_set, callback=asiodnp3.PrintingCommandCallback.Get(), - config=opendnp3.TaskConfig().Default()): - """ - Direct operate a set of commands - - :param command_set: set of command headers - :param callback: callback that will be invoked upon completion or failure - :param config: optional configuration that controls normal callbacks and allows the user to be specified for SA - """ - self.master.DirectOperate(command_set, callback, config) - - def send_select_and_operate_command(self, command, index, callback=asiodnp3.PrintingCommandCallback.Get(), - config=opendnp3.TaskConfig().Default()): - """ - Select and operate a single command - - :param command: command to operate - :param index: index of the command - :param callback: callback that will be invoked upon completion or failure - :param config: optional configuration that controls normal callbacks and allows the user to be specified for SA - """ - self.master.SelectAndOperate(command, index, callback, config) - - def send_select_and_operate_command_set(self, command_set, callback=asiodnp3.PrintingCommandCallback.Get(), - config=opendnp3.TaskConfig().Default()): - """ - Select and operate a set of commands - - :param command_set: set of command headers - :param callback: callback that will be invoked upon completion or failure - :param config: optional configuration that controls normal callbacks and allows the user to be specified for SA - """ - self.master.SelectAndOperate(command_set, callback, config) - - def shutdown(self): - """ - Shutdown manager and terminate the threadpool - """ - del self.master - del self.channel - if self.manager: - self.manager.Shutdown() - - -class VisitorIndexedBinary(opendnp3.IVisitorIndexedBinary): - """ - Override IVisitorIndexedBinary in this manner to implement visiting elements of IndexedBinary collection. - - This is used in SOEHandler callback. - """ - - def __init__(self): - super(VisitorIndexedBinary, self).__init__() - self.index_and_value = [] - - def OnValue(self, indexed_instance): - """ - Process current value visiting. - - :param indexed_instance: current value visiting, an instance of IndexedBinary - """ - self.index_and_value.append((indexed_instance.index, indexed_instance.value.value)) - - -class VisitorIndexedDoubleBitBinary(opendnp3.IVisitorIndexedDoubleBitBinary): - """ - Override IVisitorIndexedDoubleBitBinary in this manner to implement visiting elements of IndexedDoubleBitBinary - collection. - - This is used in SOEHandler callback. - """ - - def __init__(self): - super(VisitorIndexedDoubleBitBinary, self).__init__() - self.index_and_value = [] - - def OnValue(self, indexed_instance): - """ - Process current value visiting. - - :param indexed_instance: current value visiting, an instance of IndexedDoubleBitBinary - """ - self.index_and_value.append((indexed_instance.index, indexed_instance.value.value)) - - -class VisitorIndexedCounter(opendnp3.IVisitorIndexedCounter): - """ - Override IVisitorIndexedCounter in this manner to implement visiting elements of IndexedCounter collection. - - This is used in SOEHandler callback. - """ - - def __init__(self): - super(VisitorIndexedCounter, self).__init__() - self.index_and_value = [] - - def OnValue(self, indexed_instance): - """ - Process current value visiting. - - :param indexed_instance: current value visiting, an instance of IndexedCounter - """ - self.index_and_value.append((indexed_instance.index, indexed_instance.value.value)) - - -class VisitorIndexedFrozenCounter(opendnp3.IVisitorIndexedFrozenCounter): - """ - Override IVisitorIndexedFrozenCounter in this manner to implement visiting elements of IndexedFrozenCounter - collection. - - This is used in SOEHandler callback. - """ - - def __init__(self): - super(VisitorIndexedFrozenCounter, self).__init__() - self.index_and_value = [] - - def OnValue(self, indexed_instance): - """ - Process current value visiting. - - :param indexed_instance: current value visiting, an instance of IndexedFrozenCounter - """ - self.index_and_value.append((indexed_instance.index, indexed_instance.value.value)) - - -class VisitorIndexedAnalog(opendnp3.IVisitorIndexedAnalog): - """ - Override IVisitorIndexedAnalog in this manner to implement visiting elements of IndexedAnalog collection. - - This is used in SOEHandler callback. - """ - - def __init__(self): - super(VisitorIndexedAnalog, self).__init__() - self.index_and_value = [] - - def OnValue(self, indexed_instance): - """ - Process current value visiting. - - :param indexed_instance: current value visiting, an instance of IndexedAnalog - """ - self.index_and_value.append((indexed_instance.index, indexed_instance.value.value)) - - -class VisitorIndexedBinaryOutputStatus(opendnp3.IVisitorIndexedBinaryOutputStatus): - """ - Override IVisitorIndexedBinaryOutputStatus in this manner to implement visiting elements of - IndexedBinaryOutputStatus collection. - - This is used in SOEHandler callback. - """ - - def __init__(self): - super(VisitorIndexedBinaryOutputStatus, self).__init__() - self.index_and_value = [] - - def OnValue(self, indexed_instance): - """ - Process current value visiting. - - :param indexed_instance: current value visiting, an instance of IndexedBinaryOutputStatus - """ - self.index_and_value.append((indexed_instance.index, indexed_instance.value.value)) - - -class VisitorIndexedAnalogOutputStatus(opendnp3.IVisitorIndexedAnalogOutputStatus): - """ - Override IVisitorIndexedAnalogOutputStatus in this manner to implement visiting elements of - IndexedAnalogOutputStatus collection. - - This is used in SOEHandler callback. - """ - - def __init__(self): - super(VisitorIndexedAnalogOutputStatus, self).__init__() - self.index_and_value = [] - - def OnValue(self, indexed_instance): - """ - Process current value visiting. - - :param indexed_instance: current value visiting, an instance of IndexedAnalogOutputStatus - """ - self.index_and_value.append((indexed_instance.index, indexed_instance.value.value)) - - -class VisitorIndexedTimeAndInterval(opendnp3.IVisitorIndexedTimeAndInterval): - """ - Override IVisitorIndexedTimeAndInterval in this manner to implement visiting elements of - IndexedTimeAndInterval collection. - - This is used in SOEHandler callback. - """ - - def __init__(self): - super(VisitorIndexedTimeAndInterval, self).__init__() - self.index_and_value = [] - - def OnValue(self, indexed_instance): - """ - Process current value visiting. - - :param indexed_instance: current value visiting, an instance of IndexedTimeAndInterval - """ - # The TimeAndInterval class is a special case, because it doesn't have a "value" per se. - ti_instance = indexed_instance.value - ti_dnptime = ti_instance.time - ti_interval = ti_instance.interval - self.index_and_value.append((indexed_instance.index, (ti_dnptime.value, ti_interval))) - - -class LogHandler(openpal.ILogHandler): - """ - Override ILogHandler in this manner to implement application-specific logging behavior. - """ - - def __init__(self): - super(LogHandler, self).__init__() - - def Log(self, entry): - flag = opendnp3.LogFlagToString(entry.filters.GetBitfield()) - filters = entry.filters.GetBitfield() - location = entry.location.rsplit('/')[-1] if entry.location else '' - message = entry.message - _log.debug('LOG\t\t{:<10}\tfilters={:<5}\tlocation={:<25}\tentry={}'.format(flag, filters, location, message)) - - -class ChannelListener(asiodnp3.IChannelListener): - """ - Override IChannelListener in this manner to implement application-specific channel behavior. - """ - - def __init__(self): - super(ChannelListener, self).__init__() - - def OnStateChange(self, state): - _log.debug('In AppChannelListener.OnStateChange: state={}'.format(opendnp3.ChannelStateToString(state))) - - -class SOEHandler(opendnp3.ISOEHandler): - """ - Override ISOEHandler in this manner to implement application-specific sequence-of-events behavior. - - This is an interface for SequenceOfEvents (SOE) callbacks from the Master stack to the application layer. - """ - - def __init__(self): - super(SOEHandler, self).__init__() - self.result = { - "Binary": {}, - "DoubleBitBinary": {}, - "Counter": {}, - "FrozenCounter": {}, - "Analog": {}, - "BinaryOutputStatus": {}, - "AnalogOutputStatus": {}, - "TimeAndInterval": {} - } - - def Process(self, info, values): - """ - Process measurement data. - - :param info: HeaderInfo - :param values: A collection of values received from the Outstation (various data types are possible). - """ - visitor_class_types = { - opendnp3.ICollectionIndexedBinary: VisitorIndexedBinary, - opendnp3.ICollectionIndexedDoubleBitBinary: VisitorIndexedDoubleBitBinary, - opendnp3.ICollectionIndexedCounter: VisitorIndexedCounter, - opendnp3.ICollectionIndexedFrozenCounter: VisitorIndexedFrozenCounter, - opendnp3.ICollectionIndexedAnalog: VisitorIndexedAnalog, - opendnp3.ICollectionIndexedBinaryOutputStatus: VisitorIndexedBinaryOutputStatus, - opendnp3.ICollectionIndexedAnalogOutputStatus: VisitorIndexedAnalogOutputStatus, - opendnp3.ICollectionIndexedTimeAndInterval: VisitorIndexedTimeAndInterval - } - - visitor_class = visitor_class_types[type(values)] - visitor = visitor_class() - - # Visit all the elements of a collection - values.Foreach(visitor) - - for index, value in visitor.index_and_value: - self.result[type(values).__name__.split("ICollectionIndexed")[1]][index] = value - - def Start(self): - pass - - def End(self): - pass - - -class MasterApplication(opendnp3.IMasterApplication): - def __init__(self): - super(MasterApplication, self).__init__() - - # Overridden method - def AssignClassDuringStartup(self): - _log.debug('In MasterApplication.AssignClassDuringStartup') - return False - - # Overridden method - def OnClose(self): - _log.debug('In MasterApplication.OnClose') - - # Overridden method - def OnOpen(self): - _log.debug('In MasterApplication.OnOpen') - - # Overridden method - def OnReceiveIIN(self, iin): - _log.debug('In MasterApplication.OnReceiveIIN') - - # Overridden method - def OnTaskComplete(self, info): - _log.debug('In MasterApplication.OnTaskComplete') - - # Overridden method - def OnTaskStart(self, type, id): - _log.debug('In MasterApplication.OnTaskStart') - - -def collection_callback(result=None): - """ - :type result: opendnp3.CommandPointResult - """ - print("Header: {0} | Index: {1} | State: {2} | Status: {3}".format( - result.headerIndex, - result.index, - opendnp3.CommandPointStateToString(result.state), - opendnp3.CommandStatusToString(result.status) - )) - - -def command_callback(result=None): - """ - :type result: opendnp3.ICommandTaskResult - """ - print("Received command result with summary: {}".format(opendnp3.TaskCompletionToString(result.summary))) - result.ForeachItem(collection_callback) - - -def restart_callback(result=opendnp3.RestartOperationResult()): - if result: - if result.summary == opendnp3.TaskCompletion.SUCCESS: - status_message = "Success, Time: {0}".format(result.restartTime.GetMilliseconds()) - else: - status_message = "Failure: {0}".format(opendnp3.TaskCompletionToString(result.summary)) - else: - status_message = "Failure: No result returned" - - _log.debug(status_message) - - -def main(): - dnp3_master = DNP3Master(log_handler=LogHandler(), - channel_listener=ChannelListener(), - soe_handler=SOEHandler(), - platform_application=MasterApplication()) - dnp3_master.connect() - # Ad-hoc tests can be inserted here if desired. - dnp3_master.shutdown() - - -if __name__ == '__main__': - main() diff --git a/services/core/DNP3Agent/function_test.py b/services/core/DNP3Agent/function_test.py deleted file mode 100644 index 150c41a89f..0000000000 --- a/services/core/DNP3Agent/function_test.py +++ /dev/null @@ -1,150 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - - -import os - -from dnp3.mesa.functions import FunctionDefinitions -from dnp3.points import PointDefinitions -from dnp3 import DATA_TYPES_BY_GROUP -from dnp3 import DATA_TYPE_ANALOG_OUTPUT, DATA_TYPE_BINARY_OUTPUT - -from volttron.platform import jsonapi -POINT_DEF_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'tests', 'data', 'mesa_points.config')) -FUNCTION_DEF_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'tests', 'data', 'mesa_functions.yaml')) - -DATA_TYPE_TO_PYTHON_TYPE = { - DATA_TYPE_BINARY_OUTPUT: {bool}, - DATA_TYPE_ANALOG_OUTPUT: {int, float}, -} - - -class FunctionTestException(Exception): - pass - - -class FunctionTest: - - def __init__(self, func_test_path='', func_test_json=None, func_def_path='', point_def_path=''): - self.func_def_path = func_def_path or FUNCTION_DEF_PATH - self.point_definitions = PointDefinitions(point_definitions_path=point_def_path or POINT_DEF_PATH) - self.ftest = func_test_json or jsonapi.load(open(func_test_path)) - self.function_id = self.ftest.get('function_id', self.ftest.get('id', None)) - self.function_name = self.ftest.get('function_name', self.ftest.get('name', None)) - self.name = self.ftest.get('name', None) - self.points = {k: v for k, v in self.ftest.items() if k not in ["name", "function_id", "function_name", "id"]} - - def get_function_def(self): - """ - Gets the function definition for the function test. Returns None if no definition is found. - """ - fdefs = FunctionDefinitions(point_definitions=self.point_definitions, - function_definitions_path=self.func_def_path) - return fdefs.function_for_id(self.function_id) - - @staticmethod - def get_mandatory_steps(func_def): - """ - Returns list of mandatory steps for the given function definition. - - :param func_def: function definition - """ - return [step.name for step in func_def.steps if step.optional in ['M', 'I']] - - def has_mandatory_steps(self, fdef=None): - """ - Returns True if the instance has all required steps, and raises an exception if not. - - :param fdef: function definition - """ - fdef = fdef or self.get_function_def() - if not fdef: - raise FunctionTestException("Function definition not found: {}".format(self.function_id)) - - missing_steps = list(set(self.get_mandatory_steps(fdef)) - set(self.ftest.keys())) - if missing_steps: - raise FunctionTestException("Function Test missing mandatory steps: {}".format(missing_steps)) - - return True - - def points_resolve(self, func_def): - """ - Returns true if all the points in the instance resolve to point names in the function definition, - and raises an exception if not. - - :param func_def: function definition of the given instance - """ - # It would have been more informative to identify the mismatched step/point name, - # but that would break a pytest assertion that matches on this specific exception description. - if not all(step_name in [step.point_def.name for step in func_def.steps if step.point_def] for step_name in - self.points.keys()): - raise FunctionTestException("Not all points resolve") - return True - - def correct_point_types(self): - """ - Check valid point value. - """ - for point_name, point_value in self.points.items(): - point_def = self.point_definitions.point_named(point_name) - point_values = sum([list(v.values()) for v in point_value], []) if point_def.is_array else [point_value] - for value in point_values: - if type(value) not in DATA_TYPE_TO_PYTHON_TYPE[DATA_TYPES_BY_GROUP[point_def.group]]: - # It would have been more informative to display the value and/or type in the error message, - # but that would break a pytest assertion that matches on this specific exception description. - raise FunctionTestException("Invalid point value: {}".format(point_name)) - return True - - def is_valid(self): - """ - Returns True if the function test passes two validation steps: - 1. it has all the mandatory steps - 2. its point names resolve to point names in the function definition - 3. its point value is valid - If the function test is invalid, an exception is raised. - """ - f_def = self.get_function_def() - - try: - self.has_mandatory_steps(f_def) - self.points_resolve(f_def) - self.correct_point_types() - return True - except Exception as err: - raise FunctionTestException("Validation Error: {}".format(str(err))) - - -def main(): - function_test = FunctionTest(func_test_path=os.path.abspath(os.path.join(os.path.dirname(__file__), - 'tests', 'data', 'watt_var_curve.json'))) - function_test.is_valid() - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/services/core/DNP3Agent/install_dnp3_agent.sh b/services/core/DNP3Agent/install_dnp3_agent.sh deleted file mode 100644 index 420ae1dd4d..0000000000 --- a/services/core/DNP3Agent/install_dnp3_agent.sh +++ /dev/null @@ -1,19 +0,0 @@ -# This script assumes that $VOLTTRON_ROOT is the directory where VOLTTRON source code is loaded from github. - -export DNP3_ROOT=$VOLTTRON_ROOT/services/core/DNP3Agent - -# Install the agent that resides in the dnp3 subdirectory -export AGENT_MODULE=dnp3.agent - -cd $VOLTTRON_ROOT - -python scripts/install-agent.py -s $DNP3_ROOT -i dnp3agent -c $DNP3_ROOT/config -t dnp3agent -f - -# Put the agent's point definitions in the config store. -cd $VOLTTRON_ROOT -vctl config store dnp3agent mesa_points.config $DNP3_ROOT/dnp3/mesa_points.config - -echo -echo Stored point configurations in config store... -vctl config list dnp3agent -echo diff --git a/services/core/DNP3Agent/install_mesa_agent.sh b/services/core/DNP3Agent/install_mesa_agent.sh deleted file mode 100644 index b84ed53189..0000000000 --- a/services/core/DNP3Agent/install_mesa_agent.sh +++ /dev/null @@ -1,25 +0,0 @@ -#/bin/sh -# This script assumes that $VOLTTRON_ROOT is the directory where VOLTTRON source code is loaded from github. - -export DNP3_ROOT=$VOLTTRON_ROOT/services/core/DNP3Agent - -# Install the agent that resides in the dnp3.mesa subdirectory -export AGENT_MODULE=dnp3.mesa.agent - -cd $VOLTTRON_ROOT - -python scripts/install-agent.py -s $DNP3_ROOT -i mesaagent -c $DNP3_ROOT/mesaagent.config -t mesaagent -f - -# Convert function YAML to JSON -cd $DNP3_ROOT -python dnp3/mesa/conversion.py < dnp3/mesa/mesa_functions.yaml > dnp3/mesa/mesa_functions.config - -# Put the agent's point definitions and function definitions in the config store. -cd $VOLTTRON_ROOT -vctl config store mesaagent mesa_points.config $DNP3_ROOT/dnp3/mesa_points.config -vctl config store mesaagent mesa_functions.config $DNP3_ROOT/dnp3/mesa/mesa_functions.config - -echo -echo Stored point and function configurations in config store... -vctl config list mesaagent -echo diff --git a/services/core/DNP3Agent/mesa_master.py b/services/core/DNP3Agent/mesa_master.py deleted file mode 100644 index 803caa01a7..0000000000 --- a/services/core/DNP3Agent/mesa_master.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - -import os -import time - -from pydnp3 import opendnp3 - -from dnp3 import DIRECT_OPERATE, SELECT, OPERATE, DATA_TYPE_BINARY_OUTPUT -from dnp3.points import PointDefinitions -from dnp3_master import DNP3Master -from function_test import FunctionTest - -POINT_DEF_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'tests', 'data', 'mesa_points.config')) - -OUTPUT_TYPES = { - float: opendnp3.AnalogOutputFloat32, - int: opendnp3.AnalogOutputInt32, - bool: opendnp3.ControlRelayOutputBlock -} - - -class MesaMasterException(Exception): - pass - - -class MesaMaster(DNP3Master): - - def __init__(self, **kwargs): - DNP3Master.__init__(self, **kwargs) - - self.SEND_FUNCTIONS = { - DIRECT_OPERATE: self.send_direct_operate_command, - SELECT: self.send_select_and_operate_command, - OPERATE: self.send_select_and_operate_command, - } - - def send_command(self, send_func, pdef, point_value, index=None): - """ - Send a command to outstation. Check for valid value to send. - - :param send_func: send_direct_operate_command or send_select_and_operate_command - :param pdef: point definition - :param point_value: value of the point that will be sent to outstation - :param index: index of the point from point definition - """ - value_type = type(point_value) - - if pdef.data_type == DATA_TYPE_BINARY_OUTPUT: - point_value = opendnp3.ControlCode.LATCH_ON if point_value else opendnp3.ControlCode.LATCH_OFF - - try: - send_func(OUTPUT_TYPES[value_type](point_value), index or pdef.index) - time.sleep(0.2) - except KeyError: - raise MesaMasterException("Unrecognized output type: {}".format(value_type)) - - def send_array(self, json_array, pdef): - """ - Send point array to outstation. - - :param json_array: json array of points and values that will be sent to outstation - :param pdef: point definition - """ - for offset, value in enumerate( - record[field['name']] - for record in json_array for field in pdef.array_points): - if value not in ['', None]: - self.send_command(self.send_direct_operate_command, pdef, value, index=pdef.index+offset) - - def send_function_test(self, point_def_path='', func_def_path='', func_test_path='', func_test_json=None): - """ - Send a function test after validating the function test (as JSON). - - :param point_def_path: path to point definition config - :param func_def_path: path to function definition config - :param func_test_path: path to function test json - :param func_test_json: function test json - """ - ftest = FunctionTest(func_test_path, func_test_json, point_def_path=point_def_path, func_def_path=func_def_path) - - ftest.is_valid() - - pdefs = PointDefinitions(point_definitions_path=point_def_path or POINT_DEF_PATH) - - func_def = ftest.get_function_def() - for func_step_def in func_def.steps: - try: - point_value = ftest.points[func_step_def.name] - except KeyError: - continue - - pdef = pdefs.point_named(func_step_def.name) # No need to test for valid point name, as that was done above - if not pdef: - raise MesaMasterException("Point definition not found: {}".format(func_step_def.name)) - - if type(point_value) == list: - self.send_array(point_value, pdef) - else: - try: - send_func = self.SEND_FUNCTIONS[func_step_def.fcodes[0] if func_step_def.fcodes else DIRECT_OPERATE] - except (KeyError, IndexError): - raise MesaMasterException("Unrecognized sent command function") - - self.send_command(send_func, pdef, point_value) - - -def main(): - mesa_master = MesaMaster() - mesa_master.connect() - # Ad-hoc tests can be inserted here if desired. - mesa_master.shutdown() - - -if __name__ == '__main__': - main() diff --git a/services/core/DNP3Agent/mesaagent.config b/services/core/DNP3Agent/mesaagent.config deleted file mode 100644 index ce39874edd..0000000000 --- a/services/core/DNP3Agent/mesaagent.config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "points": "config://mesa_points.config", - "functions": "config://mesa_functions.config", - "point_topic": "mesa/point", - "function_topic": "mesa/function", - "outstation_status_topic": "mesa/outstation_status", - "outstation_config": { - "database_sizes": 10000, - "log_levels": ["NORMAL"] - }, - "local_ip": "0.0.0.0", - "port": 20000, - "all_functions_supported_by_default": true, - "function_validation": false -} diff --git a/services/core/DNP3Agent/requirements.txt b/services/core/DNP3Agent/requirements.txt deleted file mode 100644 index 9647f44d1e..0000000000 --- a/services/core/DNP3Agent/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pydnp3==0.1.0 diff --git a/services/core/DNP3Agent/setup.py b/services/core/DNP3Agent/setup.py deleted file mode 100644 index f581207dc4..0000000000 --- a/services/core/DNP3Agent/setup.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, SLAC / 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared in part as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor SLAC, nor 8minutenergy, nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# SLAC, 8minutenergy, or Kisensum. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# }}} - -from os import path, environ -from setuptools import setup, find_packages - -MAIN_MODULE = 'agent' - -# Find the agent package that contains the main module -packages = find_packages('.') -agent_package = '' -for package in find_packages(): - # Because there could be other packages such as tests - if path.isfile(package + '/' + MAIN_MODULE + '.py') is True: - agent_package = package -if not agent_package: - raise RuntimeError('None of the packages under {dir} contain the file ' - '{main_module}'.format(main_module=MAIN_MODULE + '.py', - dir=path.abspath('.'))) - -# Find the version number from the main module -agent_module = environ.get('AGENT_MODULE', agent_package + '.' + MAIN_MODULE) -_temp = __import__(agent_module, globals(), locals(), ['__version__'], 0) -__version__ = _temp.__version__ - -# Setup -setup( - name=agent_module.replace('.', ''), - version=__version__, - install_requires=['volttron'], - packages=packages, - entry_points={ - 'setuptools.installation': [ - 'eggsecutable = ' + agent_module + ':main', - ] - } -) diff --git a/services/core/DNP3Agent/tests/MesaTestAgent/setup.py b/services/core/DNP3Agent/tests/MesaTestAgent/setup.py deleted file mode 100644 index 9c01575e32..0000000000 --- a/services/core/DNP3Agent/tests/MesaTestAgent/setup.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - -from os import path -from setuptools import setup, find_packages - -MAIN_MODULE = 'agent' - -# Find the agent package that contains the main module -packages = find_packages('.') -agent_package = '' -for package in find_packages(): - # Because there could be other packages such as tests - if path.isfile(package + '/' + MAIN_MODULE + '.py') is True: - agent_package = package -if not agent_package: - raise RuntimeError('None of the packages under {dir} contain the file ' - '{main_module}'.format(main_module=MAIN_MODULE + '.py', - dir=path.abspath('.'))) - -# Find the version number from the main module -agent_module = agent_package + '.' + MAIN_MODULE -_temp = __import__(agent_module, globals(), locals(), ['__version__'], 0) -__version__ = _temp.__version__ - -# Setup -setup( - name=agent_package + 'agent', - version=__version__, - install_requires=['volttron'], - packages=packages, - entry_points={ - 'setuptools.installation': [ - 'eggsecutable = ' + agent_module + ':main', - ] - } -) diff --git a/services/core/DNP3Agent/tests/MesaTestAgent/testagent.config b/services/core/DNP3Agent/tests/MesaTestAgent/testagent.config deleted file mode 100644 index 1f73dc61fa..0000000000 --- a/services/core/DNP3Agent/tests/MesaTestAgent/testagent.config +++ /dev/null @@ -1,23 +0,0 @@ -{ - "mesaagent_id": "mesaagent", - # The point configuration can be defined here by the test agent, or the test agent - # can rely on the DNP3 driver's config (e.g. dnp3.csv). If a point configuration is - # defined here, and the test agent is started after the PlatformDriverAgent, the test - # agent's point config will override the DNP3 driver config. - # "point_config": { - # "DCHD.WTgt": {"group": 41, "index": 65}, - # "DCHD.WinTms": {"group": 41, "index": 66}, - # "DCHD.RmpTms": {"group": 41, "index": 67}, - # "DCHD.RevtTms": {"group": 41, "index": 68}, - # "DCHD.RmpUpRte": {"group": 41, "index": 69}, - # "DCHD.RmpDnRte": {"group": 41, "index": 70}, - # "DCHD.ChaRmpUpRte": {"group": 41, "index": 71}, - # "DCHD.ChaRmpDnRte": {"group": 41, "index": 72}, - # "DCHD.ModPrty": {"group": 41, "index": 9}, - # "DCHD.VArAct": {"group": 41, "index": 10}, - # "DCHD.ModEna": {"group": 12, "index": 5} - # }, - "point_topic": "mesa/point", - "function_topic": "mesa/function", - "outstation_status_topic": "mesa/outstation_status" -} diff --git a/services/core/DNP3Agent/tests/MesaTestAgent/testagent/__init__.py b/services/core/DNP3Agent/tests/MesaTestAgent/testagent/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/services/core/DNP3Agent/tests/MesaTestAgent/testagent/agent.py b/services/core/DNP3Agent/tests/MesaTestAgent/testagent/agent.py deleted file mode 100644 index 80ae3731ec..0000000000 --- a/services/core/DNP3Agent/tests/MesaTestAgent/testagent/agent.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - - - -import logging -import sys - -from volttron.platform.agent import utils -from volttron.platform.vip.agent import Agent, Core, RPC -from volttron.platform.scheduling import periodic - -utils.setup_logging() -_log = logging.getLogger(__name__) - -__version__ = '1.0' - -RPC_INTERVAL_SECS = 10 - -TEST_GET_POINT_NAME1 = 'DCHD.ModEna' -TEST_GET_POINT_NAME2 = 'DCHD.VArAct.out' -TEST_GET_SELECTOR_BLOCK_POINT_NAME = 'Curve Edit Selector' -TEST_SET_POINT_NAME = 'DCHD.WTgt.1' -TEST_SET_SUPPORT_POINT_NAME = 'DCHA.Beh' -# Test has been disabled: these points are not part of the current production data definitions. -# TEST_DEVICE_ARRAY = { -# "Inverter power readings": [ -# { -# "Inverter active power output - Present Active Power output level": 302, -# "Inverter reactive output - Present reactive power output level": 100 -# } -# ] -# } -TEST_INPUT_CURVE = { - "FMAR.in.PairArray.CsvPts": [ - {"FMAR.in.PairArray.CsvPts.xVal": 30, "FMAR.in.PairArray.CsvPts.yVal": 130}, - {"FMAR.in.PairArray.CsvPts.xVal": 31, "FMAR.in.PairArray.CsvPts.yVal": 131}, - {"FMAR.in.PairArray.CsvPts.xVal": 32, "FMAR.in.PairArray.CsvPts.yVal": 132} - ] -} - - -def mesa_test_agent(config_path, **kwargs): - """ - Parse the TestAgent configuration file and return an instance of - the agent that has been created using that configuration. - - See initialize_config() method documentation for a description of each configurable parameter. - - This agent can be installed from a command-line shell as follows: - export VOLTTRON_ROOT= - export MESA_TEST=$VOLTTRON_ROOT/services/core/MesaAgent/tests/TestAgent - cd $VOLTTRON_ROOT - python scripts/install-agent.py -s $$MESA_TEST -i mesatest -c $MESA_TEST/testagent.config -t mesatest -f - - :param config_path: (str) Path to a configuration file. - :returns: TestAgent instance - """ - try: - config = utils.load_config(config_path) - except (Exception, err): - _log.error("Error loading MesaTestAgent configuration: {}".format(err)) - config = {} - mesaagent_id = config.get('mesaagent_id', 'mesaagent') - point_topic = config.get('point_topic', 'mesa/point') - function_topic = config.get('function_topic', 'mesa/function') - outstation_status_topic = config.get('outstation_status_topic', 'mesa/outstation_status') - point_config = config.get('point_config', None) - return MesaTestAgent(mesaagent_id, point_topic, function_topic, outstation_status_topic, point_config, **kwargs) - - -class MesaTestAgent(Agent): - """ - This is a sample test agent that demonstrates and tests MesaAgent. - It exercises MesaAgent's exposed RPC calls and consumes VOLTTRON messages published by MesaAgent. - """ - - def __init__(self, mesaagent_id, point_topic, function_topic, outstation_status_topic, point_config, **kwargs): - super(MesaTestAgent, self).__init__(**kwargs) - self.mesaagent_id = None - self.point_topic = None - self.function_topic = None - self.outstation_status_topic = None - self.point_config = None - self.default_config = {'mesaagent_id': mesaagent_id, - 'point_topic': point_topic, - 'function_topic': function_topic, - 'outstation_status_topic': outstation_status_topic, - 'point_config': point_config} - self.vip.config.set_default("config", self.default_config) - self.vip.config.subscribe(self._configure, actions=["NEW", "UPDATE"], pattern="config") - self.initialize_config(self.default_config) - - def _configure(self, config_name, action, contents): - """The agent's config may have changed. Re-initialize it.""" - config = self.default_config.copy() - config.update(contents) - self.initialize_config(config) - - def initialize_config(self, config): - self.mesaagent_id = config['mesaagent_id'] - self.point_topic = config['point_topic'] - self.function_topic = config['function_topic'] - self.outstation_status_topic = config['outstation_status_topic'] - self.point_config = config['point_config'] - _log.debug('MesaTestAgent configuration parameters:') - _log.debug('\tmesaagent_id={}'.format(self.mesaagent_id)) - _log.debug('\tpoint_topic={}'.format(self.point_topic)) - _log.debug('\tfunction_topic={}'.format(self.function_topic)) - _log.debug('\toutstation_status_topic={}'.format(self.outstation_status_topic)) - _log.debug('\tpoint_config={}'.format(self.point_config)) - - @Core.receiver('onstart') - def onstart_method(self, sender): - """The test agent has started. Perform initialization and spawn the main process loop.""" - _log.debug('Starting MesaTestAgent') - if self.point_config: - # This test agent can configure the points itself, or (by default) it can rely on the DNP3 driver to do it. - _log.debug('Sending DNP3 point map: {}'.format(self.point_config)) - self.send_rpc('config_points', self.point_config) - # Subscribe to the MesaAgent's point, function, and outstation_status publications. - self.vip.pubsub.subscribe(peer='pubsub', prefix=self.point_topic, callback=self.receive_point_value) - self.vip.pubsub.subscribe(peer='pubsub', prefix=self.function_topic, callback=self.receive_function) - self.vip.pubsub.subscribe(peer='pubsub', prefix=self.outstation_status_topic, callback=self.receive_status) - self.core.schedule(periodic(RPC_INTERVAL_SECS), self.issue_rpcs) - - @staticmethod - def receive_point_value(peer, sender, bus, topic, headers, point_value): - """(Subscription callback) Receive a point value.""" - _log.debug('MesaTestAgent received point_value={}'.format(point_value)) - - def receive_function(self, peer, sender, bus, topic, headers, point_value): - """(Subscription callback) Receive a function.""" - _log.debug('MesaTestAgent received function={}'.format(point_value)) - if 'expected_response' in point_value: - # The function step expects a response. Send one. - self.set_point(point_value['expected_response'], 1) - - @staticmethod - def receive_status(peer, sender, bus, topic, headers, point_value): - """(Subscription callback) Receive outstation status.""" - _log.debug('MesaTestAgent received outstation status={}'.format(point_value)) - - def issue_rpcs(self): - """Periodically issue RPCs to the DNP3 agent.""" - self.get_point(TEST_GET_POINT_NAME1) - self.get_point(TEST_GET_POINT_NAME2) - self.get_selector_block(TEST_GET_SELECTOR_BLOCK_POINT_NAME, 3) - self.set_point(TEST_SET_POINT_NAME, 10) - self.set_point(TEST_SET_SUPPORT_POINT_NAME, True) - # self.set_points(TEST_DEVICE_ARRAY) - self.set_points(TEST_INPUT_CURVE) - - def get_point(self, point_name): - """Get a single metric from the MesaAgent via an RPC call.""" - point_value = self.send_rpc('get_point', point_name) - _log.debug('MesaTestAgent get_point received {}={}'.format(point_name, point_value)) - - def get_selector_block(self, point_name, edit_selector): - """Get a selector block from the MesaAgent via an RPC call.""" - selector_block = self.send_rpc('get_selector_block', point_name, edit_selector) - _log.debug('MesaTestAgent get_selector_block {} selector {} received {}'.format(point_name, - edit_selector, - selector_block)) - - def set_point(self, point_name, value): - """Send a single point value to the MesaAgent via an RPC call.""" - _log.debug('MesaTestAgent set_point sent {}={}'.format(point_name, value)) - self.send_rpc('set_point', point_name, value) - - def set_points(self, json_payload): - """Send a single point value to the MesaAgent via an RPC call.""" - _log.debug('MesaTestAgent sending points: {}'.format(json_payload)) - self.send_rpc('set_points', json_payload) - - def send_rpc(self, rpc_name, *args, **kwargs): - """Send an RPC request to the MesaAgent, and return its response (if any).""" - response = self.vip.rpc.call(self.mesaagent_id, rpc_name, *args, **kwargs) - return response.get(30) - - -def main(): - """Start the agent.""" - utils.vip_main(mesa_test_agent, identity='mesa_test_agent', version=__version__) - - -if __name__ == '__main__': - try: - sys.exit(main()) - except KeyboardInterrupt: - pass diff --git a/services/core/DNP3Agent/tests/README.md b/services/core/DNP3Agent/tests/README.md deleted file mode 100644 index 8238796c8f..0000000000 --- a/services/core/DNP3Agent/tests/README.md +++ /dev/null @@ -1,43 +0,0 @@ -The tests/ subdirectory of DNP3Agent contains several types of tests: - -# MesaAgent Regression Tests - -**test_mesa_agent.py** contains MesaAgent pytest regression tests as follows: - -1. Load point and function definitions. -2. Start a MesaAgent process. -3. Test routing of DNP3 output: - - Send point values from a simulated Master. - - Verify that MesaAgent has published them correctly on the VOLTTRON message bus. -4. Test routing of DNP3 input: - - Use RPC calls to set point values. - - Verify that the simulated Master has received them correctly. - -# DNP3Agent Regression Tests - -**test_dnp3_agent.py** contains DNP3Agent pytest regression tests as follows: - -1. Load point definitions. -2. Start a DNP3Agent process. -3. Test routing of DNP3 output, similar to the MesaAgent tests above. -4. Test routing of DNP3 input, similar to the MesaAgent tests above. - -# Data Regression Tests - -**test_mesa_data.py** contains pytest regression tests of MesaAgent data. - -The test strategy in test_mesa_data.py is similar to the other pytest strategies, -but rather than working with a small, controlled set of data, this module's tests -use "production" point and function definitions. - -# Ad-Hoc Unit Test Support - -**unit_test_point_definitions.py** contains a mix of standalone non-pytest -methods that test and validate various types of data and behavior. - -**MesaTestAgent** is a VOLTTRON agent that interacts with MesaAgent, sending -RPC calls and subscribing to MesaAgent publication of data. - -**mesa_platform_cmd.py** is a standalone command-line utility (built on the Python -Cmd library) that sends point and function values from the master to -the (MesaAgent) DNP3 outstation. diff --git a/services/core/DNP3Agent/tests/data/connect_and_disconnect.json b/services/core/DNP3Agent/tests/data/connect_and_disconnect.json deleted file mode 100644 index 26ba349c17..0000000000 --- a/services/core/DNP3Agent/tests/data/connect_and_disconnect.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "function_id": "connect_and_disconnect", - "function_name": "Connect and Disconnect", - "DCTE.WinTms.AO16": 10, - "DCTE.RvrtTms.AO17": 12, - "CSWI.Pos.BO5": true -} \ No newline at end of file diff --git a/services/core/DNP3Agent/tests/data/enable_watt_var_power_mode.json b/services/core/DNP3Agent/tests/data/enable_watt_var_power_mode.json deleted file mode 100644 index 756b598ebe..0000000000 --- a/services/core/DNP3Agent/tests/data/enable_watt_var_power_mode.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "function_id": "enable_watt-var_power_mode", - "function_name": "Enable Watt-Var Power Mode", - "DWVR.ModPrio.AO221": 1, - "DWVR.WinTms.AO222": 2, - "DWVR.RmpTms.AO223": 3, - "DWVR.RvrtTms.AO224": 4, - "DWVR.EcpRef.AO225": 5, - "DWVR.OpnLoopMax.AO227": 10, - "DWVR.OpnLoopMax.AO228": 1, - "DWVR.WVArCrv.AO226": 2, - "DWVR.ModEna.BO30": true -} \ No newline at end of file diff --git a/services/core/DNP3Agent/tests/data/enable_watt_var_schedule.json b/services/core/DNP3Agent/tests/data/enable_watt_var_schedule.json deleted file mode 100644 index a30f249fa4..0000000000 --- a/services/core/DNP3Agent/tests/data/enable_watt_var_schedule.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "function_id": "enable_schedules", - "function_name": "Enable Watt-Var Schedule", - "FSCHxx.Mod.BO42": true, - "FSCC.Schd.AO461": 2, - "FSCHxx.SchdReuse.BO43": true, - "FSCHxx.SchdReuse.BO44": false, - "FSCHxx.SchdReuse.BO45": false, - "FSCHxx.SchdReuse.BO46": false, - "FSCHxx.SchdReuse.BO47": false, - "FSCHxx.SchdReuse.BO48": false, - "FSCHxx.SchdReuse.BO49": false -} \ No newline at end of file diff --git a/services/core/DNP3Agent/tests/data/mesa_functions.yaml b/services/core/DNP3Agent/tests/data/mesa_functions.yaml deleted file mode 100644 index fdad5de95b..0000000000 --- a/services/core/DNP3Agent/tests/data/mesa_functions.yaml +++ /dev/null @@ -1,2581 +0,0 @@ -functions: -- id: connect_and_disconnect - name: Connect and Disconnect - ref: AN2018 Spec section 2.4.4 Table 29 - steps: - - description: Set time window - fcodes: - - direct_operate - optional: I - point_name: DCTE.WinTms.AO16 - response: DCTE.WinTms.AI60 - step_number: 1 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DCTE.RvrtTms.AO17 - response: DCTE.RvrtTms.AI61 - step_number: 2 - - description: Retrieve status of switch - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.DEROpSt.off.BI23 - step_number: 3 - - action: publish - description: Issue switch control command and receive response - fcodes: - - select - - operate - optional: M - point_name: CSWI.Pos.BO5 - response: DSTO.DEROpSt.off.BI23 - step_number: 4 - - description: Detect if switch is moving - fcodes: - - read - - response - optional: O - point_name: n/a - response: CSWI.Pos.BI24 - step_number: 5 -- id: cease_to_energize_and_return_to_service - name: Cease to Energize and Return to Service - ref: AN2018 Spec section 2.4.5 Table 30 - steps: - - description: Set Cease to Energize Time Window - fcodes: - - direct_operate - optional: I - point_name: DCTE.WinTms.AO13 - response: DCTE.WinTms.AI57 - step_number: 1 - - description: Set Cease to Energize Ramp DownTime - fcodes: - - direct_operate - optional: I - point_name: DCTE.RmpTms.AO14 - response: DCTE.RmpTms.AI58 - step_number: 2 - - description: Set Cease to Energize Timeout Period - fcodes: - - direct_operate - optional: I - point_name: DCTE.RvrtTms.AO15 - response: DCTE.RvrtTms.AI59 - step_number: 3 - - description: Cause DER to Cease to Energize - fcodes: - - select - - operate - optional: M - point_name: DCTE.CeaEngzReq.BO2 - response: DSTO.DEROpSt.connectedandidle.BI14 - step_number: 4 - - description: Give DER Permission to Stop - fcodes: - - select - - operate - optional: M - point_name: DSTO.PrmDscon.BO4 - response: DSTO.PrmDscon.BI17 - step_number: 5 - - description: Confirm DER is Stopping - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.DEROpSt.stopping.BI13 - step_number: 6 - - description: Confirm DER has Ceased to Energize - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.DEROpSt.ceasedtoenergize.BI15 - step_number: 7 - - description: Set High Voltage Limit - fcodes: - - direct_operate - optional: I - point_name: DCTE.VHiLim.AO6 - response: DCTE.VHiLim.AI50 - step_number: 8 - - description: Set Low Voltage Limit - fcodes: - - direct_operate - optional: I - point_name: DCTE.VLoLim.AO7 - response: DCTE.VLoLim.AI51 - step_number: 9 - - description: Set High Frequency Limit - fcodes: - - direct_operate - optional: I - point_name: DCTE.HzHiLim.AO8 - response: DCTE.HzHiLim.AI52 - step_number: 10 - - description: Set Low Frequency Limit - fcodes: - - direct_operate - optional: I - point_name: DCTE.HzLoLim.AO9 - response: DCTE.HzLoLim.AI53 - step_number: 11 - - description: Set Delay Time - fcodes: - - direct_operate - optional: I - point_name: DCTE.RtnDlyTmms.AO10 - response: DCTE.RtnDlTmms.AI54 - step_number: 12 - - description: Set Return to Service Time Window - fcodes: - - direct_operate - optional: I - point_name: DCTE.WinTms.AO11 - response: DCTE.WinTms.AI55 - step_number: 13 - - description: Set Return to Service Ramp Up Time - fcodes: - - direct_operate - optional: I - point_name: DCTE.RtnRmpTmms.AO12 - response: DCTE.RtnRmpTmms.AI56 - step_number: 14 - - description: Cause DER to Return to Service - fcodes: - - select - - operate - optional: M - point_name: DCTE.RtnSrvReq.BO1 - response: DSTO.DEROpSt.startingandsynchronizing.BI12 - step_number: 15 - - action: publish - description: Give DER Permission to Start - fcodes: - - select - - operate - optional: M - point_name: DSTO.PrmConn.BO3 - response: DSTO.PrmConn.BI16 - step_number: 16 - - description: Confirm DER is Started - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.DEROpSt.connectedandidle.BI14 - step_number: 17 -- id: enable_low_high_voltage_ride-through_mode - mode_types: - curve: - - 9 - - 10 - - 11 - - 12 - schedule: - - 1 - - 2 - - 3 - - 4 - name: Enable Low/High Voltage Ride-Through Mode - ref: AN2018 Spec section 2.5.1 Table 33 - steps: - - description: Set the Reference Voltage if it is not already set - fcodes: - - direct_operate - optional: I - point_name: DECP.VRef.AO0 - response: DECP.VRef.AI29 - step_number: 1 - - description: Set the Reference Voltage Offset if it is not already set - fcodes: - - direct_operate - optional: I - point_name: DECP.VRefOfs.AO1 - response: DECP.VRefOfs.AI30 - step_number: 2 - - description: Identify the meter used to measure the voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DHVT.EcpRef.AO22 - response: DHVT.EcpRef.AI71 - step_number: 3 - - description: 'DGSMn.ModTyp.AO245 = <9> HVRT Must Trip: If the curve is a must - trip curve, identify the index of the curve which specifies trip points when - the voltage is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTOV.BlkRef.AO23 - response: PTOV.BlkRef.AI73 - step_number: 4 - - description: 'DGSMn.ModTyp.AO245 = <11> LVRT Must Trip: If the curve is a must - trip curve, identify the index of the curve which specifies trip points when - the voltage is low' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTUV.BlkRef.AO24 - response: PTUV.BlkRef.AI74 - step_number: 5 - - description: 'DGSMn.ModTyp.AO245 = <10> HVRT Momentary Cessation: If the curve - is a must trip curve, identify the index of the curve which specifies where - generation/discharging must stop when the voltage is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTOV.BlkRef.AO25 - response: PTOV.BlkRef.AI75 - step_number: 6 - - description: 'DGSMn.ModTyp.AO245 = <12> LVRT Momentary Cessation: If the curve - is a must trip curve, identify the index of the curve which specifies where - generation/discharging must stop when the voltage is low' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTUV.BlkRef.AO26 - response: PTUV.BlkRef.AI76 - step_number: 7 - - action: publish - description: Enable the Low/High Voltage Ride-Through Mode - fcodes: - - select - - operate - optional: M - point_name: DHVT.ModEna.BO12 - response: DHVT.ModEna.BI64 - step_number: 8 -- id: enable_low_high_frequency_ride-through_mode - mode_types: - curve: - - 13 - - 14 - - 15 - - 16 - schedule: - - 5 - - 6 - - 7 - - 8 - name: Enable Low/High Frequency Ride-Through Mode - ref: AN2018 Spec section 2.5.2 Table 35 - steps: - - description: Set the Nominal Grid Frequency if it is not already set - fcodes: - - direct_operate - optional: I - point_name: DECP.EcpNomHz.AO2 - response: DECP.EcpNomHz.AI31 - step_number: 1 - - description: Identify the meter used to measure the frequency. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DHFT.EcpRef.AO27 - response: DHFT.EcpRef.AI77 - step_number: 2 - - description: 'DGSMn.ModTyp.AO245 = <13> HFRT Must Trip: Identify the index of - the frequency ride through curve which specifies trip ponts when the frequency - is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTOF.BlkRef.AO28 - response: PTOF.BlkRef.AI79 - step_number: 3 - - description: 'DGSMn.ModTyp.AO245 = <15> LFRT Must Trip: Identify the index of - the frequency ride through curve which specifies trip ponts when the voltage - is low' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTUF.BlkRef.AO29 - response: PTUF.BlkRef.AI80 - step_number: 4 - - description: 'DGSMn.ModTyp.AO245 = <14> HFRT Mandatory Operation: Identify the - index of the frequency ride through curve which specifies where generation/discharging - must stop when the frequency is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTOF.BlkRef.AO30 - response: PTOF.BlkRef.AI81 - step_number: 5 - - description: 'DGSMn.ModTyp.AO245 = <16> LFRT Mandatory Operation: Identify the - index of the frequency ride through curve which specifies where generation/discharging - must stop when the frequency is high' - fcodes: - - direct_operate - func_ref: curve - optional: O - point_name: PTUF.BlkRef.AO31 - response: PTUF.BlkRef.AI82 - step_number: 6 - - action: publish - description: Enable the Low/High Frequency Ride-Through Mode - fcodes: - - select - - operate - optional: M - point_name: DHFT.ModEna.BO13 - response: DHFT.ModEna.BI65 - step_number: 7 -- id: enable_frequency-watt_mode - name: Enable Frequency-Watt Mode - ref: AN2018 Spec section 2.5.3 Table 36 - mode_types: - schedule: - - 11 - steps: - - description: If not already established, set the Nominal Grid Frequency - fcodes: - - direct_operate - optional: I - point_name: DECP.EcpNomHz.AO2 - response: DECP.EcpNomHz.AI31 - step_number: 1 - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DHFW2.ModPrio.AO57 - response: DHFW2.ModPrio.AI115 - step_number: 2 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DHFW.WinTms.AO58 - response: DHFW.WinTms.AI116 - step_number: 3 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DHFW.RmpTms.AO59 - response: DHFW.RmpTms.AI117 - step_number: 4 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DHFW.RvrtTms.AO60 - response: DHFW.RvrtTms.AI118 - step_number: 5 - - description: Identify the meter used to measure the frequency. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DHFW.EcpRef.AO61 - response: DHFW2.EcpRef.AI119 - step_number: 6 - - description: Set the High Starting Frequency - fcodes: - - direct_operate - optional: I - point_name: DHFW.HzStr.AO62 - response: DHFW2.HzStr.AI121 - step_number: 7 - - description: Set the High Stopping Frequency - fcodes: - - direct_operate - optional: I - point_name: DHFW.HzStop.AO63 - response: DHFW2.HzStop.AI122 - step_number: 8 - - description: Set the High Discharging Gradient - fcodes: - - direct_operate - optional: I - point_name: DHFW.WGra.AO64 - response: DHFW.WGra.AI123 - step_number: 9 - - description: Set the High Charging Gradient - fcodes: - - direct_operate - optional: I - point_name: DHFW.WChaGra.AO65 - response: DHFW.WChaGra.AI124 - step_number: 10 - - description: Set the Low Starting Frequency - fcodes: - - direct_operate - optional: I - point_name: DLFW.HzStr.AO66 - response: DLFW2.HzStr.AI125 - step_number: 11 - - description: Set the Low Stopping Frequency - fcodes: - - direct_operate - optional: I - point_name: DLFW.HzStop.AO67 - response: DLFW2.HzStop.AI126 - step_number: 12 - - description: Set the Low Discharging Gradient - fcodes: - - direct_operate - optional: I - point_name: DLFW.WGra.AO68 - response: DLFW.WGra.AI127 - step_number: 13 - - description: Set the Low Charging Gradient - fcodes: - - direct_operate - optional: I - point_name: DLFW.WChaGra.AO69 - response: DLFW.WChaGra.AI128 - step_number: 14 - - description: Set the Start Delay - fcodes: - - direct_operate - optional: I - point_name: DHFW2.ActStrDlTmms.AO70 - response: DHFW2.ActStrDlTmms.AI129 - step_number: 15 - - description: Set the Stop Delay - fcodes: - - direct_operate - optional: I - point_name: DHFW2.ActStopDlTmms.AO71 - response: DHFW2.ActStopDlTmms.AI130 - step_number: 16 - - description: Set the Ramp Up Time Constant - fcodes: - - direct_operate - optional: I - point_name: DHFW.OpnLoop.AO72 - response: DLFW.OpnLoopMax.AI131 - step_number: 17 - - description: Set the Ramp Down Time Constant - fcodes: - - direct_operate - optional: I - point_name: DHFW.OpnLoop.AO73 - response: DHFW.OpnLoopMax.AI132 - step_number: 18 - - description: Set the Discharging Up Ramp Rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.DschRpuRte.AO74 - response: DHFW.RpuRte.AI133 - step_number: 19 - - description: Set the Discharging Down Ramp Rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.DschRpdRte.AO75 - response: DHFW.RpdRteMax.AI134 - step_number: 20 - - description: Set the Charging Up Ramp Rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.ChaRpuRte.AO76 - response: DHFW.RpuChaRte.AI135 - step_number: 21 - - description: Set the Charging Down Ramp Rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.ChaRpdRte.AO77 - response: DHFW.RpdChaRteMax.AI136 - step_number: 22 - - description: Set the Hight Return Gradient - fcodes: - - direct_operate - optional: I - point_name: DHFW.RtnRmpRte.AO78 - response: DHFW2.RtnRmpRte.AI137 - step_number: 23 - - description: Set the Low Return Gradient - fcodes: - - direct_operate - optional: I - point_name: DLFW.RtnRmpRte.AO79 - response: DLFW2.RtnRmpRte.AI138 - step_number: 24 - - description: Set the minium State of Charge to be used by this mode - fcodes: - - direct_operate - optional: I - point_name: DHFW.SocUseMin.AO80 - response: DAGC.SocUseMinPct.AI140 - step_number: 25 - - description: Set the maximum State of Charge to be used by this mode - fcodes: - - direct_operate - optional: I - point_name: DHFW.SocUseMax.AO81 - response: DAGC.SocUseMaxPct.AI141 - step_number: 26 - - description: Enable or Disable Hysteresis - fcodes: - - direct_operate - optional: I - point_name: DHFW.HysEna.BO34 - response: DHFW.HysEna.BI86 - step_number: 27 - - description: Enable or Disable Snapshot of Power - fcodes: - - direct_operate - optional: I - point_name: DHFW.SnptEna.BO35 - response: DHFW.SnptEna.BI87 - step_number: 28 - - action: publish - description: Enable Frequency-Watt Mode - fcodes: - - select - - operate - optional: M - point_name: DHFW.ModEna.BO16 - response: DHFW.ModEna.BI68 - step_number: 29 -- id: enable_dynamic_reactive_current_support_mode - name: Enable Dynamic Reactive Current Support Mode - ref: AN2018 Spec section 2.5.4 Table 37 - mode_types: - schedule: - - 9 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DRGS.ModPrio.AO32 - response: DRGS.ModPrio.AI83 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DRGS.WinTms.AO33 - response: DRGS.WinTms.AI84 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DRGS.RmpTms.AO34 - response: DRGS.RmpTms.AI85 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DRGS.RvrtTms.AO35 - response: DRGS.RvrtTms.AI86 - step_number: 4 - - description: Identify the meter used to measure the voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DRGS.EcpRef.AO36 - response: DRGS.EcpRef.AI87 - step_number: 5 - - description: Set the Gradient Mode to select the curve shape - fcodes: - - direct_operate - optional: M - point_name: DRGS.ArGraMod.AO37 - response: DRGS.ArGraMod.AI91 - step_number: 6 - - description: Set the Deadband Minimum Voltage - fcodes: - - direct_operate - optional: M - point_name: DRGS.DbVMin.AO38 - response: DRGS.DbVMin.AI92 - step_number: 7 - - description: Set the Deadband Maximum Voltage - fcodes: - - direct_operate - optional: M - point_name: DRGS.DbVMax.AO39 - response: DRGS.DbVMax.AI93 - step_number: 8 - - description: Set the Reactive Current Support Gradient for Sags - fcodes: - - direct_operate - optional: M - point_name: DRGS.ArGraSag.AO40 - response: DRGS.ArGraSag.AI94 - step_number: 9 - - description: Set the Reactive Current Support Gradient for Swells - fcodes: - - direct_operate - optional: M - point_name: DRGS.ArGraSwl.AO41 - response: DRGS.ArGraSwl.AI95 - step_number: 10 - - description: Set the Filter Time for the Moving Average Voltage in seconds - fcodes: - - direct_operate - optional: M - point_name: DRGS.FilTms.AO42 - response: DRGS.FilTms.AI96 - step_number: 11 - - description: Enable Event-Based Reactive Current Support if required. It shall - default to Disabled. - fcodes: - - direct_operate - optional: I - point_name: DRGS.ArGraMod.BO33 - response: DRGS.ModEna.BI85 - step_number: 12 - - description: Set the Hold Time in milliseconds if Event-Based Reactive Current - Support is required. - fcodes: - - direct_operate - optional: I - point_name: DRGS.HoldTmms.AO46 - response: DRGS.HoldTmms.AI100 - step_number: 13 - - description: Set the Block Zone Voltage if required. Otherwise it shall default - to zero. - fcodes: - - direct_operate - optional: I - point_name: DRGS.BlkZnV.AO43 - response: DRGS.BlkZnV.AI97 - step_number: 14 - - description: Set the Hysteresis Block Zone Voltage if required. Otherwise it - shall default to zero. - fcodes: - - direct_operate - optional: I - point_name: DRGS.HysBlkZnV.AO44 - response: DRGS.HysBlkZnV.AI98 - step_number: 15 - - description: Set the Block Zone Time in milliseconds if required. Otherwise it - shall default to zero. - fcodes: - - direct_operate - optional: I - point_name: DRGS.BlkZnTmms.AO45 - response: DRGS.BlkZnTmms.AI99 - step_number: 16 - - action: publish - description: Enable Dynamic Reactive Current Mode - fcodes: - - select - - operate - optional: M - point_name: DRGS.ModEna.BO14 - response: DRGS.ModEna.BI66 - step_number: 17 -- id: enable_volt-watt_mode - name: Enable Volt-Watt Mode - ref: AN2018 Spec section 2.5.5 Table 38 - steps: - - description: If not already established, set the Reference Voltage - fcodes: - - direct_operate - optional: I - point_name: DECP.VRef.AO0 - response: DECP.VRef.AI29 - step_number: 1 - - description: If not already established, set the Reference Voltage Offset - fcodes: - - direct_operate - optional: I - point_name: DECP.VRefOfs.AO1 - response: DECP.VRefOfs.AI30 - step_number: 2 - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DVWD.ModPrio.AO48 - response: DVWD.ModPrio.AI102 - step_number: 3 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DVWD.WinTms.AO49 - response: DVWD.WinTms.AI103 - step_number: 4 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DVWD.RmpTms.AO50 - response: DVWD.RmpTms.AI104 - step_number: 5 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DVWD.RvrtTms.AO51 - response: DVWD.RvrtTms.AI105 - step_number: 6 - - description: Identify the meter used to measure the voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DVWD2.EcpRef.AO52 - response: DVWD2.EcpRef.AI106 - step_number: 7 - - description: Set the Dynamic Volt-Watt Gradient - fcodes: - - direct_operate - optional: I - point_name: DVWD.DynVWGra.AO53 - response: DVWD.DynVWGra.AI110 - step_number: 8 - - description: Set the Dynamic Volt-Watt Filter Time - fcodes: - - direct_operate - optional: I - point_name: DVWD.VWFilTms.AO54 - response: DVWD.VWFilTms.AI111 - step_number: 9 - - description: Set the Dynamic Volt-Watt Lower Deadband - fcodes: - - direct_operate - optional: I - point_name: DVWD.DbVWLo.AO55 - response: DVWD.DbVWLo.AI112 - step_number: 10 - - description: Set the Dynamic Volt-Watt Upper Deadband - fcodes: - - direct_operate - optional: I - point_name: DVWD.DbVWHi.AO56 - response: DVWD.DbVWHi.AI113 - step_number: 11 - - action: publish - description: Enable Dynamic Volt-Watt mode - fcodes: - - select - - operate - optional: M - point_name: DVWD.ModEna.BO15 - response: DVWD.ModEna.BI67 - step_number: 12 -- id: enable_active_power_limit_mode - name: Enable Active Power Limit Mode - ref: AN2018 Spec section 2.6.1 Table 39 - mode_types: - schedule: - - 12 - - 13 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DWMX.ModPrio.AO82 - response: DWMX.ModPrio.AI142 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DWMX.WinTms.AO83 - response: DWMX.WinTms.AI143 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DWMX.RmpTms.AO84 - response: DWMX.RmpTms.AI144 - step_number: 3 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DWMX.RvrtTms.AO85 - response: DWMX.RvrtTms.AI145 - step_number: 4 - - description: Identify the meter used to measure the active power. By default - this is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DWMX.EcpRef.AO86 - response: DWMX.EcpRef.AI146 - step_number: 5 - - description: Retrieve Maximum Active Generation Power Capability - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.WMax.AI32 - step_number: 6 - - description: Retrieve Maximum Active Charging Power Capability - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.ChaWMax.AI33 - step_number: 7 - - description: Set maximum output in percent of nominal Watts (Charging) - fcodes: - - direct_operate - optional: M - point_name: DWMX.WLimPct.AO87 - response: DWMX.WLimPct.AI148 - step_number: 8 - - description: Set maximum output in percent of nominal Watts (Generating) - fcodes: - - direct_operate - optional: M - point_name: DWMN.WLimPct.AO88 - response: DWMN.WLimPct.AI149 - step_number: 9 - - action: publish - description: Enable Active Power Limit mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DWLM.ModEna.BO17 - response: DWLM.ModEna.BI69 - step_number: 10 -- id: enable_charge_discharge_storage_mode - name: Enable Charge/Discharge Storage Mode - ref: AN2018 Spec section 2.6.2 Table 41 - mode_types: - schedule: - - 14 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DWGC.ModPrio.AO89 - response: DWGC.ModPrio.AI150 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DWGC.WinTms.AO90 - response: DWGC.WinTms.AI151 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DWGC.RmpTms.AO91 - response: DWGC.RmpTms.AI152 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DWGC.RvrtTms.AO92 - response: DWGC.RvrtTms.AI153 - step_number: 4 - - description: Select whether to use Ramp Rates or Time Constants - fcodes: - - direct_operate - optional: I - point_name: DWGC.UseRmpRte.BO38 - response: DWGC.UseRmpRte.BI90 - step_number: 5 - - description: 'If DWGC.UseRmpRte = 0: Set Charge/Discharge Time Constant Ramp Up - Time' - fcodes: - - direct_operate - optional: O - point_name: DWGC.OpnLoop.AO94 - response: DWGC.OpnLoopMax.AI155 - step_number: 6 - - description: 'If DWGC.UseRmpRte = 0: Set Charge/Discharge Time Constant Ramp Down - Time' - fcodes: - - direct_operate - optional: O - point_name: DWGC.OpnLoop.AO95 - response: DWGC.OpnLoopMax.AI156 - step_number: 7 - - description: 'If DWGC.UseRmpRte = 1: Set Discharge Ramp Up Rate' - fcodes: - - direct_operate - optional: O - point_name: DWGC.DschRpuRte.AO96 - response: DWGC.RpuRte.AI157 - step_number: 8 - - description: 'If DWGC.UseRmpRte = 1: Set Discharge Ramp Down Rate' - fcodes: - - direct_operate - optional: O - point_name: DWGC.DschRpdRte.AO97 - response: DWGC.RpdRteMax.AI158 - step_number: 9 - - description: 'If DWGC.UseRmpRte = 1: Set Charge Ramp Up Rate' - fcodes: - - direct_operate - optional: O - point_name: DWGC.ChaRpuRte.AO98 - response: DWGC.RpuChaRte.AI159 - step_number: 10 - - description: 'If DWGC.UseRmpRte = 1: Set Charge Ramp Down Rate' - fcodes: - - direct_operate - optional: O - point_name: DWGC.ChaRpdRte.AO99 - response: DWGC.RpdChaRteMax.AI160 - step_number: 11 - - description: Set Minimum Reserve for Storage (percent of Battery Capacity Rating) - fcodes: - - direct_operate - optional: I - point_name: DWGC.SocUseMinPct.AO100 - response: DWGC.SocUseMinPct.AI161 - step_number: 12 - - description: Set Maximum Reserve for Storage (percent of Battery Capacity Rating) - fcodes: - - direct_operate - optional: I - point_name: DWGC.SocUseMaxPct.AO101 - response: DWGC.SocUseMaxPct.AI162 - step_number: 13 - - description: Set discharge/charge Active Power Target. Positive is discharging, - negative is charging. - fcodes: - - direct_operate - optional: M - point_name: DWGC.GnWPctSpt.AO93 - response: DWGC.GnWPctSpt.AI154 - step_number: 14 - - action: publish - description: Enable charge/discharge mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DWGC.ModEna.BO18 - response: DWGC.ModEna.BI70 - step_number: 15 -- id: enable_coordinated_charge_discharge_management_mode - name: Enable Coordinated Charge/Discharge Management Mode - ref: AN2018 Spec section 2.6.3 Table 42 - mode_types: - schedule: - - 15 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DTCD.ModPrio.AO102 - response: DTCD.ModPrio.AI163 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DTCD.WinTms.AO103 - response: DTCD.WinTms.AI164 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DTCD.RmpTms.AO104 - response: DTCD.RmpTms.AI165 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DTCD.RvrtTms.AO105 - response: DTCD.RvrtTms.AI166 - step_number: 4 - - description: Set the Target State of Charge, as a percentage of Usable Capacity - fcodes: - - direct_operate - optional: M - point_name: DTCD.SocUseTgtPct.AO106 - response: DTCD.SocUseTgtPct.AI167 - step_number: 5 - - description: Set the Target Date Charge Needed - fcodes: - - direct_operate - optional: M - point_name: DTCD.DateTgt.AO107 - response: DTCD.DateTgt.AI168 - step_number: 6 - - description: Set the Target Time Charge Needed (milliseconds since midnight) - fcodes: - - direct_operate - optional: M - point_name: DTCD.DateTgtTms.AO108 - response: DTCD.DateTgtTms.AI169 - step_number: 7 - - action: publish - description: Enable coordinated charge/discharge mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DWGC.ModEna.BO18 - response: DTCD.ModEna.BI71 - step_number: 8 -- id: enable_active_power_response_modes - name: Enable Active Power Response Modes - ref: AN2018 Spec section 2.6.4 Table 43 - mode_types: - schedule: - - 16 - - 17 - - 18 - steps: - - description: 'Set the priority of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.ModPrio.AO115 - response: DPKP.ModPrio.AI176 - step_number: 1 - - description: 'Set the priority of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.ModPrio.AO124 - response: DGFL.ModPrio.AI187 - step_number: 2 - - description: 'Set the priority of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.ModPrio.AO133 - response: DLFL.ModPrio.AI198 - step_number: 3 - - description: 'Set enabling time window of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.WinTms.AO116 - response: DPKP.WinTms.AI177 - step_number: 4 - - description: 'Set enabling time window of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.WinTms.AO125 - response: DGFL.WinTms.AI188 - step_number: 5 - - description: 'Set enabling time window of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.WinTms.AO134 - response: DLFL.WinTms.AI199 - step_number: 6 - - description: 'Set enabling ramp time of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.RmpTms.AO117 - response: DPKP.RmpTms.AI178 - step_number: 7 - - description: 'Set enabling ramp time of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.RmpTms.AO126 - response: DGFL.RmpTms.AI189 - step_number: 8 - - description: 'Set enabling ramp time of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.RmpTms.AO135 - response: DLFL.RmpTms.AI200 - step_number: 9 - - description: 'Set reversion timeout period of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.RvrtTms.AO118 - response: DPKP.RvrtTms.AI179 - step_number: 10 - - description: 'Set reversion timeout period of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.RvrtTms.AO127 - response: DGFL.RvrtTms.AI190 - step_number: 11 - - description: 'Set reversion timeout period of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.RvrtTms.AO136 - response: DLFL.RvrtTms.AI201 - step_number: 12 - - description: 'Identify the meter used to measure the Reference Power Input of - mode #1. By default this is the System Meter (ID = 0)' - fcodes: - - direct_operate - optional: I - point_name: DPKP.EcpRef.AO119 - response: DPKP.EcpRef.AI180 - step_number: 13 - - description: 'Identify the meter used to measure the Reference Power Input of - mode #2. By default this is the System Meter (ID = 0)' - fcodes: - - direct_operate - optional: I - point_name: DGFL.EcpRef.AO128 - response: DGFL.EcpRef.AI191 - step_number: 14 - - description: 'Identify the meter used to measure the Reference Power Input of - mode #3. By default this is the System Meter (ID = 0)' - fcodes: - - direct_operate - optional: I - point_name: DLFL.EcpRef.AO137 - response: DLFL.EcpRef.AI202 - step_number: 15 - - description: 'Set the power threshold for activating mode #1' - fcodes: - - direct_operate - optional: M - point_name: DPKP.PkPwrWLim.AO120 - response: DPKP.PkPwrWLim.AI182 - step_number: 16 - - description: 'Set the power threshold for activating mode #2' - fcodes: - - direct_operate - optional: M - point_name: DGFL.PkPwrWLim.AO129 - response: DGFL.PkPwrWLim.AI193 - step_number: 17 - - description: 'Set the power threshold for activating mode #3' - fcodes: - - direct_operate - optional: M - point_name: DLFL.PkPwrWLim.AO138 - response: DLFL.PkPwrWLim.AI204 - step_number: 18 - - description: 'Set the ratio used to calculate the output power from the measured - power of mode #1' - fcodes: - - direct_operate - optional: M - point_name: DPKP.PkPwrFolPct.AO121 - response: DPKP.PkPwrFolPct.AI183 - step_number: 19 - - description: 'Set the ratio used to calculate the output power from the measured - power of mode #2' - fcodes: - - direct_operate - optional: M - point_name: DGFL.PkPwrFolPct.AO130 - response: DGFL.PkPwrFolPct.AI194 - step_number: 20 - - description: 'Set the ratio used to calculate the output power from the measured - power of mode #3' - fcodes: - - direct_operate - optional: M - point_name: DLFL.PkPwrFolPct.AO139 - response: DLFL.PkPwrFolPct.AI205 - step_number: 21 - - description: 'Set the maximum ramp up rate of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.RpuRte.AO122 - response: DPKP.RpuRte.AI184 - step_number: 22 - - description: 'Set the maximum ramp up rate of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.RpuRte.AO131 - response: DGFL.RpuRte.AI195 - step_number: 23 - - description: 'Set the maximum ramp up rate of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.RpuRte.AO140 - response: DLFL.RpuRte.AI206 - step_number: 24 - - description: 'Set the maximum ramp down rate of mode #1' - fcodes: - - direct_operate - optional: I - point_name: DPKP.RpdRte.AO123 - response: DPKP.RpdRte.AI185 - step_number: 25 - - description: 'Set the maximum ramp down rate of mode #2' - fcodes: - - direct_operate - optional: I - point_name: DGFL.RpdRte.AO132 - response: DGFL.RpdRte.AI196 - step_number: 26 - - description: 'Set the maximum ramp down rate of mode #3' - fcodes: - - direct_operate - optional: I - point_name: DLFL.RpdRte.AO141 - response: DLFL.RpdRte.AI207 - step_number: 27 - - description: 'Enable the active response mode #1' - fcodes: - - select - - operate - optional: M - point_name: DPKP.ModEna.BO20 - response: DPKP.ModEna.BI72 - step_number: 28 - - description: 'Enable the active response mode #2' - fcodes: - - select - - operate - optional: M - point_name: DGFL.ModEna.BO21 - response: DGFL.ModEna.BI73 - step_number: 29 - - action: publish - description: 'Enable the active response mode #3' - fcodes: - - select - - operate - optional: M - point_name: DLFL.ModEna.BO22 - response: DLFL.ModEna.BI74 - step_number: 30 -- id: perform_automatic_generation_control_mode - name: Perform Automatic Generation Control Mode - ref: AN2018 Spec section 2.6.5 Table 45 - mode_types: - schedule: - - 19 - steps: - - description: Set priority of the mode - fcodes: - - direct_operate - optional: I - point_name: DAGC.ModPrio.AO142 - response: DAGC.ModPrio.AI209 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DAGC.WinTms.AO143 - response: DAGC.WinTms.AI210 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DAGC.RmpTms.AO144 - response: DAGC.RmpTms.AI211 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DAGC.RvrtTms.AO145 - response: DAGC.RvrtTms.AI212 - step_number: 4 - - description: Select whether to use Ramp Rates or Time Constants - fcodes: - - direct_operate - optional: I - point_name: DAGC.UseRmpRte.BO39 - response: DAGC.UseRmpRte.BI91 - step_number: 5 - - description: 'If DAGC.UseRmpRte = 0: Set AGC Ramp Time Constant Up Time' - fcodes: - - direct_operate - optional: O - point_name: DAGC.OpnLoop.AO147 - response: DAGC.RmpUpTms.AI214 - step_number: 6 - - description: 'If DAGC.UseRmpRte = 0: Set AGC Ramp Time Constant Down Time' - fcodes: - - direct_operate - optional: O - point_name: DAGC.OpnLoop.AO148 - response: DAGC.RmpDnTms.AI215 - step_number: 7 - - description: 'If DAGC.UseRmpRte = 1: Set AGC Discharge Ramp Up Rate' - fcodes: - - direct_operate - optional: O - point_name: DAGC.DschRpuRte.AO149 - response: DAGC.RpuRte.AI216 - step_number: 8 - - description: 'If DAGC.UseRmpRte = 1: Set AGC Discharge Ramp Down Rate' - fcodes: - - direct_operate - optional: O - point_name: DAGC.DschRpdRte.AO150 - response: DAGC.RpdRte.AI217 - step_number: 9 - - description: 'If DAGC.UseRmpRte = 1: Set AGC Charge Ramp Up Rate' - fcodes: - - direct_operate - optional: O - point_name: DAGC.ChaRpuRte.AO151 - response: DAGC.RpuChaRte.AI218 - step_number: 10 - - description: 'If DAGC.UseRmpRte = 1: Set AGC Charge Ramp Down Rate' - fcodes: - - direct_operate - optional: O - point_name: DAGC.ChaRpdRte.AO152 - response: DAGC.RpdChaRte.AI219 - step_number: 11 - - description: Set Minimum Usable State of Charge (percent of Usable Capacity Rating) - fcodes: - - direct_operate - optional: I - point_name: DAGC.SocUseMinPct.AO153 - response: DAGC.SocUseMinPct.AI220 - step_number: 12 - - description: Set Maximum Usable State of Charge (percent of Usable Capacity Rating) - fcodes: - - direct_operate - optional: I - point_name: DAGC.SocUseMaxPct.AO154 - response: DAGC.SocUseMaxPct.AI221 - step_number: 13 - - description: Set the Active Power Target (in Watts) Positive is discharging, negative - is charging. - fcodes: - - direct_operate - optional: M - point_name: DAGC.GnWSpt.AO146 - response: DAGC.GnWSpt.AI213 - step_number: 14 - - description: Enable AGC mode and receive response. - fcodes: - - select - - operate - optional: M - point_name: DAGC.ModEna.BO23 - response: DAGC.ModEna.BI75 - step_number: 15 - - action: publish - description: Once the mode is enabled, periodically update the Active Power Target. - fcodes: - - direct_operate - optional: M - point_name: DAGC.GnWSpt.AO146 - response: DAGC.GnWSpt.AI213 - step_number: 16 - - description: Read the predicted State of Charge - fcodes: - - read - optional: O - point_name: n/a - response: DAGC.SocExpc.AI224 - step_number: 17 -- id: enable_active_power_smoothing - name: Enable Active Power Smoothing - ref: AN2018 Spec section 2.6.6 Table 46 - mode_types: - schedule: - - 20 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DWSM.ModPrio.AO155 - response: DWSM.ModPrio.AI227 - step_number: 1 - - description: Set time window - fcodes: - - direct_operate - optional: I - point_name: DWSM.WinTms.AO156 - response: DWSM.WinTms.AI228 - step_number: 2 - - description: Set ramp time - fcodes: - - direct_operate - optional: I - point_name: DWSM.RmpTms.AO157 - response: DWSM.RmpTms.AI229 - step_number: 3 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DWSM.RvrtTms.AO158 - response: DWSM.RvrtTms.AI230 - step_number: 4 - - description: Identify the meter used to measure the Reference Power Input. By - default this is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DWSM.EcpRef.AO159 - response: DWSM.EcpRef.AI231 - step_number: 5 - - description: Set the Active Power Smoothing Gradient - fcodes: - - direct_operate - optional: I - point_name: DWSM.WSmthGra.AO160 - response: DWSM.WSmthGra.AI233 - step_number: 6 - - description: Set the Active Power Smoothing Lower Limit - fcodes: - - direct_operate - optional: I - point_name: DWSM.WSmthLoLim.AO161 - response: DWSM.WSmthLoLim.AI234 - step_number: 7 - - description: Set the Active Power Smoothing Upper Limit - fcodes: - - direct_operate - optional: I - point_name: DWSM.WSmthHiLim.AO162 - response: DWSM.WSmthHiLim.AI235 - step_number: 8 - - description: Set the Active Power Smoothing Filter Time - fcodes: - - direct_operate - optional: I - point_name: DWSM.FilTms.AO163 - response: DWSM.FilTms.AI236 - step_number: 9 - - description: Set the Discharge Ramp Up Rate - fcodes: - - direct_operate - optional: I - point_name: DWSM.DschRpuRte.AO164 - response: DWSM.RpuRte.AI237 - step_number: 10 - - description: Set the Discharge Ramp Down Rate - fcodes: - - direct_operate - optional: I - point_name: DWSM.DschRpdRte.AO165 - response: DWSM.RpdRte.AI238 - step_number: 11 - - description: Set the Charge Ramp Up Rate - fcodes: - - direct_operate - optional: I - point_name: DWSM.ChaRpuRte.AO166 - response: DWSM.RpuChaRte.AI239 - step_number: 12 - - description: Set the Charge Ramp Down Rate - fcodes: - - direct_operate - optional: I - point_name: DWSM.ChaRpdRte.AO167 - response: DWSM.RpdChaRte.AI240 - step_number: 13 - - action: publish - description: Enable Active Power Smoothing Mode - fcodes: - - select - - operate - optional: M - point_name: DWSM.ModEna.BO24 - response: DWSM.ModEna.BI76 - step_number: 14 -- id: enable_volt-watt_curve - mode_types: - curve: - - 5 - schedule: - - 21 - name: Enable Volt-Watt Curve - ref: AN2018 Spec section 2.6.7 Table 47 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DVWC.ModPrio.AO168 - response: DVWC.ModPrio.AI242 - step_number: 1 - - description: Set time window - fcodes: - - direct_operate - optional: I - point_name: DVWC.WinTms.AO169 - response: DVWC.WinTms.AI243 - step_number: 2 - - description: Set ramp time - fcodes: - - direct_operate - optional: I - point_name: DVWC.RmpTms.AO170 - response: DVWC.RmpTms.AI244 - step_number: 3 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DVWC.RvrtTms.AO171 - response: DVWC.RvrtTms.AI245 - step_number: 4 - - description: Identify the meter used to measure the Voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DVWC.EcpRef.AO172 - response: DVWC.EcpRef.AI246 - step_number: 5 - - description: Set the reference voltage if it has not already been set - fcodes: - - direct_operate - optional: I - point_name: DECP.VRef.AO0 - response: DECP.VRef.AI29 - step_number: 6 - - description: Set the reference voltage offset if it has not already been set - fcodes: - - direct_operate - optional: I - point_name: DECP.VRefOfs.AO1 - response: DECP.VRefOfs.AI30 - step_number: 7 - - description: Identify the index of the curve being used - fcodes: - - direct_operate - func_ref: curve - optional: M - point_name: DVWC.VWCrv.AO173 - response: DVWC.VWCrv.AI248 - step_number: 8 - - action: publish - description: Enable the Volt-Watt Mode - fcodes: - - select - - operate - optional: M - point_name: DVWC.ModEna.BO25 - response: DVWC.ModEna.BI77 - step_number: 9 - - description: Read the maximum active power the outstation will attempt to generate - or absorb based on the voltage and the curve in use. - fcodes: - - read - optional: O - point_name: n/a - response: DVWC.ReqWLim.AI249 - step_number: 10 - - description: Read the actual active power produced or absorbed - fcodes: - - read - optional: O - point_name: n/a - response: MMXU.TotW.AI537 - step_number: 11 -- id: enable_frequency-watt_curve_mode - mode_types: - curve: - - 3 - schedule: - - 22 - - 23 - - 24 - name: Enable Frequency-Watt Curve Mode - ref: AN2018 Spec section 2.6.8 Table 48 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DHFW.ModPrio.AO181 - response: DHFW.ModPrio.AI257 - step_number: 1 - - description: Set time window - fcodes: - - direct_operate - optional: I - point_name: DHFW.WinTms.AO182 - response: DHFW.WinTms.AI258 - step_number: 2 - - description: Set ramp time - fcodes: - - direct_operate - optional: I - point_name: DHFW.RvrtTms.AO184 - response: DHFW.RmpTms.AI259 - step_number: 3 - - description: Set reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DHFW.RmpTms.AO183 - response: DHFW.RvrtTms.AI260 - step_number: 4 - - description: Identify the meter used to measure the Frequency. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DHFW.EcpRef.AO185 - response: DHFW.EcpRef.AI261 - step_number: 5 - - description: Set the Nominal Grid Frequency if it is not already set - fcodes: - - direct_operate - optional: I - point_name: DECP.EcpNomHz.AO2 - response: DECP.EcpNomHz.AI31 - step_number: 6 - - description: Set the starting delays - fcodes: - - direct_operate - optional: I - point_name: DHFW.ActStrDlTmms.AO189 - response: DHFW.ActStrDlTmms.AI266 - step_number: 7 - - description: Set the stopping delays - fcodes: - - direct_operate - optional: I - point_name: DHFW.ActStopDlTmms.AO190 - response: DHFW.ActStopDlTmms.AI267 - step_number: 8 - - description: Set the frequency-watt curve ramp up time constant for the output - fcodes: - - direct_operate - optional: I - point_name: DHFW.OpnLoopMax.AO191 - response: DHFW.OpnLoopMax.AI268 - step_number: 9 - - description: Set the frequency-watt curve ramp down time constant for the output - fcodes: - - direct_operate - optional: I - point_name: DHFW.OpnLoopMax.AO192 - response: DHFW.OpnLoopMax.AI269 - step_number: 10 - - description: Set the frequency-watt curve discharge ramp up rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.RpuRte.AO193 - response: DHFW.RpuRte.AI270 - step_number: 11 - - description: Set the frequency-watt curve discharge ramp down rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.RpdRte.AO194 - response: DHFW.RpdRte.AI271 - step_number: 12 - - description: Set the frequency-watt curve charge ramp up rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.RpuChaRte.AO195 - response: DHFW.RpuChaRte.AI272 - step_number: 13 - - description: Set the frequency-watt curve charge ramp down rate - fcodes: - - direct_operate - optional: I - point_name: DHFW.RpdChaRte.AO196 - response: DHFW.RpdChaRte.AI273 - step_number: 14 - - description: Identify the index of the main curve being used - fcodes: - - direct_operate - func_ref: curve - optional: I - point_name: DHFW.HzWCrv.AO186 - response: DHFW.HzWCrv.AI263 - step_number: 15 - - description: Identify the index of the high frequency hyteresis curve being used - fcodes: - - direct_operate - func_ref: curve - optional: I - point_name: DHFW.HysCrv.AO187 - response: DHFW.HysCrv.AI264 - step_number: 16 - - description: Identify the index of the low frequency hyteresis curve being used - fcodes: - - direct_operate - func_ref: curve - optional: I - point_name: DLFW.HysCrv.AO188 - response: DLFW.HysCrv.AI265 - step_number: 17 - - description: Set the minimum state of charge in which this mode shall operate - fcodes: - - direct_operate - optional: I - point_name: DHFW.SocUseMinPct.AO197 - response: DHFW.SocUseMinPct.AI275 - step_number: 18 - - description: Set the maximum state of charge in which this mode shall operate - fcodes: - - direct_operate - optional: I - point_name: DHFW.SocUseMaxPct.AO198 - response: DHFW.SocUseMaxPct.AI276 - step_number: 19 - - description: Choose whether to use hysteresis - fcodes: - - direct_operate - optional: I - point_name: DLFW.HysEna.BO36 - response: DLFW.HysEna.BI88 - step_number: 20 - - description: Choose whether to snapshot power - fcodes: - - direct_operate - optional: I - point_name: DLFW.SnptEna.BO37 - response: DLFW.SnptEna.BI89 - step_number: 21 - - action: publish - description: Enable the Frequency-Watt Curve Mode - fcodes: - - select - - operate - optional: M - point_name: DHFW.ModEna.BO26 - response: DHFW.ModEna.BI78 - step_number: 22 -- id: set_constant_var_output - name: Set Constant Var Output - ref: AN2018 Spec section 2.7.1 Table 50 - mode_types: - schedule: - - 25 - steps: - - description: Set the priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DVAR.ModPrio.AO199 - response: DVAR.ModPrio.AI277 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DVAR.WinTms.AO200 - response: DVAR.WinTms.AI278 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DVAR.RmpTms.AO201 - response: DVAR.RmpTms.AI279 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DVAR.RvrtTms.AO202 - response: DVAR.RvrtTms.AI280 - step_number: 4 - - description: Set the ramp up Time Constants - fcodes: - - direct_operate - optional: I - point_name: DVAR.OpnLoopMax.AO204 - response: DVAR.OpnLoopMax.AI282 - step_number: 5 - - description: Set the ramp down Time Constants - fcodes: - - direct_operate - optional: I - point_name: DVAR.OpnLoopMax.AO205 - response: DVAR.OpnLoopMax.AI283 - step_number: 6 - - description: Choose whether the time constants represent 3-Tau limits or Open - Loop Response Times - fcodes: - - direct_operate - optional: I - point_name: DSTO.OpnLoopTau.BO9 - response: DSTO.OpnLoopTau.BI28 - step_number: 7 - - description: If Open Loop Response Times are selected, choose the percentage of - final output represented by the time constant (e.g. 90% or 95%) - fcodes: - - direct_operate - optional: I - point_name: DSTO.OpnLoopPct.AO3 - response: DGEN.OpnLoopPct.AI40 - step_number: 8 - - description: Select the meaning of the Constant VArs Reactive Power Target - fcodes: - - direct_operate - optional: I - point_name: DSTO.VArRef.AO5 - response: DGEN.VArSetRef.AI42 - step_number: 9 - - description: 'If DSTO.VArRef = 1: Read percent of maximum active generation power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.WMax.AI32 - step_number: 10 - - description: 'If DSTO.VArRef = 1: Read percent of maximum active charging power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.ChaWMax.AI33 - step_number: 11 - - description: 'If DSTO.VArRef = 2: Read percent of maximum reactive injection power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.IvarMax.AI34 - step_number: 12 - - description: 'If DSTO.VArRef = 2: Read percent of maximum reactive absorption - power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.AvarMax.AI35 - step_number: 13 - - description: 'If DSTO.VArRef = 3: Read percent of system reactive injection power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.AvarAvl.AI45 - step_number: 14 - - description: 'If DSTO.VArRef = 3: Read percent of system reactive absorption power' - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.IvarAvl.AI46 - step_number: 15 - - description: Set the Constant VArs Reactive Power Target in percent - fcodes: - - direct_operate - optional: M - point_name: DVAR.VArTgtPct.AO203 - response: DVAR.VArTgtPct.AI281 - step_number: 16 - - action: publish - description: Enable Constant VArs mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DVAR.ModEna.BO27 - response: DVAR.ModEna.BI79 - step_number: 17 -- id: set_a_fixed_power_factor - name: Set a Fixed Power Factor - ref: AN2018 Spec section 2.7.2 Table 52 - mode_types: - schedule: - - 26 - steps: - - description: Set the priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DFPF.ModPrio.AO206 - response: DFPF.ModPrio.AI284 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DFPF.WinTms.AO207 - response: DFPF.WinTms.AI285 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DFPF.RmpTms.AO208 - response: DFPF.RmpTms.AI286 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DFPF.RvrtTms.AO209 - response: DFPF.RvrtTms.AI287 - step_number: 4 - - description: Set the requirement for whether to inject or absorb VARs (PFExt) - when discharging / generating - fcodes: - - direct_operate - optional: I - point_name: DFPF.PFGnExtSet.BO10 - response: DFPF.PFGnExtSet.BI29 - step_number: 5 - - description: Set the requirement for whether to inject or absorb VARs (PFExt) - when charging - fcodes: - - direct_operate - optional: I - point_name: DFPF.PFLodExtSet.BO11 - response: DFPF.PFLodExtSet.BI30 - step_number: 6 - - description: Set Fixed Power Factor Setpoint to use when generating / discharging - fcodes: - - direct_operate - optional: M - point_name: DFPF.PFGnTgt.AO210 - response: DFPF.PFGnTgt.AI288 - step_number: 7 - - description: Set Fixed Power Factor Setpoint to use when charging - fcodes: - - direct_operate - optional: M - point_name: DFPF.PFLodTgt.AO211 - response: DFPF.PFLodTgt.AI289 - step_number: 8 - - action: publish - description: Enable fixed power factor mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DFPF.ModEna.BO28 - response: DFPF.BI47 - step_number: 9 -- id: change_and_select_volt-var_control_mode - mode_types: - curve: - - 2 - schedule: - - 27 - name: Change and Select Volt-Var Control Mode - ref: AN2018 Spec section 2.7.3 Table 54 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DVVR.ModPrio.AO212 - response: DVVR.ModPrio.AI290 - step_number: 1 - - description: Set the enabling time window - fcodes: - - direct_operate - optional: I - point_name: DVVR.WinTms.AO213 - response: DVVR.WinTms.AI291 - step_number: 2 - - description: Set the enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DVVR.RmpTms.AO214 - response: DVVR.RmpTms.AI292 - step_number: 3 - - description: Set the enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DVVR.RvrtTms.AO215 - response: DVVR.RvrtTms.AI293 - step_number: 4 - - description: Identify the meter used to measure the voltage. By default this - is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DVVR.EcpRef.AO216 - response: DVVR.EcpRef.AI294 - step_number: 5 - - description: If using a fixed Voltage reference, set the reference voltage if - it has not already been set - fcodes: - - direct_operate - optional: O - point_name: DECP.VRef.AO0 - response: DECP.VRef.AI29 - step_number: 6 - - description: If using a fixed Voltage reference, set the reference voltage offset - if it has not already been set - fcodes: - - direct_operate - optional: O - point_name: DECP.VRefOfs.AO1 - response: DECP.VRefOfs.AI30 - step_number: 7 - - description: If autonomously adjusting the Voltage reference, set the time constant - for the lowpass filter - fcodes: - - direct_operate - optional: O - point_name: DVVR.VRefTmms.AO220 - response: DVVR.VRefTmms.AI300 - step_number: 8 - - description: If autonomously adjusting the Voltage reference, enable autonomous - adjustment - fcodes: - - direct_operate - optional: O - point_name: DVVR.VRefAdjEna.BO41 - response: DVVR.VRefAdjEna.BI93 - step_number: 9 - - description: Set the ramp up time constant for the output of the curve - fcodes: - - direct_operate - optional: I - point_name: DVVR.OpnLoopMax.AO218 - response: DVVR.OpnLoopMax.AI298 - step_number: 10 - - description: Set the ramp down time constant for the output of the curve - fcodes: - - direct_operate - optional: I - point_name: DVVR.OpnLoopMax.AO219 - response: DVVR.OpnLoopMax.AI299 - step_number: 11 - - description: Identify the index of the curve being used - fcodes: - - direct_operate - func_ref: curve - optional: M - point_name: DVVR.VVArCrv.AO217 - response: DVVR.VVArCrv.AI297 - step_number: 12 - - action: publish - description: Enable the Volt-VAr Control Mode - fcodes: - - select - - operate - optional: M - point_name: DVVC.ModEna.BO29 - response: DVVC.BI48 - step_number: 13 - - description: Read the adjusted reference voltage, if it is not fixed - fcodes: - - read - optional: O - point_name: n/a - response: DVVR.VRefSet.AI296 - step_number: 14 - - description: Read the measured Voltage - fcodes: - - read - optional: O - point_name: n/a - response: MMXN.Vol.AI295 - step_number: 15 - - description: Read the attempted VArs - fcodes: - - read - optional: O - point_name: n/a - response: DVVR.ReqVAr.AI301 - step_number: 16 - - description: Read the actual VArs (if using system meter) - fcodes: - - read - optional: O - point_name: n/a - response: MMXU.TotVAr.AI541 - step_number: 17 -- id: enable_watt-var_power_mode - mode_types: - curve: - - 4 - schedule: - - 28 - name: Enable Watt-Var Power Mode - ref: AN2018 Spec section 2.7.4 Table 55 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DWVR.ModPrio.AO221 - response: DWVR.ModPrio.AI302 - step_number: 1 - - description: Set the enabling time window - fcodes: - - direct_operate - optional: I - point_name: DWVR.WinTms.AO222 - response: DWVR.WinTms.AI303 - step_number: 2 - - description: Set the enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DWVR.RmpTms.AO223 - response: DWVR.RmpTms.AI304 - step_number: 3 - - description: Set the enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DWVR.RvrtTms.AO224 - response: DWVR.RvrtTms.AI305 - step_number: 4 - - description: Identify the meter used to measure the active power. By default - this is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DWVR.EcpRef.AO225 - response: DWVR.EcpRef.AI306 - step_number: 5 - - description: Read the maximum generation power used as the reference for percent - Watts - fcodes: - - read - - response - optional: O - point_name: n/a - response: DGEN.WMax.AI32 - step_number: 6 - - description: Read the maximum charging power used as the reference for percent - Watts - fcodes: - - read - - response - optional: O - point_name: n/a - response: DSTO.ChaWMax.AI33 - step_number: 7 - - description: Set the ramp up time constant for the output of the curve - fcodes: - - direct_operate - optional: I - point_name: DWVR.OpnLoopMax.AO227 - response: DWVR.OpnLoopMax.AI309 - step_number: 8 - - description: Set the ramp down time constant for the output of the curve - fcodes: - - direct_operate - optional: I - point_name: DWVR.OpnLoopMax.AO228 - response: DWVR.OpnLoopMax.AI310 - step_number: 9 - - description: Identify the index of the curve being used - fcodes: - - direct_operate - func_ref: curve - optional: M - point_name: DWVR.WVArCrv.AO226 - response: DWVR.WVArCrv.AI308 - step_number: 10 - - action: publish - description: Enable the Watt-VAr Power Mode - fcodes: - - select - - operate - optional: M - point_name: DWVR.ModEna.BO30 - response: DWVR.BI49 - step_number: 11 -- id: enable_power_factor_correction_mode - name: Enable Power Factor Correction Mode - ref: AN2018 Spec section 2.7.5 Table 56 - mode_types: - schedule: - - 29 - steps: - - description: Set the priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DPFC.ModPrio.AO229 - response: DPFC.ModPrio.AI312 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DPFC.WinTms.AO230 - response: DPFC.WinTms.AI313 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DPFC.RmpRte.AO231 - response: DPFC.RmpTms.AI314 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DPFC.RvrtTms.AO232 - response: DPFC.RvrtTms.AI315 - step_number: 4 - - description: Identify the meter used to measure the active power. By default - this is the System Meter (ID = 0) - fcodes: - - direct_operate - optional: I - point_name: DPFC.EcpRef.AO233 - response: DPFC.EcpRef.AI316 - step_number: 5 - - description: Set the requirement for whether to inject or absorb VARs (PFExt) - when discharging - fcodes: - - direct_operate - optional: I - point_name: DFPF.PFGnExtSet.BO10 - response: DFPF.PFGnExtSet.BI29 - step_number: 6 - - description: Set the requirement for whether to inject or absorb VARs (PFExt) - when charging - fcodes: - - direct_operate - optional: I - point_name: DFPF.PFLodExtSet.BO11 - response: DFPF.PFLodExtSet.BI30 - step_number: 7 - - description: Set the Average PF Target - fcodes: - - direct_operate - optional: M - point_name: DPFC.PFTrg.AO234 - response: MMXU.TotPF.AI317 - step_number: 8 - - description: Set the Lower PF Limit - fcodes: - - direct_operate - optional: M - point_name: DPFC.PFCorRef.rangeC.AO235 - response: DPFC.PFTrg.AI318 - step_number: 9 - - description: Set the Upper PF Limit - fcodes: - - direct_operate - optional: M - point_name: DPFC.PFCorRef.rangeC.AO236 - response: DPFC.PFCorRef.rangeC.AI319 - step_number: 10 - - action: publish - description: Enable Power Factor Correction Mode - fcodes: - - select - - operate - optional: M - point_name: DPFC.ModEna.BO31 - response: DPFC.ModEna.BI83 - step_number: 11 -- id: signal_a_price_change - name: Signal a Price Change - ref: AN2018 Spec section 2.8 Table 57 - steps: - - description: Set priority of this mode - fcodes: - - direct_operate - optional: I - point_name: DPRG.ModPrio.AO237 - response: DPRG.ModPrio.AI321 - step_number: 1 - - description: Set enabling time window - fcodes: - - direct_operate - optional: I - point_name: DPRG.WinTms.AO238 - response: DPRG.WinTms.AI322 - step_number: 2 - - description: Set enabling ramp time - fcodes: - - direct_operate - optional: I - point_name: DPRG.RmpTms.AO239 - response: DPRG.RmpTms.AI323 - step_number: 3 - - description: Set enabling reversion timeout - fcodes: - - direct_operate - optional: I - point_name: DPRG.RvrtTms.AO240 - response: DPRG.RvrtTms.AI324 - step_number: 4 - - description: Set pricing mode time constant for ramping up - fcodes: - - direct_operate - optional: I - point_name: DPRG.OpnLoopMax.AO242 - response: DPRG.OpnLoopMax.AI326 - step_number: 5 - - description: Set pricing mode time constant for ramping down - fcodes: - - direct_operate - optional: I - point_name: DPRG.OpnLoopMax.AO243 - response: DPRG.OpnLoopMax.AI327 - step_number: 6 - - description: Set pricing signal and receive response - fcodes: - - select - - operate - optional: M - point_name: DPRG.PrcRef.AO241 - response: DPRG.PrcRef.AI325 - step_number: 7 - - action: publish - description: Enable pricing signal mode and receive response - fcodes: - - select - - operate - optional: M - point_name: DPRG.ModEna.BO32 - response: DPRG.ModEna.BI84 - step_number: 8 -- id: enable_schedules - name: Enable Schedules - ref: AN2018 Spec section 2.9 Table 59 - steps: - - description: Enable the Schedule by changing its state to ready - fcodes: - - select - - operate - optional: M - point_name: FSCHxx.Mod.BO42 - response: FSCH.SchdSt.3.BI108 - step_number: 1 - - description: Select shedule index - fcodes: - - direct_operate - func_ref: schedule - optional: M - point_name: FSCC.Schd.AO461 - response: FSCC.Schd.AI570 - step_number: 2 - - description: Check that outstation validates the selected schedule - fcodes: - - read - optional: O - point_name: n/a - response: FSCH.SchdSt.2.BI109 - step_number: 3 - - description: Set selected schedule repeat weekly Sunday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO43 - response: FSCHxx.SchdReuse.BI110 - step_number: 4 - - description: Set selected schedule repeat weekly Monday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO44 - response: FSCHxx.SchdReuse.BI111 - step_number: 5 - - description: Set selected schedule repeat weekly Tuesday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO45 - response: FSCHxx.SchdReuse.BI112 - step_number: 6 - - description: Set selected schedule repeat weekly Wednesday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO46 - response: FSCHxx.SchdReuse.BI113 - step_number: 7 - - description: Set selected schedule repeat weekly Thursday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO47 - response: FSCHxx.SchdReuse.BI114 - step_number: 8 - - description: Set selected schedule repeat weekly Friday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO48 - response: FSCHxx.SchdReuse.BI115 - step_number: 9 - - action: publish - description: Set selected schedule repeat weekly Saturday - fcodes: - - select - - operate - optional: I - point_name: FSCHxx.SchdReuse.BO49 - response: FSCHxx.SchdReuse.BI116 - step_number: 10 - - description: Be notified when the schedule is running - fcodes: - - read - optional: O - point_name: n/a - response: FSCH1.SchdSt.AI579 - step_number: 11 -- id: curve - name: Curve - ref: AN2018 Spec Curve Definition - steps: - - description: Select which curve to edit - fcodes: - - direct_operate - optional: M - point_name: DGSMn.InCrv.AO244 - response: DGSMn.InCrv.AI328 - step_number: 1 - - description: Specify the Curve Mode Type - fcodes: - - direct_operate - optional: M - point_name: DGSMn.ModTyp.AO245 - response: DGSMn.ModTyp.AI329 - step_number: 2 - - description: Specify that the Independent (X-Value) units for the curve - fcodes: - - direct_operate - optional: M - point_name: FMARn.IndpUnits.AO247 - response: FMARn.IndpUnits.AI331 - step_number: 3 - - description: Specify the Dependent (Y-Value) units for the curve - fcodes: - - direct_operate - optional: M - point_name: FMARn.DepRef.AO248 - response: FMARn.DepRef.AI332 - step_number: 4 - - description: Set X-Value and Y-Values pairs for the curve - fcodes: - - direct_operate - optional: M - point_name: FMARn.PairArr.CrvPts.AO249 - response: FMARn.PairArr.CrvPts.AI333 - step_number: 5 - - action: publish - description: Set number of points used for the curve - fcodes: - - direct_operate - optional: M - point_name: FMARn.PairArr.NumPts.AO246 - response: FMARn.PairArr.NumPts.AI330 - step_number: 6 -- id: schedule - name: Schedule - ref: AN2018 Spec Schedule Definition - steps: - - description: Select which schedule to edit. This is the index of the schedule, - not its identity. The indexes shall be the monotonically increasing integers - 12, 13, 14 .etc. while the curve identities may be any unique number. - fcodes: - - direct_operate - optional: M - point_name: FSCC.Schd.AO461 - response: FSCC.Schd.AI570 - step_number: 1 - - description: Set the identity of the schedule to a unique number - fcodes: - - direct_operate - optional: M - point_name: FSCC.Schd.AO462 - response: FSCC.Schd.AI571 - step_number: 2 - - description: Set the priority for the schedule - fcodes: - - direct_operate - optional: M - point_name: FSCH1.SchdPrio.AO463 - response: FSCH.SchdPrio.AI572 - step_number: 3 - - description: Set the meaning of the Y-values of the schedule, i.e. the schedule - type. Refer to Table 58. - fcodes: - - direct_operate - optional: M - point_name: FSCH.SchdVal.valEq.AO464 - response: AI573 - step_number: 4 - - description: Set the date for the schedule to start - fcodes: - - direct_operate - optional: M - point_name: FSCH.StrTm.AO465 - response: FSCH.StrTm.AI574 - step_number: 5 - - description: Set the time for the schedule to start - fcodes: - - direct_operate - optional: M - point_name: FSCH.StrTm.AO466 - response: FSCH.StrTm.AI575 - step_number: 6 - - description: Set the repetition interval - fcodes: - - direct_operate - optional: M - point_name: FSCH.NxtStrTm.AO467 - response: FSCH.NxtStrTm.AI576 - step_number: 7 - - description: Set the units of the repetition interval - fcodes: - - direct_operate - optional: M - point_name: FSCH.SchdReuse.AO468 - response: FSCH.SchdReuse.AI577 - step_number: 8 - - description: Set the Time Offset (X-Values) and Schedule Value (Y-Values) for - each schedule point - fcodes: - - direct_operate - optional: M - point_name: FSCHn.SchdEntr.AO470 - response: FSCHn.SchdEntr.AI581 - step_number: 9 - - action: publish - description: Set the number of points used for the schedule. - fcodes: - - direct_operate - optional: M - point_name: FSCH.NumEntr.AO469 - response: FSCH.NumEntr.AI580 - step_number: 10 \ No newline at end of file diff --git a/services/core/DNP3Agent/tests/data/mesa_points.config b/services/core/DNP3Agent/tests/data/mesa_points.config deleted file mode 100644 index 1ce6cdace7..0000000000 --- a/services/core/DNP3Agent/tests/data/mesa_points.config +++ /dev/null @@ -1,10276 +0,0 @@ -[ - { - "index": 0, - "description": "Reference Voltage", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "minimum": 0, - "data_object": "VRef", - "name": "DECP.VRef.AO0" - }, - { - "index": 1, - "description": "Reference Voltage Offset", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "data_object": "VRefOfs", - "name": "DECP.VRefOfs.AO1" - }, - { - "index": 2, - "description": "Nominal Grid Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DECP", - "units": "Hz", - "minimum": 0, - "data_object": "EcpNomHz", - "name": "DECP.EcpNomHz.AO2" - }, - { - "index": 3, - "description": "Open Loop Response Time Percentage. Percent of target to reach within the open loop response time. Default is 90%.", - "data_type": "AO", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DSTO", - "units": "Percent", - "minimum": 0, - "data_object": "OpnLoopPct", - "name": "DSTO.OpnLoopPct.AO3" - }, - { - "index": 4, - "description": "Power Factor Sign convention", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 2, - "ln_class": "MMXU", - "units": "None", - "minimum": 1, - "data_object": "PFSign", - "allowed_values": { - "1": "IEC active power", - "2": "IEEE lead/lag" - }, - "type": "enumerated", - "name": "MMXU.PFSign.AO4" - }, - { - "index": 5, - "description": "Reference for Reactive Power Setpoints. Selects which setpoint is active. Default is <3>.", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 3, - "ln_class": "DSTO", - "units": "None (list)", - "minimum": 0, - "data_object": "VArRef", - "allowed_values": { - "0": "Not applicable / Unknown", - "1": "Percent of Maximum Active Power (WMax)", - "2": "Percent of Maximum Reactive Power (VArMax)", - "3": "Percent of Available Reactive Power (VArAval)" - }, - "type": "enumerated", - "name": "DSTO.VArRef.AO5" - }, - { - "index": 6, - "description": "DER Start (Return to Service) Voltage High Limit. Percent of Reference Voltage.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 20000, - "ln_class": "DCTE", - "units": "Percent", - "minimum": 0, - "data_object": "VHiLim", - "name": "DCTE.VHiLim.AO6" - }, - { - "index": 7, - "description": "DER Start (Return to Service) Voltage Low Limit. Percent of Reference Voltage.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 10000, - "ln_class": "DCTE", - "units": "Percent", - "minimum": 0, - "data_object": "VLoLim", - "name": "DCTE.VLoLim.AO7" - }, - { - "index": 8, - "description": "DER Start (Return to Service) Frequency High Limit", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DCTE", - "units": "Hz", - "minimum": 0, - "data_object": "HzHiLim", - "name": "DCTE.HzHiLim.AO8" - }, - { - "index": 9, - "description": "DER Start (Return to Service) Frequency Low Limit", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DCTE", - "units": "Hz", - "minimum": 0, - "data_object": "HzLoLim", - "name": "DCTE.HzLoLim.AO9" - }, - { - "index": 10, - "description": "DER Start (Return to Service) Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RtnDlyTmms", - "name": "DCTE.RtnDlyTmms.AO10" - }, - { - "index": 11, - "description": "DER Start (Return to Service) Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AO11" - }, - { - "index": 12, - "description": "DER Start (Return to Service) Ramp Up Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RtnRmpTmms", - "name": "DCTE.RtnRmpTmms.AO12" - }, - { - "index": 13, - "description": "DER Stop (Cease to Energize) Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AO13" - }, - { - "index": 14, - "description": "DER Stop (Cease to Energize) Ramp Down Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DCTE.RmpTms.AO14" - }, - { - "index": 15, - "description": "DER Stop (Cease to Energize) Reversion Timeout Period. Time to revert from the stopped state and return to service.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DCTE.RvrtTms.AO15" - }, - { - "index": 16, - "description": "Connect/Disconnect Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AO16" - }, - { - "index": 17, - "description": "Connect/Disconnect Reversion Timeout Period. Timeout (reversion time is for the Disconnect only).", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DCTE.RvrtTms.AO17" - }, - { - "index": 18, - "description": "Requested Settings Group", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "allowed_values": { - "0": "Not Used", - "1": "Unspecified / Autonomously Determined (see BO Enable Sensed Grid Config Detection)", - "2": "Factory Configuration", - "3": "Default Configuration / Comms Lost", - "4": "Normal Grid-Connected Configuration", - "5": "Islanded Condition 1 (small, local island)", - "6": "Islanded Condition 2 (larger, area island)", - "7": "Islanded Condition 3 (largest, regional island)", - "8": "1st Alternate Grid-Connected Configuration", - "9": "2nd Alternate Grid-Connected Configuration", - "10": "3rd Alternate Grid-Connected Configuration" - }, - "type": "enumerated", - "name": "DECP1.EcpIsldSt.AO18" - }, - { - "index": 19, - "description": "Settings Group Being Edited", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "DRCC", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "name": "DRCC1.EcpIsldSt.AO19" - }, - { - "index": 20, - "description": "Freeze Counter Interval. Interval between freeze counter operations after the initial occurrence. A zero value means the free counter operation is not repeated.", - "data_type": "AO", - "minimum": 0, - "name": "AO20" - }, - { - "index": 21, - "description": "Freeze Counter Interval Units. Units of the interval between freeze counter operations.", - "data_type": "AO", - "maximum": 9, - "minimum": 0, - "units": "None (list)", - "allowed_values": { - "0": "The outstation does not repeat the action, regardless of the Interval count.", - "1": "Milliseconds - In this case the interval is always counted relative to the Start Time and is constant regardless of the clock time set at the Outstation.", - "2": "Seconds - At the same millisecond within the second that is specified in the Start Time.", - "3": "Minutes - At the same second and millisecond within the minute that is specified in the Start Time.", - "4": "Hours - At the same minute,second and B7millisecond within the hour that is specified in the Start Time.", - "5": "Days - At the same time of day that is specified in the Start Time.", - "6": "Weeks - On the same day of the week at the same time of day that is specified in the Start Time", - "7": "Months - On the same day of each month at the same time of day that is specified in the Start Time. If the Start Time falls on the 29th or greater day of the month, the outstation shall not perform the action in months that do not have such a day.", - "8": "Months on Same Day of Week from Start of Month - At the same time of the day on the same day of the week after the beginning of the month as the day specified in the Start Time. For instance, if the Start Time specifies the second Tuesday of February and the Interval Count is 2, the next action shall occur on the second Tuesday of April. In the same example, if the Interval Count is set to 12, this is the same as specifying, Every year on the second Tuesday in February. If the specified day does not occur in a given month when an action was scheduled to occur, the outstation shall not perform the action that month but shall perform it at the next valid scheduled time.", - "9": "Months on Same Day of Week from End of Month - The outstation shall interpret this setting as in <8>, but the day of the week shall be measured from the end of the month, e.g., the second-last Tuesday in February." - }, - "type": "enumerated", - "name": "AO21" - }, - { - "index": 22, - "description": "Low/High Voltage Ride-Through Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DHVT", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHVT.EcpRef.AO22" - }, - { - "index": 23, - "description": "Low/High Voltage Ride-Through High Must Trip Curve Index. Index of the Voltage Ride-through curve which specifies trip points when the voltage is high.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTOV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOV.BlkRef.AO23" - }, - { - "index": 24, - "description": "Low/High Voltage Ride-Through Low Must Trip Curve Index. Index of the Voltage Ride-through curve which specifies trip points when the voltage is low.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTUV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUV.BlkRef.AO24" - }, - { - "index": 25, - "description": "Low/High Voltage Ride-Through High Momentary Cessation Curve Index. Index of the Voltage Ride-through curve which specifies where generation/discharging must stop when the voltage is high.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTOV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOV.BlkRef.AO25" - }, - { - "index": 26, - "description": "Low/High Voltage Ride-Through Low Momentary Cessation Curve Index. Index of the Voltage Ride-through curve which specifies where generation/discharging must stop when the voltage is low.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTUV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUV.BlkRef.AO26" - }, - { - "index": 27, - "description": "Low/High Frequency Ride-Through Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DHFT", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFT.EcpRef.AO27" - }, - { - "index": 28, - "description": "Low/High Frequency Ride-Through High Must Trip Curve Index. Index of the Frequency Ride-through curve which specifies trip points when the frequency is high.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTOF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOF.BlkRef.AO28" - }, - { - "index": 29, - "description": "Low/High Frequency Ride-Through Low Must Trip Curve Index. Index of the Frequency Ride-through curve which specifies trip points when the frequency is low.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTUF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUF.BlkRef.AO29" - }, - { - "index": 30, - "description": "Low/High Frequency Ride-Through High Momentary Cessation Curve Index. Index of the Frequency Ride-through curve which specifies where generation/discharging must stop when the frequency is high.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTOF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOF.BlkRef.AO30" - }, - { - "index": 31, - "description": "Low/High Frequency Ride-Through Low Momentary Cessation Curve Index. Index of the Frequency Ride-through curve which specifies where generation/discharging must stop when the frequency is low.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "PTUF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUF.BlkRef.AO31" - }, - { - "index": 32, - "description": "Dynamic Reactive Current Support Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "minimum": 0, - "data_object": "ModPrio", - "name": "DRGS.ModPrio.AO32" - }, - { - "index": 33, - "description": "Dynamic Reactive Current Support Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DRGS.WinTms.AO33" - }, - { - "index": 34, - "description": "Dynamic Reactive Current Support Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DRGS.RmpTms.AO34" - }, - { - "index": 35, - "description": "Dynamic Reactive Current Support Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DRGS.RvrtTms.AO35" - }, - { - "index": 36, - "description": "Dynamic Reactive Current Support Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DRGS", - "minimum": 0, - "data_object": "EcpRef", - "name": "DRGS.EcpRef.AO36" - }, - { - "index": 37, - "description": "Dynamic Reactive Current Support - Gradient Mode.", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 2, - "ln_class": "DRGS", - "units": "None (list)", - "minimum": 0, - "data_object": "ArGraMod", - "allowed_values": { - "0": "Undefined", - "1": "Gradients reach 0 at the moving average Voltage", - "2": "Gradients reach 0 at the Voltage deadbands" - }, - "type": "enumerated", - "name": "DRGS.ArGraMod.AO37" - }, - { - "index": 38, - "description": "Dynamic Reactive Current Support Deadband Minimum Voltage. Percentage of the nominal voltage (DRCT.Vref), measured from the moving average voltage (RDGS.VAv). Support is no longer applied when the voltage stays above this value for the length of the Hold Time.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 0, - "ln_class": "DRGS", - "units": "Percent", - "minimum": -10000, - "data_object": "DbVMin", - "name": "DRGS.DbVMin.AO38" - }, - { - "index": 39, - "description": "Dynamic Reactive Current Support Deadband Maximum Voltage. Percentage of the nominal voltage (DRCT.Vref), measured from the moving average voltage (RDGS.VAv). Support is no longer applied when the voltage stays below this value for the length of the Hold Time.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 10000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "DbVMax", - "name": "DRGS.DbVMax.AO39" - }, - { - "index": 40, - "description": "Dynamic Reactive Current Support Gradient for Sags. Percentage of the rated current (DRAT.ARtg) to apply capacitively per percentage of the negative deviation from the moving average voltage (RDGS.Av). It is a ratio of percent and is therefore unitless.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DRGS", - "units": "Percent current per percent voltage deviation", - "data_object": "ArGraSag", - "name": "DRGS.ArGraSag.AO40" - }, - { - "index": 41, - "description": "Dynamic Reactive Current Support Gradient for Swells. Percentage of the rated current (DRAT.ARtg) to apply inductively per percentage of the positive deviation from the moving average voltage (RDGS.Av). It is a ratio of percent and is therefore unitless.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DRGS", - "units": "Percent current per percent voltage deviation", - "data_object": "ArGraSwl", - "name": "DRGS.ArGraSwl.AO41" - }, - { - "index": 42, - "description": "Dynamic Reactive Current Support Filter Time for Moving Average Voltage (RDGS.VAv). Used to determine amount of dynamic reactive current support.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DRGS.FilTms.AO42" - }, - { - "index": 43, - "description": "Dynamic Reactive Current Support Block Zone Voltage. Percentage of the nominal voltage (DRCT.VRef) below which no reactive current support shall be applied.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "BlkZnV", - "name": "DRGS.BlkZnV.AO43" - }, - { - "index": 44, - "description": "Dynamic Reactive Current Support Hysteresis Block Zone Voltage. Percentage of the nominal voltage (DRCT.VRef). After being blocked, reactive current support shall not resume until the voltage has been above BlkZnV + HysBlkZnV.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "HysBlkZnV", - "name": "DRGS.HysBlkZnV.AO44" - }, - { - "index": 45, - "description": "Dynamic Reactive Current Support Block Zone Time. Time in milliseconds from the beginning of any \"sag\" event,before which dynamic reactive current support will always continue,regardless of how low voltage may sag.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "BlkZnTmms", - "name": "DRGS.BlkZnTmms.AO45" - }, - { - "index": 46, - "description": "Dynamic Reactive Current Support Start Hold Time. When the voltage exceeds the deadband limits for this length of time (measured in milliseconds),the \"sag\" or \"swell\" event begins and the DER may begin altering active power output.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "HoldTmms", - "name": "DRGS.HoldTmms.AO46" - }, - { - "index": 47, - "description": "Dynamic Reactive Current Support End Hold Time. When the voltage returns to within the deadband limits for this length of time (measured in milliseconds),the \"sag\" or \"swell\" event is considered to be over. Reactive current support ends,frozen values are unfrozen,and a new event can begin.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "HoldTmms", - "name": "DRGS.HoldTmms.AO47" - }, - { - "index": 48, - "description": "Dynamic Volt-Watt Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWD", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVWD.ModPrio.AO48" - }, - { - "index": 49, - "description": "Dynamic Volt-Watt Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVWD.WinTms.AO49" - }, - { - "index": 50, - "description": "Dynamic Volt-Watt Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVWD.RmpTms.AO50" - }, - { - "index": 51, - "description": "Dynamic Volt-Watt Reversion Timeout period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVWD.RvrtTms.AO51" - }, - { - "index": 52, - "description": "Dynamic Volt-Watt Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DVWD", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVWD2.EcpRef.AO52" - }, - { - "index": 53, - "description": "Dynamic Volt-Watt Gradient. Signed unit-less quantity that establishes the ratio of additional Watts supplied (expressed in terms of % DRCT.WMax) to the present difference from the moving average voltage (expressed as % DRCT.VRef).", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DVWD", - "units": "Percent watts per percent voltage difference", - "data_object": "DynVWGra", - "name": "DVWD.DynVWGra.AO53" - }, - { - "index": 54, - "description": "Dynamic Volt-Watt Filter Time. The time in seconds used to calculate the moving average voltage for dynamic Volt-Watt support.", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "VWFilTms", - "name": "DVWD.VWFilTms.AO54" - }, - { - "index": 55, - "description": "Dynamic Volt-Watt Lower Deadband. Percentage of the nominal voltage (DRCT.Vref) measured below the moving average voltage. If the present voltage is above this value, no additional Watts shall be supplied.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVWD", - "units": "Percent", - "minimum": 0, - "data_object": "DbVWLo", - "name": "DVWD.DbVWLo.AO55" - }, - { - "index": 56, - "description": "Dynamic Volt-Watt Upper Deadband. Percentage of the nominal voltage (DRCT.Vref) measured above the moving average voltage. If the present voltage is below this value,no additional Watts shall be supplied.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVWD", - "units": "Percent", - "minimum": 0, - "data_object": "DbVWHi", - "name": "DVWD.DbVWHi.AO56" - }, - { - "index": 57, - "description": "Frequency-Watt Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "ModPrio", - "name": "DHFW2.ModPrio.AO57" - }, - { - "index": 58, - "description": "Frequency-Watt Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DHFW.WinTms.AO58" - }, - { - "index": 59, - "description": "Frequency-Watt Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DHFW.RmpTms.AO59" - }, - { - "index": 60, - "description": "Frequency-Watt Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DHFW.RvrtTms.AO60" - }, - { - "index": 61, - "description": "Frequency-Watt Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFW.EcpRef.AO61" - }, - { - "index": 62, - "description": "Frequency-Watt High Starting Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DHFW", - "units": "Hz", - "minimum": 0, - "data_object": "HzStr", - "name": "DHFW.HzStr.AO62" - }, - { - "index": 63, - "description": "Frequency-Watt High Stopping Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DHFW", - "units": "Hz", - "minimum": 0, - "data_object": "HzStop", - "name": "DHFW.HzStop.AO63" - }, - { - "index": 64, - "description": "Frequency-Watt High Discharging/Generating Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WGra", - "name": "DHFW.WGra.AO64" - }, - { - "index": 65, - "description": "Frequency-Watt High Charging Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WChaGra", - "name": "DHFW.WChaGra.AO65" - }, - { - "index": 66, - "description": "Frequency-Watt Low Starting Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 0, - "ln_class": "DLFW", - "units": "Hz", - "minimum": -70000, - "data_object": "HzStr", - "name": "DLFW.HzStr.AO66" - }, - { - "index": 67, - "description": "Frequency-Watt Low Stopping Frequency", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 0, - "ln_class": "DLFW", - "units": "Hz", - "minimum": -70000, - "data_object": "HzStop", - "name": "DLFW.HzStop.AO67" - }, - { - "index": 68, - "description": "Frequency-Watt Low Discharging/Generating Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WGra", - "name": "DLFW.WGra.AO68" - }, - { - "index": 69, - "description": "Frequency-Watt Low Charging Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WChaGra", - "name": "DLFW.WChaGra.AO69" - }, - { - "index": 70, - "description": "Frequency-Watt Start Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStrDlTmms", - "name": "DHFW2.ActStrDlTmms.AO70" - }, - { - "index": 71, - "description": "Frequency-Watt Stop Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStopDlTmms", - "name": "DHFW2.ActStopDlTmms.AO71" - }, - { - "index": 72, - "description": "Frequency-Watt Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DHFW.OpnLoop.AO72" - }, - { - "index": 73, - "description": "Frequency-Watt Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DHFW.OpnLoop.AO73" - }, - { - "index": 74, - "description": "Frequency-Watt Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DHFW.DschRpuRte.AO74" - }, - { - "index": 75, - "description": "Frequency-Watt Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DHFW.DschRpdRte.AO75" - }, - { - "index": 76, - "description": "Frequency-Watt Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DHFW.ChaRpuRte.AO76" - }, - { - "index": 77, - "description": "Frequency-Watt Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DHFW.ChaRpdRte.AO77" - }, - { - "index": 78, - "description": "Frequency-Watt Hi Return Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "RtnRmpRte", - "name": "DHFW.RtnRmpRte.AO78" - }, - { - "index": 79, - "description": "Frequency-Watt Low Return Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "RtnRmpRte", - "name": "DLFW.RtnRmpRte.AO79" - }, - { - "index": 80, - "description": "Frequency-Watt Minimum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMin", - "name": "DHFW.SocUseMin.AO80" - }, - { - "index": 81, - "description": "Frequency-Watt Maximum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMax", - "name": "DHFW.SocUseMax.AO81" - }, - { - "index": 82, - "description": "Active Power Limit Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWMX", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWMX.ModPrio.AO82" - }, - { - "index": 83, - "description": "Active Power Limit Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWMX.WinTms.AO83" - }, - { - "index": 84, - "description": "Active Power Limit Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWMX.RmpTms.AO84" - }, - { - "index": 85, - "description": "Active Power Limit Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWMX.RvrtTms.AO85" - }, - { - "index": 86, - "description": "Active Power Limit Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DWMX", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWMX.EcpRef.AO86" - }, - { - "index": 87, - "description": "Active Power Limit Charge Setpoint. Maximum allowed Watts as a percentage of Maximum Active Power capability.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWMX", - "units": "Percent", - "minimum": 0, - "data_object": "WLimPct", - "name": "DWMX.WLimPct.AO87" - }, - { - "index": 88, - "description": "Active Power Limit Discharge Setpoint. Maximum allowed Watts as a percentage of Maximum Active Power capability.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWMN", - "units": "Percent", - "minimum": 0, - "data_object": "WLimPct", - "name": "DWMN.WLimPct.AO88" - }, - { - "index": 89, - "description": "Charge/Discharge Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWGC.ModPrio.AO89" - }, - { - "index": 90, - "description": "Charge/Discharge Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWGC.WinTms.AO90" - }, - { - "index": 91, - "description": "Charge/Discharge Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWGC.RmpTms.AO91" - }, - { - "index": 92, - "description": "Charge/Discharge Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWGC.RvrtTms.AO92" - }, - { - "index": 93, - "description": "Charge/Discharge Active Power Target. Percentage of maxmum active power.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "GnWPctSpt", - "name": "DWGC.GnWPctSpt.AO93" - }, - { - "index": 94, - "description": "Charge/Discharge Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DWGC.OpnLoop.AO94" - }, - { - "index": 95, - "description": "Charge/Discharge Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DWGC.OpnLoop.AO95" - }, - { - "index": 96, - "description": "Charge/Discharge Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DWGC.DschRpuRte.AO96" - }, - { - "index": 97, - "description": "Charge/Discharge Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DWGC.DschRpdRte.AO97" - }, - { - "index": 98, - "description": "Charge/Discharge Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DWGC.ChaRpuRte.AO98" - }, - { - "index": 99, - "description": "Charge/Discharge Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DWGC.ChaRpdRte.AO99" - }, - { - "index": 100, - "description": "Charge/Discharge Minimum Reserve for Storage. The minimum level to which the storage system may be discharged,expressed as a percentage of the total usable storage.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "SocUseMinPct", - "name": "DWGC.SocUseMinPct.AO100" - }, - { - "index": 101, - "description": "Charge/Discharge Maximum Reserve for Storage. The maximum level to which the storage system may be discharged,expressed as a percentage of the total usable storage.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "SocUseMaxPct", - "name": "DWGC.SocUseMaxPct.AO101" - }, - { - "index": 102, - "description": "Coordinated Charge/Discharge Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "minimum": 0, - "data_object": "ModPrio", - "name": "DTCD.ModPrio.AO102" - }, - { - "index": 103, - "description": "Coordinated Charge/Discharge Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DTCD.WinTms.AO103" - }, - { - "index": 104, - "description": "Coordinated Charge/Discharge Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DTCD.RmpTms.AO104" - }, - { - "index": 105, - "description": "Coordinated Charge/Discharge Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DTCD.RvrtTms.AO105" - }, - { - "index": 106, - "description": "Coordinated Charge/Discharge Target State of Charge. Charge that the system is expected to achieve,as a percentage of the usable capacity.", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DTCD", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseTgtPct", - "name": "DTCD.SocUseTgtPct.AO106" - }, - { - "index": 107, - "description": "Coordinated Charge/Discharge Target Date. Date by which the storage system must reach the target SOC. Expressed as number of days since January 1, 1970, UTC.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Days", - "minimum": 0, - "data_object": "DateTgt", - "name": "DTCD.DateTgt.AO107" - }, - { - "index": 108, - "description": "Coordinated Charge/Discharge Target Time. Time by which storage system must reach the target SOC. Expressed as number of milliseconds since the start of Target Date.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "DateTgtTms", - "name": "DTCD.DateTgtTms.AO108" - }, - { - "index": 109, - "description": "Coordinated Charge/Discharge Energy Request", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Watt-hours", - "minimum": 0, - "data_object": "SocWReq", - "name": "DTCD.SocWReq.AO109" - }, - { - "index": 110, - "description": "Coordinated Charge/Discharge Minimum Charging Duration", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "ChaDurTms", - "name": "DTCD.ChaDurTms.AO110" - }, - { - "index": 111, - "description": "Coordinated Charge/Discharge Date of Reference", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Days", - "minimum": 0, - "data_object": "DateTgt", - "name": "DTCD.DateTgt.AO111" - }, - { - "index": 112, - "description": "Coordinated Charge/Discharge Time of Reference", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "SocDateTms", - "name": "DTCD.SocDateTms.AO112" - }, - { - "index": 113, - "description": "Coordinated Charge/Discharge Duration at Maximum Charge Rate", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "ChaDurMax", - "name": "DTCD.ChaDurMax.AO113" - }, - { - "index": 114, - "description": "Coordinated Charge/Discharge Duration at Maximum Discharge Rate", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "DschDurMax", - "name": "DTCD.DschDurMax.AO114" - }, - { - "index": 115, - "description": "Active Power Response Mode #1 Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPKP", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPKP.ModPrio.AO115" - }, - { - "index": 116, - "description": "Active Power Response Mode #1 Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPKP.WinTms.AO116" - }, - { - "index": 117, - "description": "Active Power Response Mode #1 Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPKP.RmpTms.AO117" - }, - { - "index": 118, - "description": "Active Power Response Mode #1 Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPKP.RvrtTms.AO118" - }, - { - "index": 119, - "description": "Active Power Response Mode #1 Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DPKP", - "minimum": 0, - "data_object": "EcpRef", - "name": "DPKP.EcpRef.AO119" - }, - { - "index": 120, - "description": "Active Power Response Mode #1 Power Threshold", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DPKP", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DPKP.PkPwrWLim.AO120" - }, - { - "index": 121, - "description": "Active Power Response Mode #1 Ratio", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DPKP", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DPKP.PkPwrFolPct.AO121" - }, - { - "index": 122, - "description": "Active Power Response Mode #1 Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DPKP", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DPKP.RpuRte.AO122" - }, - { - "index": 123, - "description": "Active Power Response Mode #1 Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DPKP", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DPKP.RpdRte.AO123" - }, - { - "index": 124, - "description": "Active Power Response Mode #2 Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DGFL", - "minimum": 0, - "data_object": "ModPrio", - "name": "DGFL.ModPrio.AO124" - }, - { - "index": 125, - "description": "Active Power Response Mode #2 Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DGFL.WinTms.AO125" - }, - { - "index": 126, - "description": "Active Power Response Mode #2 Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DGFL.RmpTms.AO126" - }, - { - "index": 127, - "description": "Active Power Response Mode #2 Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DGFL.RvrtTms.AO127" - }, - { - "index": 128, - "description": "Active Power Response Mode #2 Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DGFL", - "minimum": 0, - "data_object": "EcpRef", - "name": "DGFL.EcpRef.AO128" - }, - { - "index": 129, - "description": "Active Power Response Mode #2 Power Threshold", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DGFL", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DGFL.PkPwrWLim.AO129" - }, - { - "index": 130, - "description": "Active Power Response Mode #2 Ratio", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DGFL", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DGFL.PkPwrFolPct.AO130" - }, - { - "index": 131, - "description": "Active Power Response Mode #2 Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DGFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DGFL.RpuRte.AO131" - }, - { - "index": 132, - "description": "Active Power Response Mode #2 Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DGFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DGFL.RpdRte.AO132" - }, - { - "index": 133, - "description": "Active Power Response Mode #3 Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DLFL", - "minimum": 0, - "data_object": "ModPrio", - "name": "DLFL.ModPrio.AO133" - }, - { - "index": 134, - "description": "Active Power Response Mode #3 Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DLFL.WinTms.AO134" - }, - { - "index": 135, - "description": "Active Power Response Mode #3 Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DLFL.RmpTms.AO135" - }, - { - "index": 136, - "description": "Active Power Response Mode #3 Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DLFL.RvrtTms.AO136" - }, - { - "index": 137, - "description": "Active Power Response Mode #3 Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DLFL", - "minimum": 0, - "data_object": "EcpRef", - "name": "DLFL.EcpRef.AO137" - }, - { - "index": 138, - "description": "Active Power Response Mode #3 Power Threshold", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DLFL", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DLFL.PkPwrWLim.AO138" - }, - { - "index": 139, - "description": "Active Power Response Mode #3 Ratio", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DLFL", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DLFL.PkPwrFolPct.AO139" - }, - { - "index": 140, - "description": "Active Power Response Mode #3 Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DLFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DLFL.RpuRte.AO140" - }, - { - "index": 141, - "description": "Active Power Response Mode #3 Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DLFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DLFL.RpdRte.AO141" - }, - { - "index": 142, - "description": "AGC Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DAGC.ModPrio.AO142" - }, - { - "index": 143, - "description": "AGC Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DAGC.WinTms.AO143" - }, - { - "index": 144, - "description": "AGC Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DAGC.RmpTms.AO144" - }, - { - "index": 145, - "description": "AGC Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DAGC.RvrtTms.AO145" - }, - { - "index": 146, - "description": "AGC Active Power Target", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DAGC", - "units": "Watts", - "data_object": "GnWSpt", - "name": "DAGC.GnWSpt.AO146" - }, - { - "index": 147, - "description": "AGC Ramp Time Constant Up Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DAGC.OpnLoop.AO147" - }, - { - "index": 148, - "description": "AGC Ramp Time Constant Down Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DAGC.OpnLoop.AO148" - }, - { - "index": 149, - "description": "AGC Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DAGC.DschRpuRte.AO149" - }, - { - "index": 150, - "description": "AGC Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DAGC.DschRpdRte.AO150" - }, - { - "index": 151, - "description": "AGC Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DAGC.ChaRpuRte.AO151" - }, - { - "index": 152, - "description": "AGC Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DAGC.ChaRpdRte.AO152" - }, - { - "index": 153, - "description": "AGC Minimum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DAGC.SocUseMinPct.AO153" - }, - { - "index": 154, - "description": "AGC Maximum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DAGC.SocUseMaxPct.AO154" - }, - { - "index": 155, - "description": "Active Power Smoothing Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWSM.ModPrio.AO155" - }, - { - "index": 156, - "description": "Active Power Smoothing Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWSM.WinTms.AO156" - }, - { - "index": 157, - "description": "Active Power Smoothing Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWSM.RmpTms.AO157" - }, - { - "index": 158, - "description": "Active Power Smoothing Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWSM.RvrtTms.AO158" - }, - { - "index": 159, - "description": "Active Power Smoothing Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DWSM", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWSM.EcpRef.AO159" - }, - { - "index": 160, - "description": "Active Power Smoothing Gradient", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DWSM", - "units": "Watts per delta-watt", - "data_object": "WSmthGra", - "name": "DWSM.WSmthGra.AO160" - }, - { - "index": 161, - "description": "Active Power Smoothing Lower Limit. Difference in Watts from the moving average of the reference power (MMXN1.Watt) above which no smoothing shall be applied.", - "data_type": "AO", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DWSM", - "units": "Watts", - "data_object": "WSmthLoLim", - "name": "DWSM.WSmthLoLim.AO161" - }, - { - "index": 162, - "description": "Active Power Smoothing Upper Limit. Difference in Watts from the moving average of the reference power (MMXN.Watt) below which no smoothing shall be applied.", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DWSM", - "units": "Watts", - "minimum": 0, - "data_object": "WSmthHiLim", - "name": "DWSM.WSmthHiLim.AO162" - }, - { - "index": 163, - "description": "Active Power Smoothing Filter Time (Seconds). Time in seconds used to calculate the moving average of the reference load or generation (MMXN1.Watt) being smoothed.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DWSM.FilTms.AO163" - }, - { - "index": 164, - "description": "Active Power Smoothing Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DWSM.DschRpuRte.AO164" - }, - { - "index": 165, - "description": "Active Power Smoothing Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DWSM.DschRpdRte.AO165" - }, - { - "index": 166, - "description": "Active Power Smoothing Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DWSM.ChaRpuRte.AO166" - }, - { - "index": 167, - "description": "Active Power Smoothing Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DWSM.ChaRpdRte.AO167" - }, - { - "index": 168, - "description": "Volt-Watt Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVWC.ModPrio.AO168" - }, - { - "index": 169, - "description": "Volt-Watt Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVWC.WinTms.AO169" - }, - { - "index": 170, - "description": "Volt-Watt Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVWC.RmpTms.AO170" - }, - { - "index": 171, - "description": "Volt-Watt Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVWC.RvrtTms.AO171" - }, - { - "index": 172, - "description": "Volt-Watt Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVWC.EcpRef.AO172" - }, - { - "index": 173, - "description": "Volt-Watt Curve Index", - "data_type": "AO", - "common_data_class": "CSG", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "VWCrv", - "name": "DVWC.VWCrv.AO173" - }, - { - "index": 174, - "description": "Volt-Watt Filter Time (Seconds)", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DVWC.FilTms.AO174" - }, - { - "index": 175, - "description": "Volt-Watt Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DVWC.OpnLoop.AO175" - }, - { - "index": 176, - "description": "Volt-Watt Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoop", - "name": "DVWC.OpnLoop.AO176" - }, - { - "index": 177, - "description": "Volt-Watt Discharging Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpuRte", - "name": "DVWC.DschRpuRte.AO177" - }, - { - "index": 178, - "description": "Volt-Watt Discharging Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "DschRpdRte", - "name": "DVWC.DschRpdRte.AO178" - }, - { - "index": 179, - "description": "Volt-Watt Charging Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpuRte", - "name": "DVWC.ChaRpuRte.AO179" - }, - { - "index": 180, - "description": "Volt-Watt Charging Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "ChaRpdRte", - "name": "DVWC.ChaRpdRte.AO180" - }, - { - "index": 181, - "description": "Frequency-Watt Curve Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "ModPrio", - "name": "DHFW.ModPrio.AO181" - }, - { - "index": 182, - "description": "Frequency-Watt Curve Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DHFW.WinTms.AO182" - }, - { - "index": 183, - "description": "Frequency-Watt Curve Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DHFW.RmpTms.AO183" - }, - { - "index": 184, - "description": "Frequency-Watt Curve Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DHFW.RvrtTms.AO184" - }, - { - "index": 185, - "description": "Frequency-Watt Curve Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFW.EcpRef.AO185" - }, - { - "index": 186, - "description": "Frequency-Watt Curve - Curve Index", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "HzWCrv", - "name": "DHFW.HzWCrv.AO186" - }, - { - "index": 187, - "description": "Frequency-Watt Curve - High Frequency Hysteresis Curve Index", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "HysCrv", - "name": "DHFW.HysCrv.AO187" - }, - { - "index": 188, - "description": "Frequency-Watt Curve - Low Frequency Hysteresis Curve Index", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DLFW", - "minimum": 0, - "data_object": "HysCrv", - "name": "DLFW.HysCrv.AO188" - }, - { - "index": 189, - "description": "Frequency-Watt Curve Start Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStrDlTmms", - "name": "DHFW.ActStrDlTmms.AO189" - }, - { - "index": 190, - "description": "Frequency-Watt Curve Stop Delay", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStopDlTmms", - "name": "DHFW.ActStopDlTmms.AO190" - }, - { - "index": 191, - "description": "Frequency-Watt Curve Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AO191" - }, - { - "index": 192, - "description": "Frequency-Watt Curve Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AO192" - }, - { - "index": 193, - "description": "Frequency-Watt Curve Discharge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DHFW.RpuRte.AO193" - }, - { - "index": 194, - "description": "Frequency-Watt Curve Discharge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DHFW.RpdRte.AO194" - }, - { - "index": 195, - "description": "Frequency-Watt Curve Charge Ramp Up Rate", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DHFW.RpuChaRte.AO195" - }, - { - "index": 196, - "description": "Frequency-Watt Curve Charge Ramp Down Rate", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DHFW.RpdChaRte.AO196" - }, - { - "index": 197, - "description": "Frequency-Watt Curve Minimum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DHFW.SocUseMinPct.AO197" - }, - { - "index": 198, - "description": "Frequency-Watt Curve Maximum Usable SOC", - "data_type": "AO", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DHFW.SocUseMaxPct.AO198" - }, - { - "index": 199, - "description": "Constant VArs Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVAR.ModPrio.AO199" - }, - { - "index": 200, - "description": "Constant VArs Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVAR.WinTms.AO200" - }, - { - "index": 201, - "description": "Constant VArs Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVAR.RmpTms.AO201" - }, - { - "index": 202, - "description": "Constant VArs Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVAR.RvrtTms.AO202" - }, - { - "index": 203, - "description": "Constant VArs Reactive Power Target. Percentage of maxmum reactive power.", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVAR", - "units": "Percent", - "minimum": -1000, - "data_object": "VArTgtPct", - "name": "DVAR.VArTgtPct.AO203" - }, - { - "index": 204, - "description": "Constant VArs Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVAR.OpnLoopMax.AO204" - }, - { - "index": 205, - "description": "Constant VArs Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVAR.OpnLoopMax.AO205" - }, - { - "index": 206, - "description": "Fixed Power Factor Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DFPF", - "minimum": 0, - "data_object": "ModPrio", - "name": "DFPF.ModPrio.AO206" - }, - { - "index": 207, - "description": "Fixed Power Factor Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DFPF.WinTms.AO207" - }, - { - "index": 208, - "description": "Fixed Power Factor Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DFPF.RmpTms.AO208" - }, - { - "index": 209, - "description": "Fixed Power Factor Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DFPF.RvrtTms.AO209" - }, - { - "index": 210, - "description": "Fixed Power Factor Setpoint - Generation/Discharging", - "data_type": "AO", - "common_data_class": "APC", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DFPF", - "units": "None", - "minimum": 0, - "data_object": "PFGnTgt", - "name": "DFPF.PFGnTgt.AO210" - }, - { - "index": 211, - "description": "Fixed Power Factor Setpoint - Charging", - "data_type": "AO", - "common_data_class": "APC", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DFPF", - "units": "None", - "minimum": 0, - "data_object": "PFLodTgt", - "name": "DFPF.PFLodTgt.AO211" - }, - { - "index": 212, - "description": "Volt-VAr Control Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVVR.ModPrio.AO212" - }, - { - "index": 213, - "description": "Volt-VAr Control Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVVR.WinTms.AO213" - }, - { - "index": 214, - "description": "Volt-VAr Control Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVVR.RmpTms.AO214" - }, - { - "index": 215, - "description": "Volt-VAr Control Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVVR.RvrtTms.AO215" - }, - { - "index": 216, - "description": "Volt-VAr Control Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVVR.EcpRef.AO216" - }, - { - "index": 217, - "description": "Volt-VAr Curve Index", - "data_type": "AO", - "common_data_class": "CSG", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "VVArCrv", - "name": "DVVR.VVArCrv.AO217" - }, - { - "index": 218, - "description": "Volt-VAr Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVVR.OpnLoopMax.AO218" - }, - { - "index": 219, - "description": "Volt-VAr Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVVR.OpnLoopMax.AO219" - }, - { - "index": 220, - "description": "Volt-VAr Autonomous Voltage Reference Adjustment Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "VRefTmms", - "name": "DVVR.VRefTmms.AO220" - }, - { - "index": 221, - "description": "Watt-VAr Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWVR.ModPrio.AO221" - }, - { - "index": 222, - "description": "Watt-VAr Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWVR.WinTms.AO222" - }, - { - "index": 223, - "description": "Watt-VAr Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWVR.RmpTms.AO223" - }, - { - "index": 224, - "description": "Watt-VAr Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWVR.RvrtTms.AO224" - }, - { - "index": 225, - "description": "Watt-VAr Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWVR.EcpRef.AO225" - }, - { - "index": 226, - "description": "Watt-VAr Curve Index", - "data_type": "AO", - "common_data_class": "CSG", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "WVArCrv", - "name": "DWVR.WVArCrv.AO226" - }, - { - "index": 227, - "description": "Watt-VAr Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWVR.OpnLoopMax.AO227" - }, - { - "index": 228, - "description": "Watt-VAr Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWVR.OpnLoopMax.AO228" - }, - { - "index": 229, - "description": "Power Factor Correction Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPFC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPFC.ModPrio.AO229" - }, - { - "index": 230, - "description": "Power Factor Correction Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPFC.WinTms.AO230" - }, - { - "index": 231, - "description": "Power Factor Correction Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpRte", - "name": "DPFC.RmpRte.AO231" - }, - { - "index": 232, - "description": "Power Factor Correction Reversion Timeout Period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPFC.RvrtTms.AO232" - }, - { - "index": 233, - "description": "Power Factor Correction Signal Meter ID", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DPFC", - "minimum": 0, - "data_object": "EcpRef", - "name": "DPFC.EcpRef.AO233" - }, - { - "index": 234, - "description": "Power Factor Correction Average PF Target", - "data_type": "AO", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFTrg", - "name": "DPFC.PFTrg.AO234" - }, - { - "index": 235, - "description": "Power Factor Correction Lower PF Limit", - "data_type": "AO", - "common_data_class": "Int", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFCorRef.rangeC", - "name": "DPFC.PFCorRef.rangeC.AO235" - }, - { - "index": 236, - "description": "Power Factor Correction Upper PF Limit", - "data_type": "AO", - "common_data_class": "Int", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFCorRef.rangeC", - "name": "DPFC.PFCorRef.rangeC.AO236" - }, - { - "index": 237, - "description": "Pricing Mode Priority", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "None", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPRG.ModPrio.AO237" - }, - { - "index": 238, - "description": "Pricing Mode Enabling Time Window", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPRG.WinTms.AO238" - }, - { - "index": 239, - "description": "Pricing Mode Enabling Ramp Time", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPRG.RmpTms.AO239" - }, - { - "index": 240, - "description": "Pricing Mode Reversion Timeout period", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPRG.RvrtTms.AO240" - }, - { - "index": 241, - "description": "Pricing Mode Setpoint. Hundredths of local currency per Kilowatt-Hr.", - "data_type": "AO", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "ln_class": "DPRG", - "units": "100ths of local currency", - "data_object": "PrcRef", - "name": "DPRG.PrcRef.AO241" - }, - { - "index": 242, - "description": "Pricing Mode Ramp Up Time Constant", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DPRG.OpnLoopMax.AO242" - }, - { - "index": 243, - "description": "Pricing Mode Ramp Down Time Constant", - "data_type": "AO", - "common_data_class": "ASG", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DPRG.OpnLoopMax.AO243" - }, - { - "index": 244, - "description": "Curve Edit Selector. Writing to this point selects which of the curves can currently be viewed and changed.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "DGSM", - "minimum": 1, - "data_object": "InCrv", - "name": "DGSMn.InCrv.AO244", - "type": "selector_block", - "selector_block_start": 244, - "selector_block_end": 448 - }, - { - "index": 245, - "description": "Curve Mode Type", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 20, - "ln_class": "DGSM", - "units": "None (list)", - "minimum": 0, - "data_object": "ModTyp", - "allowed_values": { - "0": "Curve disabled", - "1": "Not applicable / Unknown", - "2": "Volt-Var modes VV11-VV12", - "3": "Frequency-Watt mode FW22", - "4": "Watt-VAr mode WP42", - "5": "Voltage-Watt modes VW51-VW52", - "6": "Remain Connected", - "7": "Temperature mode", - "8": "Pricing signal mode", - "9": "HVRT Must Trip", - "10": "HVRT Momentary Cessation", - "11": "LVRT Must Trip", - "12": "LVRT Momentary Cessation", - "13": "HFRT Must Trip", - "14": "HFRT Momentary Cessation", - "15": "LFRT Must Trip", - "16": "LFRT Mandatory Operation" - }, - "type": "enumerated", - "name": "DGSMn.ModTyp.AO245" - }, - { - "index": 246, - "description": "Curve Number of Points", - "data_type": "AO", - "common_data_class": "CSG", - "maximum": 100, - "ln_class": "FMAR", - "minimum": 0, - "data_object": "PairArr.NumPts", - "name": "FMARn.PairArr.NumPts.AO246" - }, - { - "index": 247, - "description": "Independent (X-Value) Units for Curve", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "FMAR", - "units": "None (list)", - "minimum": 0, - "data_object": "IndpUnits", - "allowed_values": { - "0": "Curve disabled", - "1": "Not applicable / Unknown", - "4": "Time", - "23": "Celsius Temperature", - "29": "Voltage", - "33": "Frequency", - "38": "Watts", - "100": "Price in hundredths of local currency", - "129": "Percent Voltage", - "133": "Percent Frequency", - "138": "Percent Watts", - "233": "Frequency Deviation" - }, - "type": "enumerated", - "name": "FMARn.IndpUnits.AO247" - }, - { - "index": 248, - "description": "Dependent (Y-Value) Units for Curve", - "data_type": "AO", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "FMAR", - "units": "None (list)", - "minimum": 0, - "data_object": "DepRef", - "allowed_values": { - "0": "Curve disabled", - "1": "Not applicable / unknown", - "2": "VArs as percent of max VArs (VARMax)", - "3": "VArs as percent of max available VArs (VArAval)", - "4": "Vars as percent of max Watts (Wmax) not used", - "5": "Watts as percent of max Watts (Wmax)", - "6": "Watts as percent of frozen active power (DeptSnptRef)", - "7": "Power Factor in EEI notation", - "8": "Volts as a percent of the nominal voltage (VRef)", - "9": "Frequency as a percent of the nominal grid frequency (ECPNomHz)" - }, - "type": "enumerated", - "name": "FMARn.DepRef.AO248" - }, - { - "index": 249, - "description": "Curve X-Value and Y-Value pairs for curve points 1 - 100", - "data_type": "AO", - "common_data_class": "CSG", - "ln_class": "FMAR", - "units": "Varies", - "data_object": "PairArr.CrvPts", - "name": "FMARn.PairArr.CrvPts.AO249", - "type": "array", - "array_times_repeated": 100, - "array_points": [ - { - "name": "FMARn.PairArr.CrvPts.AO249.xVal" - }, - { - "name": "FMARn.PairArr.CrvPts.AO249.yVal" - } - ] - }, - { - "index": 449, - "description": "System Meter Active Power - High Threshold", - "data_type": "AO", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW.rangeC.hLim", - "name": "MMXU.TotW.rangeC.hLim.AO449" - }, - { - "index": 450, - "description": "System Meter Active Power - Low Threshold", - "data_type": "AO", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW.rangeC.lLim", - "name": "MMXU.TotW.rangeC.lLim.AO450" - }, - { - "index": 451, - "description": "System Meter Reactive Power - High Threshold", - "data_type": "AO", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "minimum": 0, - "data_object": "TotVAr.rangeC.hLim", - "name": "MMXU.TotVAr.rangeC.hLim.AO451" - }, - { - "index": 452, - "description": "System Meter at Reactive Power - Low Threshold", - "data_type": "AO", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "minimum": 0, - "data_object": "TotVAr.rangeC.lLim", - "name": "MMXU.TotVAr.rangeC.lLim.AO452" - }, - { - "index": 453, - "description": "System Meter at Power Factor - High Threshold", - "data_type": "AO", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF.rangeC.hLim", - "name": "MMXU.TotPF.rangeC.hLim.AO453" - }, - { - "index": 454, - "description": "System Meter at Power Factor - Low Threshold", - "data_type": "AO", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF.rangeC.lLim", - "name": "MMXU.TotPF.rangeC.lLim.AO454" - }, - { - "index": 455, - "description": "System Meter Phase A Volts - High Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.rangeC.hLim", - "name": "MMXU.PhV.phsA.rangeC.hLim.AO455" - }, - { - "index": 456, - "description": "System Meter Phase A Volts - Low Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.rangeC.lLim", - "name": "MMXU.PhV.phsA.rangeC.lLim.AO456" - }, - { - "index": 457, - "description": "System Meter Phase B Volts High Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.rangeC.hLim", - "name": "MMXU.PhV.phsB.rangeC.hLim.AO457" - }, - { - "index": 458, - "description": "System Meter Phase B Volts - Low Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.rangeC.lLim", - "name": "MMXU.PhV.phsB.rangeC.lLim.AO458" - }, - { - "index": 459, - "description": "System Meter Phase C Volts - High Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.rangeC.hLim", - "name": "MMXU.PhV.phsC.rangeC.hLim.AO459" - }, - { - "index": 460, - "description": "System Meter Phase C Volts - Low Threshold", - "data_type": "AO", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.rangeC.lLim", - "name": "MMXU.PhV.phsC.rangeC.lLim.AO460" - }, - { - "index": 461, - "description": "Schedule to Edit Selector. Selects which of the schedules can be currently viewed and changed.", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "Schd", - "name": "FSCC.Schd.AO461", - "type": "selector_block", - "selector_block_start": 461, - "selector_block_end": 669 - - }, - { - "index": 462, - "description": "Selected Schedule Identity", - "data_type": "AO", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "Schd", - "name": "FSCC.Schd.AO462" - }, - { - "index": 463, - "description": "Selected Schedule Priority. Priority of the schedule relative to other running schedules. Lower values have higher priority over higher values.", - "data_type": "AO", - "common_data_class": "ING", - "ln_class": "FSCH", - "minimum": 0, - "data_object": "SchdPrio", - "name": "FSCH1.SchdPrio.AO463" - }, - { - "index": 464, - "description": "Selected Schedule Type", - "data_type": "AO", - "common_data_class": "SCR", - "maximum": 30, - "ln_class": "FSCH", - "units": "None (list)", - "minimum": 0, - "data_object": "SchdVal.valEq", - "allowed_values": { - "1": "Low/High Voltage Ride-Through - Hi Must Trip", - "2": "Low/High Voltage Ride-Through - Low Must Trip", - "3": "Low/High Voltage Ride-Through - Hi Momentary", - "4": "Low/High Voltage Ride-Through - Lo Momentary", - "5": "Low/High Frequency Ride-Through - Hi Must Trip", - "6": "Low/High Frequency Ride-Through - Lo Must Trip", - "7": "Low/High Frequency Ride-Through - Hi Momentary", - "8": "Low/High Frequency Ride-Through - Low Momentary", - "9": "Dynamic Reactive Current Support - On/Off", - "10": "Dynamic Volt-Watt - On/Off", - "11": "Frequency-Watt - On/Off", - "12": "Active Power Limit - Charging", - "13": "Active Power Limit - Generating", - "14": "Charge/Discharge - Percent of Maximum", - "15": "Coordinated Charge/Discharge - SOC Target", - "16": "Active Power Response #1 - On/Off", - "17": "Active Power Response #2 - On/Off", - "18": "Active Power Response #3 - On/Off", - "19": "AGC - Watts", - "20": "Active Power Smoothing - On/Off", - "21": "Volt-Watt - Curve Index", - "22": "Frequency-Watt Curve - Curve Index", - "23": "Frequency-Watt Curve - High Hysteresis", - "24": "Frequency-Watt Curve - Low Hysteresis", - "25": "Constant VArs - Percent of Maximum", - "26": "Fixed Power Factor - Power Factor", - "27": "Volt-VAr - Curve Index", - "28": "Watt-VAr - Curve Index", - "29": "Power Factor Correction - On/Off", - "30": "Reserved - For pricing mode" - }, - "type": "enumerated", - "name": "FSCH.SchdVal.valEq.AO464" - }, - { - "index": 465, - "description": "Selected Schedule Start Date. Number of days since January 1, 1970, UTC.", - "data_type": "AO", - "common_data_class": "TSG", - "ln_class": "FSCH", - "units": "Days", - "minimum": 0, - "data_object": "StrTm", - "name": "FSCH.StrTm.AO465" - }, - { - "index": 466, - "description": "Selected Schedule Start Time. Milliseconds since the start of Schedule Start Date.", - "data_type": "AO", - "common_data_class": "TSG", - "maximum": 86400000, - "ln_class": "FSCH", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "StrTm", - "name": "FSCH.StrTm.AO466" - }, - { - "index": 467, - "description": "Selected Schedule Repeat Interval. Interval between actions after the initial occurrence. A zero value means the schedule is not repeated.", - "data_type": "AO", - "common_data_class": "TCS", - "ln_class": "FSCH", - "minimum": 0, - "data_object": "NxtStrTm", - "name": "FSCH.NxtStrTm.AO467" - }, - { - "index": 468, - "description": "Selected Schedule Repeat Interval Units", - "data_type": "AO", - "common_data_class": "SPG", - "maximum": 8, - "ln_class": "FSCH", - "units": "None (list)", - "minimum": 0, - "data_object": "SchdReuse", - "allowed_values": { - "0": "No Repeat", - "1": "Seconds", - "2": "Minutes", - "3": "Hours", - "4": "Days", - "5": "Weeks", - "6": "Months", - "7": "Months on Same Day of Week", - "8": "Months on Same Day of Week from End" - }, - "type": "enumerated", - "name": "FSCH.SchdReuse.AO468" - }, - { - "index": 469, - "description": "Selected Schedule Number of Points", - "data_type": "AO", - "common_data_class": "ING", - "maximum": 100, - "ln_class": "FSCH", - "minimum": 0, - "data_object": "NumEntr", - "name": "FSCH.NumEntr.AO469" - }, - { - "index": 470, - "description": "Select schedule time offset and value pairs for points 1 - 100", - "data_type": "AO", - "minimum": 0, - "name": "FSCHn.SchdEntr.AO470", - "type": "array", - "array_times_repeated": 100, - "array_points": [ - { - "name": "FSCHn.SchdEntr.AO470.time", - "description": "Number of seconds from the start of the schedule when this point becomes active", - "units": "Seconds" - }, - { - "name": "FSCHn.SchdEntr.AO470.val", - "ln_class": "FSCH", - "data_object": "SchdEntr" - } - ] - }, - { - "index": 0, - "description": "DER Profile Version Number. Always the number 1.00 for this specification.", - "data_type": "AI", - "scaling_multiplier": 0.01, - "maximum": 100, - "minimum": 100, - "event_class": 3, - "name": "AI0" - }, - { - "index": 1, - "description": "DER Profile Implementation Level. 1, 2 or 3 to indicate support for Level 1, Level 2 or Level 3 respectively.", - "data_type": "AI", - "maximum": 3, - "minimum": 1, - "event_class": 3, - "name": "AI1" - }, - { - "index": 2, - "description": "Nameplate Minimum Voltage Rating", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DGEN", - "units": "Volts", - "minimum": 0, - "data_object": "VMinRtg", - "event_class": 3, - "name": "DGEN.VMinRtg.AI2" - }, - { - "index": 3, - "description": "Nameplate Maximum Voltage Rating", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DGEN", - "units": "Volts", - "minimum": 0, - "data_object": "VMaxRtg", - "event_class": 3, - "name": "DGEN.VMaxRtg.AI3" - }, - { - "index": 4, - "description": "Nameplate Active Generation Power Rating at Unity Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Watts", - "minimum": 0, - "data_object": "WMaxRtg", - "event_class": 3, - "name": "DGEN.WMaxRtg.AI4" - }, - { - "index": 5, - "description": "Nameplate Active Charging Power Rating at Unity Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "Watts", - "data_object": "ChaWMaxRtg", - "event_class": 3, - "name": "DSTO.ChaWMaxRtg.AI5" - }, - { - "index": 6, - "description": "Nameplate Active Generation Power Rating at Specified Over-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Watts", - "minimum": 0, - "data_object": "WOvPFRtg", - "event_class": 3, - "name": "DGEN.WOvPFRtg.AI6" - }, - { - "index": 7, - "description": "Nameplate Active Charging Power Rating at Specified Over-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "Watts", - "data_object": "ChaWOvPFRtg", - "event_class": 3, - "name": "DSTO.ChaWOvPFRtg.AI7" - }, - { - "index": 8, - "description": "Specified Over-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DGEN", - "units": "None", - "minimum": -100, - "data_object": "OvPFRtg", - "event_class": 3, - "name": "DGEN.OvPFRtg.AI8" - }, - { - "index": 9, - "description": "Nameplate Active Generation Power Rating at Specified Under-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Watts", - "minimum": 0, - "data_object": "WUnPFRtg", - "event_class": 3, - "name": "DGEN.WUnPFRtg.AI9" - }, - { - "index": 10, - "description": "Nameplate Active Charging Power Rating at Specified Under-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "Watts", - "data_object": "ChaWUnPFRtg", - "event_class": 3, - "name": "DSTO.ChaWUnPFRtg.AI10" - }, - { - "index": 11, - "description": "Specified Under-Excited Power Factor", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DGEN", - "units": "None", - "minimum": -100, - "data_object": "UnPFRtg", - "event_class": 3, - "name": "DGEN.UnPFRtg.AI11" - }, - { - "index": 12, - "description": "Nameplate Reactive Supply (Injection) Power Rating", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "VARs", - "minimum": 0, - "data_object": "IvarMaxRtg", - "event_class": 3, - "name": "DGEN.IvarMaxRtg.AI12" - }, - { - "index": 13, - "description": "Nameplate Reactive Absorption Power Rating", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DGEN", - "units": "VARs", - "data_object": "AvarMaxRtg", - "event_class": 3, - "name": "DGEN.AvarMaxRtg.AI13" - }, - { - "index": 14, - "description": "Nameplate Apparent Generation Power Rating", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "VAs", - "minimum": 0, - "data_object": "VAMaxRtg", - "event_class": 3, - "name": "DGEN.VAMaxRtg.AI14" - }, - { - "index": 15, - "description": "Nameplate Apparent Charging Power Rating", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "VAs", - "data_object": "ChaVAMaxRtg", - "event_class": 3, - "name": "DSTO.ChaVAMaxRtg.AI15" - }, - { - "index": 16, - "description": "Nameplate Storage Actual Energy Capacity. Nameplate (original) actual total energy capacity of the storage system expressed in Storage Capacity Units.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DSTO", - "units": "Amp-hrs or Watt-hrs", - "minimum": 0, - "data_object": "WhRtg", - "event_class": 3, - "name": "DSTO.WhRtg.AI16" - }, - { - "index": 17, - "description": "Storage Effective Actual Energy Capacity. Present actual total energy capacity of the storage system expressed in Storage Capacity Units.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DSTO", - "units": "Amp-hrs or Watt-hrs", - "minimum": 0, - "data_object": "EffWh", - "event_class": 3, - "name": "DSTO.EffWh.AI17" - }, - { - "index": 18, - "description": "Storage Usable Energy Capacity. Usable energy capacity of the storage system expressed in Storage Capacity Units.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DSTO", - "units": "Amp-hrs or Watt-hrs", - "minimum": 0, - "data_object": "UseWh", - "event_class": 3, - "name": "DSTO.UseWh.AI18" - }, - { - "index": 19, - "description": "Nameplate AC Current Maximum Generation Rating", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DGEN", - "units": "Amps", - "minimum": 0, - "data_object": "AMaxRtg", - "event_class": 3, - "name": "DGEN.AMaxRtg.AI19" - }, - { - "index": 20, - "description": "Nameplate AC Current Maximum Charging Rating", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 0, - "ln_class": "DSTO", - "units": "Amps", - "data_object": "ChaAMaxRtg", - "event_class": 3, - "name": "DSTO.ChaAMaxRtg.AI20" - }, - { - "index": 21, - "description": "Remaining Reactive Susceptance", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Siemens", - "data_object": "SuscRtg", - "event_class": 3, - "name": "DGEN.SuscRtg.AI21" - }, - { - "index": 22, - "description": "IEEE 1547 Normal Operating Performance Category.", - "data_type": "AI", - "maximum": 2, - "minimum": 0, - "units": "None (list)", - "event_class": 3, - "allowed_values": { - "0": "unknown", - "1": "Category A", - "2": "Category B" - }, - "type": "enumerated", - "name": "AI22" - }, - { - "index": 23, - "description": "IEEE 1547 Abnormal Operating Performance Category.", - "data_type": "AI", - "maximum": 3, - "minimum": 0, - "units": "None (list)", - "event_class": 3, - "allowed_values": { - "0": "unknown", - "1": "Category I", - "2": "Category II", - "3": "Category III" - }, - "type": "enumerated", - "name": "AI23" - }, - { - "index": 24, - "description": "Number of System Schedules", - "data_type": "AI", - "minimum": 0, - "units": "None", - "event_class": 3, - "name": "AI24" - }, - { - "index": 25, - "description": "Number of Meters", - "data_type": "AI", - "minimum": 0, - "units": "None", - "event_class": 3, - "name": "AI25" - }, - { - "index": 26, - "description": "Number of Inverters", - "data_type": "AI", - "minimum": 0, - "units": "None", - "event_class": 3, - "name": "AI26" - }, - { - "index": 27, - "description": "Number of Batteries", - "data_type": "AI", - "minimum": 0, - "units": "None", - "event_class": 3, - "name": "AI27" - }, - { - "index": 28, - "description": "Number of DER units connected to controller", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DSTO", - "units": "None", - "minimum": 0, - "data_object": "InclDER", - "event_class": 3, - "name": "DSTO.InclDER.AI28" - }, - { - "index": 29, - "description": "Reference Voltage", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "minimum": 0, - "data_object": "VRef", - "name": "DECP.VRef.AI29" - }, - { - "index": 30, - "description": "Reference Voltage Offset", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "data_object": "VRefOfs", - "name": "DECP.VRefOfs.AI30" - }, - { - "index": 31, - "description": "Nominal Grid Frequency", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DECP", - "units": "Hz", - "minimum": 0, - "data_object": "EcpNomHz", - "name": "DECP.EcpNomHz.AI31" - }, - { - "index": 32, - "description": "Maximum Active Generation Power", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "Watts", - "minimum": 0, - "data_object": "WMax", - "name": "DGEN.WMax.AI32" - }, - { - "index": 33, - "description": "Maximum Active Charging Power", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "Watts", - "data_object": "ChaWMax", - "name": "DSTO.ChaWMax.AI33" - }, - { - "index": 34, - "description": "Maximum Reactive Injection Power", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "VARs", - "minimum": 0, - "data_object": "IvarMax", - "name": "DGEN.IvarMax.AI34" - }, - { - "index": 35, - "description": "Maximum Reactive Absorption Power", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DGEN", - "units": "VARs", - "data_object": "AvarMax", - "name": "DGEN.AvarMax.AI35" - }, - { - "index": 36, - "description": "Maximum Apparent Generation Power", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGEN", - "units": "VA", - "minimum": 0, - "data_object": "VAMax", - "name": "DGEN.VAMax.AI36" - }, - { - "index": 37, - "description": "Maximum Apparent Charging Power", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DSTO", - "units": "VA", - "data_object": "ChaVAMax", - "name": "DSTO.ChaVAMax.AI37" - }, - { - "index": 38, - "description": "Minimum Voltage", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "minimum": 0, - "data_object": "VMin", - "name": "DECP.VMin.AI38" - }, - { - "index": 39, - "description": "Maximum Voltage", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "ln_class": "DECP", - "units": "Volts", - "minimum": 0, - "data_object": "VMax", - "name": "DECP.VMax.AI39" - }, - { - "index": 40, - "description": "Open Loop Response Time Percentage. Percent of target to reach within the open loop response time. Default is 90%.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DGEN", - "units": "Percent", - "minimum": 0, - "data_object": "OpnLoopPct", - "name": "DGEN.OpnLoopPct.AI40" - }, - { - "index": 41, - "description": "Power Factor Sign Convention.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 2, - "ln_class": "MMXU", - "units": "None", - "minimum": 1, - "data_object": "PFSign", - "allowed_values": { - "1": "IEC active power", - "2": "IEEE lead/lag" - }, - "type": "enumerated", - "name": "MMXU.PFSign.AI41" - }, - { - "index": 42, - "description": "Reference for Reactive Power Setpoints. Selects which setpoint is active. Default is <3>.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 3, - "ln_class": "DGEN", - "units": "None (list)", - "minimum": 0, - "data_object": "VArSetRef", - "allowed_values": { - "0": "Not applicable / Unknown", - "1": "Percent of Maximum Active Power (WMax)", - "2": "Percent of Maximum Reactive Power (VArMax)", - "3": "Percent of Available Reactive Power (VArAvl)" - }, - "type": "enumerated", - "name": "DGEN.VArSetRef.AI42" - }, - { - "index": 43, - "description": "System Available Active Generation Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW", - "name": "MMXU.TotW.AI43" - }, - { - "index": 44, - "description": "System Available Active Charging Power", - "data_type": "AI", - "common_data_class": "MV", - "maximum": 0, - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotChaW", - "name": "MMXU.TotChaW.AI44" - }, - { - "index": 45, - "description": "System Available Reactive Injection Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DGEN", - "units": "VARs", - "minimum": 0, - "data_object": "AvarAvl", - "name": "DGEN.AvarAvl.AI45" - }, - { - "index": 46, - "description": "System Available Reactive Absorption Power", - "data_type": "AI", - "common_data_class": "MV", - "maximum": 0, - "ln_class": "DGEN", - "units": "VARs", - "data_object": "IvarAvl", - "name": "DGEN.IvarAvl.AI46" - }, - { - "index": 47, - "description": "System Available Actual State of Charge - Present energy in the DER as a percentage of Storage Effective Actual Capacity", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DSTO", - "units": "Percent", - "minimum": 0, - "data_object": "SocPct", - "name": "DSTO.SocPct.AI47" - }, - { - "index": 48, - "description": "System Usable State of Charge - Present usable energy in the DER as a percentage of Nameplate Storage Usable Capacity", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DSTO", - "units": "Percent", - "minimum": 0, - "data_object": "UseSocPct", - "name": "DSTO.UseSocPct.AI48" - }, - { - "index": 49, - "description": "System Start-up Status", - "data_type": "AI", - "common_data_class": "ENS", - "maximum": 99, - "ln_class": "DGEN", - "units": "None (list)", - "minimum": -1, - "data_object": "DEROpSt", - "name": "DGEN.DEROpSt.AI49" - }, - { - "index": 50, - "description": "DER Start (Return to Service) Voltage High Limit. Percent of Reference Voltage.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 20000, - "ln_class": "DCTE", - "units": "Percent", - "minimum": 0, - "data_object": "VHiLim", - "name": "DCTE.VHiLim.AI50" - }, - { - "index": 51, - "description": "DER Start (Return to Service) Voltage Low Limit. Percent of Reference Voltage.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 10000, - "ln_class": "DCTE", - "units": "Percent", - "minimum": 0, - "data_object": "VLoLim", - "name": "DCTE.VLoLim.AI51" - }, - { - "index": 52, - "description": "DER Start (Return to Service) Frequency High Limit", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DCTE", - "units": "Hz", - "minimum": 0, - "data_object": "HzHiLim", - "name": "DCTE.HzHiLim.AI52" - }, - { - "index": 53, - "description": "DER Start (Return to Service) Frequency Low Limit", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DCTE", - "units": "Hz", - "minimum": 0, - "data_object": "HzLoLim", - "name": "DCTE.HzLoLim.AI53" - }, - { - "index": 54, - "description": "DER Start (Return to Service) Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RtnDlTmms", - "name": "DCTE.RtnDlTmms.AI54" - }, - { - "index": 55, - "description": "DER Start (Return to Service) Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AI55" - }, - { - "index": 56, - "description": "DER Start (Return to Service) Ramp Up Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RtnRmpTmms", - "name": "DCTE.RtnRmpTmms.AI56" - }, - { - "index": 57, - "description": "DER Stop (Cease to Energize) Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AI57" - }, - { - "index": 58, - "description": "DER Stop (Cease to Energize) Ramp Down Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DCTE.RmpTms.AI58" - }, - { - "index": 59, - "description": "DER Stop (Cease to Energize) Reversion Timeout Period. Time to revert from the stopped state and return to service.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DCTE.RvrtTms.AI59" - }, - { - "index": 60, - "description": "Connect/Disconnect Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DCTE.WinTms.AI60" - }, - { - "index": 61, - "description": "Connect/Disconnect Reversion Timeout Period. Timeout (reversion time is for the Disconnect only).", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DCTE", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DCTE.RvrtTms.AI61" - }, - { - "index": 62, - "description": "Maximum Generation Ramp Up Rate. The maximum generation ramp up rate expressed as a percentage of the Maximum Generation Rate (WMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DCTE", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRteMax", - "name": "DCTE.RpuRteMax.AI62" - }, - { - "index": 63, - "description": "Maximum Generation Ramp Down Rate. The maximum generation ramp down rate expressed as a percentage of the Maximum Generation Rate (WMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DCTE", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRteMax", - "name": "DCTE.RpdRteMax.AI63" - }, - { - "index": 64, - "description": "Maximum Charging Ramp Up Rate. The maximum charging ramp up rate expressed as a percentage of the Maximum Charging Rate (WChaMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DCTE", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRteMax", - "name": "DCTE.RpuChaRteMax.AI64" - }, - { - "index": 65, - "description": "Maximum Charging Ramp Down Rate. The maximum charging ramp down rate expressed as a percentage of the Maximum Charnging Rate (WChaMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DCTE", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRteMax", - "name": "DCTE.RpdChaRteMax.AI65" - }, - { - "index": 66, - "description": "Requested Settings Group.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "allowed_values": { - "0": "Not Used", - "1": "Unspecified / Autonomously Determined (see BO Enable Sensed Grid Config Detection)", - "2": "Factory Configuration", - "3": "Default Configuration / Comms Lost", - "4": "Normal Grid-Connected Configuration", - "5": "Islanded Condition 1 (small, local island)", - "6": "Islanded Condition 2 (larger, area island)", - "7": "Islanded Condition 3 (largest, regional island)", - "8": "1st Alternate Grid-Connected Configuration", - "9": "2nd Alternate Grid-Connected Configuration", - "10": "3rd Alternate Grid-Connected Configuration" - }, - "type": "enumerated", - "name": "DECP.EcpIsldSt.AI66" - }, - { - "index": 67, - "description": "Settings Group Being Edited.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "allowed_values": { - "0": "Not Used", - "1": "Unspecified / Autonomously Determined (see BO Enable Sensed Grid Config Detection)", - "2": "Factory Configuration", - "3": "Default Configuration / Comms Lost", - "4": "Normal Grid-Connected Configuration", - "5": "Islanded Condition 1 (small, local island)", - "6": "Islanded Condition 2 (larger, area island)", - "7": "Islanded Condition 3 (largest, regional island)", - "8": "1st Alternate Grid-Connected Configuration", - "9": "2nd Alternate Grid-Connected Configuration", - "10": "3rd Alternate Grid-Connected Configuration" - }, - "type": "enumerated", - "name": "DECP.EcpIsldSt.AI67" - }, - { - "index": 68, - "description": "Active Settings Group. Note this may differ from the Requested Settings Group or Settings Group Being Edited analog outputs depending on whether communications has been lost and how the Enable Sensed Grid Config Detection binary output is set.", - "data_type": "AI", - "common_data_class": "ENS", - "maximum": 255, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpIsldSt", - "allowed_values": { - "0": "Not Used", - "1": "Unspecified / Autonomously Determined (see BO42)", - "2": "Factory Configuration", - "3": "Default Configuration / Comms Lost", - "4": "Normal Grid-Connected Configuration", - "5": "Islanded Condition 1 (small, local island)", - "6": "Islanded Condition 2 (larger, area island)", - "7": "Islanded Condition 3 (largest, regional island)", - "8": "1st Alternate Grid-Connected Configuration", - "9": "2nd Alternate Grid-Connected Configuration", - "10": "3rd Alternate Grid-Connected Configuration" - }, - "type": "enumerated", - "name": "DECP.EcpIsldSt.AI68" - }, - { - "index": 69, - "description": "Freeze Counter Interval. interval between freeze counter operations after the initial occurrence. A zero value means the free counter operation is not repeated.", - "data_type": "AI", - "minimum": 0, - "name": "AI69" - }, - { - "index": 70, - "description": "Freeze Counter Interval Units. Units of the interval between freeze counter operations.", - "data_type": "AI", - "maximum": 9, - "minimum": 0, - "units": "None (list)", - "allowed_values": { - "0": "The outstation does not repeat the action,regardless of the Interval count.", - "1": "Milliseconds - In this case the interval is always counted relative to the Start Time and is constant regardless of the clock time set at the Outstation.", - "2": "Seconds - At the same millisecond within the second that is specified in the Start Time.", - "3": "Minutes - At the same second and millisecond within the minute that is specified in the Start Time.", - "4": "Hours - At the same minute,second and B7millisecond within the hour that is specified in the Start Time.", - "5": "Days - At the same time of day that is specified in the Start Time.", - "6": "Weeks - On the same day of the week at the same time of day that is specified in the Start Time", - "7": "Months - On the same day of each month at the same time of day that is specified in the Start Time. If the Start Time falls on the 29th or greater day of the month,the outstation shall not perform the action in months that do not have such a day", - "8": "Months on Same Day of Week from Start of Month - At the same timeof day on the same day of the week after the beginning of the month as the day specified in the Start Time. For instance,if the Start Time specifies the second Tuesday of February and the Interval Count is 2,the next action shall occur on the second Tuesday of April. In the same example,if the Interval Count is set to 12,this is the same as specifying,Every year on the second Tuesday in February. If the specified day does not occur in a given month when an action was scheduled to occur,the outstation shall not perform the action that month but shall perform it at the next valid scheduled time.", - "9": "Months on Same Day of Week from End of Month - The outstation shall interpret this setting as in <8>,but the day of the week shall be measured from the end of the month,e.g.,the second-last Tuesday in February." - }, - "type": "enumerated", - "name": "AI70" - }, - { - "index": 71, - "description": "Low/High Voltage Ride-Through Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DHVT", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHVT.EcpRef.AI71" - }, - { - "index": 72, - "description": "Low/High Voltage Ride-Through Voltage Reference Input. Active voltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN.Vol.AI72" - }, - { - "index": 73, - "description": "Low/High Voltage Ride-Through High Must Trip Curve Index. Index of the Voltage Ride-through curve which specifies trip points when the voltage is high.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTOV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOV.BlkRef.AI73" - }, - { - "index": 74, - "description": "Low/High Voltage Ride-Through Low Must Trip Curve Index. Index of the Voltage Ride-through curve which specifies trip points when the voltage is low.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTUV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUV.BlkRef.AI74" - }, - { - "index": 75, - "description": "Low/High Voltage Ride-Through High Momentary Cessation Curve Index. Index of the Voltage Ride-through curve which specifies where generation/discharging must stop when the voltage is high.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTOV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOV.BlkRef.AI75" - }, - { - "index": 76, - "description": "Low/High Voltage Ride-Through Low Momentary Cessation Curve Index. Index of the Voltage Ride-through curve which specifies where generation/discharging must stop when the voltage is low.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTUV", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUV.BlkRef.AI76" - }, - { - "index": 77, - "description": "Low/High Frequency Ride-Through Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DHFT", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFT.EcpRef.AI77" - }, - { - "index": 78, - "description": "Low/High Frequency Ride-Through Frequency Reference Input. Active frequency measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "Hz", - "name": "MMXU.Hz.AI78" - }, - { - "index": 79, - "description": "Low/High Frequency Ride-Through High Must Trip Curve Index. Index of the Frequency Ride-through curve which specifies trip points when the frequency is high.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTOF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOF.BlkRef.AI79" - }, - { - "index": 80, - "description": "Low/High Frequency Ride-Through Low Must Trip Curve Index. Index of the Frequency Ride-through curve which specifies trip points when the frequency is low.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTUF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUF.BlkRef.AI80" - }, - { - "index": 81, - "description": "Low/High Frequency Ride-Through High Momentary Cessation Curve Index. Index of the Frequency Ride-through curve which specifies where generation/discharging must stop when the frequency is high.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTOF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTOF.BlkRef.AI81" - }, - { - "index": 82, - "description": "Low/High Frequency Ride-Through Low Momentary Cessation Curve Index. Index of the Frequency Ride-through curve which specifies where generation/discharging must stop when the frequency is low.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "PTUF", - "minimum": 0, - "data_object": "BlkRef", - "name": "PTUF.BlkRef.AI82" - }, - { - "index": 83, - "description": "Dynamic Reactive Current Support Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "minimum": 0, - "data_object": "ModPrio", - "name": "DRGS.ModPrio.AI83" - }, - { - "index": 84, - "description": "Dynamic Reactive Current Support Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DRGS.WinTms.AI84" - }, - { - "index": 85, - "description": "Dynamic Reactive Current Support Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DRGS.RmpTms.AI85" - }, - { - "index": 86, - "description": "Dynamic Reactive Current Support Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DRGS.RvrtTms.AI86" - }, - { - "index": 87, - "description": "Dynamic Reactive Current Support Signal Meter ID. Referenced ECP. This is the meter from which current is being read to evaluate and provide support.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DRGS", - "minimum": 0, - "data_object": "EcpRef", - "name": "DRGS.EcpRef.AI87" - }, - { - "index": 88, - "description": "Dynamic Reactive Current Support Voltage Reference Input. Votltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN2.Vol.AI88" - }, - { - "index": 89, - "description": "Dynamic Reactive Current Support Moving Average Voltage", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DRGS", - "units": "Volts", - "minimum": 0, - "data_object": "VAv", - "name": "DRGS.VAv.AI89" - }, - { - "index": 90, - "description": "Dynamic Reactive Current Support Present Delta Voltage. Difference in Volts between the present measured Voltage and the Moving Average Voltage (RDGS.Vav) as a percentage of the reference voltage (VRef).", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 10000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": -10000, - "data_object": "DelV", - "name": "DRGS.DelV.AI90" - }, - { - "index": 91, - "description": "Dynamic Reactive Current Support - Gradient Mode.", - "data_type": "AI", - "common_data_class": "SPG", - "maximum": 2, - "ln_class": "DRGS", - "units": "None (list)", - "minimum": 0, - "data_object": "ArGraMod", - "allowed_values": { - "0": "Undefined", - "1": "Gradients reach 0 at the moving average Voltage", - "2": "Gradients reach 0 at the Voltage deadbands" - }, - "type": "enumerated", - "name": "DRGS.ArGraMod.AI91" - }, - { - "index": 92, - "description": "Dynamic Reactive Current Support Deadband Minimum Voltage. Percentage of the nominal voltage (DRCT.Vref), measured from the moving average voltage (RDGS.VAv). Support is no longer applied when the voltage stays above this value for the length of the Hold Time.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 0, - "ln_class": "DRGS", - "units": "Percent", - "minimum": -10000, - "data_object": "DbVMin", - "name": "DRGS.DbVMin.AI92" - }, - { - "index": 93, - "description": "Dynamic Reactive Current Support Deadband Maximum Voltage. Percentage of the nominal voltage (DRCT.Vref), measured from the moving average voltage (RDGS.VAv). Support is no longer applied when the voltage stays below this value for the length of the Hold Time.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 10000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "DbVMax", - "name": "DRGS.DbVMax.AI93" - }, - { - "index": 94, - "description": "Dynamic Reactive Current Support Gradient for Sags. Percentage of the rated current (DRAT.ARtg) to apply capacitively per percentage of the negative deviation from the moving average voltage (RDGS.Av). It is a ratio of percent and is therefore unitless.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DRGS", - "units": "Percent current per percent voltage deviation", - "data_object": "ArGraSag", - "name": "DRGS.ArGraSag.AI94" - }, - { - "index": 95, - "description": "Dynamic Reactive Current Support Gradient for Swells. Percentage of the rated current (DRAT.ARtg) to apply inductively per percentage of the positive deviation from the moving average voltage (RDGS.Av). It is a ratio of percent and is therefore unitless.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DRGS", - "units": "Percent current per percent voltage deviation", - "data_object": "ArGraSwl", - "name": "DRGS.ArGraSwl.AI95" - }, - { - "index": 96, - "description": "Dynamic Reactive Current Support Filter Time for Moving Average Voltage (RDGS.VAv). Used to determine amount of dynamic reactive current support.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DRGS.FilTms.AI96" - }, - { - "index": 97, - "description": "Dynamic Reactive Current Support Block Zone Voltage. Percentage of the nominal voltage (DRCT.VRef) below which no reactive current support shall be applied.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "BlkZnV", - "name": "DRGS.BlkZnV.AI97" - }, - { - "index": 98, - "description": "Dynamic Reactive Current Support Hysteresis Block Zone Voltage. Percentage of the nominal voltage (DRCT.VRef). After being blocked,reactive current support shall not resume until the voltage has been above BlkZnV + HysBlkZnV.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DRGS", - "units": "Percent", - "minimum": 0, - "data_object": "HysBlkZnV", - "name": "DRGS.HysBlkZnV.AI98" - }, - { - "index": 99, - "description": "Dynamic Reactive Current Support Block Zone Time. Time in milliseconds from the beginning of any \"sag\" event, before which dynamic reactive current support will always continue, regardless of how low voltage may sag.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "BlkZnTmms", - "name": "DRGS.BlkZnTmms.AI99" - }, - { - "index": 100, - "description": "Dynamic Reactive Current Support Hold Time. When the voltage returns to within the deadband limits (RDGS.dbVMin annd RDGS.dbVMax) for this length of time (measured in milliseconds), the \"sag\" or \"swell\" event is considered to be over. Reactive current support ends, frozen values are unfrozen, and a new event can begin.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DRGS", - "units": "ms", - "minimum": 0, - "data_object": "HoldTmms", - "name": "DRGS.HoldTmms.AI100" - }, - { - "index": 101, - "description": "Dynamic Reactive Current Attempted Output. Current output that the mode is attempting to achieve based on the Voltage input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DRGS", - "units": "Amps", - "minimum": 0, - "data_object": "ReqA", - "name": "DRGS.ReqA.AI101" - }, - { - "index": 102, - "description": "Dynamic Volt-Watt Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWD", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVWD.ModPrio.AI102" - }, - { - "index": 103, - "description": "Dynamic Volt-Watt Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVWD.WinTms.AI103" - }, - { - "index": 104, - "description": "Dynamic Volt-Watt Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVWD.RmpTms.AI104" - }, - { - "index": 105, - "description": "Dynamic Volt-Watt Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVWD.RvrtTms.AI105" - }, - { - "index": 106, - "description": "Dynamic Volt-Watt Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DVWD", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVWD2.EcpRef.AI106" - }, - { - "index": 107, - "description": "Dynamic Volt-Watt Voltage Reference Input. Votltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN2.Vol.AI107" - }, - { - "index": 108, - "description": "Dynamic Volt-Watt Moving Average Voltage", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DVWD", - "units": "Volts", - "minimum": 0, - "data_object": "VAv", - "name": "DVWD2.VAv.AI108" - }, - { - "index": 109, - "description": "Dynamic Volt-Watt Present Delta Voltage", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DVWD", - "units": "Volts", - "minimum": 0, - "data_object": "DelV", - "name": "DVWD2.DelV.AI109" - }, - { - "index": 110, - "description": "Dynamic Volt-Watt Gradient. Signed quantity that establishes the ratio of additional Watts supplied (expressed in terms of % DRCT.WMax) to the present difference from the moving average voltage (expressed as % DRCT.VRef).", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DVWD", - "units": "Percent watts per percent voltage difference", - "data_object": "DynVWGra", - "name": "DVWD.DynVWGra.AI110" - }, - { - "index": 111, - "description": "Dynamic Volt-Watt Filter Time. The time in seconds used to calculate the moving average voltage for dynamic Volt-Watt support.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DVWD", - "units": "Seconds", - "minimum": 0, - "data_object": "VWFilTms", - "name": "DVWD.VWFilTms.AI111" - }, - { - "index": 112, - "description": "Dynamic Volt-Watt Lower Deadband. Percentage of the nominal voltage (DRCT.Vref) measured below the moving average voltage. If the present voltage is above this value,no additional Watts shall be supplied.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 0, - "ln_class": "DVWD", - "units": "Percent", - "minimum": -1000, - "data_object": "DbVWLo", - "name": "DVWD.DbVWLo.AI112" - }, - { - "index": 113, - "description": "Dynamic Volt-Watt Upper Deadband. Percentage of the nominal voltage (DRCT.Vref) measured above the moving average voltage. If the present voltage is below this value, no additional Watts shall be supplied.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVWD", - "units": "Percent", - "minimum": 0, - "data_object": "DbVWHi", - "name": "DVWD.DbVWHi.AI113" - }, - { - "index": 114, - "description": "Dynamic Volt-Watt Attempted Output. Watt output that the mode is attempting to achieve based on the Voltage input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DVWD", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DVWD.ReqWSet.AI114" - }, - { - "index": 115, - "description": "Frequency-Watt Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "ModPrio", - "name": "DHFW2.ModPrio.AI115" - }, - { - "index": 116, - "description": "Frequency-Watt Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DHFW.WinTms.AI116" - }, - { - "index": 117, - "description": "Frequency-Watt Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DHFW.RmpTms.AI117" - }, - { - "index": 118, - "description": "Frequency-Watt Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DHFW.RvrtTms.AI118" - }, - { - "index": 119, - "description": "Frequency-Watt Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFW2.EcpRef.AI119" - }, - { - "index": 120, - "description": "Frequency-Watt Frequency Reference Input. Frequency measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "MMXU", - "units": "Hz", - "minimum": 0, - "data_object": "Hz", - "name": "MMXU2.Hz.AI120" - }, - { - "index": 121, - "description": "Frequency-Watt High Starting Frequency. Delta frequency between start frequency and nominal grid frequency for high frequency events.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DHFW", - "units": "Hz", - "minimum": 0, - "data_object": "HzStr", - "name": "DHFW2.HzStr.AI121" - }, - { - "index": 122, - "description": "Frequency-Watt High Stopping Frequency. Delta frequency between stop frequency and nominal grid frequency for high frequency events.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "DHFW", - "units": "Hz", - "minimum": 0, - "data_object": "HzStop", - "name": "DHFW2.HzStop.AI122" - }, - { - "index": 123, - "description": "Frequency-Watt High Discharging/Generating Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WGra", - "name": "DHFW.WGra.AI123" - }, - { - "index": 124, - "description": "Frequency-Watt High Charging Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WChaGra", - "name": "DHFW.WChaGra.AI124" - }, - { - "index": 125, - "description": "Frequency-Watt Low Starting Frequency. Delta frequency between start frequency and nominal grid frequency for low frequency events.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 0, - "ln_class": "DLFW", - "units": "Hz", - "minimum": -70000, - "data_object": "HzStr", - "name": "DLFW2.HzStr.AI125" - }, - { - "index": 126, - "description": "Frequency-Watt Low Stopping Frequency. Delta frequency between stop frequency and nominal grid frequency for low frequency events.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "maximum": 0, - "ln_class": "DLFW", - "units": "Hz", - "minimum": -70000, - "data_object": "HzStop", - "name": "DLFW2.HzStop.AI126" - }, - { - "index": 127, - "description": "Frequency-Watt Low Discharging/Generating Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WGra", - "name": "DLFW.WGra.AI127" - }, - { - "index": 128, - "description": "Frequency-Watt Low Charging Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "data_object": "WChaGra", - "name": "DLFW.WChaGra.AI128" - }, - { - "index": 129, - "description": "Frequency-Watt Start Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStrDlTmms", - "name": "DHFW2.ActStrDlTmms.AI129" - }, - { - "index": 130, - "description": "Frequency-Watt Stop Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStopDlTmms", - "name": "DHFW2.ActStopDlTmms.AI130" - }, - { - "index": 131, - "description": "Frequency-Watt Ramp Up Time Constant. Time constant or open loop response time for moving from the current active power target to a higher active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DLFW.OpnLoopMax.AI131" - }, - { - "index": 132, - "description": "Frequency-Watt Ramp Down Time Constant. Time constant or open loop response time for moving from the current active power target to a lower active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AI132" - }, - { - "index": 133, - "description": "Frequency-Watt Discharge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DHFW.RpuRte.AI133" - }, - { - "index": 134, - "description": "Frequency-Watt Discharge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRteMax", - "name": "DHFW.RpdRteMax.AI134" - }, - { - "index": 135, - "description": "Frequency-Watt Charge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DHFW.RpuChaRte.AI135" - }, - { - "index": 136, - "description": "Frequency-Watt Charge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRteMax", - "name": "DHFW.RpdChaRteMax.AI136" - }, - { - "index": 137, - "description": "Frequency-Watt High Return Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent watts per percent frequency difference", - "minimum": 0, - "data_object": "RtnRmpRte", - "name": "DHFW2.RtnRmpRte.AI137" - }, - { - "index": 138, - "description": "Frequency-Watt Low Return Gradient", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DLFW", - "units": "Percent watts per percent frequency difference", - "minimum": 0, - "data_object": "RtnRmpRte", - "name": "DLFW2.RtnRmpRte.AI138" - }, - { - "index": 139, - "description": "Frequency-Watt Attempted Output. Watt output that the mode is attempting to achieve based on the Frequency input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DHFW", - "units": "Watts", - "data_object": "ReqWLim", - "name": "DHFW.ReqWLim.AI139" - }, - { - "index": 140, - "description": "Frequency-Watt Minimum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DAGC.SocUseMinPct.AI140" - }, - { - "index": 141, - "description": "Frequency-Watt Maximum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DAGC.SocUseMaxPct.AI141" - }, - { - "index": 142, - "description": "Active Power Limit Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWMX", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWMX.ModPrio.AI142" - }, - { - "index": 143, - "description": "Active Power Limit Enabling Time Window. Time window (in seconds) within which to randomly execute a command. If the time window is zero, the command will be executed immediately.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWMX.WinTms.AI143" - }, - { - "index": 144, - "description": "Active Power Limit Enabling Ramp Time. Ramp time, in seconds, for moving from current operational mode settings to new operational mode settings.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWMX.RmpTms.AI144" - }, - { - "index": 145, - "description": "Active Power Limit Reversion Timeout Period. Reversion Timeout Period (in seconds), after which the device will revert to its default status, such as closing the switch to reconnect to the grid or allowing maximum watts output, in case communications are lost or mitigating messages are not received.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWMX", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWMX.RvrtTms.AI145" - }, - { - "index": 146, - "description": "Active Power Limit Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DWMX", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWMX.EcpRef.AI146" - }, - { - "index": 147, - "description": "Active Power Limit Reference Input. Active Power measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "name": "MMXU.TotW.AI147" - }, - { - "index": 148, - "description": "Active Power Limit Charge Setpoint", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWMX", - "units": "Percent", - "minimum": 0, - "data_object": "WLimPct", - "name": "DWMX.WLimPct.AI148" - }, - { - "index": 149, - "description": "Active Power Limit Generation Setpoint", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWMN", - "units": "Percent", - "minimum": 0, - "data_object": "WLimPct", - "name": "DWMN.WLimPct.AI149" - }, - { - "index": 150, - "description": "Charge/Discharge Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWGC.ModPrio.AI150" - }, - { - "index": 151, - "description": "Charge/Discharge Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWGC.WinTms.AI151" - }, - { - "index": 152, - "description": "Charge/Discharge Enabling Ramp Time. Ramp time, in seconds, for moving from current operational mode settings to new operational mode settings.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWGC.RmpTms.AI152" - }, - { - "index": 153, - "description": "Charge/Discharge Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWGC.RvrtTms.AI153" - }, - { - "index": 154, - "description": "Charge/Discharge Active Power Target. Percentage of maximum active power.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "GnWPctSpt", - "name": "DWGC.GnWPctSpt.AI154" - }, - { - "index": 155, - "description": "Charge/Discharge Ramp Up Time Constant. Ramp time, in seconds, for moving from the current active power target to a higher active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWGC.OpnLoopMax.AI155" - }, - { - "index": 156, - "description": "Charge/Discharge Ramp Down Time Constant. Ramp time, in seconds, for moving from the current active power target to a lower active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWGC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWGC.OpnLoopMax.AI156" - }, - { - "index": 157, - "description": "Charge/Discharge Discharge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DWGC.RpuRte.AI157" - }, - { - "index": 158, - "description": "Charge/Discharge Discharge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRteMax", - "name": "DWGC.RpdRteMax.AI158" - }, - { - "index": 159, - "description": "Charge/Discharge Charge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DWGC.RpuChaRte.AI159" - }, - { - "index": 160, - "description": "Charge/Discharge Charge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRteMax", - "name": "DWGC.RpdChaRteMax.AI160" - }, - { - "index": 161, - "description": "Charge/Discharge Minimum Reserve for Storage. The reserve level below which the storage system may be only be discharged in emergency situations, expressed as a percentage of the usable capacity.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "SocUseMinPct", - "name": "DWGC.SocUseMinPct.AI161" - }, - { - "index": 162, - "description": "Charge/Discharge Maximum Reserve for Storage. The reserve level above which the storage system may be only be charged in emergency situations, expressed as a percentage of the usable capacity.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DWGC", - "units": "Percent", - "minimum": -1000, - "data_object": "SocUseMaxPct", - "name": "DWGC.SocUseMaxPct.AI162" - }, - { - "index": 163, - "description": "Coordinated Charge/Discharge Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "minimum": 0, - "data_object": "ModPrio", - "name": "DTCD.ModPrio.AI163" - }, - { - "index": 164, - "description": "Coordinated Charge/Discharge Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DTCD.WinTms.AI164" - }, - { - "index": 165, - "description": "Coordinated Charge/Discharge Enabling Ramp Time. Ramp time, in seconds, for moving from current operational mode settings to new operational mode settings", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DTCD.RmpTms.AI165" - }, - { - "index": 166, - "description": "Coordinated Charge/Discharge Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DTCD.RvrtTms.AI166" - }, - { - "index": 167, - "description": "Coordinated Charge/Discharge Target State of Charge. Charge that the system is expected to achieve, as a percentage of the usable capacity.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DTCD", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseTgtPct", - "name": "DTCD.SocUseTgtPct.AI167" - }, - { - "index": 168, - "description": "Coordinated Charge/Discharge Target Date. Date by which the storage system must reach the target SOC. Days since January 1, 1970, UTC.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Days", - "minimum": 0, - "data_object": "DateTgt", - "name": "DTCD.DateTgt.AI168" - }, - { - "index": 169, - "description": "Coordinated Charge/Discharge Target Time. Time by when the storage system must reach the target SOC. Expressed as the number of seconds since the start of Target Date.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Milliseconds", - "minimum": 0, - "data_object": "DateTgtTms", - "name": "DTCD.DateTgtTms.AI169" - }, - { - "index": 170, - "description": "Coordinated Charge/Discharge Energy Request. Amount of energy that must be transferred from the grid to the charger to move the SOC from the value at the specific time of reference to the target SOC.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Watt-hours", - "minimum": 0, - "data_object": "SocWReq", - "name": "DTCD.SocWReq.AI170" - }, - { - "index": 171, - "description": "Coordinated Charge/Discharge Minimum Charging Duration. Minimum duration to move from the SOC at the time of reference to the target SOC.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "ChaDurTms", - "name": "DTCD.ChaDurTms.AI171" - }, - { - "index": 172, - "description": "Coordinated Charge/Discharge Date of Reference. Date that the SOC is measured or computed by the storage system and is the basis for the Energy Request, Minimum Charging Duration, and other parameters.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Days", - "minimum": 0, - "data_object": "DateTgt", - "name": "DTCD.DateTgt.AI172" - }, - { - "index": 173, - "description": "Coordinated Charge/Discharge Time of Reference. Time that the SOC is measured or computed by the storage system and is the basis for the Energy Request, Minimum Charging Duration, and other parameters.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Milliseconds", - "minimum": 0, - "data_object": "SocDateTms", - "name": "DTCD.SocDateTms.AI173" - }, - { - "index": 174, - "description": "Coordinated Charge/Discharge Duration at Maximum Charge Rate. Duration that energy can be stored at the Maximum Charge Rate.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "ChaDurMax", - "name": "DTCD.ChaDurMax.AI174" - }, - { - "index": 175, - "description": "Coordinated Charge/Discharge Duration Maximum Discharge Rate. Duration that energy can be delivered at the Maximum Discharge Rate.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DTCD", - "units": "Seconds", - "minimum": 0, - "data_object": "DschDurMax", - "name": "DTCD.DschDurMax.AI175" - }, - { - "index": 176, - "description": "Active Power Response Mode #1 Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPKP", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPKP.ModPrio.AI176" - }, - { - "index": 177, - "description": "Active Power Response Mode #1 Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPKP.WinTms.AI177" - }, - { - "index": 178, - "description": "Active Power Response Mode #1 Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPKP.RmpTms.AI178" - }, - { - "index": 179, - "description": "Active Power Response Mode #1 Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPKP", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPKP.RvrtTms.AI179" - }, - { - "index": 180, - "description": "Active Power Response Mode #1 Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DPKP", - "minimum": 0, - "data_object": "EcpRef", - "name": "DPKP.EcpRef.AI180" - }, - { - "index": 181, - "description": "Active Power Response Mode #1 Reference Power Measured", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "name": "MMXU.TotW.AI181" - }, - { - "index": 182, - "description": "Active Power Response Mode #1 Power Threshold", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DPKP", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DPKP.PkPwrWLim.AI182" - }, - { - "index": 183, - "description": "Active Power Response Mode #1 Ratio", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DPKP", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DPKP.PkPwrFolPct.AI183" - }, - { - "index": 184, - "description": "Active Power Response Mode #1 Ramp Up Rate. Maximum ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DPKP", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DPKP.RpuRte.AI184" - }, - { - "index": 185, - "description": "Active Power Response Mode #1 Ramp Down Rate. Maximum ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DPKP", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DPKP.RpdRte.AI185" - }, - { - "index": 186, - "description": "Active Power Response Mode #1 Attempted Output. Watt output that the mode is attempting to achieve based on the Watts input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DPKP", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DPKP.ReqWSet.AI186" - }, - { - "index": 187, - "description": "Active Power Response Mode #2 Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DGFL", - "minimum": 0, - "data_object": "ModPrio", - "name": "DGFL.ModPrio.AI187" - }, - { - "index": 188, - "description": "Active Power Response Mode #2 Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DGFL.WinTms.AI188" - }, - { - "index": 189, - "description": "Active Power Response Mode #2 Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DGFL.RmpTms.AI189" - }, - { - "index": 190, - "description": "Active Power Response Mode #2 Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DGFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DGFL.RvrtTms.AI190" - }, - { - "index": 191, - "description": "Active Power Response Mode #2 Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DGFL", - "minimum": 0, - "data_object": "EcpRef", - "name": "DGFL.EcpRef.AI191" - }, - { - "index": 192, - "description": "Active Power Response Mode #2 Reference Power Measured", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "name": "MMXU.TotW.AI192" - }, - { - "index": 193, - "description": "Active Power Response Mode #2 Power Threshold", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DGFL", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DGFL.PkPwrWLim.AI193" - }, - { - "index": 194, - "description": "Active Power Response Mode #2 Ratio", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DGFL", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DGFL.PkPwrFolPct.AI194" - }, - { - "index": 195, - "description": "Active Power Response Mode #2 Ramp Up Rate. Maximum ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DGFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DGFL.RpuRte.AI195" - }, - { - "index": 196, - "description": "Active Power Response Mode #2 Ramp Down Rate. Maximum ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DGFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DGFL.RpdRte.AI196" - }, - { - "index": 197, - "description": "Active Power Response Mode #2 Attempted Output. Watt output that the mode is attempting to achieve based on the Watts input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DGFL", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DGFL.ReqWSet.AI197" - }, - { - "index": 198, - "description": "Active Power Response Mode #3 Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFL", - "minimum": 0, - "data_object": "ModPrio", - "name": "DLFL.ModPrio.AI198" - }, - { - "index": 199, - "description": "Active Power Response Mode #3 Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DLFL.WinTms.AI199" - }, - { - "index": 200, - "description": "Active Power Response Mode #3 Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DLFL.RmpTms.AI200" - }, - { - "index": 201, - "description": "Active Power Response Mode #3 Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DLFL", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DLFL.RvrtTms.AI201" - }, - { - "index": 202, - "description": "Active Power Response Mode #3 Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DLFL", - "minimum": 0, - "data_object": "EcpRef", - "name": "DLFL.EcpRef.AI202" - }, - { - "index": 203, - "description": "Active Power Response Mode #3 Reference Power Measured", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "name": "MMXU.TotW.AI203" - }, - { - "index": 204, - "description": "Active Power Response Mode #3 Power Threshold", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DLFL", - "units": "Watts", - "data_object": "PkPwrWLim", - "name": "DLFL.PkPwrWLim.AI204" - }, - { - "index": 205, - "description": "Active Power Response Mode #3 Ratio", - "data_type": "AI", - "common_data_class": "ING", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DLFL", - "units": "Percent", - "minimum": 0, - "data_object": "PkPwrFolPct", - "name": "DLFL.PkPwrFolPct.AI205" - }, - { - "index": 206, - "description": "Active Power Response Mode #3 Ramp Up Rate. Maximum ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DLFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DLFL.RpuRte.AI206" - }, - { - "index": 207, - "description": "Active Power Response Mode #3 Ramp Down Rate. Maximum ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DLFL", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DLFL.RpdRte.AI207" - }, - { - "index": 208, - "description": "Active Power Response Mode #3 Attempted Output. Watt output that the mode is attempting to achieve based on the Watts input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DLFL", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DLFL.ReqWSet.AI208" - }, - { - "index": 209, - "description": "AGC Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DAGC.ModPrio.AI209" - }, - { - "index": 210, - "description": "AGC Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DAGC.WinTms.AI210" - }, - { - "index": 211, - "description": "AGC Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DAGC.RmpTms.AI211" - }, - { - "index": 212, - "description": "AGC Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DAGC.RvrtTms.AI212" - }, - { - "index": 213, - "description": "AGC Active Power Target", - "data_type": "AI", - "common_data_class": "APC", - "ln_class": "DAGC", - "units": "Watts", - "data_object": "GnWSpt", - "name": "DAGC.GnWSpt.AI213" - }, - { - "index": 214, - "description": "AGC Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpUpTms", - "name": "DAGC.RmpUpTms.AI214" - }, - { - "index": 215, - "description": "AGC Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpDnTms", - "name": "DAGC.RmpDnTms.AI215" - }, - { - "index": 216, - "description": "AGC Discharge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DAGC.RpuRte.AI216" - }, - { - "index": 217, - "description": "AGC Discharge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DAGC.RpdRte.AI217" - }, - { - "index": 218, - "description": "AGC Charge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DAGC.RpuChaRte.AI218" - }, - { - "index": 219, - "description": "AGC Charge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DAGC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DAGC.RpdChaRte.AI219" - }, - { - "index": 220, - "description": "AGC Minimum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DAGC.SocUseMinPct.AI220" - }, - { - "index": 221, - "description": "AGC Maximum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DAGC.SocUseMaxPct.AI221" - }, - { - "index": 222, - "description": "AGC Maximum Watts Available", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DAGC", - "units": "Watts", - "data_object": "WMaxAvl", - "name": "DAGC.WMaxAvl.AI222" - }, - { - "index": 223, - "description": "AGC Minimum Watts Available", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DAGC", - "units": "Watts", - "data_object": "WMinAvl", - "name": "DAGC.WMinAvl.AI223" - }, - { - "index": 224, - "description": "AGC Expected State of Charge", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SocExpc", - "name": "DAGC.SocExpc.AI224" - }, - { - "index": 225, - "description": "AGC Expected State of Energy", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DAGC", - "units": "Percent", - "minimum": 0, - "data_object": "SoeExpc", - "name": "DAGC.SoeExpc.AI225" - }, - { - "index": 226, - "description": "AGC Expected State of Charge Time Interval", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DAGC", - "units": "Seconds", - "minimum": 0, - "data_object": "SocExpcTms", - "name": "DAGC.SocExpcTms.AI226" - }, - { - "index": 227, - "description": "Active Power Smoothing Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWSM.ModPrio.AI227" - }, - { - "index": 228, - "description": "Active Power Smoothing Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWSM.WinTms.AI228" - }, - { - "index": 229, - "description": "Active Power Smoothing Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWSM.RmpTms.AI229" - }, - { - "index": 230, - "description": "Active Power Smoothing Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWSM.RvrtTms.AI230" - }, - { - "index": 231, - "description": "Active Power Smoothing Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DWSM", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWSM.EcpRef.AI231" - }, - { - "index": 232, - "description": "Active Power Smoothing Reference Power Input. Active Power measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "minimum": 0, - "data_object": "TotW", - "name": "MMXU.TotW.AI232" - }, - { - "index": 233, - "description": "Active Power Smoothing Gradient. Signed quantity that establishes the ratio of additional smoothing Watts provided to the present delta-watts of the reference load or generation. Delta Watts is the difference between the moving average and the present value of the reference power. Positive values of this gradient are for following load (increased reference load results in a dynamic increase in DER output), and negative values are for following generation (increased reference generation results in a dynamic decrease in DER output).", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.001, - "ln_class": "DWSM", - "units": "Watts per Delta-watt", - "data_object": "WSmthGra", - "name": "DWSM.WSmthGra.AI233" - }, - { - "index": 234, - "description": "Active Power Smoothing Lower Limit. Difference in Watts from the moving average of the reference power above which no smoothing shall be applied.", - "data_type": "AI", - "common_data_class": "ASG", - "maximum": 0, - "ln_class": "DWSM", - "units": "Watts", - "data_object": "WSmthLoLim", - "name": "DWSM.WSmthLoLim.AI234" - }, - { - "index": 235, - "description": "Active Power Smoothing Upper Limit. Difference in Watts from the moving average of the reference power below which no smoothing shall be applied.", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DWSM", - "units": "Watts", - "minimum": 0, - "data_object": "WSmthHiLim", - "name": "DWSM.WSmthHiLim.AI235" - }, - { - "index": 236, - "description": "Active Power Smoothing Filter Time (Seconds). Time in seconds used to calculate the moving average of the reference load or generation being smoothed.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWSM", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DWSM.FilTms.AI236" - }, - { - "index": 237, - "description": "Active Power Smoothing Discharge Ramp Up Rate. The maximum generation ramp up rate expressed as a percentage of the Maximum Generation Rate (WMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DWSM.RpuRte.AI237" - }, - { - "index": 238, - "description": "Active Power Smoothing Discharge Ramp Down Rate. The maximum generation ramp down rate expressed as a percentage of the Maximum Generation Rate (WMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DWSM.RpdRte.AI238" - }, - { - "index": 239, - "description": "Active Power Smoothing Charge Ramp Up Rate. The maximum charging ramp up rate expressed as a percentage of the Maximum Charging Rate (WChaMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DWSM.RpuChaRte.AI239" - }, - { - "index": 240, - "description": "Active Power Smoothing Charge Ramp Down Rate. The maximum charging ramp down rate expressed as a percentage of the Maximum Charnging Rate (WChaMax) per second.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DWSM", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DWSM.RpdChaRte.AI240" - }, - { - "index": 241, - "description": "Active Power Smoothing Attempted Output. Watt output that the mode is attempting to achieve based on the Watt input and other parameters.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DWSM", - "units": "Watts", - "data_object": "ReqWSet", - "name": "DWSM.ReqWSet.AI241" - }, - { - "index": 242, - "description": "Volt-Watt Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVWC.ModPrio.AI242" - }, - { - "index": 243, - "description": "Volt-Watt Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVWC.WinTms.AI243" - }, - { - "index": 244, - "description": "Volt-Watt Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVWC.RmpTms.AI244" - }, - { - "index": 245, - "description": "Volt-Watt Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVWC.RvrtTms.AI245" - }, - { - "index": 246, - "description": "Volt-Watt Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVWC.EcpRef.AI246" - }, - { - "index": 247, - "description": "Volt-Watt Reference Voltage Input. Voltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN.Vol.AI247" - }, - { - "index": 248, - "description": "Volt-Watt Curve Index. Index of the Volt-Watt curve that should be used by the mode.", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DVWC", - "minimum": 0, - "data_object": "VWCrv", - "name": "DVWC.VWCrv.AI248" - }, - { - "index": 249, - "description": "Volt-Watt Attempted Output. Maximum active power the outstation will attempt to generate or absorb based on the Voltage input and selected curve.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DVWC", - "units": "Watts", - "data_object": "ReqWLim", - "name": "DVWC.ReqWLim.AI249" - }, - { - "index": 250, - "description": "Volt-Watt Filter Time (Seconds)", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "FilTms", - "name": "DVWC.FilTms.AI250" - }, - { - "index": 251, - "description": "Volt-Watt Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVWC.OpnLoopMax.AI251" - }, - { - "index": 252, - "description": "Volt-Watt Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVWC", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVWC.OpnLoopMax.AI252" - }, - { - "index": 253, - "description": "Volt-Watt Discharging Ramp Up Rate. Maximum ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DVWC.RpuRte.AI253" - }, - { - "index": 254, - "description": "Volt-Watt Discharging Ramp Down Rate. Maximum ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DVWC.RpdRte.AI254" - }, - { - "index": 255, - "description": "Volt-Watt Charging Ramp Up Rate. Maximum charging ramp up rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DVWC.RpuChaRte.AI255" - }, - { - "index": 256, - "description": "Volt-Watt Charging Ramp Down Rate. Maximum charging ramp down rate.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DVWC", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DVWC.RpdChaRte.AI256" - }, - { - "index": 257, - "description": "Frequency-Watt Curve Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "ModPrio", - "name": "DHFW.ModPrio.AI257" - }, - { - "index": 258, - "description": "Frequency-Watt Curve Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DHFW.WinTms.AI258" - }, - { - "index": 259, - "description": "Frequency-Watt Curve Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DHFW.RmpTms.AI259" - }, - { - "index": 260, - "description": "Frequency-Watt Curve Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DHFW.RvrtTms.AI260" - }, - { - "index": 261, - "description": "Frequency-Watt Curve Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "EcpRef", - "name": "DHFW.EcpRef.AI261" - }, - { - "index": 262, - "description": "Frequency-Watt Curve Frequency Reference Input. Frequency measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "MMXU", - "units": "Hz", - "minimum": 0, - "data_object": "Hz", - "name": "MMXU.Hz.AI262" - }, - { - "index": 263, - "description": "Frequency-Watt Curve - Curve Index. Index of the Frequency-Watt curve that should be used by the mode.", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "HzWCrv", - "name": "DHFW.HzWCrv.AI263" - }, - { - "index": 264, - "description": "Frequency-Watt Curve - High Frequency Hysteresis Curve Index", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DHFW", - "minimum": 0, - "data_object": "HysCrv", - "name": "DHFW.HysCrv.AI264" - }, - { - "index": 265, - "description": "Frequency-Watt Curve - Low Frequency Hysteresis Curve Index", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DLFW", - "minimum": 0, - "data_object": "HysCrv", - "name": "DLFW.HysCrv.AI265" - }, - { - "index": 266, - "description": "Frequency-Watt Curve Start Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStrDlTmms", - "name": "DHFW.ActStrDlTmms.AI266" - }, - { - "index": 267, - "description": "Frequency-Watt Curve Stop Delay", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "ActStopDlTmms", - "name": "DHFW.ActStopDlTmms.AI267" - }, - { - "index": 268, - "description": "Frequency-Watt Curve Ramp Up Time Constant. Time constant or open loop response time for moving from the current active power target to a higher active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AI268" - }, - { - "index": 269, - "description": "Frequency-Watt Curve Ramp Down Time Constant. Time constant or open loop response time for moving from the current active power target to a lower active power target.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DHFW", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DHFW.OpnLoopMax.AI269" - }, - { - "index": 270, - "description": "Frequency-Watt Curve Discharge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuRte", - "name": "DHFW.RpuRte.AI270" - }, - { - "index": 271, - "description": "Frequency-Watt Curve Discharge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdRte", - "name": "DHFW.RpdRte.AI271" - }, - { - "index": 272, - "description": "Frequency-Watt Curve Charge Ramp Up Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpuChaRte", - "name": "DHFW.RpuChaRte.AI272" - }, - { - "index": 273, - "description": "Frequency-Watt Curve Charge Ramp Down Rate", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 500000, - "ln_class": "DHFW", - "units": "Percent per Second", - "minimum": 0, - "data_object": "RpdChaRte", - "name": "DHFW.RpdChaRte.AI273" - }, - { - "index": 274, - "description": "Frequency-Watt Attempted Output. Watt output that the mode is attempting to achieve based on the Frequency input and selected curve. If Snapshot of Power is not enabled,this is the maximum active power the outstation will attempt to generate or absorb.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DHFW", - "units": "Watts", - "data_object": "ReqWLim", - "name": "DHFW.ReqWLim.AI274" - }, - { - "index": 275, - "description": "Frequency-Watt Curve Minimum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMinPct", - "name": "DHFW.SocUseMinPct.AI275" - }, - { - "index": 276, - "description": "Frequency-Watt Curve Maximum Usable SOC", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DHFW", - "units": "Percent", - "minimum": 0, - "data_object": "SocUseMaxPct", - "name": "DHFW.SocUseMaxPct.AI276" - }, - { - "index": 277, - "description": "Constant VArs Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVAR.ModPrio.AI277" - }, - { - "index": 278, - "description": "Constant VArs Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVAR.WinTms.AI278" - }, - { - "index": 279, - "description": "Constant VArs Enabling Ramp Time. Ramp time, in seconds, for moving from current operational mode settings to new operational mode settings.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVAR.RmpTms.AI279" - }, - { - "index": 280, - "description": "Constant VArs Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVAR.RvrtTms.AI280" - }, - { - "index": 281, - "description": "Constant VArs Reactive Power Target. Percentage of maximum reactive power.", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.1, - "maximum": 1000, - "ln_class": "DVAR", - "units": "Percent", - "minimum": -1000, - "data_object": "VArTgtPct", - "name": "DVAR.VArTgtPct.AI281" - }, - { - "index": 282, - "description": "Constant VArs Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVAR.OpnLoopMax.AI282" - }, - { - "index": 283, - "description": "Constant VArs Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVAR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVAR.OpnLoopMax.AI283" - }, - { - "index": 284, - "description": "Fixed Power Factor Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DFPF", - "minimum": 0, - "data_object": "ModPrio", - "name": "DFPF.ModPrio.AI284" - }, - { - "index": 285, - "description": "Fixed Power Factor Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DFPF.WinTms.AI285" - }, - { - "index": 286, - "description": "Fixed Power Factor Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DFPF.RmpTms.AI286" - }, - { - "index": 287, - "description": "Fixed Power Factor Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DFPF", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DFPF.RvrtTms.AI287" - }, - { - "index": 288, - "description": "Fixed Power Factor Setpoint - Generation/Discharging", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DFPF", - "units": "None", - "minimum": 0, - "data_object": "PFGnTgt", - "name": "DFPF.PFGnTgt.AI288" - }, - { - "index": 289, - "description": "Fixed Power Factor Setpoint - Charging", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DFPF", - "units": "None", - "minimum": 0, - "data_object": "PFLodTgt", - "name": "DFPF.PFLodTgt.AI289" - }, - { - "index": 290, - "description": "Volt-Var Control Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DVVR.ModPrio.AI290" - }, - { - "index": 291, - "description": "Volt-VAr Control Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DVVR.WinTms.AI291" - }, - { - "index": 292, - "description": "Volt-VAr Control Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DVVR.RmpTms.AI292" - }, - { - "index": 293, - "description": "Volt-VAr Control Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DVVR.RvrtTms.AI293" - }, - { - "index": 294, - "description": "Volt-VAr Control Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "EcpRef", - "name": "DVVR.EcpRef.AI294" - }, - { - "index": 295, - "description": "Volt-VAr Control Voltage Input. Voltage measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "MMXN", - "units": "Volts", - "minimum": 0, - "data_object": "Vol", - "name": "MMXN.Vol.AI295" - }, - { - "index": 296, - "description": "Volt-VAr Control Adjusted Voltage Reference. The Voltage used as reference for Volt-VAr control. If Autonomous Voltage Reference Adjustment is disabled,this is the same fixed value as the Reference Voltage.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.1, - "ln_class": "DVVR", - "units": "Volts", - "minimum": 0, - "data_object": "VRefSet", - "name": "DVVR.VRefSet.AI296" - }, - { - "index": 297, - "description": "Volt-VAr Curve Index. Index of the Volt-VAr curve that should be used by the mode.", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DVVR", - "minimum": 0, - "data_object": "VVArCrv", - "name": "DVVR.VVArCrv.AI297" - }, - { - "index": 298, - "description": "Volt-VAr Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVVR.OpnLoopMax.AI298" - }, - { - "index": 299, - "description": "Volt-VAr Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DVVR.OpnLoopMax.AI299" - }, - { - "index": 300, - "description": "Volt-VAr Autonomous Voltage Reference Adjustment Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DVVR", - "units": "Seconds", - "minimum": 0, - "data_object": "VRefTmms", - "name": "DVVR.VRefTmms.AI300" - }, - { - "index": 301, - "description": "Volt-VAr Attempted Output. VAr output that the mode is attempting to achieve based on the Voltage input and selected curve.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DVVR", - "units": "VARs", - "data_object": "ReqVAr", - "name": "DVVR.ReqVAr.AI301" - }, - { - "index": 302, - "description": "Watt-VAr Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "ModPrio", - "name": "DWVR.ModPrio.AI302" - }, - { - "index": 303, - "description": "Watt-VAr Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DWVR.WinTms.AI303" - }, - { - "index": 304, - "description": "Watt-VAr Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DWVR.RmpTms.AI304" - }, - { - "index": 305, - "description": "Watt-VAr Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DWVR.RvrtTms.AI305" - }, - { - "index": 306, - "description": "Watt-VAr Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "EcpRef", - "name": "DWVR.EcpRef.AI306" - }, - { - "index": 307, - "description": "Watt-VAr Reference Power Input. Power measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW", - "name": "MMXU.TotW.AI307" - }, - { - "index": 308, - "description": "Watt-VAr Curve Index. Index of the Watt-VAr curve that should be used by the mode.", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "DWVR", - "minimum": 0, - "data_object": "WVArCrv", - "name": "DWVR.WVArCrv.AI308" - }, - { - "index": 309, - "description": "Watt-VAr Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWVR.OpnLoopMax.AI309" - }, - { - "index": 310, - "description": "Watt-VAr Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DWVR", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DWVR.OpnLoopMax.AI310" - }, - { - "index": 311, - "description": "Watt-VAr Attempted Output. VAr output that the mode is attempting to achieve based on the Watt input and selected curve.", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "DWVR", - "units": "VARs", - "data_object": "ReqVAr", - "name": "DWVR.ReqVAr.AI311" - }, - { - "index": 312, - "description": "Power Factor Correction Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPFC", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPFC.ModPrio.AI312" - }, - { - "index": 313, - "description": "Power Factor Correction Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPFC.WinTms.AI313" - }, - { - "index": 314, - "description": "Power Factor Correction Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPFC.RmpTms.AI314" - }, - { - "index": 315, - "description": "Power Factor Correction Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPFC", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPFC.RvrtTms.AI315" - }, - { - "index": 316, - "description": "Power Factor Correction Signal Meter ID", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DPFC", - "minimum": 0, - "data_object": "EcpRef", - "name": "DPFC.EcpRef.AI316" - }, - { - "index": 317, - "description": "Power Factor Correction Reference Power Factor Input. Power factor measurement read from the meter and used as an input to the mode.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF", - "name": "MMXU.TotPF.AI317" - }, - { - "index": 318, - "description": "Power Factor Correction Average PF Target", - "data_type": "AI", - "common_data_class": "ASG", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFTrg", - "name": "DPFC.PFTrg.AI318" - }, - { - "index": 319, - "description": "Power Factor Correction Lower PF Limit", - "data_type": "AI", - "common_data_class": "Int", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFCorRef.rangeC", - "name": "DPFC.PFCorRef.rangeC.AI319" - }, - { - "index": 320, - "description": "Power Factor Correction Upper PF Limit", - "data_type": "AI", - "common_data_class": "Int", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "DPFC", - "units": "None", - "minimum": -100, - "data_object": "PFCorRef.rangeC", - "name": "DPFC.PFCorRef.rangeC.AI320" - }, - { - "index": 321, - "description": "Pricing Mode Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPRG", - "minimum": 0, - "data_object": "ModPrio", - "name": "DPRG.ModPrio.AI321" - }, - { - "index": 322, - "description": "Pricing Mode Enabling Time Window", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "WinTms", - "name": "DPRG.WinTms.AI322" - }, - { - "index": 323, - "description": "Pricing Mode Enabling Ramp Time", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "RmpTms", - "name": "DPRG.RmpTms.AI323" - }, - { - "index": 324, - "description": "Pricing Mode Reversion Timeout Period", - "data_type": "AI", - "common_data_class": "ASG", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "RvrtTms", - "name": "DPRG.RvrtTms.AI324" - }, - { - "index": 325, - "description": "Pricing Mode Setpoint: Hundredths of local currency per Kilowatt-Hr.", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "ln_class": "DPRG", - "units": "100ths of local currency", - "data_object": "PrcRef", - "name": "DPRG.PrcRef.AI325" - }, - { - "index": 326, - "description": "Pricing Mode Ramp Up Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DPRG.OpnLoopMax.AI326" - }, - { - "index": 327, - "description": "Pricing Mode Ramp Down Time Constant", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "DPRG", - "units": "Seconds", - "minimum": 0, - "data_object": "OpnLoopMax", - "name": "DPRG.OpnLoopMax.AI327" - }, - { - "index": 328, - "description": "Curve Edit Selector Index of the curve which is currently being viewed and/or changed", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "DGSM", - "minimum": 1, - "data_object": "InCrv", - "name": "DGSMn.InCrv.AI328", - "type": "selector_block", - "selector_block_start": 328, - "selector_block_end": 532 - - }, - { - "index": 329, - "description": "Curve Mode Type", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 20, - "ln_class": "DGSM", - "units": "None (list)", - "minimum": 0, - "data_object": "ModTyp", - "allowed_values": { - "0": "Curve is not defined", - "1": "None, dimensionless", - "2": "Volt-Var modes VV11-VV12", - "3": "Frequency-Watt mode FW22", - "4": "Watt-VAr mode WP42", - "5": "Voltage-Watt modes VW51-VW52", - "6": "Remain Connected", - "7": "Temperature mode", - "8": "Pricing signal mode", - "9": "HVRT Must Trip", - "10": "HVRT Momentary Cessation", - "11": "LVRT Must Trip", - "12": "LVRT Momentary Cessation", - "13": "HFRT Must Trip", - "14": "HFRT Momentary Cessation", - "15": "LFRT Must Trip", - "16": "LFRT Momentary Cessation" - }, - "type": "enumerated", - "name": "DGSMn.ModTyp.AI329" - }, - { - "index": 330, - "description": "Curve Number of Points", - "data_type": "AI", - "common_data_class": "CSG", - "maximum": 100, - "ln_class": "FMAR", - "minimum": 0, - "data_object": "PairArr.NumPts", - "name": "FMARn.PairArr.NumPts.AI330" - }, - { - "index": 331, - "description": "Independent (X-Value) Units for Curve", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "FMAR", - "units": "None (list)", - "allowed_values": { - "0": "Curve is not defined", - "1": "Not applicable / Unknown", - "4": "Time", - "23": "Celsius Temperature", - "29": "Voltage", - "33": "Frequency", - "38": "Watts", - "100": "Price in hundredths of local currency", - "129": "Percent Voltage", - "133": "Percent Frequency", - "138": "Percent Watts", - "233": "Frequency Deviation" - }, - "type": "enumerated", - "minimum": 0, - "data_object": "IndpUnits", - "name": "FMARn.IndpUnits.AI331" - }, - { - "index": 332, - "description": "Dependent (Y-Value) Units for Curve", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 255, - "ln_class": "FMAR", - "units": "None (list)", - "minimum": 0, - "data_object": "DepRef", - "allowed_values": { - "0": "Curve is not defined", - "1": "Not applicable / unknown", - "2": "VArs as percent of max VArs (VARMax)", - "3": "VArs as percent of max available VArs (VArAval)", - "4": "Vars as percent of max Watts (Wmax) - not used", - "5": "Watts as percent of max Watts (Wmax)", - "6": "Watts as percent of frozen active power (DeptSnptRef)", - "7": "Power Factor in EEI notation", - "8": "Volts as a percent of the nominal voltage (VRef)", - "9": "Frequency as a percentage of the Nominal Grid Frequency (ECPNomHz)" - }, - "type": "enumerated", - "name": "FMARn.DepRef.AI332" - }, - { - "index": 333, - "description": "Curve X-Value and Y-Value pairs for curve points 1 - 100", - "data_type": "AI", - "common_data_class": "CSG", - "ln_class": "FMAR", - "units": "Varies", - "data_object": "PairArr.CrvPts", - "name": "FMARn.PairArr.CrvPts.AI333", - "type": "array", - "array_times_repeated": 100, - "array_points": [ - { - "name": "FMARn.PairArr.CrvPts.AI333.xVal" - }, - { - "name": "FMARn.PairArr.CrvPts.AI333.yVal" - } - ] - }, - { - "index": 533, - "description": "System Meter Type of Connection Point", - "data_type": "AI", - "common_data_class": "ENS", - "maximum": 99, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "EcpConnType", - "event_class": 3, - "allowed_values": { - "0": "unknown", - "1": "DER to local EPS", - "2": "Internal to DER", - "3": "local EPS with load to area EPS (PCC with load)", - "4": "local EPS w/o load to area EPS (PCC without load)", - "5": "Load to local EPS", - "6": "External to DER beyond the PCC", - "7": "External to DER within the local EPS", - "8": "Auxiliary DER Load", - "9": "Group of DERs to the area EPS", - "99": "Other" - }, - "type": "enumerated", - "name": "DECP.EcpConnType.AI533" - }, - { - "index": 534, - "description": "System Meter Type of Circuit Phases", - "data_type": "AI", - "common_data_class": "ENS", - "maximum": 8, - "ln_class": "DECP", - "units": "None (list)", - "minimum": 0, - "data_object": "PhsConnTyp", - "event_class": 3, - "allowed_values": { - "0": "unknown", - "1": "Single phase", - "2": "Split phase", - "3": "2-phase", - "4": "3-phase delta", - "5": "3-phase wye", - "6": "3-phase wye grounded", - "7": "3-phase / 3-wire (inverter type)", - "8": "3-phase / 4-wire (inverter type)" - }, - "type": "enumerated", - "name": "DECP.PhsConnTyp.AI534" - }, - { - "index": 535, - "description": "System Meter Apparent Power Calculation Method. Calculation method for total apparent power calculation.", - "data_type": "AI", - "common_data_class": "ENG", - "maximum": 2, - "ln_class": "MMXU", - "units": "None (list)", - "minimum": 0, - "data_object": "ClcTotVA", - "allowed_values": { - "0": "unknown", - "1": "vector", - "2": "arithmetic" - }, - "type": "enumerated", - "name": "MMXU.ClcTotVA.AI535" - }, - { - "index": 536, - "description": "System Meter Frequency", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.001, - "maximum": 70000, - "ln_class": "MMXU", - "units": "Hz", - "minimum": 0, - "data_object": "Hz", - "event_class": 3, - "name": "MMXU.Hz.AI536" - }, - { - "index": 537, - "description": "System Meter Active Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "TotW", - "event_class": 3, - "name": "MMXU.TotW.AI537" - }, - { - "index": 538, - "description": "System Meter Active Power A", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "W.phsA.mag", - "event_class": 1, - "name": "MMXU.W.phsA.mag.AI538" - }, - { - "index": 539, - "description": "System Meter Active Power B", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "W.phsB.mag", - "event_class": 1, - "name": "MMXU.W.phsB.mag.AI539" - }, - { - "index": 540, - "description": "System Meter Active Power C", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "Watts", - "data_object": "W.phsC.mag", - "event_class": 1, - "name": "MMXU.W.phsC.mag.AI540" - }, - { - "index": 541, - "description": "System Meter Reactive Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "data_object": "TotVAr", - "event_class": 3, - "name": "MMXU.TotVAr.AI541" - }, - { - "index": 542, - "description": "System Meter Reactive Power A", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "VAr", - "data_object": "VAr.phsA.mag", - "event_class": 1, - "name": "MMXU.VAr.phsA.mag.AI542" - }, - { - "index": 543, - "description": "System Meter Reactive Power B", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "VAr", - "data_object": "VAr.phsB.mag", - "event_class": 1, - "name": "MMXU.VAr.phsB.mag.AI543" - }, - { - "index": 544, - "description": "System Meter Reactive Power C", - "data_type": "AI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "units": "VAr", - "data_object": "VAr.phsC.mag", - "event_class": 1, - "name": "MMXU.VAr.phsC.mag.AI544" - }, - { - "index": 545, - "description": "System Meter Power Factor", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF", - "event_class": 3, - "name": "MMXU.TotPF.AI545" - }, - { - "index": 546, - "description": "System Meter Apparent Power", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VA", - "data_object": "TotVA", - "event_class": 3, - "name": "MMXU.TotVA.AI546" - }, - { - "index": 547, - "description": "System Meter Phase A Volts", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.mag", - "event_class": 3, - "name": "MMXU.PhV.phsA.mag.AI547" - }, - { - "index": 548, - "description": "System Meter Phase A Angle", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "maximum": 3600, - "ln_class": "MMXU", - "units": "Degrees", - "minimum": 0, - "data_object": "PhV.phsA.ang", - "event_class": 3, - "name": "MMXU.PhV.phsA.ang.AI548" - }, - { - "index": 549, - "description": "System Meter Phase B Volts", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.mag", - "event_class": 3, - "name": "MMXU.PhV.phsB.mag.AI549" - }, - { - "index": 550, - "description": "System Meter Phase B Angle", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "maximum": 3600, - "ln_class": "MMXU", - "units": "Degrees", - "minimum": 0, - "data_object": "PhV.phsB.ang", - "event_class": 3, - "name": "MMXU.PhV.phsB.ang.AI550" - }, - { - "index": 551, - "description": "System Meter Phase C Volts", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.mag", - "event_class": 3, - "name": "MMXU.PhV.phsC.mag.AI551" - }, - { - "index": 552, - "description": "System Meter Phase C Angle", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "maximum": 3600, - "ln_class": "MMXU", - "units": "Degrees", - "minimum": 0, - "data_object": "PhV.phsC.ang", - "event_class": 3, - "name": "MMXU.PhV.phsC.ang.AI552" - }, - { - "index": 553, - "description": "System Meter Average Line to Line Voltage", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "AvPPVPhs", - "event_class": 1, - "name": "MMXU.AvPPVPhs.AI553" - }, - { - "index": 554, - "description": "System Meter Current A", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Amps", - "data_object": "A.phsA.mag", - "event_class": 1, - "name": "MMXU.A.phsA.mag.AI554" - }, - { - "index": 555, - "description": "System Meter Current B", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Amps", - "data_object": "A.phsB.mag", - "event_class": 1, - "name": "MMXU.A.phsB.mag.AI555" - }, - { - "index": 556, - "description": "System Meter Current C", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Amps", - "data_object": "A.phsC.mag", - "event_class": 1, - "name": "MMXU.A.phsC.mag.AI556" - }, - { - "index": 557, - "description": "System Meter Active Power - High Threshold", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW.rangeC.hLim", - "event_class": 3, - "name": "MMXU.TotW.rangeC.hLim.AI557" - }, - { - "index": 558, - "description": "System Meter Active Power - Low Threshold", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "Watts", - "minimum": 0, - "data_object": "TotW.rangeC.lLim", - "event_class": 3, - "name": "MMXU.TotW.rangeC.lLim.AI558" - }, - { - "index": 559, - "description": "System Meter Reactive Power - High Threshold", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "minimum": 0, - "data_object": "TotVAr.rangeC.hLim", - "event_class": 3, - "name": "MMXU.TotVAr.rangeC.hLim.AI559" - }, - { - "index": 560, - "description": "System Meter Reactive Power - Low Threshold", - "data_type": "AI", - "common_data_class": "MV", - "ln_class": "MMXU", - "units": "VARs", - "minimum": 0, - "data_object": "TotVAr.rangeC.lLim", - "event_class": 3, - "name": "MMXU.TotVAr.rangeC.lLim.AI560" - }, - { - "index": 561, - "description": "System Meter Power Factor - High Threshold", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF.rangeC.hLim", - "event_class": 3, - "name": "MMXU.TotPF.rangeC.hLim.AI561" - }, - { - "index": 562, - "description": "System Meter Power Factor - Low Threshold", - "data_type": "AI", - "common_data_class": "MV", - "scaling_multiplier": 0.01, - "maximum": 100, - "ln_class": "MMXU", - "units": "None", - "minimum": -100, - "data_object": "TotPF.rangeC.lLim", - "event_class": 3, - "name": "MMXU.TotPF.rangeC.lLim.AI562" - }, - { - "index": 563, - "description": "System Meter Phase A Volts - High Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.rangeC.hLim", - "event_class": 3, - "name": "MMXU.PhV.phsA.rangeC.hLim.AI563" - }, - { - "index": 564, - "description": "System Meter Phase A Volts - Low Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsA.rangeC.lLim", - "event_class": 3, - "name": "MMXU.PhV.phsA.rangeC.lLim.AI564" - }, - { - "index": 565, - "description": "System Meter Phase B Volts - High Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.rangeC.hLim", - "event_class": 3, - "name": "MMXU.PhV.phsB.rangeC.hLim.AI565" - }, - { - "index": 566, - "description": "System Meter Phase B Volts - Low Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsB.rangeC.lLim", - "event_class": 3, - "name": "MMXU.PhV.phsB.rangeC.lLim.AI566" - }, - { - "index": 567, - "description": "System Meter Phase C Volts - High Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.rangeC.hLim", - "event_class": 3, - "name": "MMXU.PhV.phsC.rangeC.hLim.AI567" - }, - { - "index": 568, - "description": "System Meter Phase C Volts - Low Threshold", - "data_type": "AI", - "common_data_class": "WYE", - "scaling_multiplier": 0.1, - "ln_class": "MMXU", - "units": "Volts", - "minimum": 0, - "data_object": "PhV.phsC.rangeC.lLim", - "event_class": 3, - "name": "MMXU.PhV.phsC.rangeC.lLim.AI568" - }, - { - "index": 569, - "description": "Running Schedule Index. Index of the highest priority schedule that is currently running or 0 if no schedule is currently running.", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "ActSchdRef", - "name": "FSCC1.ActSchdRef.AI569" - }, - { - "index": 570, - "description": "Schedule to Edit Selector", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "Schd", - "event_class": 3, - "name": "FSCC.Schd.AI570", - "type": "selector_block", - "selector_block_start": 570, - "selector_block_end": 780 - - }, - { - "index": 571, - "description": "Selected Schedule Identity", - "data_type": "AI", - "common_data_class": "ORG", - "ln_class": "FSCC", - "minimum": 0, - "data_object": "Schd", - "event_class": 3, - "name": "FSCC.Schd.AI571" - }, - { - "index": 572, - "description": "Selected Schedule Priority. Priority of the schedule relative to other running schedules. Lower values have higher priority over higher values.", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "FSCH", - "minimum": 1, - "data_object": "SchdPrio", - "event_class": 3, - "name": "FSCH.SchdPrio.AI572" - }, - { - "index": 573, - "description": "Selected Schedule Type.", - "data_type": "AI", - "maximum": 21, - "minimum": 0, - "units": "None (list)", - "event_class": 3, - "allowed_values": { - "1": "Low/High Voltage Ride-Through Hi Must Trip", - "2": "Low/High Voltage Ride-Through Low Must Trip", - "3": "Low/High Voltage Ride-Through Hi Momentary", - "4": "Low/High Voltage Ride-Through Lo Momentary", - "5": "Low/High Frequency Ride-Through Hi Must Trip", - "6": "Low/High Frequency Ride-Through Lo Must Trip", - "7": "Low/High Frequency Ride-Through Hi Momentary", - "8": "Low/High Frequency Ride-Through Low Momentary", - "9": "Dynamic Reactive Current Support - On/Off", - "10": "Dynamic Volt-Watt - On/Off", - "11": "Frequency-Watt - On/Off", - "12": "Active Power Limit - Charging", - "13": "Active Power Limit - Generating", - "14": "Charge/Discharge - Percent of Maximum", - "15": "Coordinated Charge/Discharge - SOC Target", - "16": "Active Power Response #1 - On/Off", - "17": "Active Power Response #2 - On/Off", - "18": "Active Power Response #3 - On/Off", - "19": "AGC Watts", - "20": "Active Power Smoothing - On/Off", - "21": "Volt-Watt Curve Index", - "22": "Frequency-Watt Curve Curve Index", - "23": "Frequency-Watt Curve High Hysteresis", - "24": "Frequency-Watt Curve Low Hysteresis", - "25": "Constant VArs - Percent of Maximum", - "26": "Fixed Power Factor - Power Factor", - "27": "Volt-VAr Curve Index", - "28": "Watt-VAr Curve Index", - "29": "Power Factor Correction - On/Off", - "30": "Reserved - For pricing mode" - }, - "type": "enumerated", - "name": "AI573" - }, - { - "index": 574, - "description": "Selected Schedule Start Date. Number of days since January 1, 1970, UTC.", - "data_type": "AI", - "common_data_class": "TSG", - "ln_class": "FSCH", - "units": "Days", - "minimum": 0, - "data_object": "StrTm", - "event_class": 3, - "name": "FSCH.StrTm.AI574" - }, - { - "index": 575, - "description": "Selected Schedule Start Time. Milliseconds since the start of Schedule Start Date.", - "data_type": "AI", - "common_data_class": "TSG", - "maximum": 86400000, - "ln_class": "FSCH", - "units": "Milli-seconds", - "minimum": 0, - "data_object": "StrTm", - "event_class": 3, - "name": "FSCH.StrTm.AI575" - }, - { - "index": 576, - "description": "Selected Schedule Repeat Interval. Interval between actions after the initial occurrence. A zero value means the schedule is not repeated.", - "data_type": "AI", - "common_data_class": "TCS", - "ln_class": "FSCH", - "units": "Varies", - "minimum": 0, - "data_object": "NxtStrTm", - "event_class": 3, - "name": "FSCH.NxtStrTm.AI576" - }, - { - "index": 577, - "description": "Selected Schedule Repeat Interval Units", - "data_type": "AI", - "common_data_class": "SPG", - "maximum": 8, - "ln_class": "FSCH", - "minimum": 0, - "data_object": "SchdReuse", - "event_class": 3, - "allowed_values": { - "0": "No Repeat", - "1": "sec", - "2": "Minutes", - "3": "Hours", - "4": "Days", - "5": "Weeks", - "6": "Months", - "7": "Months on Same Day of Week", - "8": "Months on Same Day of Week from End" - }, - "type": "enumerated", - "name": "FSCH.SchdReuse.AI577" - }, - { - "index": 578, - "description": "Selected Schedule Validation Status", - "data_type": "AI", - "common_data_class": "ENSScheduleState", - "maximum": 4, - "ln_class": "FSCH", - "minimum": 0, - "data_object": "SchdSt", - "event_class": 3, - "name": "FSCH1.SchdSt.AI578" - }, - { - "index": 579, - "description": "Selected Schedule Status", - "data_type": "AI", - "common_data_class": "ENSScheduleState", - "maximum": 4, - "ln_class": "FSCH", - "units": "None (list)", - "minimum": 0, - "data_object": "SchdSt", - "allowed_values": { - "0": "unknown", - "1": "Not available", - "2": "Inactive", - "3": "Ready-to-Run", - "4": "Running" - }, - "type": "enumerated", - "name": "FSCH1.SchdSt.AI579" - }, - { - "index": 580, - "description": "Selected Schedule Number of Points", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "FSCH", - "minimum": 0, - "data_object": "NumEntr", - "event_class": 3, - "name": "FSCH.NumEntr.AI580" - }, - { - "index": 581, - "description": "Select schedule time offset and value pairs for points 1 - 100", - "data_type": "AI", - "minimum": 0, - "name": "FSCHn.SchdEntr.AI581", - "type": "array", - "array_times_repeated": 100, - "array_points": [ - { - "name": "FSCHn.SchdEntr.AI581.time", - "units": "Seconds" - }, - { - "name": "FSCHn.SchdEntr.AI581.val", - "ln_class": "FSCH", - "data_object": "SchdEntr" - } - ] - }, - { - "index": 781, - "description": "Schedule 1 Status", - "data_type": "AI", - "common_data_class": "ENSScheduleState", - "maximum": 4, - "ln_class": "FSCH", - "units": "None (list)", - "minimum": 0, - "data_object": "SchdSt", - "allowed_values": { - "0": "unknown", - "1": "Not available", - "2": "Inactive", - "3": "Ready-to-Run", - "4": "Running" - }, - "type": "enumerated", - "name": "FSCH1.SchdSt.AI781" - }, - { - "index": 782, - "description": "Schedule 1 Priority", - "data_type": "AI", - "common_data_class": "ING", - "ln_class": "FSCH", - "minimum": 1, - "data_object": "SchdPrio", - "name": "FSCH.SchdPrio.AI782" - }, - { - "index": 783, - "description": "Schedule 1 Active Time Value. This is the index of the time value entry the schedule is currently running. First entry is 1. Zero if the schedule is not running.", - "data_type": "AI", - "common_data_class": "INS", - "maximum": 10, - "ln_class": "FSCH", - "minimum": 0, - "data_object": "ActStrTm", - "name": "FSCH1.ActStrTm.AI783" - }, - { - "category": "alarm", - "index": 0, - "description": "System Communication Error", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "LCCH", - "data_object": "ChLiv", - "allowed_values": { - "0": "Normal", - "1": "Alarm: Communications error exists in the ESS" - }, - "event_class": 1, - "name": "LCCH.ChLiv.BI0" - }, - { - "category": "alarm", - "index": 1, - "description": "System Has Priority 1 Alarms", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "CALH", - "data_object": "GrAlm", - "allowed_values": { - "0": "No P1 Alarms Active", - "1": "Alarm: One or More P1 Alarms Active" - }, - "event_class": 1, - "name": "CALH.GrAlm.BI1" - }, - { - "category": "alarm", - "index": 2, - "description": "System Has Priority 2 Alarms", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "CALH", - "data_object": "GrWrn", - "allowed_values": { - "0": "No P2 Alarms Active", - "1": "Alarm: One or More P2 Alarms Active" - }, - "event_class": 1, - "name": "CALH.GrWrn.BI2" - }, - { - "category": "alarm", - "index": 3, - "description": "System Has Priority 3 Alarms", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "CALH", - "data_object": "GrInd", - "allowed_values": { - "0": "No P3 Alarms Active", - "1": "Alarm: One or More P3 Alarms Active" - }, - "event_class": 1, - "name": "CALH.GrInd.BI3" - }, - { - "category": "alarm", - "index": 4, - "description": "Storage State of Charge at Maximum. Maximum Usable State of Charge Reached.", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DSTO", - "data_object": "SocHiWrn", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DSTO.SocHiWrn.BI4" - }, - { - "category": "alarm", - "index": 5, - "description": "Storage State of Charge is Too High. Maximum Reserve Percentage (of usable capacity) reached.", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DSTO", - "data_object": "SocHiAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DSTO.SocHiAlm.BI5" - }, - { - "category": "alarm", - "index": 6, - "description": "Storage State of Charge is Too Low. Minimum Reserve Percentage (of usable capacity) reached.", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DSTO", - "data_object": "SocLoAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DSTO.SocLoAlm.BI6" - }, - { - "category": "alarm", - "index": 7, - "description": "Storage State of Charge is Depleted. Minimum Usable State of Charge Reached.", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DSTO", - "data_object": "SohLoAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DSTO.SohLoAlm.BI7" - }, - { - "category": "alarm", - "index": 8, - "description": "Storage Internal Temperature is Too High", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DBAT", - "data_object": "IntnTmpHiAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DBAT.IntnTmpHiAlm.BI8" - }, - { - "category": "alarm", - "index": 9, - "description": "Storage External (Ambient) Temperature is Too High", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "DBAT", - "data_object": "ExtTmpHiAlm", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "DBAT.ExtTmpHiAlm.BI9" - }, - { - "index": 10, - "description": "System Is In Local State. System has been locked by a local operator which prevents other operators from executing commands. Note: Local State is also sometimes referred to as Maintenance State. Local State overrides Lockout State.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and in maintenance", - "allowed_values": { - "0": "System not in local state", - "1": "System in local state" - }, - "name": "DSTO.DEROpSt.disconnectedandinmaintenance.BI10" - }, - { - "index": 11, - "description": "System Is In Lockout State. System has been locked by an operator such that other operators may not execute commands. Lockout State is also sometimes referred to as Blocked State.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and blocked", - "allowed_values": { - "0": "System not locked out", - "1": "System locked out" - }, - "name": "DSTO.DEROpSt.disconnectedandblocked.BI11" - }, - { - "index": 12, - "description": "System Is Starting Up. Set to 1 when a BO \"System Initiate Start-up Sequence\" command has been received.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.starting and synchronizing", - "allowed_values": { - "0": "Not Starting Up", - "1": "Start command has been received." - }, - "name": "DSTO.DEROpSt.startingandsynchronizing.BI12" - }, - { - "index": 13, - "description": "System Is Stopping. Set to 1 when an B0 \"System Execute Stop\" command has been received.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.stopping", - "allowed_values": { - "0": "Not Stopping", - "1": "Emergency stop command has been received." - }, - "name": "DSTO.DEROpSt.stopping.BI13" - }, - { - "index": 14, - "description": "System is Started (Return to Service). If any of the DER Units are started,then true. DER Units in the maintenance operational state are excluded.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.connected and idle", - "allowed_values": { - "0": "Null", - "1": "Started" - }, - "name": "DSTO.DEROpSt.connectedandidle.BI14" - }, - { - "index": 15, - "description": "System is Stopped (Cease to Energize). If all of the DER Units are stopped, then true. DER Units in the maintenance operational state are excluded.", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.ceased to energize", - "allowed_values": { - "0": "Null", - "1": "Stopped" - }, - "name": "DSTO.DEROpSt.ceasedtoenergize.BI15" - }, - { - "index": 16, - "description": "System Permission to Start Status", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DSTO", - "data_object": "PrmConn", - "allowed_values": { - "0": "Start Permission Not Granted", - "1": "Start Permission Granted" - }, - "name": "DSTO.PrmConn.BI16" - }, - { - "index": 17, - "description": "System Permission to Stop Status", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DSTO", - "data_object": "PrmDscon", - "allowed_values": { - "0": "Stop Permission Not Granted", - "1": "Stop Permission Granted" - }, - "name": "DSTO.PrmDscon.BI17" - }, - { - "index": 18, - "description": "DER is Connected and Idle", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.connected and idle", - "allowed_values": { - "0": "Null", - "1": "Idle-Connected" - }, - "name": "DSTO.DEROpSt.connectedandidle.BI18" - }, - { - "index": 19, - "description": "DER is Connected and Generating", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.connected and generating", - "allowed_values": { - "0": "Null", - "1": "On-Connected" - }, - "name": "DSTO.DEROpSt.connectedandgenerating.BI19" - }, - { - "index": 20, - "description": "DER is Connected and Charging", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.connected and consuming", - "allowed_values": { - "0": "Null", - "1": "On-Charging-Connected" - }, - "name": "DSTO.DEROpSt.connectedandconsuming.BI20" - }, - { - "index": 21, - "description": "DER is Off but Available to Start", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and available", - "allowed_values": { - "0": "Null", - "1": "Off-Available" - }, - "name": "DSTO.DEROpSt.disconnectedandavailable.BI21" - }, - { - "index": 22, - "description": "DER is Off and Not Available to Start", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and stand-by", - "allowed_values": { - "0": "Null", - "1": "Off-Not-Available" - }, - "name": "DSTO.DEROpSt.disconnectedandstand-by.BI22" - }, - { - "index": 23, - "description": "DER Connect/Disconnect Switch Closed Status", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.off", - "allowed_values": { - "0": "Open", - "1": "Closed" - }, - "name": "DSTO.DEROpSt.off.BI23" - }, - { - "index": 24, - "description": "DER Connect/Disconnect Switch Movement Status", - "data_type": "BI", - "common_data_class": "DPC", - "ln_class": "CSWI", - "data_object": "Pos", - "allowed_values": { - "0": "Not Moving", - "1": "Moving" - }, - "name": "CSWI.Pos.BI24" - }, - { - "index": 25, - "description": "Islanded Mode. Determines how the DER behaves when in an Islanded configuration.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DSTO", - "data_object": "IsldCtlFol", - "allowed_values": { - "0": "Isochronous Mode. DER attempts to control voltage and frequency independent of configured curves and settings up to the limits of the machine's capabilities in order to achieve the AO Reference Voltage and AO nominal frequency.", - "1": "Droop Mode. DER acts as a follower using Volt/VAR and Freq/Watt curves." - }, - "event_class": 3, - "name": "DSTO.IsldCtlFol.BI25" - }, - { - "index": 26, - "description": "Sensed Grid Config Detection Enabled. If Enabled, the DER may independently change its Active Settings Group based on locally observed grid conditions.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DECP", - "data_object": "ECPIsldAuto", - "allowed_values": { - "0": "No Autonomous Detection.", - "1": "Autonomous Detection. Inverter's Active Settings Group may differ from the Requested Settings Group" - }, - "event_class": 3, - "name": "DECP.ECPIsldAuto.BI26" - }, - { - "index": 27, - "description": "Storage Capacity Units. Determines whether energy storage values are expressed in units of Amp-hrs or Watt-hrs.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DSTO", - "data_object": "AGra", - "allowed_values": { - "0": "Amp-hrs (default)", - "1": "Watt-hrs" - }, - "event_class": 3, - "name": "DSTO.AGra.BI27" - }, - { - "index": 28, - "description": "Time Constant Mode. Indicates whether Time Constant Ramp parameters are interpreted as Open Loop Response times or 3Tau values.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DSTO", - "data_object": "OpnLoopTau", - "allowed_values": { - "0": "Open Loop Response Time", - "1": "3Tau Value" - }, - "event_class": 3, - "name": "DSTO.OpnLoopTau.BI28" - }, - { - "index": 29, - "description": "Power Factor Excitation When Discharging/Generating", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DFPF", - "data_object": "PFGnExtSet", - "allowed_values": { - "0": "Injecting VARs - Q1", - "1": "Absorbing VARs - Q4" - }, - "name": "DFPF.PFGnExtSet.BI29" - }, - { - "index": 30, - "description": "Power Factor Excitation When Charging", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DFPF", - "data_object": "PFLodExtSet", - "allowed_values": { - "0": "Injecting VARs - Q2", - "1": "Absorbing VARs - Q3" - }, - "name": "DFPF.PFLodExtSet.BI30" - }, - { - "index": 31, - "description": "Supports Low/High Voltage Ride-Through Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DHVT", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DHVT.BI31" - }, - { - "index": 32, - "description": "Supports Low/High Frequency Ride-Through Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DHFT", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DHFT.BI32" - }, - { - "index": 33, - "description": "Supports Dynamic Reactive Current Support Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DRGS", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DRGS.BI33" - }, - { - "index": 34, - "description": "Supports Dynamic Volt-Watt Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DVWD", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DVWD.BI34" - }, - { - "index": 35, - "description": "Supports Frequency-Watt Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DHFW", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DHFW.BI35" - }, - { - "index": 36, - "description": "Supports Active Power Limit Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DWLM", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DWLM.BI36" - }, - { - "index": 37, - "description": "Supports Charge/Discharge Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DWGC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DWGC.BI37" - }, - { - "index": 38, - "description": "Supports Coordinated Charge/Discharge Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DTCD", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DTCD.BI38" - }, - { - "index": 39, - "description": "Supports Active Power Response Mode #1", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DLFL", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DLFL.BI39" - }, - { - "index": 40, - "description": "Supports Active Power Response Mode #2", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DGFL", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DGFL.BI40" - }, - { - "index": 41, - "description": "Supports Active Power Response Mode #3", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DGFL", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DGFL.BI41" - }, - { - "index": 42, - "description": "Supports Automatic Generation Control Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DAGC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DAGC.BI42" - }, - { - "index": 43, - "description": "Supports Active Power Smoothing Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DWSM", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DWSM.BI43" - }, - { - "index": 44, - "description": "Supports Volt-Watt Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DVWC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DVWC.BI44" - }, - { - "index": 45, - "description": "Supports Frequency-Watt Curve Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DFWC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DFWC.BI45" - }, - { - "index": 46, - "description": "Supports Constant VArs Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DVAR", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DVAR.BI46" - }, - { - "index": 47, - "description": "Supports Fixed Power Factor Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DFPF", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DFPF.BI47" - }, - { - "index": 48, - "description": "Supports Volt-VAr Control Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DVVC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DVVC.BI48" - }, - { - "index": 49, - "description": "Supports Watt-VAr Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DWVR", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DWVR.BI49" - }, - { - "index": 50, - "description": "Supports Power Factor Correction Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DPFC", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DPFC.BI50" - }, - { - "index": 51, - "description": "Supports Pricing Mode", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "DPRG", - "allowed_values": { - "0": "Not Supported", - "1": "Supported" - }, - "event_class": 0, - "name": "DPRG.BI51" - }, - { - "index": 52, - "description": "Overvoltage Disconnect Protection Blocked", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "PTOV", - "data_object": "Blk", - "allowed_values": { - "0": "Not Blocked", - "1": "Blocked (Disabled)" - }, - "event_class": 1, - "name": "PTOV.Blk.BI52" - }, - { - "index": 53, - "description": "Overvoltage Disconnect Protection Started", - "data_type": "BI", - "common_data_class": "ACD", - "ln_class": "PTOV", - "data_object": "Str.general", - "allowed_values": { - "0": "Not Started", - "1": "Started (Evaluating)" - }, - "event_class": 1, - "name": "PTOV.Str.general.BI53" - }, - { - "index": 54, - "description": "Overvoltage Disconnect Protection Operated", - "data_type": "BI", - "common_data_class": "ACT", - "ln_class": "PTOV", - "data_object": "Op.general", - "allowed_values": { - "0": "Not Operated", - "1": "Operated (Disconnected)" - }, - "event_class": 1, - "name": "PTOV.Op.general.BI54" - }, - { - "index": 55, - "description": "Undervoltage Disconnect Protection Blocked", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "PTUV", - "data_object": "Blk", - "allowed_values": { - "0": "Not Blocked", - "1": "Blocked (Disabled)" - }, - "event_class": 1, - "name": "PTUV.Blk.BI55" - }, - { - "index": 56, - "description": "Undervoltage Disconnect Protection Started", - "data_type": "BI", - "common_data_class": "ACD", - "ln_class": "PTUV", - "data_object": "Str.general", - "allowed_values": { - "0": "Not Started", - "1": "Started (Evaluating)" - }, - "event_class": 1, - "name": "PTUV.Str.general.BI56" - }, - { - "index": 57, - "description": "Undervoltage Disconnect Protection Operated", - "data_type": "BI", - "common_data_class": "ACT", - "ln_class": "PTUV", - "data_object": "Op.general", - "allowed_values": { - "0": "Not Operated", - "1": "Operated (Disconnected)" - }, - "event_class": 1, - "name": "PTUV.Op.general.BI57" - }, - { - "index": 58, - "description": "Over Frequency Disconnect Protection Blocked", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "PTOV", - "data_object": "Blk", - "allowed_values": { - "0": "Not Blocked", - "1": "Blocked (Disabled)" - }, - "event_class": 1, - "name": "PTOV.Blk.BI58" - }, - { - "index": 59, - "description": "Over Frequency Disconnect Protection Started", - "data_type": "BI", - "common_data_class": "ACD", - "ln_class": "PTOV", - "data_object": "Str.general", - "allowed_values": { - "0": "Not Started", - "1": "Started (Evaluating)" - }, - "event_class": 1, - "name": "PTOV.Str.general.BI59" - }, - { - "index": 60, - "description": "Over Frequency Disconnect Protection Operated", - "data_type": "BI", - "common_data_class": "ACT", - "ln_class": "PTOV", - "data_object": "Op.general", - "allowed_values": { - "0": "Not Operated", - "1": "Operated (Disconnected)" - }, - "event_class": 1, - "name": "PTOV.Op.general.BI60" - }, - { - "index": 61, - "description": "Under Frequency Disconnect Protection Blocked", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "PTUV", - "data_object": "Blk", - "allowed_values": { - "0": "Not Blocked", - "1": "Blocked (Disabled)" - }, - "event_class": 1, - "name": "PTUV.Blk.BI61" - }, - { - "index": 62, - "description": "Under Frequency Disconnect Protection Started", - "data_type": "BI", - "common_data_class": "ACD", - "ln_class": "PTUV", - "data_object": "Str.general", - "allowed_values": { - "0": "Not Started", - "1": "Started (Evaluating)" - }, - "event_class": 1, - "name": "PTUV.Str.general.BI62" - }, - { - "index": 63, - "description": "Under Frequency Disconnect Protection Operated", - "data_type": "BI", - "common_data_class": "ACT", - "ln_class": "PTUV", - "data_object": "Op.general", - "allowed_values": { - "0": "Not Operated", - "1": "Operated (Disconnected)" - }, - "event_class": 1, - "name": "PTUV.Op.general.BI63" - }, - { - "category": "mode_enable", - "index": 64, - "description": "Operating Mode - Low/High Voltage Ride-Through", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DHVT", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHVT.ModEna.BI64" - }, - { - "category": "mode_enable", - "index": 65, - "description": "Operating Mode - Low/High Frequency Ride-Through", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DHFT", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHFT.ModEna.BI65" - }, - { - "category": "mode_enable", - "index": 66, - "description": "Operating Mode - Dynamic Reactive Current Support Enabled", - "data_type": "BI", - "common_data_class": "ENC", - "ln_class": "DRGS", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DRGS.ModEna.BI66" - }, - { - "category": "mode_enable", - "index": 67, - "description": "Operating Mode - Dynamic Volt-Watt Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DVWD", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVWD.ModEna.BI67" - }, - { - "category": "mode_enable", - "index": 68, - "description": "Operating Mode - Frequency-Watt Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DHFW", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHFW.ModEna.BI68" - }, - { - "category": "mode_enable", - "index": 69, - "description": "Operating Mode - Active Power Limit Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DWLM", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DWLM.ModEna.BI69" - }, - { - "category": "mode_enable", - "index": 70, - "description": "Operating Mode - Charge/Discharge Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DWGC", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DWGC.ModEna.BI70" - }, - { - "category": "mode_enable", - "index": 71, - "description": "Operating Mode - Coordinated Charge/Discharge Management Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DTCD", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DTCD.ModEna.BI71" - }, - { - "category": "mode_enable", - "index": 72, - "description": "Operating Mode - Active Power Response Mode #1 Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DPKP", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DPKP.ModEna.BI72" - }, - { - "category": "mode_enable", - "index": 73, - "description": "Operating Mode - Active Power Response Mode #2 Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DGFL", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DGFL.ModEna.BI73" - }, - { - "category": "mode_enable", - "index": 74, - "description": "Operating Mode - Active Power Response Mode #3 Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DLFL", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DLFL.ModEna.BI74" - }, - { - "category": "mode_enable", - "index": 75, - "description": "Operating Mode - Automatic Generation Control Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DAGC", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DAGC.ModEna.BI75" - }, - { - "category": "mode_enable", - "index": 76, - "description": "Operating Mode - Active Power Smoothing Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DWSM", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DWSM.ModEna.BI76" - }, - { - "category": "mode_enable", - "index": 77, - "description": "Operating Mode - Volt-Watt Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DVWC", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVWC.ModEna.BI77" - }, - { - "category": "mode_enable", - "index": 78, - "description": "Operating Mode - Frequency-Watt Curve Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DHFW", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHFW.ModEna.BI78" - }, - { - "category": "mode_enable", - "index": 79, - "description": "Operating Mode - Constant VArs Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DVAR", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVAR.ModEna.BI79" - }, - { - "category": "mode_enable", - "index": 80, - "description": "Operating Mode - Fixed Power Factor Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DFPF", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DFPF.ModEna.BI80" - }, - { - "category": "mode_enable", - "index": 81, - "description": "Operating Mode - Volt-VAR Control Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DVVR", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVVR.ModEna.BI81" - }, - { - "category": "mode_enable", - "index": 82, - "description": "Operating Mode - Watt-VAr Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DWVR", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DWVR.ModEna.BI82" - }, - { - "category": "mode_enable", - "index": 83, - "description": "Operating Mode - Power Factor Correction Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DPFC", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DPFC.ModEna.BI83" - }, - { - "category": "mode_enable", - "index": 84, - "description": "Operating Mode - Pricing Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DPRG", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DPRG.ModEna.BI84" - }, - { - "category": "mode_enable", - "index": 85, - "description": "Operating Mode - Event-Based Reactive Current Support Enabled", - "data_type": "BI", - "common_data_class": "SPC", - "ln_class": "DRGS", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DRGS.ModEna.BI85" - }, - { - "index": 86, - "description": "Frequency-Watt Mode - Use Hysteresis", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DHFW", - "data_object": "HysEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DHFW.HysEna.BI86" - }, - { - "index": 87, - "description": "Frequency-Watt Mode - Snapshot of Power", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DHFW", - "data_object": "SnptEna", - "allowed_values": { - "0": "Not Active", - "1": "Active" - }, - "name": "DHFW.SnptEna.BI87" - }, - { - "index": 88, - "description": "Frequency-Watt Curve Mode - Use Hysteresis", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DLFW", - "data_object": "HysEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DLFW.HysEna.BI88" - }, - { - "index": 89, - "description": "Frequency-Watt Curve Mode - Snapshot of Power", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DLFW", - "data_object": "SnptEna", - "allowed_values": { - "0": "Not Active", - "1": "Active" - }, - "name": "DLFW.SnptEna.BI89" - }, - { - "index": 90, - "description": "Charge/Discharge Mode - Use Ramp Rates. Indicates whether or not Charge/Discharge should use specified ramp rates or ramp times.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DWGC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constants", - "1": "Use Ramp Rates" - }, - "name": "DWGC.UseRmpRte.BI90" - }, - { - "index": 91, - "description": "AGC Mode - Use Ramp Rates. Indicates whether or not charge/discharge should use specified ramp rates or ramp times.", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DAGC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constants", - "1": "Use Ramp Rates" - }, - "name": "DAGC.UseRmpRte.BI91" - }, - { - "index": 92, - "description": "Volt-Watt - Use Ramp Rates and Time Constants", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DVWC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constants", - "1": "Use Ramp Rates AND Time Constants" - }, - "name": "DVWC.UseRmpRte.BI92" - }, - { - "index": 93, - "description": "Volt-VAr Enable Autonomous Voltage Reference Adjustment", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "DVVR", - "data_object": "VRefAdjEna", - "allowed_values": { - "0": "Disabled", - "1": "Enabled" - }, - "name": "DVVR.VRefAdjEna.BI93" - }, - { - "category": "alarm", - "index": 94, - "description": "System Meter Active Power is Too High", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotW.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotW.range.BI94" - }, - { - "category": "alarm", - "index": 95, - "description": "System Meter Active Power is Too Low", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotW.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotW.range.BI95" - }, - { - "category": "alarm", - "index": 96, - "description": "System Meter Reactive Power is Too High", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotVAr.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotVAr.range.BI96" - }, - { - "category": "alarm", - "index": 97, - "description": "System Meter Reactive Power is Too Low", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotVAr.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotVAr.range.BI97" - }, - { - "category": "alarm", - "index": 98, - "description": "System Meter Power Factor is Too High", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotPF.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotPF.range.BI98" - }, - { - "category": "alarm", - "index": 99, - "description": "System Meter Power Factor is Too Low", - "data_type": "BI", - "common_data_class": "MV", - "ln_class": "MMXU", - "data_object": "TotPF.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.TotPF.range.BI99" - }, - { - "category": "alarm", - "index": 100, - "description": "System Meter Phase A Voltage is Too High", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsA.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsA.range.BI100" - }, - { - "category": "alarm", - "index": 101, - "description": "System Meter Phase A Voltage is Too Low", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsA.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsA.range.BI101" - }, - { - "category": "alarm", - "index": 102, - "description": "System Meter Phase B Voltage is Too High", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsB.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsB.range.BI102" - }, - { - "category": "alarm", - "index": 103, - "description": "System Meter Phase B Voltage is Too Low", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsB.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsB.range.BI103" - }, - { - "category": "alarm", - "index": 104, - "description": "System Meter Phase C Voltage is Too High", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsC.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsC.range.BI104" - }, - { - "category": "alarm", - "index": 105, - "description": "System Meter Phase C Voltage is Too Low", - "data_type": "BI", - "common_data_class": "WYE", - "ln_class": "MMXU", - "data_object": "PhV.phsC.range", - "allowed_values": { - "0": "Normal", - "1": "Alarm" - }, - "event_class": 1, - "name": "MMXU.PhV.phsC.range.BI105" - }, - { - "category": "alarm", - "index": 106, - "description": "System Meter Communication Error", - "data_type": "BI", - "common_data_class": "SPS", - "ln_class": "LCCH", - "data_object": "ChLiv", - "allowed_values": { - "0": "Normal: No Active Communications Error", - "1": "Alarm: Active Communications Error" - }, - "event_class": 1, - "name": "LCCH.ChLiv.BI106" - }, - { - "index": 107, - "description": "Selected Curve is Referenced by a Mode", - "data_type": "BI", - "allowed_values": { - "0": "Curve is not Referenced", - "1": "Curve is Referenced" - }, - "event_class": 1, - "name": "BI107" - }, - { - "index": 108, - "description": "Selected Schedule Is Ready", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "FSCH", - "data_object": "SchdSt.3", - "allowed_values": { - "0": "Not Ready", - "1": "Ready" - }, - "name": "FSCH.SchdSt.3.BI108" - }, - { - "index": 109, - "description": "Selected Schedule is Validated", - "data_type": "BI", - "common_data_class": "ENS", - "ln_class": "FSCH", - "data_object": "SchdSt.2", - "allowed_values": { - "0": "Not validated", - "1": "Validated" - }, - "name": "FSCH.SchdSt.2.BI109" - }, - { - "index": 110, - "description": "Selected Schedule Repeat Weekly Sunday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI110" - }, - { - "index": 111, - "description": "Selected Schedule Repeat Weekly Monday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI111" - }, - { - "index": 112, - "description": "Selected Schedule Repeat Weekly Tuesday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI112" - }, - { - "index": 113, - "description": "Selected Schedule Repeat Weekly Wednesday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI113" - }, - { - "index": 114, - "description": "Selected Schedule Repeat Weekly Thursday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI114" - }, - { - "index": 115, - "description": "Selected Schedule Repeat Weekly Friday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI115" - }, - { - "index": 116, - "description": "Selected Schedule Repeat Weekly Saturday", - "data_type": "BI", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BI116" - }, - { - "index": 0, - "description": "System Set Lockout State", - "data_type": "BO", - "common_data_class": "ENS", - "ln_class": "DSTO", - "data_object": "DEROpSt.disconnected and blocked", - "allowed_values": { - "0": "Not Locked Out", - "1": "Lock Out" - }, - "name": "DSTO.DEROpSt.disconnectedandblocked.BO0" - }, - { - "index": 1, - "description": "System Initiate Start-up Sequence (Return to Service). Setting this to 1 does the following: - Sets BI \"System Is Starting Up\" to 1 indicating that the system is starting up. Additional start-up status can be found in AI \"System Start-up Status\". - Instructs all batteries to connect. - Once each battery has reported that it has connect successfully, instructs corresponding DER Unit to start. System can be shut down by executing B0 \"Emergency Stop\" command. This operation is the same as California Rule 21 \"Soft Start\".", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DCTE", - "data_object": "RtnSrvReq", - "allowed_values": { - "0": "No Change", - "1": "Initiate Start-up" - }, - "name": "DCTE.RtnSrvReq.BO1" - }, - { - "index": 2, - "description": "System Execute Stop (Cease to Energize). Setting this to 1 does the following: - Sets BI \"System Is Emergency Stopping\" to 1 indicating that an emergency stop is in progress. - Ensures that any executing operating modes are shut down (disabled). - Ensures that any executing schedules are shut down (disabled). - Instructs all inverters to shut down. - Instructs all batteries to disconnect. System can be started again by executing BO \"Initiate Start-up Sequence\" command.", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DCTE", - "data_object": "CeaEngzReq", - "allowed_values": { - "0": "No Change", - "1": "Stop (Emergency)" - }, - "name": "DCTE.CeaEngzReq.BO2" - }, - { - "index": 3, - "description": "System Permission to Start", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DSTO", - "data_object": "PrmConn", - "allowed_values": { - "0": "DCTE", - "1": "Start Permission Granted" - }, - "name": "DSTO.PrmConn.BO3" - }, - { - "index": 4, - "description": "System Permission to Stop", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DSTO", - "data_object": "PrmDscon", - "allowed_values": { - "0": "DCTE", - "1": "Stop Permission Granted" - }, - "name": "DSTO.PrmDscon.BO4" - }, - { - "index": 5, - "description": "DER Connect/Disconnect Switch", - "data_type": "BO", - "common_data_class": "DPC", - "ln_class": "CSWI", - "data_object": "Pos", - "allowed_values": { - "0": "Open Switch", - "1": "Close Switch" - }, - "name": "CSWI.Pos.BO5" - }, - { - "index": 6, - "description": "Islanded Mode. Determines how the DER behaves when in an Islanded configuration.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DGEN", - "data_object": "IsldCtlFol", - "allowed_values": { - "0": "Isochronous Mode. DER attempts to control voltage and frequency independent of configured curves and settings up to the limits of the machine's capabilities in order to achieve AO reference voltage and AO nominal frequency.", - "1": "Droop Mode. DER acts as a follower using Volt/VAR and Freq/Watt curves." - }, - "name": "DGEN.IsldCtlFol.BO6" - }, - { - "index": 7, - "description": "Enable Sensed Grid Config Detection. If Enabled, the DER may independently change its Active Settings Group based on locally observed grid conditions.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DECP", - "data_object": "ECPIsldAuto", - "allowed_values": { - "0": "No Autonomous Detection.", - "1": "Autonomous Detection. Inverter's Active Settings Group may differ from the Requested Settings Group" - }, - "name": "DECP.ECPIsldAuto.BO7" - }, - { - "index": 8, - "description": "Storage Capacity Units. Determines whether the energy storage values are expressed in Amp-hrs or Watt-hrs.", - "data_type": "BO", - "common_data_class": "ASG", - "ln_class": "DSTO", - "data_object": "AGra", - "allowed_values": { - "0": "Amp-hrs (default)", - "1": "Watt-hrs" - }, - "name": "DSTO.AGra.BO8" - }, - { - "index": 9, - "description": "Time Constant Mode. Indicates whether Time Constant Ramp parameters are interpreted as Open Loop Response times or 3Tau values.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DSTO", - "data_object": "OpnLoopTau", - "allowed_values": { - "0": "Open Loop Response Time", - "1": "3Tau Value" - }, - "name": "DSTO.OpnLoopTau.BO9" - }, - { - "index": 10, - "description": "Power Factor Excitation When Discharging/Generating", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DFPF", - "data_object": "PFGnExtSet", - "allowed_values": { - "0": "Producing VARs - Q1", - "1": "Absorbing VARs - Q4" - }, - "name": "DFPF.PFGnExtSet.BO10" - }, - { - "index": 11, - "description": "Power Factor Excitation When Charging", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DFPF", - "data_object": "PFLodExtSet", - "allowed_values": { - "0": "Producing VARs - Q2", - "1": "Absorbing VARs - Q3" - }, - "name": "DFPF.PFLodExtSet.BO11" - }, - { - "category": "mode_enable", - "index": 12, - "description": "Enable Low/High Voltage Ride-Through Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DHVT", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DHVT.ModEna.BI64", - "name": "DHVT.ModEna.BO12" - }, - { - "category": "mode_enable", - "index": 13, - "description": "Enable Low/High Frequency Ride-Through Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DHFT", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DHFT.ModEna.BI65", - "name": "DHFT.ModEna.BO13" - }, - { - "category": "mode_enable", - "index": 14, - "description": "Enable Dynamic Reactive Current Support Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DRGS", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DRGS.ModEna.BI66", - "name": "DRGS.ModEna.BO14" - }, - { - "category": "mode_enable", - "index": 15, - "description": "Enable Dynamic Volt-Watt Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DVWD", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DVWD.ModEna.BI67", - "name": "DVWD.ModEna.BO15" - }, - { - "category": "mode_enable", - "index": 16, - "description": "Enable Frequency-Watt Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DHFW", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DHFW.ModEna.BI68", - "name": "DHFW.ModEna.BO16" - }, - { - "category": "mode_enable", - "index": 17, - "description": "Enable Active Power Limit Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DWLM", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DWLM.ModEna.BI69", - "name": "DWLM.ModEna.BO17" - }, - { - "category": "mode_enable", - "index": 18, - "description": "Enable Charge/Discharge Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DWGC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DTCD.ModEna.BI71", - "name": "DWGC.ModEna.BO18" - }, - { - "category": "mode_enable", - "index": 19, - "description": "Enable Coordinated Charge/Discharge Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DTCD", - "action": "publish", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DTCD.ModEna.BO19" - }, - { - "category": "mode_enable", - "index": 20, - "description": "Enable Active Power Response Mode #1", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DPKP", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DPKP.ModEna.BI72", - "name": "DPKP.ModEna.BO20" - }, - { - "category": "mode_enable", - "index": 21, - "description": "Enable Active Power Response Mode #2", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DGFL", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DGFL.ModEna.BI73", - "name": "DGFL.ModEna.BO21" - }, - { - "category": "mode_enable", - "index": 22, - "description": "Enable Active Power Response Mode #3", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DLFL", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DLFL.ModEna.BI74", - "name": "DLFL.ModEna.BO22" - }, - { - "category": "mode_enable", - "index": 23, - "description": "Enable Automatic Generation Control Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DAGC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DAGC.ModEna.BI75", - "name": "DAGC.ModEna.BO23" - }, - { - "category": "mode_enable", - "index": 24, - "description": "Enable Active Power Smoothing Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DWSM", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DWSM.ModEna.BI76", - "name": "DWSM.ModEna.BO24" - }, - { - "category": "mode_enable", - "index": 25, - "description": "Enable Volt-Watt Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DVWC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DVWC.ModEna.BI77", - "name": "DVWC.ModEna.BO25" - }, - { - "category": "mode_enable", - "index": 26, - "description": "Enable Frequency-Watt Curve Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DHFW", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DHFW.ModEna.BI78", - "name": "DHFW.ModEna.BO26" - }, - { - "category": "mode_enable", - "index": 27, - "description": "Enable Constant VArs Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DVAR", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DVAR.ModEna.BI79", - "name": "DVAR.ModEna.BO27" - }, - { - "category": "mode_enable", - "index": 28, - "description": "Enable Fixed Power Factor Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DFPF", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DFPF.BI47", - "name": "DFPF.ModEna.BO28" - }, - { - "category": "mode_enable", - "index": 29, - "description": "Enable Volt-VAR Control Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DVVC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DVVC.BI48", - "name": "DVVC.ModEna.BO29" - }, - { - "category": "mode_enable", - "index": 30, - "description": "Enable Watt-VAr Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DWVR", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DWVR.BI49", - "name": "DWVR.ModEna.BO30" - }, - { - "category": "mode_enable", - "index": 31, - "description": "Enable Power Factor Correction Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DPFC", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DPFC.ModEna.BI83", - "name": "DPFC.ModEna.BO31" - }, - { - "category": "mode_enable", - "index": 32, - "description": "Enable Pricing Mode", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DPRG", - "action": "publish_and_respond", - "data_object": "ModEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "response": "DPRG.ModEna.BI84", - "name": "DPRG.ModEna.BO32" - }, - { - "index": 33, - "description": "Enable Event-Based Reactive Current Support Mode, in which the moving average voltage and the base reactive current are frozen until after the voltage has returned to within the deadband for a specified hold time. Dynamic Reactive Current Support mode must be Enable for this setting to apply.", - "data_type": "BO", - "common_data_class": "SPC", - "ln_class": "DRGS", - "data_object": "ArGraMod", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DRGS.ArGraMod.BO33" - }, - { - "index": 34, - "description": "Frequency-Watt Mode - Use Hysteresis", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DHFW", - "data_object": "HysEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DHFW.HysEna.BO34" - }, - { - "index": 35, - "description": "Frequency-Watt Mode - Snapshot of Power", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DHFW", - "data_object": "SnptEna", - "allowed_values": { - "0": "Not Active", - "1": "Active" - }, - "name": "DHFW.SnptEna.BO35" - }, - { - "index": 36, - "description": "Frequency-Watt Curve Mode - Use Hysteresis", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DLFW", - "data_object": "HysEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DLFW.HysEna.BO36" - }, - { - "index": 37, - "description": "Frequency-Watt Curve Mode - Snapshot of Power", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DLFW", - "data_object": "SnptEna", - "allowed_values": { - "0": "Not Active", - "1": "Active" - }, - "name": "DLFW.SnptEna.BO37" - }, - { - "index": 38, - "description": "Charge/Discharge Mode - Use Ramp Rates. Indicates whether or not Charge/Discharge should use specified ramp rates or time constants.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DWGC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constatnts", - "1": "Use Ramp Rates" - }, - "name": "DWGC.UseRmpRte.BO38" - }, - { - "index": 39, - "description": "AGC Mode - Use Ramp Rates. Indicates whether or not AGC mode should use specified ramp rates or time constants.", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DAGC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constatnts", - "1": "Use Ramp Rates" - }, - "name": "DAGC.UseRmpRte.BO39" - }, - { - "index": 40, - "description": "Volt-Watt - Use Ramp Rates and Time Constants. Indicates whether Volt-Watt mode should use only Time Constants,or both Time Constants and Ramp Rates", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DVWC", - "data_object": "UseRmpRte", - "allowed_values": { - "0": "Use Time Constatnts", - "1": "Use Ramp Rates AND Time Constants" - }, - "name": "DVWC.UseRmpRte.BO40" - }, - { - "index": 41, - "description": "Volt-VAr Enable Autonomous Voltage Reference Adjustment", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "DVVR", - "data_object": "VRefAdjEna", - "allowed_values": { - "0": "Disable", - "1": "Enable" - }, - "name": "DVVR.VRefAdjEna.BO41" - }, - { - "index": 42, - "description": "Set Selected Scheduled Ready", - "data_type": "BO", - "common_data_class": "ENC", - "ln_class": "FSCH", - "data_object": "Mod", - "allowed_values": { - "0": "Not Ready", - "1": "Ready" - }, - "name": "FSCHxx.Mod.BO42" - }, - { - "index": 43, - "description": "Set Selected Schedule Repeat Weekly Sunday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO43" - }, - { - "index": 44, - "description": "Set Selected Schedule Repeat Weekly Monday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO44" - }, - { - "index": 45, - "description": "Set Selected Schedule Repeat Weekly Tuesday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO45" - }, - { - "index": 46, - "description": "Set Selected Schedule Repeat Weekly Wednesday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO46" - }, - { - "index": 47, - "description": "Set Selected Schedule Repeat Weekly Thursday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO47" - }, - { - "index": 48, - "description": "Set Selected Schedule Repeat Weekly Friday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO48" - }, - { - "index": 49, - "description": "Set Selected Schedule Repeat Weekly Saturday", - "data_type": "BO", - "common_data_class": "SPG", - "ln_class": "FSCH", - "data_object": "SchdReuse", - "allowed_values": { - "0": "Do Not Repeat", - "1": "Repeat" - }, - "name": "FSCHxx.SchdReuse.BO49" - }, - { - "index": 900, - "description": "Test Point for Database Size", - "data_type": "BI", - "name": "TestPoint.BI900" - } -] \ No newline at end of file diff --git a/services/core/DNP3Agent/tests/data/mesaagent.config b/services/core/DNP3Agent/tests/data/mesaagent.config deleted file mode 100644 index ecfe2a73cb..0000000000 --- a/services/core/DNP3Agent/tests/data/mesaagent.config +++ /dev/null @@ -1,15 +0,0 @@ -{ - "points": "config://mesa_points.config", - "functions": "config://mesa_functions.config", - "point_topic": "mesa/point", - "function_topic": "mesa/function", - "outstation_status_topic": "mesa/outstation_status", - "outstation_config": { - "database_sizes": 2000, - "log_levels": ["NORMAL"] - }, - "local_ip": "0.0.0.0", - "port": 20000, - "all_functions_supported_by_default": true, - "function_validation": false -} diff --git a/services/core/DNP3Agent/tests/data/watt_var_curve.json b/services/core/DNP3Agent/tests/data/watt_var_curve.json deleted file mode 100644 index 5de59f07eb..0000000000 --- a/services/core/DNP3Agent/tests/data/watt_var_curve.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "function_id": "curve", - "function_name": "Watt-Var Curve", - "DGSMn.InCrv.AO244": 2, - "DGSMn.ModTyp.AO245": 4, - "FMARn.IndpUnits.AO247": 138, - "FMARn.DepRef.AO248": 2, - "FMARn.PairArr.CrvPts.AO249": [ - {"FMARn.PairArr.CrvPts.AO249.xVal": 1, - "FMARn.PairArr.CrvPts.AO249.yVal": 2 - }, - {"FMARn.PairArr.CrvPts.AO249.xVal": 3, - "FMARn.PairArr.CrvPts.AO249.yVal": 4 - }, - {"FMARn.PairArr.CrvPts.AO249.xVal": 5, - "FMARn.PairArr.CrvPts.AO249.yVal": 6 - }, - {"FMARn.PairArr.CrvPts.AO249.xVal": 7, - "FMARn.PairArr.CrvPts.AO249.yVal": 8 - }, - {"FMARn.PairArr.CrvPts.AO249.xVal": 9, - "FMARn.PairArr.CrvPts.AO249.yVal": 10 - } - ], - "FMARn.PairArr.NumPts.AO246": 5 -} \ No newline at end of file diff --git a/services/core/DNP3Agent/tests/data/watt_var_schedule.json b/services/core/DNP3Agent/tests/data/watt_var_schedule.json deleted file mode 100644 index 6a7a509aab..0000000000 --- a/services/core/DNP3Agent/tests/data/watt_var_schedule.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "function_id": "schedule", - "function_name": "Watt-Var Schedule", - "FSCC.Schd.AO461": 2, - "FSCC.Schd.AO462": 1, - "FSCH1.SchdPrio.AO463": 1, - "FSCH.SchdVal.valEq.AO464": 28, - "FSCH.StrTm.AO465": 19, - "FSCH.StrTm.AO466": 5, - "FSCH.NxtStrTm.AO467": 0, - "FSCH.SchdReuse.AO468": 0, - "FSCHn.SchdEntr.AO470": [ - {"FSCHn.SchdEntr.AO470.time": 1, - "FSCHn.SchdEntr.AO470.val": 2 - }, - {"FSCHn.SchdEntr.AO470.time": 3, - "FSCHn.SchdEntr.AO470.val": 4 - }, - {"FSCHn.SchdEntr.AO470.time": 5, - "FSCHn.SchdEntr.AO470.val": 6 - }, - {"FSCHn.SchdEntr.AO470.time": 7, - "FSCHn.SchdEntr.AO470.val": 8 - }, - {"FSCHn.SchdEntr.AO470.time": 9, - "FSCHn.SchdEntr.AO470.val": 10 - } - ], - "FSCH.NumEntr.AO469": 5 -} \ No newline at end of file diff --git a/services/core/DNP3Agent/tests/mesa_master_cmd.py b/services/core/DNP3Agent/tests/mesa_master_cmd.py deleted file mode 100644 index 62043a5d2a..0000000000 --- a/services/core/DNP3Agent/tests/mesa_master_cmd.py +++ /dev/null @@ -1,155 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - -import pytest -try: - import dnp3 -except ImportError: - pytest.skip("pydnp3 not found!", allow_module_level=True) - -import cmd -import logging -import sys - -from pydnp3 import opendnp3 - -from dnp3.points import PointDefinitions -from dnp3 import DIRECT_OPERATE -from mesa_master import MesaMaster -from function_test import FunctionTest - -LOG_LEVELS = opendnp3.levels.NORMAL -SERVER_IP = "127.0.0.1" -CLIENT_IP = "0.0.0.0" -PORT_NUMBER = 20000 -POINT_DEFINITIONS_PATH = 'tests/data/mesa_points.config' -FUNCTION_DEFINITIONS_PATH = 'tests/data/mesa_functions.yaml' - -CURVE_JSON = { - "name": "function_test_curve", - "function_id": "curve", - "function_name": "curve_function", - "Curve Edit Selector": 3, - "Curve Mode Type": 40, - "Curve Time Window": 5000, - "Curve Ramp Time": 24, - "Curve Revert Time": 51, - "Curve Maximum Number of Points": 671, - "Independent (X-Value) Units for Curve": 51, - "Dependent (Y-Value) Units for Curve": 625, - "Curve Time Constant": 612, - "Curve Decreasing Max Ramp Rate": 331, - "Curve Increasing Ramp Rate": 451, - "CurveStart-X": [ - {"Curve-X": 111, "Curve-Y": 2}, - {"Curve-X": 3, "Curve-Y": 4}, - {"Curve-X": 5, "Curve-Y": 6}, - {"Curve-X": 7, "Curve-Y": 8}, - {"Curve-X": 9, "Curve-Y": 10} - ], - "Curve Number of Points": 5 -} - -stdout_stream = logging.StreamHandler(sys.stdout) -stdout_stream.setFormatter(logging.Formatter('%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s')) - -_log = logging.getLogger(__name__) -_log.addHandler(stdout_stream) -_log.setLevel(logging.DEBUG) - - -class MesaMasterCmd(cmd.Cmd): - """ - Run MesaMaster from the command line in support of certain types of ad-hoc outstation testing. - """ - - def __init__(self): - cmd.Cmd.__init__(self) - self.prompt = 'master> ' # Used by the Cmd framework, displayed when issuing a command-line prompt. - self._application = None - - @property - def application(self): - if self._application is None: - self._application = MesaMaster(local_ip=SERVER_IP, port=PORT_NUMBER) - self._application.connect() - return self._application - - def startup(self): - """Display the command-line interface's menu and issue a prompt.""" - self.do_menu('') - self.cmdloop('Please enter a command.') - exit() - - def do_menu(self, line): - """Display a menu of command-line options. Command syntax is: menu""" - print('\tfunction\tSend all data/commands for the MESA-ESS function.') - print('\tquit') - - def do_function(self, line): - """Send a function test after validating the function test (as JSON).""" - point_defs = PointDefinitions(point_definitions_path=POINT_DEFINITIONS_PATH) - ftest = FunctionTest(FUNCTION_DEFINITIONS_PATH, CURVE_JSON) - ftest.is_valid() - for func_step_def in ftest.get_function_def().steps: - try: - point_value = ftest.points[func_step_def.name] - except KeyError: - continue - pdef = point_defs.point_named(func_step_def.name) - if not pdef: - raise ValueError("Point definition not found: {}".format(pdef.name)) - - if type(point_value) == list: - self.application.send_array(point_value, pdef) - else: - try: - send_func = self.application.SEND_FUNCTIONS[func_step_def.fcodes[0] - if func_step_def.fcodes - else DIRECT_OPERATE] - except (KeyError, IndexError): - raise ValueError("Unrecognized sent command function") - - self.application.send_command(send_func, pdef, point_value) - - def do_quit(self, line): - """Quit the command line interface. Command syntax is: quit""" - self.application.shutdown() - exit() - - -def main(): - cmd_interface = MesaMasterCmd() - _log.debug('Initialization complete. In command loop.') - cmd_interface.startup() - _log.debug('Exiting.') - - -if __name__ == '__main__': - main() diff --git a/services/core/DNP3Agent/tests/mesa_master_test.py b/services/core/DNP3Agent/tests/mesa_master_test.py deleted file mode 100644 index b1d301c458..0000000000 --- a/services/core/DNP3Agent/tests/mesa_master_test.py +++ /dev/null @@ -1,131 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - -import pytest -try: - import dnp3 -except ImportError: - pytest.skip("pydnp3 not found!", allow_module_level=True) - -from volttron.platform import jsonapi -from collections import OrderedDict - -from dnp3 import DIRECT_OPERATE -from dnp3_master import SOEHandler -from mesa_master import MesaMaster -from dnp3.mesa.functions import FunctionDefinitions -from function_test import DATA_TYPE_TO_PYTHON_TYPE - - -class MesaMasterTestException(Exception): - pass - - -class MesaMasterTest(MesaMaster): - - def __init__(self, **kwargs): - MesaMaster.__init__(self, soe_handler=SOEHandler(), **kwargs) - - def shutdown(self): - """ - Override MesaMaster shutdown - """ - self.master.Disable() - del self.master - del self.channel - - def send_single_point(self, pdefs, point_name, point_value): - """ - Send a single non-function point to the outstation. Check for validation. - - Used by DNP3Agent (not MesaAgent). - - :param pdefs: point definitions - :param point_name: name of the point that will be sent - :param point_value: value of the point that will be sent - """ - pdef = pdefs.point_named(point_name) - if not pdef: - raise MesaMasterTestException("Point definition not found: {}".format(point_name)) - if not pdef.data_type: - raise MesaMasterTestException("Unrecognized data type: {}".format(pdef.data_type)) - if pdef.data_type in DATA_TYPE_TO_PYTHON_TYPE and \ - type(point_value) not in DATA_TYPE_TO_PYTHON_TYPE[pdef.data_type]: - raise MesaMasterTestException("Invalid point value: {}".format(pdef.name)) - self.send_command(self.send_direct_operate_command, pdef, point_value) - - def send_json(self, pdefs, func_def_path, send_json_path='', send_json=None): - """ - Send a json in order for testing purpose. - - :param pdefs: point definitions - :param func_def_path: path to function definition - :param send_json_path: path to json that will be sent to the outstation - :param send_json: json that will be sent to the outstation - :return: - """ - if send_json_path: - send_json = jsonapi.load(open(send_json_path), object_pairs_hook=OrderedDict) - - try: - function_id = send_json['function_id'] - except KeyError: - raise MesaMasterTestException('Missing function_id') - - fdefs = FunctionDefinitions(pdefs, function_definitions_path=func_def_path) - - try: - fdef = fdefs[function_id] - except KeyError: - raise MesaMasterTestException('Invalid function_id {}'.format(function_id)) - - step = 1 - for name, value in send_json.items(): - if name not in ['name', 'function_id', 'function_name']: - pdef = pdefs.point_named(name) - step_def = fdef[pdef] - if step != step_def.step_number: - raise MesaMasterTestException("Step not in order: {}".format(step)) - if type(value) == list: - self.send_array(value, pdef) - else: - send_func = self.SEND_FUNCTIONS.get(step_def.fcodes[0] if step_def.fcodes else DIRECT_OPERATE, None) - self.send_command(send_func, pdef, value) - step += 1 - - -def main(): - mesa_platform_test = MesaMasterTest() - mesa_platform_test.connect() - # Ad-hoc tests can be inserted here if desired. - mesa_platform_test.shutdown() - - -if __name__ == '__main__': - main() diff --git a/services/core/DNP3Agent/tests/test_dnp3_agent.py b/services/core/DNP3Agent/tests/test_dnp3_agent.py deleted file mode 100644 index e497beb30b..0000000000 --- a/services/core/DNP3Agent/tests/test_dnp3_agent.py +++ /dev/null @@ -1,273 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, SLAC / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor SLAC, nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# SLAC, or Kisensum. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# }}} - -import pytest -try: - import dnp3 -except ImportError: - pytest.skip("pydnp3 not found!", allow_module_level=True) - -import gevent -import os -import pytest - -from volttron.platform import get_services_core, jsonapi -from volttron.platform.agent.utils import strip_comments - -from dnp3.points import PointDefinitions -from mesa_master_test import MesaMasterTest - -from pydnp3 import asiodnp3, asiopal, opendnp3, openpal - -FILTERS = opendnp3.levels.NORMAL | opendnp3.levels.ALL_COMMS -HOST = "127.0.0.1" -LOCAL = "0.0.0.0" -PORT = 20000 - -DNP3_AGENT_ID = 'dnp3agent' -POINT_TOPIC = "dnp3/point" -TEST_GET_POINT_NAME = 'DCTE.WinTms.AO11' -TEST_SET_POINT_NAME = 'DCTE.WinTms.AI55' - -input_group_map = { - 1: "Binary", - 2: "Binary", - 30: "Analog", - 31: "Analog", - 32: "Analog", - 33: "Analog", - 34: "Analog" -} - -DNP3_AGENT_CONFIG = { - "points": "config://mesa_points.config", - "point_topic": POINT_TOPIC, - "outstation_config": { - "log_levels": ["NORMAL", "ALL_APP_COMMS"] - }, - "local_ip": "0.0.0.0", - "port": 20000 -} - -# Get point definitions from the files in the test directory. -POINT_DEFINITIONS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'mesa_points.config')) - -pdefs = PointDefinitions(point_definitions_path=POINT_DEFINITIONS_PATH) - -AGENT_CONFIG = { - "points": "config://mesa_points.config", - "outstation_config": { - "database_sizes": 700, - "log_levels": ["NORMAL"] - }, - "local_ip": "0.0.0.0", - "port": 20000 -} - -messages = {} - - -def onmessage(peer, sender, bus, topic, headers, message): - """Callback: As DNP3Agent publishes mesa/point messages, store them in a multi-level global dictionary.""" - global messages - messages[topic] = {'headers': headers, 'message': message} - - -def dict_compare(source_dict, target_dict): - """Assert that the value for each key in source_dict matches the corresponding value in target_dict. - - Ignores keys in target_dict that are not in source_dict. - """ - for name, source_val in source_dict.items(): - target_val = target_dict.get(name, None) - assert source_val == target_val, "Source value of {}={}, target value={}".format(name, source_val, target_val) - - -def add_definitions_to_config_store(test_agent): - """Add PointDefinitions to the mesaagent's config store.""" - with open(POINT_DEFINITIONS_PATH, 'r') as f: - points_json = jsonapi.loads(strip_comments(f.read())) - test_agent.vip.rpc.call('config.store', 'manage_store', DNP3_AGENT_ID, - 'mesa_points.config', points_json, config_type='raw') - - -@pytest.fixture(scope="module") -def agent(request, volttron_instance): - """Build the test agent for rpc call.""" - - test_agent = volttron_instance.build_agent(identity="test_agent") - capabilities = {'edit_config_store': {'identity': 'dnp3agent'}} - volttron_instance.add_capabilities(test_agent.core.publickey, capabilities) - add_definitions_to_config_store(test_agent) - - print('Installing DNP3Agent') - os.environ['AGENT_MODULE'] = 'dnp3.agent' - agent_id = volttron_instance.install_agent(agent_dir=get_services_core("DNP3Agent"), - config_file=AGENT_CONFIG, - vip_identity=DNP3_AGENT_ID, - start=True) - - # Subscribe to DNP3 point publication - test_agent.vip.pubsub.subscribe(peer='pubsub', prefix=POINT_TOPIC, callback=onmessage) - - def stop(): - """Stop test agent.""" - if volttron_instance.is_running(): - volttron_instance.stop_agent(agent_id) - volttron_instance.remove_agent(agent_id) - test_agent.core.stop() - - gevent.sleep(12) # wait for agents and devices to start - - request.addfinalizer(stop) - - return test_agent - - -@pytest.fixture(scope="module") -def run_master(request): - """Run Mesa master application.""" - master = MesaMasterTest(local_ip=AGENT_CONFIG['local_ip'], port=AGENT_CONFIG['port']) - master.connect() - - def stop(): - master.shutdown() - - request.addfinalizer(stop) - - return master - - -@pytest.fixture(scope="function") -def reset(agent): - """Reset agent and global variable messages before running every test.""" - global messages - messages = {} - agent.vip.rpc.call(DNP3_AGENT_ID, 'reset').get() - - -class TestDNP3Agent: - """Regression tests for (non-MESA) DNP3Agent.""" - - @staticmethod - def get_point(agent, point_name): - """Ask DNP3Agent for a point value for a DNP3 resource.""" - return agent.vip.rpc.call(DNP3_AGENT_ID, 'get_point', point_name).get(timeout=10) - - @staticmethod - def get_point_definitions(agent, point_names): - """Ask DNP3Agent for a list of point definitions.""" - return agent.vip.rpc.call(DNP3_AGENT_ID, 'get_point_definitions', point_names).get(timeout=10) - - @staticmethod - def get_point_by_index(agent, data_type, index): - """Ask DNP3Agent for a point value for a DNP3 resource.""" - return agent.vip.rpc.call(DNP3_AGENT_ID, 'get_point_by_index', data_type, index).get(timeout=10) - - @staticmethod - def set_point(agent, point_name, value): - """Use DNP3Agent to set a point value for a DNP3 resource.""" - response = agent.vip.rpc.call(DNP3_AGENT_ID, 'set_point', point_name, value).get(timeout=10) - gevent.sleep(5) # Give the Master time to receive an echoed point value back from the Outstation. - return response - - @staticmethod - def set_points(agent, point_dict): - """Use DNP3Agent to set point values for a DNP3 resource.""" - return agent.vip.rpc.call(DNP3_AGENT_ID, 'set_points', point_dict).get(timeout=10) - - @staticmethod - def send_single_point(master, point_name, point_value): - """ - Send a point name and value from the Master to DNP3Agent. - - Return a dictionary with an exception key and error, empty if successful. - """ - try: - master.send_single_point(pdefs, point_name, point_value) - return {} - except Exception as err: - exception = {'key': type(err).__name__, 'error': str(err)} - print("Exception sending point from master: {}".format(exception)) - return exception - - @staticmethod - def get_value_from_master(master, point_name): - """Get value of the point from master after being set by test agent.""" - try: - pdef = pdefs.point_named(point_name) - group = input_group_map[pdef.group] - index = pdef.index - return master.soe_handler.result[group][index] - except KeyError: - return None - - def get_point_definition(self, agent, point_name): - """Confirm that the agent has a point definition named point_name. Return the definition.""" - point_defs = self.get_point_definitions(agent, [point_name]) - point_def = point_defs.get(point_name, None) - assert point_def is not None, "Agent has no point definition for {}".format(TEST_GET_POINT_NAME) - return point_def - - @staticmethod - def subscribed_points(): - """Return point values published by DNP3Agent using the dnp3/point topic.""" - return messages[POINT_TOPIC].get('message', {}) - - # ********** - # ********** OUTPUT TESTS (send data from Master to Agent to ControlAgent) ************ - # ********** - - def test_get_point_definition(self, run_master, agent, reset): - """Ask the agent whether it has a point definition for a point name.""" - self.get_point_definition(agent, TEST_GET_POINT_NAME) - - def test_send_point(self, run_master, agent, reset): - """Send a point from the master and get its value from DNP3Agent.""" - exceptions = self.send_single_point(run_master, TEST_GET_POINT_NAME, 45) - assert exceptions == {} - received_point = self.get_point(agent, TEST_GET_POINT_NAME) - # Confirm that the agent's received point value matches the value that was sent. - assert received_point == 45, "Expected {} = {}, got {}".format(TEST_GET_POINT_NAME, 45, received_point) - dict_compare({TEST_GET_POINT_NAME: 45}, self.subscribed_points()) - - # ********** - # ********** INPUT TESTS (send data from ControlAgent to Agent to Master) ************ - # ********** - - def test_set_point(self, run_master, agent, reset): - """Test set an input point and confirm getting the same value for that point.""" - self.set_point(agent, TEST_SET_POINT_NAME, 45) - received_val = self.get_value_from_master(run_master, TEST_SET_POINT_NAME) - assert received_val == 45, "Expected {} = {}, got {}".format(TEST_SET_POINT_NAME, 45, received_val) diff --git a/services/core/DNP3Agent/tests/test_functions.py b/services/core/DNP3Agent/tests/test_functions.py deleted file mode 100644 index ce3cdfc92f..0000000000 --- a/services/core/DNP3Agent/tests/test_functions.py +++ /dev/null @@ -1,369 +0,0 @@ -import pytest -try: - import dnp3 -except ImportError: - pytest.skip("pydnp3 not found!", allow_module_level=True) - -import copy - -from dnp3.points import PointDefinitions -from dnp3.mesa.functions import FunctionDefinitions, FunctionDefinition, StepDefinition - -from test_mesa_agent import POINT_DEFINITIONS_PATH, FUNCTION_DEFINITIONS_PATH - - -POINT_DEFINITIONS = PointDefinitions(point_definitions_path=POINT_DEFINITIONS_PATH) - -enable_high_voltage_ride_through_mode = { - 'id': 'enable_high_voltage_ride_through_mode', - 'name': 'Enable High Volatge Ride-Through Mode', - 'ref': 'AN2018 Spec section 2.5.1 Table 33', - 'steps': [ - { - 'step_number': 1, - 'description': 'Set the Reference Voltage if it is not already set', - 'point_name': 'DECP.VRef.AO0', - 'optional': 'I', - 'fcode': ['direct_operate'], - 'response': 'DECP.VRef.AI29' - }, - { - 'step_number': 2, - 'description': 'Set the Reference Voltage Offset if it is not already set', - 'point_name': 'DECP.VRefOfs.AO1', - 'optional': 'I', - 'fcode': ['direct_operate'], - 'response': 'DECP.VRefOfs.AI30' - }, - { - 'step_number': 3, - 'description': 'Identify the meter used to measure the voltage. By default this is the System Meter', - 'point_name': 'DHVT.EcpRef.AO22', - 'optional': 'I', - 'fcode': ['direct_operate'], - 'response': 'DHVT.EcpRef.AI71' - }, - { - 'step_number': 4, - 'description': 'Identify the index of the curve which specifies trip points when the voltage is high', - 'point_name': 'PTOV.BlkRef.AO23', - 'optional': 'M', - 'fcode': ['direct_operate'], - 'response': 'PTOV.BlkRef.AI73', - 'func_ref': 'curve' - }, - { - 'step_number': 5, - 'description': 'Enable the Low/High Voltage Ride-Through Mode', - 'point_name': 'DHVT.ModEna.BO12', - 'optional': 'M', - 'fcode': ['select', 'operate'], - 'response': 'DHVT.ModEna.BI64' - } - ] -} - -curve_selector_block = { - 'id': 'curve', - 'name': 'Curve', - 'ref': 'AN2018 Spec Curve Definition', - 'steps': [ - { - 'step_number': 1, - 'description': 'Select which curve to edit', - 'point_name': 'DGSMn.InCrv.AO244', - 'optional': 'M', - 'fcode': ['direct_operate'], - 'response': 'DGSMn.InCrv.AI328' - }, - { - 'step_number': 2, - 'description': 'Specify the Curve Mode Type', - 'point_name': 'DGSMn.ModTyp.AO245', - 'optional': 'M', - 'fcode': ['direct_operate'], - 'response': 'DGSMn.ModTyp.AI329' - }, - { - 'step_number': 3, - 'description': 'Specify that the Independent (X-Value) units for the curve', - 'point_name': 'FMARn.IndpUnits.AO247', - 'optional': 'M', - 'fcode': ['direct_operate'], - 'response': 'FMARn.IndpUnits.AI331' - }, - { - 'step_number': 4, - 'description': 'Specify the Dependent (Y-Value) units for the curve', - 'point_name': 'FMARn.DepRef.AO248', - 'optional': 'M', - 'fcode': ['direct_operate'], - 'response': 'FMARn.DepRef.AI332', - 'action': 'publish' - }, - { - 'step_number': 5, - 'description': 'Set X-Value and Y-Values pairs for the curve', - 'point_name': 'FMARn.PairArr.CrvPts.AO249', - 'optional': 'M', - 'fcode': ['direct_operate'], - 'response': 'FMARn.PairArr.CrvPts.AI333' - }, - { - 'step_number': 6, - 'description': 'Set number of points used for the curve', - 'point_name': 'FMARn.PairArr.NumPts.AO246', - 'optional': 'M', - 'fcode': ['direct_operate'], - 'response': 'FMARn.PairArr.NumPts.AI330' - } - ] -} - - -class TestStepDefinition: - """Regression tests for Step Definition.""" - - @property - def function_id(self): - return 'enable_high_voltage_ride_through_mode' - - @property - def step_number(self): - return 1 - - @property - def step_json(self): - """Return function enable_high_voltage_ride_through_mode step 1""" - return copy.deepcopy(enable_high_voltage_ride_through_mode)['steps'][self.step_number-1] - - def validate_step_definition(self, step_json): - exception = {} - try: - step_def = StepDefinition(POINT_DEFINITIONS, self.function_id, step_json) - step_def.validate() - except Exception as err: - exception['key'] = type(err).__name__ - exception['error'] = str(err) - return exception - - def test_valid_step_definition(self): - exception = self.validate_step_definition(self.step_json) - assert exception == {} - - def test_missing_step_number(self): - """Test raising exception if step missing step_number""" - step_json = self.step_json - step_json.pop('step_number') - exception = self.validate_step_definition(step_json) - assert exception == { - 'key': 'AttributeError', - 'error': 'Missing step number in function {}'.format(self.function_id) - } - - def test_missing_point_name(self): - """Test raising exception if step missing point_name""" - step_json = self.step_json - step_json.pop('point_name') - exception = self.validate_step_definition(step_json) - assert exception == { - 'key': 'AttributeError', - 'error': 'Missing name in function {} step {}'.format(self.function_id, self.step_number) - } - - def test_invalid_optionality(self): - """Test raising exception if optional not O, M, or I""" - step_json = self.step_json - step_json.update({ - 'optional': 'C' - }) - exception = self.validate_step_definition(step_json) - assert exception == { - 'key': 'AttributeError', - 'error': 'Invalid optional value in function {} step {}: C'.format(self.function_id, self.step_number) - } - - def test_invalid_fcodes_type(self): - """Test raising exception if fcodes is not a list""" - step_json = self.step_json - step_json.update({ - 'fcodes': 'direct_operate' - }) - exception = self.validate_step_definition(step_json) - assert exception == { - 'key': 'AttributeError', - 'error': "Invalid fcodes in function {} step {}, type=".format(self.function_id, - self.step_number) - } - - def test_invalid_fcode_value(self): - """Test raising exception if a str value in fcodes list is invalid""" - step_json = self.step_json - step_json.update({ - 'fcodes': ['select_operate'] - }) - exception = self.validate_step_definition(step_json) - assert exception == { - 'key': 'AttributeError', - 'error': 'Invalid fcode in function {} step {}, fcode=select_operate'.format(self.function_id, - self.step_number) - } - - def test_invalid_optionality_for_read_fcode(self): - """Test raising exception if optionality is not OPTIONAL when fcode is read""" - step_json = self.step_json - step_json.update({ - 'fcodes': ['read', 'response'] - }) - exception = self.validate_step_definition(step_json) - assert exception == { - 'key': 'AttributeError', - 'error': 'Invalid optionality in function {} step {}: must be OPTIONAL'.format(self.function_id, - self.step_number) - } - - def test_invalid_response_point(self): - step_json = self.step_json - step_json.update({ - 'response': 'invalid_point' - }) - exception = self.validate_step_definition(step_json) - assert exception == { - 'key': 'AttributeError', - 'error': 'Response point in function {} step {} does not match point definition. ' - 'Error=No point named invalid_point'.format(self.function_id, self.step_number) - } - - -class TestFunctionDefinition: - """Regression tests for Function Definition.""" - - @property - def function_json(self): - """Return function enable_high_voltage_ride_through_mode""" - return copy.deepcopy(enable_high_voltage_ride_through_mode) - - @staticmethod - def validate_function_definition(function_json): - exception = {} - try: - FunctionDefinition(POINT_DEFINITIONS, function_json) - except Exception as err: - exception['key'] = type(err).__name__ - exception['error'] = str(err) - return exception - - def test_valid_function_definition(self): - exception = self.validate_function_definition(self.function_json) - assert exception == {} - - def test_missing_function_id(self): - """Test raising exception if function missing id""" - function_json = self.function_json - function_json.pop('id') - exception = self.validate_function_definition(function_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Missing function ID' - } - - def test_missing_function_steps(self): - """Test raising exception if function missing steps""" - function_json = self.function_json - function_json.pop('steps') - exception = self.validate_function_definition(function_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Missing steps for function {}'.format(self.function_json['id']) - } - - def test_duplicated_step_number(self): - """Test raising exception if there is duplicated step_number in function""" - function_json = self.function_json - function_json['steps'][2].update({ - 'step_number': 1 - }) - exception = self.validate_function_definition(function_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Duplicated step number 1 for function {}'.format(self.function_json['id']) - } - - def test_missing_a_step(self): - """Test raising exception if function missing a step""" - function_json = self.function_json - del function_json['steps'][1] - exception = self.validate_function_definition(function_json) - assert exception == { - 'key': 'ValueError', - 'error': 'There are missing steps for function {}'.format(self.function_json['id']) - } - - def test_selector_block_function(self): - """Test raising exception if one step in selector block function is optional""" - function_json = copy.deepcopy(curve_selector_block) - exception = self.validate_function_definition(function_json) - assert exception == {} - - # Change step 2 to optional - function_json['steps'][1]['optional'] = 'O' - exception = self.validate_function_definition(function_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Function curve - Step 2: optionality must be either INITIALIZE or MANDATORY' - } - - -class TestFunctionDefinitions: - """Regression tests for Function Definitions.""" - - @property - def functions_json(self): - return [ - copy.deepcopy(enable_high_voltage_ride_through_mode), - copy.deepcopy(curve_selector_block) - ] - - @staticmethod - def validate_functions_definition(functions_json): - exception = {} - try: - function_definitions = FunctionDefinitions(POINT_DEFINITIONS) - function_definitions.load_functions(functions_json) - except Exception as err: - exception['key'] = type(err).__name__ - exception['error'] = str(err) - return exception - - def test_load_functions_yaml(self): - try: - FunctionDefinitions(POINT_DEFINITIONS, FUNCTION_DEFINITIONS_PATH) - assert True - except ValueError: - assert False - - def test_valid_functions_definitions(self): - exception = self.validate_functions_definition(self.functions_json) - assert exception == {} - - def test_duplicated_function_id(self): - """Test raising exception if there are multiple function with same id""" - functions_json = self.functions_json - functions_json[1]['id'] = self.functions_json[0]['id'] - exception = self.validate_functions_definition(functions_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Problem parsing FunctionDefinitions. ' - 'Error=There are multiple functions for function id {}'.format(functions_json[1]['id']) - } - - def test_invalid_func_ref(self): - """Test raising exception if a step has an invalid func_ref""" - functions_json = self.functions_json - functions_json[0]['steps'][3]['func_ref'] = 'invalid_curve' - exception = self.validate_functions_definition(functions_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Invalid Function Reference invalid_curve for Step 4 ' - 'in Function enable_high_voltage_ride_through_mode' - } diff --git a/services/core/DNP3Agent/tests/test_mesa_agent.py b/services/core/DNP3Agent/tests/test_mesa_agent.py deleted file mode 100644 index 0e3185207c..0000000000 --- a/services/core/DNP3Agent/tests/test_mesa_agent.py +++ /dev/null @@ -1,546 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - -import pytest -try: - import dnp3 -except ImportError: - pytest.skip("pydnp3 not found!", allow_module_level=True) - -import gevent -import os -import pytest -import yaml - -from dnp3.points import PointDefinitions -from mesa_master_test import MesaMasterTest -from volttron.platform import get_services_core, jsonapi -from volttron.platform.agent.utils import strip_comments - -MESA_AGENT_ID = 'mesaagent' - -# Get point and function definitions from the files in the test directory. -POINT_DEFINITIONS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'mesa_points.config')) -FUNCTION_DEFINITIONS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'mesa_functions.yaml')) - -pdefs = PointDefinitions(point_definitions_path=POINT_DEFINITIONS_PATH) - -input_group_map = { - 1: 'Binary', - 2: 'Binary', - 30: 'Analog', - 31: 'Analog', - 32: 'Analog', - 33: 'Analog', - 34: 'Analog' -} - -MESA_AGENT_CONFIG = { - 'points': 'config://mesa_points.config', - 'functions': 'config://mesa_functions.config', - 'point_topic': 'mesa/point', - 'function_topic': 'mesa/function', - 'outstation_status_topic': 'mesa/outstation_status', - 'outstation_config': { - 'database_sizes': 800, - 'log_levels': ['NORMAL'] - }, - 'local_ip': '0.0.0.0', - 'port': 20000, - 'all_functions_supported_by_default': True, - 'function_validation': False -} - -messages = {} - - -def onmessage(peer, sender, bus, topic, headers, message): - """Callback: As mesaagent publishes mesa/function messages, store them in a multi-level global dictionary.""" - global messages - messages[topic] = {'headers': headers, 'message': message} - - -def dict_compare(source_dict, target_dict): - """Assert that the value for each key in source_dict matches the corresponding value in target_dict. - - Ignores keys in target_dict that are not in source_dict. - """ - for name, source_val in source_dict.items(): - target_val = target_dict.get(name, None) - assert source_val == target_val, 'Source value of {}={}, target value={}'.format(name, source_val, target_val) - - -def add_definitions_to_config_store(test_agent): - """Add PointDefinitions and FunctionDefinitions to the mesaagent's config store.""" - with open(POINT_DEFINITIONS_PATH, 'r') as f: - points_json = jsonapi.loads(strip_comments(f.read())) - test_agent.vip.rpc.call('config.store', 'manage_store', MESA_AGENT_ID, - 'mesa_points.config', points_json, config_type='raw') - with open(FUNCTION_DEFINITIONS_PATH, 'r') as f: - functions_json = yaml.load(f.read()) - test_agent.vip.rpc.call('config.store', 'manage_store', MESA_AGENT_ID, - 'mesa_functions.config', functions_json, config_type='raw') - - -@pytest.fixture(scope="module") -def agent(request, volttron_instance): - """Build the test agent for rpc call.""" - - test_agent = volttron_instance.build_agent(identity="test_agent") - capabilities = {'edit_config_store': {'identity': 'mesaagent'}} - volttron_instance.add_capabilities(test_agent.core.publickey, capabilities) - - add_definitions_to_config_store(test_agent) - - print('Installing Mesa Agent') - os.environ['AGENT_MODULE'] = 'dnp3.mesa.agent' - agent_id = volttron_instance.install_agent(agent_dir=get_services_core('DNP3Agent'), - config_file=MESA_AGENT_CONFIG, - vip_identity=MESA_AGENT_ID, - start=True) - - # Subscribe to MESA functions - test_agent.vip.pubsub.subscribe(peer='pubsub', - prefix='mesa/function', - callback=onmessage) - - test_agent.vip.pubsub.subscribe(peer='pubsub', - prefix='mesa/point', - callback=onmessage) - - def stop(): - """Stop test agent.""" - if volttron_instance.is_running(): - volttron_instance.stop_agent(agent_id) - volttron_instance.remove_agent(agent_id) - test_agent.core.stop() - - gevent.sleep(3) # wait for agents and devices to start - - request.addfinalizer(stop) - - return test_agent - - -@pytest.fixture(scope="module") -def run_master(request): - """Run Mesa master application.""" - master = MesaMasterTest(local_ip=MESA_AGENT_CONFIG['local_ip'], - port=MESA_AGENT_CONFIG['port']) - master.connect() - - def stop(): - master.shutdown() - - request.addfinalizer(stop) - - return master - - -@pytest.fixture(scope="function") -def reset(agent): - """Reset agent and global variable messages before running every test.""" - global messages - messages = {} - agent.vip.rpc.call(MESA_AGENT_ID, 'reset') - - -class TestMesaAgent: - """Regression tests for the Mesa Agent.""" - - @staticmethod - def get_point(agent, point_name): - """Ask DNP3Agent for a point value for a DNP3 resource.""" - return agent.vip.rpc.call(MESA_AGENT_ID, 'get_point', point_name).get(timeout=10) - - @staticmethod - def get_point_definitions(agent, point_names): - """Ask DNP3Agent for a list of point definitions.""" - return agent.vip.rpc.call(MESA_AGENT_ID, 'get_point_definitions', point_names).get(timeout=10) - - @staticmethod - def get_point_by_index(agent, data_type, index): - """Ask DNP3Agent for a point value for a DNP3 resource.""" - return agent.vip.rpc.call(MESA_AGENT_ID, 'get_point_by_index', data_type, index).get(timeout=10) - - @staticmethod - def set_point(agent, point_name, value): - """Use DNP3Agent to set a point value for a DNP3 resource.""" - response = agent.vip.rpc.call(MESA_AGENT_ID, 'set_point', point_name, value).get(timeout=10) - gevent.sleep(1) # Give the Master time to receive an echoed point value back from the Outstation. - return response - - @staticmethod - def set_points(agent, point_dict): - """Use DNP3Agent to set point values for a DNP3 resource.""" - return agent.vip.rpc.call(MESA_AGENT_ID, 'set_points', point_dict).get(timeout=10) - - @staticmethod - def get_selector_block(agent, point_name, edit_selector): - """Get a selector block from the MesaAgent via an RPC call.""" - return agent.vip.rpc.call(MESA_AGENT_ID, 'get_selector_block', point_name, edit_selector).get(timeout=10) - - @staticmethod - def convert_json_file_to_dict(json_file): - """Convert a json file to a dictionary.""" - send_json = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', json_file)) - return jsonapi.load(open(send_json)) - - @staticmethod - def send_points(master, send_json, send_in_step_order=True): - """Master loads points from json and send them to mesa agent. - Return empty dictionary if function sent successfully, the dictionary with key and error otherwise.""" - exceptions = {} - try: - if send_in_step_order: - master.send_function_test(func_test_json=send_json) - else: - master.send_json(pdefs, FUNCTION_DEFINITIONS_PATH, send_json=send_json) - except Exception as err: - print('{}: {}'.format(type(err).__name__, str(err))) - exceptions['key'] = type(err).__name__ - exceptions['error'] = str(err) - - return exceptions - - @staticmethod - def get_value_from_master(master, point_name): - """Get value of the point from master after being set by test agent.""" - try: - pdef = pdefs.point_named(point_name) - group = input_group_map[pdef.group] - index = pdef.index - return master.soe_handler.result[group][index] - except KeyError: - return None - - def send_function_and_confirm(self, master, agent, json_file, func_ref=None): - """Test get points to confirm if points is set correctly by master.""" - send_function = self.convert_json_file_to_dict(json_file) - exceptions = self.send_points(master, send_function) - - for point_name in send_function.keys(): - if point_name not in ['name', 'function_id', 'function_name']: - - pdef = pdefs.point_named(point_name) - - if pdef.is_array_head_point: - for offset, value in enumerate( - record[field['name']] - for record in send_function[point_name] for field in pdef.array_points - ): - get_point = self.get_point_by_index(agent, pdef.data_type, pdef.index+offset) - assert get_point == value, 'Expected {} = {}, got {}'.format(point_name, value, get_point) - else: - get_point = self.get_point(agent, point_name) - # Ask the agent whether it has a point definition for that point name. - point_defs = self.get_point_definitions(agent, [point_name]) - point_def = point_defs.get(point_name, None) - assert point_def is not None, 'Agent has no point definition for {}'.format(point_name) - # Confirm that the agent's point value matches the value in the json. - json_val = send_function[point_name] - assert get_point == json_val, 'Expected {} = {}, got {}'.format(point_name, - json_val, - get_point) - if func_ref: - send_function.update({ - func_ref['name']: { - str(func_ref['index']): self.get_selector_block(agent, func_ref['name'], func_ref['index']) - } - }) - dict_compare(messages['mesa/function']['message']['points'], send_function) - assert exceptions == {} - - # ********** - # ********** OUTPUT TESTS (send data from Master to Agent to ControlAgent) ************ - # ********** - - def test_send_single_point_publish(self, run_master, agent, reset): - """Test send a single point with publish action.""" - test_point_name = 'DTCD.ModEna.BO19' - run_master.send_single_point(pdefs, test_point_name, True) - assert self.get_point(agent, test_point_name) == True - assert messages['mesa/point']['message'] == {test_point_name: True} - - def test_send_single_point_publish_and_respond(self, run_master, agent, reset): - """Test send a single point with publish_and_respond action.""" - test_point_name = 'DHVT.ModEna.BO12' - run_master.send_single_point(pdefs, test_point_name, True) - assert self.get_point(agent, test_point_name) == True - assert messages['mesa/point']['message'] == {test_point_name: True, - 'response': 'DHVT.ModEna.BI64'} - - def test_point_definition(self, agent, reset): - """Confirm whether the agent has a point def for a given name.""" - point_name = 'DCTE.VHiLim.AO6' - point_def = self.get_point_definitions(agent, [point_name]).get(point_name, None) - assert point_def is not None, 'Agent has no point definition for {}'.format(point_name) - - def test_simple_function(self, run_master, agent, reset): - """Test a simple function (not array or selector block).""" - self.send_function_and_confirm(run_master, agent, 'connect_and_disconnect.json') - - def test_curve(self, run_master, agent, reset): - """Test curve function.""" - assert self.get_selector_block(agent, 'DGSMn.InCrv.AO244', 2) is None - self.send_function_and_confirm(run_master, agent, 'watt_var_curve.json') - dict_compare(self.get_selector_block(agent, 'DGSMn.InCrv.AO244', 2), - self.convert_json_file_to_dict('watt_var_curve.json')) - - def test_enable_curve(self, run_master, agent, reset): - """Test curve function reference.""" - self.send_function_and_confirm(run_master, agent, 'watt_var_curve.json') - func_ref = { - 'name': 'DGSMn.InCrv.AO244', - 'index': 2.0 - } - self.send_function_and_confirm(run_master, agent, 'enable_watt_var_power_mode.json', func_ref) - assert messages['mesa/point']['message'] == {'DWVR.ModEna.BO30': True, - 'response': 'DWVR.BI49'} - - def test_schedule(self, run_master, agent, reset): - """Test schedule function.""" - assert self.get_selector_block(agent, 'FSCC.Schd.AO461', 2) is None - self.send_function_and_confirm(run_master, agent, 'watt_var_schedule.json') - dict_compare(self.get_selector_block(agent, 'FSCC.Schd.AO461', 2), - self.convert_json_file_to_dict('watt_var_schedule.json')) - - def test_enable_schedule(self, run_master, agent, reset): - """Test schedule function reference""" - self.send_function_and_confirm(run_master, agent, 'watt_var_schedule.json') - func_ref = { - 'name': 'FSCC.Schd.AO461', - 'index': 2.0 - } - self.send_function_and_confirm(run_master, agent, 'enable_watt_var_schedule.json', func_ref) - - def test_function_reference_fail(self, run_master, agent, reset): - """Test edit selector with Selector Block value have not set""" - send_function = self.convert_json_file_to_dict('enable_watt_var_schedule.json') - self.send_points(run_master, send_function) - assert messages == {} - - def test_invalid_function(self, run_master, agent, reset): - """Test send an invalid function, confirm getting exception error.""" - send_function = { - 'function_id': 'Invalid Function', - 'function_name': 'Testing Invalid Function', - 'point_1': 1, - 'point_2': 2 - } - exceptions = self.send_points(run_master, send_function) - assert exceptions == { - 'key': 'FunctionTestException', - 'error': 'Validation Error: Function definition not found: Invalid Function' - } - assert messages == {} - - def test_invalid_point_value(self, run_master, agent, reset): - """Test send a function with an invalid data type for a point, confirm getting exception error.""" - # Set the function support point to True - send_function = self.convert_json_file_to_dict('connect_and_disconnect.json') - - # Change the analog value to binary - send_function['DCTE.WinTms.AO16'] = True - - exceptions = self.send_points(run_master, send_function) - assert exceptions == { - 'key': 'FunctionTestException', - 'error': 'Validation Error: Invalid point value: DCTE.WinTms.AO16' - } - assert messages == {} - - # Change back to the valid point value - send_function['DCTE.WinTms.AO16'] = 10 - - # Change the binary value to analog - send_function['CSWI.Pos.BO5'] = 1 - - exceptions = self.send_points(run_master, send_function) - assert exceptions == { - 'key': 'FunctionTestException', - 'error': 'Validation Error: Invalid point value: CSWI.Pos.BO5' - } - assert messages == {} - - def test_invalid_array_value(self, run_master, agent, reset): - """Test send a function with an invalid data type for a point, confirm getting exception error.""" - send_function = self.convert_json_file_to_dict('watt_var_curve.json') - - # Change the analog array value to binary - send_function['FMARn.PairArr.CrvPts.AO249'] = [ - {'FMARn.PairArr.CrvPts.AO249.xVal': 1, - 'FMARn.PairArr.CrvPts.AO249.yVal': 2}, - {'FMARn.PairArr.CrvPts.AO249.xVal': 3, - 'FMARn.PairArr.CrvPts.AO249.yVal': 4}, - {'FMARn.PairArr.CrvPts.AO249.xVal': 5, - 'FMARn.PairArr.CrvPts.AO249.yVal': 6}, - {'FMARn.PairArr.CrvPts.AO249.xVal': 7, - 'FMARn.PairArr.CrvPts.AO249.yVal': 8}, - {'FMARn.PairArr.CrvPts.AO249.xVal': 9, - 'FMARn.PairArr.CrvPts.AO249.yVal': True} - ] - exceptions = self.send_points(run_master, send_function) - assert exceptions == { - 'key': 'FunctionTestException', - 'error': 'Validation Error: Invalid point value: FMARn.PairArr.CrvPts.AO249' - } - assert messages == {} - - def test_missing_mandatory_step(self, run_master, agent, reset): - """Test send a function missing its mandatory step, confirm getting exception error.""" - send_function = self.convert_json_file_to_dict('connect_and_disconnect.json') - - # Remove mandatory step - del send_function['DCTE.RvrtTms.AO17'] - - exceptions = self.send_points(run_master, send_function) - assert exceptions == { - 'key': 'FunctionTestException', - 'error': "Validation Error: Function Test missing mandatory steps: ['DCTE.RvrtTms.AO17']" - } - assert messages == {} - - def test_missing_point_definition(self, run_master, agent, reset): - """Test send a function with a point not defined in point definitions, confirm getting exception error.""" - send_function = self.convert_json_file_to_dict('connect_and_disconnect.json') - - # Add a point for testing - send_function['test point'] = 5 - - exceptions = self.send_points(run_master, send_function) - assert exceptions == { - 'key': 'FunctionTestException', - 'error': 'Validation Error: Not all points resolve' - } - assert messages == {} - - def test_wrong_step_order(self, run_master, agent, reset): - """Test send a function in wrong step order, confirm getting exception error.""" - connect_and_disconnect_dict = { - 'function_id': 'connect_and_disconnect', - 'name': 'Connect and Disconnect', - 'DCTE.RvrtTms.AO17': 12, # In wrong order: suppose to be step 2 instead of step 1 - 'DCTE.WinTms.AO16': 10, # In wrong order: suppose to be step 1 instead of step 2 - 'CSWI.Pos.BO5': True - } - - exceptions = self.send_points(run_master, connect_and_disconnect_dict, send_in_step_order=False) - assert exceptions == { - 'key': 'MesaMasterTestException', - 'error': 'Step not in order: 1' - } - assert messages == {} - - # ********** - # ********** INPUT TESTS (send data from ControlAgent to Agent to Master) ************ - # ********** - - def test_set_point(self, run_master, agent, reset): - """Test set an input point and confirm getting the same value for that point.""" - point_name = 'DCTE.WinTms.AI55' - self.set_point(agent, point_name, 45) - received_val = self.get_value_from_master(run_master, point_name) - assert received_val == 45, 'Expected {} = {}, got {}'.format(point_name, 45, received_val) - - def test_set_invalid_point(self, agent, reset): - """Test set an invalid input point and confirm getting exception error.""" - point_name = 'Invalid Point' - try: - self.set_point(agent, point_name, 45) - assert False, 'Input point with invalid name failed to cause an exception' - except Exception as err: - assert str(err) == "dnp3.points.DNP3Exception('No point named {}')".format(point_name) - - def test_set_invalid_point_value(self, agent, reset): - """Test set an invalid input point and confirm getting exception error.""" - point_name = 'DCTE.WinTms.AI55' - try: - self.set_point(agent, point_name, True) - assert False, 'Input point with invalid value failed to cause an exception' - except Exception as err: - assert str(err) == "dnp3.points.DNP3Exception(\"Received value for PointDefinition " \ - "{} (event_class=2, index=55, type=AI).\")".format(point_name) - - def test_set_points(self, run_master, agent, reset): - """Test set a set of points and confirm getting the correct values for all point that are set.""" - - set_points_dict = { - 'AI0': 0, - 'AI1': 1, - 'DGEN.VMinRtg.AI2': 2, - 'DGEN.VMaxRtg.AI3': 3, - 'DGEN.WMaxRtg.AI4': 4, - 'DSTO.ChaWMaxRtg.AI5': 5, - 'DGEN.WOvPFRtg.AI6': 6, - 'DSTO.ChaWOvPFRtg.AI7': 7, - 'DGEN.OvPFRtg.AI8': 8, - 'DGEN.WUnPFRtg.AI9': 9, - 'DHVT.ModEna.BI64': True - } - - self.set_points(agent, set_points_dict) - - for point_name in set_points_dict.keys(): - assert self.get_value_from_master(run_master, point_name) == set_points_dict[point_name] - - def test_set_points_array(self, run_master, agent, reset): - """Test set a set of points of an array and confirm getting the correct values for all point that are set.""" - - self.set_points(agent, { - 'FMARn.PairArr.CrvPts.AI333': [ - {'FMARn.PairArr.CrvPts.AI333.xVal': 1, - 'FMARn.PairArr.CrvPts.AI333.yVal': 2}, - {'FMARn.PairArr.CrvPts.AI333.xVal': 3, - 'FMARn.PairArr.CrvPts.AI333.yVal': 4}, - {'FMARn.PairArr.CrvPts.AI333.xVal': 5, - 'FMARn.PairArr.CrvPts.AI333.yVal': 6} - ] - }) - - pdef = pdefs.point_named('FMARn.PairArr.CrvPts.AI333') - group = input_group_map[pdef.group] - - assert run_master.soe_handler.result[group][333] == 1.0 - assert run_master.soe_handler.result[group][334] == 2.0 - assert run_master.soe_handler.result[group][335] == 3.0 - assert run_master.soe_handler.result[group][336] == 4.0 - assert run_master.soe_handler.result[group][337] == 5.0 - assert run_master.soe_handler.result[group][338] == 6.0 - - def test_wrong_database_size(self, run_master, agent, reset): - """Test set point for an index out of database size range, confirm receiving None for that point.""" - - try: - # This Input Test Point index is 800, but database size is only 700 - self.set_point(agent, 'TestPoint.BI900', True) - assert False, 'Wrong database size failed to cause an exception' - except Exception as err: - assert str(err) == "dnp3.points.DNP3Exception('Attempt to set a value for index 900 " \ - "which exceeds database size 800')" diff --git a/services/core/DNP3Agent/tests/test_points.py b/services/core/DNP3Agent/tests/test_points.py deleted file mode 100644 index b8fbf8023f..0000000000 --- a/services/core/DNP3Agent/tests/test_points.py +++ /dev/null @@ -1,177 +0,0 @@ -import pytest -try: - import dnp3 -except ImportError: - pytest.skip("pydnp3 not found!", allow_module_level=True) - -import copy - -from dnp3.points import PointDefinition, ArrayHeadPointDefinition, PointDefinitions, PointValue - -from test_mesa_agent import POINT_DEFINITIONS_PATH, FUNCTION_DEFINITIONS_PATH - - -AO_4 = { - 'index': 4, - 'description': 'Power Factor Sign convention', - 'data_type': 'AO', - 'common_data_class': 'ENG', - 'maximum': 2, - 'ln_class': 'MMXU', - 'units': 'None', - 'minimum': 1, - 'data_object': 'PFSign', - 'allowed_values': { - '1': 'IEC active power', - '2': 'IEEE lead/lag' - }, - 'type': 'enumerated', - 'name': 'MMXU.PFSign.AO4' -} - -AO_244 = { - 'index': 244, - 'description': 'Curve Edit Selector. Writing to this point selects ' - 'which of the curves can currently be viewed and changed.', - 'data_type': 'AO', - 'common_data_class': 'ORG', - 'ln_class': 'DGSM', - 'minimum': 1, - 'data_object': 'InCrv', - 'name': 'DGSMn.InCrv.AO244', - 'type': 'selector_block', - 'selector_block_start': 244, - 'selector_block_end': 448 - } - - -class TestPointDefinition: - - @property - def point_json(self): - return copy.deepcopy(AO_4) - - @staticmethod - def validate_point_definition(point_json): - exception = {} - try: - PointDefinition(point_json) - except Exception as err: - exception['key'] = type(err).__name__ - exception['error'] = str(err) - return exception - - def test_valid_point_definition(self): - exception = self.validate_point_definition(self.point_json) - assert exception == {} - - def test_missing_point_name(self): - """Test raising exception if point definition missing point name""" - point_json = self.point_json - point_json.pop('name') - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Missing point name' - } - - def test_missing_index(self): - """Test raising exception if point definition missing point index""" - point_json = self.point_json - point_json.pop('index') - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Missing index for point {}'.format(self.point_json['name']) - } - - def test_missing_data_type(self): - """Test raising exception if point definition missing data_type""" - point_json = self.point_json - point_json.pop('data_type') - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Missing data type for point {}'.format(self.point_json['name']) - } - - def test_invalid_event_class(self): - """Test raising exception if event_class is not 0, 1, 2, or 3""" - point_json = self.point_json - point_json.update({ - 'event_class': 4 - }) - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Invalid event class 4 for point {}'.format(self.point_json['name']) - } - - def test_invalid_type(self): - """Test raising exception if type is not array, selector_block, or enumerated""" - point_json = self.point_json - point_json.update({ - 'type': 'regular' - }) - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Invalid type regular for point {}'.format(self.point_json['name']) - } - - def test_missing_response(self): - """Test raising exception if the point action is publish_and_respond but missing response field""" - point_json = self.point_json - point_json.update({ - 'action': 'publish_and_respond' - }) - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Missing response point name for point {}'.format(self.point_json['name']) - } - - def test_missing_allowed_values(self): - """Test raising exception if the enumerated type missing allowed_values map""" - point_json = self.point_json - point_json.pop('allowed_values') - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'Missing allowed values mapping for point {}'.format(self.point_json['name']) - } - - def test_invalid_defined_selector_block_start(self): - """Test raising exception if selector_block_start defined for non-selector-block point""" - point_json = self.point_json - point_json.update({ - 'selector_block_start': 244 - }) - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'selector_block_start defined for non-selector-block point {}'.format(self.point_json['name']) - } - - def test_invalid_defined_selector_block_end(self): - """Test raising exception if selector_block_end defined for non-selector-block point""" - point_json = self.point_json - point_json.update({ - 'selector_block_end': 448 - }) - exception = self.validate_point_definition(point_json) - assert exception == { - 'key': 'ValueError', - 'error': 'selector_block_end defined for non-selector-block point {}'.format(self.point_json['name']) - } - - -class TestPointDefinitions: - """Regression tests for the Mesa Agent.""" - - def test_load_points_from_json_file(self): - try: - PointDefinitions(point_definitions_path=POINT_DEFINITIONS_PATH) - assert True - except ValueError: - assert False \ No newline at end of file diff --git a/services/core/DNP3Agent/tests/unit_test_point_definitions.py b/services/core/DNP3Agent/tests/unit_test_point_definitions.py deleted file mode 100644 index 896dffe088..0000000000 --- a/services/core/DNP3Agent/tests/unit_test_point_definitions.py +++ /dev/null @@ -1,212 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2018, 8minutenergy / Kisensum. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Neither 8minutenergy nor Kisensum, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by 8minutenergy or Kisensum. -# }}} - -import pytest -try: - import dnp3 -except ImportError: - pytest.skip("pydnp3 not found!", allow_module_level=True) - -from dnp3.points import ArrayHeadPointDefinition, PointDefinitions, PointValue -from dnp3.mesa.agent import MesaAgent -from dnp3.mesa.functions import FunctionDefinitions - -from test_mesa_agent import POINT_DEFINITIONS_PATH, FUNCTION_DEFINITIONS_PATH - - -def test_point_definition_load(): - point_defs = PointDefinitions(point_definitions_path=POINT_DEFINITIONS_PATH) - import pprint - pprint.pprint(point_defs._points) - pprint.pprint(point_defs._point_name_dict) - print("_point_variations_dict") - pprint.pprint(point_defs._point_variation_dict) - - -def test_point_definition(): - - test_dict = { - "name": "CurveStart-X", - "type": "array", # Start of the curve's X/Y array - "array_times_repeated": 100, - "group": 40, - "variation": 1, - "index": 207, - "description": "Starting index for a curve of up to 99 X/Y points", - "array_points": [ - { - "name": "Curve-X" - }, - { - "name": "Curve-Y" - } - ] - } - test_def = ArrayHeadPointDefinition(test_dict) - print(test_def) - - -def send_points(mesa_agent, some_points): - - for name, value, index in some_points: - pdef = mesa_agent.point_definitions.get_point_named(name,index) - point_value = PointValue('Operate', - None, - value, - pdef, - pdef.index, - None) # What is op_type used for? - - print(point_value) - mesa_agent._process_point_value(point_value) - - -def test_mesa_agent(): - mesa_agent = MesaAgent(point_topic='points_foobar', local_ip='127.0.0.1', port=8999, outstation_config={}, - function_topic='functions_foobar', outstation_status_topic='', - local_point_definitions_path=POINT_DEFINITIONS_PATH, - local_function_definitions_path=FUNCTION_DEFINITIONS_PATH) - - mesa_agent._configure('', '', {}) - point_definitions = mesa_agent.point_definitions - supported_pdef = point_definitions.get_point_named("Supports Charge/Discharge Mode") - mesa_agent.update_input_point(supported_pdef, True) - - test_points = ( - # ("DCHD.WinTms (out)", 1.0), - # ("DCHD.RmpTms (out)", 2.0), - # ("DCHD.RevtTms (out)", 3.0), - ("CurveStart-X", 1.0, None), - ("CurveStart-X", 2.0, 208), - - ) - send_points(mesa_agent, test_points) - - -def test_mesa_agent_2(): - mesa_agent = MesaAgent(point_topic='points_foobar', local_ip='127.0.0.1', port=8999, outstation_config={}, - function_topic='functions_foobar', outstation_status_topic='', - local_point_definitions_path=POINT_DEFINITIONS_PATH, - local_function_definitions_path=FUNCTION_DEFINITIONS_PATH) - - mesa_agent._configure('', '', {}) - point_definitions = mesa_agent.point_definitions - supported_pdef = point_definitions.get_point_named("Supports Charge/Discharge Mode") - mesa_agent.update_input_point(supported_pdef, True) - - test_points = ( - ("DCHD.WinTms (out)", 1.0, None), - #("DCHD.RmpTms (out)", 2.0, None), - ("DCHD.RevtTms (out)", 3.0, None), - - ) - send_points(mesa_agent, test_points) - - -def test_function_definitions(): - point_definitions = PointDefinitions(point_definitions_path=POINT_DEFINITIONS_PATH) - fdefs = FunctionDefinitions(point_definitions, function_definitions_path=FUNCTION_DEFINITIONS_PATH) - - fd = fdefs.function_for_id("curve") - print(fd) - - pdef = point_definitions.get_point_named("DCHD.WinTms (out)") - print(pdef) - print(fdefs.step_definition_for_point(pdef)) - - -def test_selector_block(): - """ - Test send a Curve function / selector block (including an array of points) to MesaAgent. - Get MesaAgent's selector block and confirm that it has the correct contents. - Do this for a variety of Edit Selectors and array contents. - """ - - def process_block_points(agt, block_points, edit_selector): - """Send each point value in block_points to the MesaAgent.""" - # print('Processing {}'.format(block_points)) - for name, value, index in block_points: - point_definitions = agt.point_definitions - pdef = point_definitions.get_point_named(name, index) - point_value = PointValue('Operate', None, value, pdef, pdef.index, None) - agt._process_point_value(point_value) - returned_block = mesa_agent.get_selector_block('Curve Edit Selector', edit_selector) - # print('get_selector_block returned {}'.format(returned_block)) - return returned_block - - mesa_agent = MesaAgent(point_topic='points_foobar', local_ip='127.0.0.1', port=8999, outstation_config={}, - function_topic='functions_foobar', outstation_status_topic='', - local_point_definitions_path=POINT_DEFINITIONS_PATH, - local_function_definitions_path=FUNCTION_DEFINITIONS_PATH) - mesa_agent._configure('', '', {}) - - block_1_points = [('Curve Edit Selector', 1, None), # index 191 - Function and SelectorBlock start - ('CurveStart-X', 1.0, None), # Point #1-X: index 207 - Array start - ('CurveStart-X', 2.0, 208), # Point #1-Y - ('Curve Number of Points', 1, None)] # index 196 - Curve function end - block_2_points = [('Curve Edit Selector', 2, None), # index 191 - Function and SelectorBlock start - ('CurveStart-X', 1.0, None), # Point #1-X: index 207 - Array start - ('CurveStart-X', 2.0, 208), # Point #1-Y - ('CurveStart-X', 3.0, 209), # Point #2-X - ('CurveStart-X', 4.0, 210), # Point #2-Y - ('Curve Number of Points', 2, None)] # index 196 - Curve function end - block_2a_points = [('Curve Edit Selector', 2, None), # index 191 - Function and SelectorBlock start - ('CurveStart-X', 1.0, None), # Point #1-X: index 207 - Array start - ('CurveStart-X', 2.0, 208), # Point #1-Y - ('CurveStart-X', 5.0, 211), # Point #3-X - ('CurveStart-X', 6.0, 212), # Point #3-Y - ('Curve Number of Points', 3, None)] # index 196 - Curve function end - - # Send block #1. Confirm that its array has a point with Y=2.0. - block = process_block_points(mesa_agent, block_1_points, 1) - assert block['CurveStart-X'][0]['Curve-Y'] == 2.0 - - # Send block #2. Confirm that its array has a point #2 with Y=4.0. - block = process_block_points(mesa_agent, block_2_points, 2) - assert block['CurveStart-X'][1]['Curve-Y'] == 4.0 - - # Send an updated block #2 with no point #2 and a new point #3. - block = process_block_points(mesa_agent, block_2a_points, 2) - # Confirm that its array still has a point #2 with Y=4.0, even though it wasn't just sent. - assert block['CurveStart-X'][1]['Curve-Y'] == 4.0 - # Confirm that its array now has a point #3 with Y=6.0. - assert block['CurveStart-X'][2]['Curve-Y'] == 6.0 - - # Re-send block #1. Confirm that selector block initialization reset the point cache: the array has no second point. - block = process_block_points(mesa_agent, block_1_points, 1) - assert len(block['CurveStart-X']) == 1 - - -if __name__ == "__main__": - # test_mesa_agent() - # test_mesa_agent_2() - # test_function_definitions() - # test_point_definition() - test_point_definition_load() - # test_selector_block() diff --git a/services/core/DNP3OutstationAgent/README.md b/services/core/DNP3OutstationAgent/README.md new file mode 100644 index 0000000000..b25354d874 --- /dev/null +++ b/services/core/DNP3OutstationAgent/README.md @@ -0,0 +1,328 @@ +# DNP3 Outstation Agent + +Distributed Network Protocol (DNP or DNP3) has achieved a large-scale acceptance since its introduction in 1993. This +protocol is an immediately deployable solution for monitoring remote sites because it was developed for communication of +critical infrastructure status, allowing for reliable remote control. + +GE-Harris Canada (formerly Westronic, Inc.) is generally credited with the seminal work on the protocol. This protocol +is, however, currently implemented by an extensive range of manufacturers in a variety of industrial applications, such +as electric utilities. + +DNP3 is composed of three layers of the OSI seven-layer functions model. These layers are application layer, data link +layer, and transport layer. Also, DNP3 can be transmitted over a serial bus connection or over a TCP/IP network. + +# Prerequisites + +* Python 3.8 + + +# Installation + +1. Install volttron and start the platform. + + Refer to the [VOLTTRON Quick Start](https://volttron.readthedocs.io/en/main/tutorials/quick-start.html) to install + the VOLTTRON platform. + + ```shell + ... + # Activate the virtual enviornment + $ source env/bin/activate + + # Start the platform + (volttron) $ ./start-volttron + + # Check (installed) agent status + (volttron) $ vctl status + UUID AGENT IDENTITY TAG STATUS HEALTH + 75 listeneragent-3.3 listeneragent-3.3_1 listener + 2f platform_driveragent-4.0 platform.driver platform_driver + ``` + +1. (If not satisfied yet,) install [dnp3-python](https://pypi.org/project/dnp3-python/) dependency. + + ```shell + (volttron) $ pip install dnp3-python==0.2.3b3 + ``` + +1. Install and start the DNP3 Outstation Agent. + + Install the DNP3 Outstation agent with the following command: + + ```shell + (volttron) $ vctl install \ + --agent-config \ + --tag \ + --vip-identity \ + -f \ + --start + ``` + + Assuming at the package root path, installing a dnp3-agent with [example-config.json](example-config.json), called " + dnp3-outstation-agent". + + ```shell + (volttron) $ vctl install ./services/core/DNP3OutstationAgent/ \ + --agent-config services/core/DNP3OutstationAgent/example-config.json \ + --tag dnp3-outstation-agent \ + --vip-identity dnp3-outstation-agent \ + -f \ + --start + + # >> + Agent 2e37a3bc-4438-4d52-8e05-cb6703cf3760 installed and started [11074] + ``` + + Please see more details about agent installation with `vctl install -h`. + +1. View the status of the installed agent (and notice a new dnp3 outstation agent is installed and running.) + + ```shell + (volttron) $ vctl status + UUID AGENT IDENTITY TAG STATUS HEALTH + 2e dnp3_outstation_agentagent-0.2.0 dnp3-outstation-agent dnp3-outstation-agent running [11074] GOOD + 75 listeneragent-3.3 listeneragent-3.3_1 listener + 2f platform_driveragent-4.0 platform.driver platform_driver + ``` + +1. Verification + + The dnp3 outstation agent acts as a server, and we will demonstrate a typical use case in the "Demonstration" + session. + +# Agent Configuration + +The required parameters for this agent are "outstation_ip", "port", "master_id", and "outstation_id". +Below is an example configuration can be found at [example-config.json](example-config.json). + +``` + { + 'outstation_ip': '0.0.0.0', + 'port': 20000, + 'master_id': 2, + 'outstation_id': 1 + } +``` + +Note: as part of the Volttron configuration framework, this file will be added to +the `$VOLTTRON_HOME/agents////` as `config`, +e.g. `~/.volttron/agents/94e54843-4bd4-45d7-9a92-3d18588b5682/dnp3_outstation_agentagent-0.2.0/dnp3_outstation_agentagent-0.2.0.dist-info/config` + +# Demonstration + +If you don't have a dedicated DNP3 Master to test the DNP3 outstation agent against, you can setup a local DNP3 Master +instead. This DNP3 Master will +be hosted at localhost on a specific port (port 20000 by default, i.e. 127.0.0.1:20000). +This Master will communicate with the DNP3 outstation agent. + +To setup a local master, we can utilize the dnp3demo module from the dnp3-python dependency. For more information about +the dnp3demo module, please refer +to [dnp3demo-Module.md](https://github.com/VOLTTRON/dnp3-python/blob/develop/docs/dnp3demo-Module.md) + +## Setup DNP3 Master + +1. Verify [dnp3-python](https://pypi.org/project/dnp3-python/) is installed properly: + + ```shell + (volttron) $ pip list | grep dnp3 + dnp3-python 0.2.3b2 + + (volttron) $ dnp3demo + ms(1676667858612) INFO manager - Starting thread (0) + ms(1676667858612) WARN server - Address already in use + 2023-02-17 15:04:18,612 dnp3demo.data_retrieval_demo DEBUG Initialization complete. OutStation in command loop. + ms(1676667858613) INFO manager - Starting thread (0) + channel state change: OPENING + ms(1676667858613) INFO tcpclient - Connecting to: 127.0.0.1 + 2023-02-17 15:04:18,613 dnp3demo.data_retrieval_demo DEBUG Initialization complete. Master Station in command loop. + ms(1676667858613) INFO tcpclient - Connected to: 127.0.0.1 + channel state change: OPEN + 2023-02-17 15:04:19.615457 ============count 1 + ====== Outstation update index 0 with 8.465443888876885 + ====== Outstation update index 1 with 17.77180643225464 + ====== Outstation update index 2 with 27.730343174887107 + ====== Outstation update index 0 with False + ====== Outstation update index 1 with True + + ... + + 2023-02-17 15:04:22,839 dnp3demo.data_retrieval_demo DEBUG Exiting. + channel state change: CLOSED + channel state change: SHUTDOWN + ms(1676667864841) INFO manager - Exiting thread (0) + ms(1676667870850) INFO manager - Exiting thread (0) + ``` + +1. Run a DNP3 Master at local (with the default parameters) + + Assuming the DNP3 outstation agent is running, run the following commands and expect the similar output. + ```shell + (volttron) $ dnp3demo master + dnp3demo.run_master {'command': 'master', 'master_ip': '0.0.0.0', 'outstation_ip': '127.0.0.1', 'port': 20000, 'master_id': 2, 'outstation_id': 1} + ms(1676668214630) INFO manager - Starting thread (0) + 2023-02-17 15:10:14,630 control_workflow_demo INFO Communication Config + 2023-02-17 15:10:14,630 control_workflow_demo INFO Communication Config + 2023-02-17 15:10:14,630 control_workflow_demo INFO Communication Config + channel state change: OPENING + ms(1676668214630) INFO tcpclient - Connecting to: 127.0.0.1 + ms(1676668214630) INFO tcpclient - Connected to: 127.0.0.1 + channel state change: OPEN + 2023-02-17 15:10:14,630 control_workflow_demo DEBUG Initialization complete. Master Station in command loop. + 2023-02-17 15:10:14,630 control_workflow_demo DEBUG Initialization complete. Master Station in command loop. + 2023-02-17 15:10:14,630 control_workflow_demo DEBUG Initialization complete. Master Station in command loop. + ==== Master Operation MENU ================================== + - set analog-output point value (for remote control) + - set binary-output point value (for remote control) +
- display/polling (outstation) database + - display configuration + ================================================================= + + ======== Your Input Here: ==(master)====== + + ``` + + Note: if the dnp3 agent is not running, you might observe the following output instead + ``` + Start retry... + Communication error. + Communication Config {'masterstation_ip_str': '0.0.0.0', 'outstation_ip_str': '127.0.0.1', 'port': 20000, 'masterstation_id_int': 2, 'outstation_id_int': 1} + ... + ``` + + This Master station runs at port 20000 by default. Please see `dnp3demo master -h` for configuration options. + Note: If using customized master parameter, please make sure the DNP3 Outstation Agent is configured accordingly. + Please refer to [DNP3-Primer.md](https://github.com/VOLTTRON/dnp3-python/blob/develop/docs/DNP3-Primer.md) for DNP3 + protocol fundamentals including connection settings. + +## Basic operation demo + +The dnp3demo master submodule is an interactive CLI tool to communicate with an outstation. The available options are +shown in the "Master Operation MENU" and should be self-explanatory. Here we can demonstrate
and commands. + +1.
- display/polling (outstation) database + + ```shell + ======== Your Input Here: ==(master)====== + dd + You chose < dd > - display database + {'Analog': {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}, 'AnalogOutputStatus': {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}, 'Binary': {0: False, 1: False, 2: False, 3: False, 4: False, 5: False, 6: False, 7: False, 8: False, 9: False}, 'BinaryOutputStatus': {0: False, 1: False, 2: False, 3: False, 4: False, 5: False, 6: False, 7: False, 8: False, 9: False}} + ==== Master Operation MENU ================================== + - set analog-output point value (for remote control) + - set binary-output point value (for remote control) +
- display/polling (outstation) database + - display configuration + ================================================================= + + ``` + + Note that an outstation is initialed with "0.0" for Analog-type points, and "False" for Binary-type points, hence the + output displayed above. + +1. - set analog-output point value (for remote control) + + ```shell + ======== Your Input Here: ==(master)====== + ao + You chose - set analog-output point value + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + + ======== Your Input Here: ==(master)====== + 0.1233 0 + SUCCESS {'AnalogOutputStatus': {0: 0.1233, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}} + You chose - set analog-output point value + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + + ======== Your Input Here: ==(master)====== + 1.3223 1 + SUCCESS {'AnalogOutputStatus': {0: 0.1233, 1: 1.3223, 2: 0.0, 3: 0.0, 4: 0.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}} + You chose - set analog-output point value + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + + ======== Your Input Here: ==(master)====== + q + ==== Master Operation MENU ================================== + - set analog-output point value (for remote control) + - set binary-output point value (for remote control) +
- display/polling (outstation) database + - display configuration + ================================================================= + + ======== Your Input Here: ==(master)====== + dd + You chose < dd > - display database + {'Analog': {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}, 'AnalogOutputStatus': {0: 0.1233, 1: 1.3223, 2: 0.0, 3: 0.0, 4: 0.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}, 'Binary': {0: False, 1: False, 2: False, 3: False, 4: False, 5: False, 6: False, 7: False, 8: False, 9: False}, 'BinaryOutputStatus': {0: False, 1: False, 2: False, 3: False, 4: False, 5: False, 6: False, 7: False, 8: False, 9: False}} + + ``` + + Explain of the operation and expected output + * We type "ao" (stands for "analog output") to enter the set point dialog. + * We set AnalogOut index0==0.1233, (the prompt indicates the operation is successful.) + * Then, we set AnalogOut index1==1.3223, (again, the prompt indicates the operation is successful.) + * We type "q" (stands for "quit") to exit the set point dialog. + * We use "dd" command and verified that AnalogOutput values are consistent to what we set ealier. + +1. Bonus script for running DNP3 outstation agent interactively + + Similar to the interactive dnp3demo master submodule, we can run the dnp3 outstation agent interactively from the + command line using [run_dnp3_outstation_agent_script.py](demo-scripts/run_dnp3_outstation_agent_script.py). + + ```shell + (volttron) $ python services/core/DNP3OutstationAgent/demo-scripts/run_dnp3_outstation_agent_script.py + ... + 2023-02-17 15:58:04,123 volttron.platform.vip.agent.core INFO: Connected to platform: router: a2ae7a58-6ce7-4386-b5eb-71e386075c15 version: 1.0 identity: e91d54f6-d4ff-4fe5-afcb-cf8f360e84af + 2023-02-17 15:58:04,123 volttron.platform.vip.agent.core DEBUG: Running onstart methods. + 2023-02-17 15:58:07,137 volttron.platform.vip.agent.subsystems.auth WARNING: Auth entry not found for e91d54f6-d4ff-4fe5-afcb-cf8f360e84af: rpc_method_authorizations not updated. If this agent does have an auth entry, verify that the 'identity' field has been included in the auth entry. This should be set to the identity of the agent + ========================= MENU ================================== + - set analog-input point value + - set analog-output point value + - set binary-input point value + - set binary-output point value + +
- display database + - display (outstation) info + - config then restart outstation + + ``` + + dd command + ```shell + ======== Your Input Here: ==(DNP3 OutStation Agent)====== + dd + You chose
- display database + {'Analog': {'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, '9': None}, 'AnalogOutputStatus': {'0': 0.1233, '1': 1.3223, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, '9': None}, 'Binary': {'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, '9': None}, 'BinaryOutputStatus': {'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, '9': None}} + + ``` + + Note: [run_dnp3_outstation_agent_script.py](demo-scripts/run_dnp3_outstation_agent_script.py) script is a wrapper on + the dnp3demo outstation submodle. For details about the interactive dnp3 station operations, please refer + to [dnp3demo-Module.md](https://github.com/VOLTTRON/dnp3-python/blob/develop/docs/dnp3demo-Module.md) + +# Run Tests + +1. Install volttron testing dependencies + ```shell + (volttron) $ python bootstrap.py --testing + UPDATE: ['testing'] + Installing required packages + + pip install --upgrade --no-deps wheel==0.30 + Requirement already satisfied: wheel==0.30 in ./env/lib/python3.10/site-packages (0.30.0) + + pip install --upgrade --install-option --zmq=bundled --no-deps pyzmq==22.2.1 + WARNING: Disabling all use of wheels due to the use of --build-option / --global-option / --install-option. + ... + ``` + +1. Run pytest + ```shell + (volttron) $ pytest services/core/DNP3OutstationAgent/tests/. + ===================================================================================================== test session starts ===================================================================================================== + platform linux -- Python 3.10.6, pytest-7.1.2, pluggy-1.0.0 -- /home/kefei/project/volttron/env/bin/python + cachedir: .pytest_cache + rootdir: /home/kefei/project/volttron, configfile: pytest.ini + plugins: rerunfailures-10.2, asyncio-0.19.0, timeout-2.1.0 + asyncio: mode=auto + timeout: 300.0s + timeout method: signal + timeout func_only: False + collected 40 items + ``` diff --git a/services/core/IEEE2030_5Agent/conftest.py b/services/core/DNP3OutstationAgent/conftest.py similarity index 100% rename from services/core/IEEE2030_5Agent/conftest.py rename to services/core/DNP3OutstationAgent/conftest.py diff --git a/services/core/DNP3OutstationAgent/demo-scripts/installation-script-notes.txt b/services/core/DNP3OutstationAgent/demo-scripts/installation-script-notes.txt new file mode 100644 index 0000000000..232c7b0e36 --- /dev/null +++ b/services/core/DNP3OutstationAgent/demo-scripts/installation-script-notes.txt @@ -0,0 +1,5 @@ +python scripts/install-agent.py -s services/core/DNP3OutstationAgent/ \ + -c services/core/DNP3OutstationAgent/config \ + -t dnp3-outstation-agent \ + -i dnp3-outstation-agent \ + -f diff --git a/services/core/DNP3OutstationAgent/demo-scripts/rpc_example.py b/services/core/DNP3OutstationAgent/demo-scripts/rpc_example.py new file mode 100644 index 0000000000..6ece1cd166 --- /dev/null +++ b/services/core/DNP3OutstationAgent/demo-scripts/rpc_example.py @@ -0,0 +1,80 @@ +""" +A demo to test dnp3-driver get_point method using rpc call. +Pre-requisite: +- install platform-driver +- configure dnp3-driver +- a dnp3 outstation/server is up and running +- platform-driver is up and running +""" + +from volttron.platform.vip.agent.utils import build_agent +from time import sleep +import datetime + + +def main(): + a = build_agent() + + # peer = "test-agent" + # peer_method = "outstation_get_config" + # + # rs = a.vip.rpc.call(peer, peer_method, ).get(timeout=10) + # print(datetime.datetime.now(), "rs: ", rs) + + peer = "dnp3-agent" + + peer_method = "get_volttron_config" + rs = a.vip.rpc.call(peer, peer_method).get(timeout=10) + print(datetime.datetime.now(), "rs: ", rs) + + # peer_method = "set_volttron_config" + # rs = a.vip.rpc.call(peer, peer_method, port=100, unused_key="unused").get(timeout=10) + # print(datetime.datetime.now(), "rs: ", rs) + # + # peer_method = "demo_config_store" + # rs = a.vip.rpc.call(peer, peer_method).get(timeout=10) + # print(datetime.datetime.now(), "rs: ", rs) + + peer_method = "set_volttron_config" + rs = a.vip.rpc.call(peer, peer_method, port=31000).get(timeout=10) + print(datetime.datetime.now(), "rs: ", rs) + + # peer_method = "outstation_get_is_connected" + # rs = a.vip.rpc.call(peer, peer_method).get(timeout=10) + # print(datetime.datetime.now(), "rs: ", rs) + + peer_method = "outstation_reset" + rs = a.vip.rpc.call(peer, peer_method).get(timeout=10) + print(datetime.datetime.now(), "rs: ", rs) + + + + # while True: + # sleep(5) + # print("============") + # try: + # peer = "test-agent" + # peer_method = "outstation_display_db" + # + # rs = a.vip.rpc.call(peer, peer_method).get(timeout=10) + # print(datetime.datetime.now(), "rs: ", rs) + # + # # rs = a.vip.rpc.call(peer, peer_method, arg1="173", arg2="arg2222", + # # something="something-else" + # # ).get(timeout=10) + # + # # rs = a.vip.rpc.call(peer, peer_method, "173", "arg2222", + # # "something-else" + # # ).get(timeout=10) + # # print(datetime.datetime.now(), "rs: ", rs) + # # reg_pt_name = "AnalogInput_index1" + # # rs = a.vip.rpc.call("platform.driver", rpc_method, + # # device_name, + # # reg_pt_name).get(timeout=10) + # # print(datetime.datetime.now(), "point_name: ", reg_pt_name, "value: ", rs) + # except Exception as e: + # print(e) + + +if __name__ == "__main__": + main() diff --git a/services/core/DNP3OutstationAgent/demo-scripts/run_dnp3_outstation_agent_script.py b/services/core/DNP3OutstationAgent/demo-scripts/run_dnp3_outstation_agent_script.py new file mode 100644 index 0000000000..c061c9a666 --- /dev/null +++ b/services/core/DNP3OutstationAgent/demo-scripts/run_dnp3_outstation_agent_script.py @@ -0,0 +1,261 @@ +import logging +import sys +import argparse + +from pydnp3 import opendnp3 +# from dnp3_python.dnp3station.outstation import MyOutStation + +from time import sleep +from volttron.platform.vip.agent.utils import build_agent +from services.core.DNP3OutstationAgent.dnp3_outstation_agent.agent import Dnp3Agent as Dnp3OutstationAgent # agent +from volttron.platform.vip.agent import Agent + +import logging +import sys +import argparse + +# from pydnp3 import opendnp3 +# from dnp3_python.dnp3station.outstation_new import MyOutStationNew + +from time import sleep + +# from volttron.client.vip.agent import build_agent +# from dnp3_outstation.agent import Dnp3OutstationAgent +# from volttron.client.vip.agent import Agent + +DNP3_AGENT_ID = "dnp3_outstation" + +stdout_stream = logging.StreamHandler(sys.stdout) +stdout_stream.setFormatter(logging.Formatter('%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s')) + +_log = logging.getLogger(__name__) +# _log = logging.getLogger("control_workflow_demo") +_log.addHandler(stdout_stream) +_log.setLevel(logging.INFO) + + +def input_prompt(display_str=None) -> str: + if display_str is None: + display_str = f""" +======== Your Input Here: ==(DNP3 OutStation Agent)====== +""" + return input(display_str) + + +def setup_args(parser: argparse.ArgumentParser) -> argparse.ArgumentParser: + parser.add_argument("-aid", "--agent-identity", action="store", default=DNP3_AGENT_ID, type=str, + metavar="", + help=f"specify agent identity (parsed as peer-name for rpc call), default '{DNP3_AGENT_ID}'.") + + return parser + + +def print_menu(): + welcome_str = rf""" +========================= MENU ================================== + - set analog-input point value + - set analog-output point value + - set binary-input point value + - set binary-output point value + +
- display database + - display (outstation) info + - config then restart outstation +================================================================= +""" + print(welcome_str) + + +def check_agent_id_existence(agent_id: str, vip_agent: Agent): + rs = vip_agent.vip.peerlist.list().get(5) + if agent_id not in rs: + raise ValueError(f"There is no agent named `{agent_id}` available on the message bus." + f"Available peers are {rs}") + # _log.warning(f"There is no agent named `{agent_id}` available on the message bus." + # f"Available peers are {rs}") + + +def main(parser=None, *args, **kwargs): + if parser is None: + # Initialize parser + parser = argparse.ArgumentParser( + prog="dnp3-outstation", + description=f"Run a dnp3 outstation agent. Specify agent identity, by default `{DNP3_AGENT_ID}`", + # epilog="Thanks for using %(prog)s! :)", + ) + parser = setup_args(parser) + + # Read arguments from command line + args = parser.parse_args() + # create volttron vip agent to evoke dnp3-agent rpc calls + a = build_agent() + peer = args.agent_identity # note: default {DNP3_AGENT_ID} or "test-agent" + # print(f"========= peer {peer}") + check_agent_id_existence(peer, a) + + def get_db_helper(): + _peer_method = Dnp3OutstationAgent.display_outstation_db.__name__ + _db_print = a.vip.rpc.call(peer, _peer_method).get(timeout=10) + return _db_print + + def get_config_helper(): + _peer_method = Dnp3OutstationAgent.get_outstation_config.__name__ + _config_print = a.vip.rpc.call(peer, _peer_method).get(timeout=10) + _config_print.update({"peer": peer}) + return _config_print + + sleep(2) + # Note: if without sleep(2) there will be a glitch when first send_select_and_operate_command + # (i.e., all the values are zero, [(0, 0.0), (1, 0.0), (2, 0.0), (3, 0.0)])) + # since it would not update immediately + + count = 0 + while count < 1000: + # sleep(1) # Note: hard-coded, master station query every 1 sec. + count += 1 + # print(f"=========== Count {count}") + peer_method = Dnp3OutstationAgent.is_outstation_connected + if a.vip.rpc.call(peer, peer_method.__name__, ).get(timeout=10): + # print("Communication Config", master_application.get_config()) + print_menu() + else: + print_menu() + print("!!!!!!!!! WARNING: The outstation is NOT connected !!!!!!!!!") + print(get_config_helper()) + # else: + # print("Communication error.") + # # print("Communication Config", outstation_application.get_config()) + # print(get_config_helper()) + # print("Start retry...") + # sleep(2) + # continue + + # print_menu() + option = input_prompt() # Note: one of ["ai", "ao", "bi", "bo", "dd", "dc"] + while True: + if option == "ai": + print("You chose - set analog-input point value") + print("Type in and . Separate with space, then hit ENTER. e.g., `1.4321, 1`.") + print("Type 'q', 'quit', 'exit' to main menu.") + input_str = input_prompt() + if input_str in ["q", "quit", "exit"]: + break + try: + p_val = float(input_str.split(" ")[0]) + index = int(input_str.split(" ")[1]) + # outstation_application.apply_update(opendnp3.Analog(value=p_val), index) + # result = {"Analog": outstation_application.db_handler.db.get("Analog")} + method = Dnp3OutstationAgent.apply_update_analog_input + peer_method = method.__name__ # i.e., "apply_update_analog_input" + response = a.vip.rpc.call(peer, peer_method, p_val, index).get(timeout=10) + result = {"Analog": get_db_helper().get("Analog")} + print(result) + sleep(2) + except Exception as e: + print(f"your input string '{input_str}'") + print(e) + elif option == "ao": + print("You chose - set analog-output point value") + print("Type in and . Separate with space, then hit ENTER. e.g., `0.1234, 0`.") + print("Type 'q', 'quit', 'exit' to main menu.") + input_str = input_prompt() + if input_str in ["q", "quit", "exit"]: + break + try: + p_val = float(input_str.split(" ")[0]) + index = int(input_str.split(" ")[1]) + method = Dnp3OutstationAgent.apply_update_analog_output + peer_method = method.__name__ # i.e., "apply_update_analog_input" + response = a.vip.rpc.call(peer, peer_method, p_val, index).get(timeout=10) + result = {"AnalogOutputStatus": get_db_helper().get("AnalogOutputStatus")} + print(result) + sleep(2) + except Exception as e: + print(f"your input string '{input_str}'") + print(e) + elif option == "bi": + print("You chose - set binary-input point value") + print("Type in <[1/0]> and . Separate with space, then hit ENTER. e.g., `1, 0`.") + input_str = input_prompt() + if input_str in ["q", "quit", "exit"]: + break + try: + p_val_input = input_str.split(" ")[0] + if p_val_input not in ["0", "1"]: + raise ValueError("binary-output value only takes '0' or '1'.") + else: + p_val = True if p_val_input == "1" else False + index = int(input_str.split(" ")[1]) + method = Dnp3OutstationAgent.apply_update_binary_input + peer_method = method.__name__ + response = a.vip.rpc.call(peer, peer_method, p_val, index).get(timeout=10) + result = {"Binary": get_db_helper().get("Binary")} + print(result) + sleep(2) + except Exception as e: + print(f"your input string '{input_str}'") + print(e) + elif option == "bo": + print("You chose - set binary-output point value") + print("Type in <[1/0]> and . Separate with space, then hit ENTER. e.g., `1, 0`.") + input_str = input_prompt() + if input_str in ["q", "quit", "exit"]: + break + try: + p_val_input = input_str.split(" ")[0] + if p_val_input not in ["0", "1"]: + raise ValueError("binary-output value only takes '0' or '1'.") + else: + p_val = True if p_val_input == "1" else False + index = int(input_str.split(" ")[1]) + method = Dnp3OutstationAgent.apply_update_binary_output + peer_method = method.__name__ + response = a.vip.rpc.call(peer, peer_method, p_val, index).get(timeout=10) + result = {"BinaryOutputStatus": get_db_helper().get("BinaryOutputStatus")} + print(result) + sleep(2) + except Exception as e: + print(f"your input string '{input_str}'") + print(e) + elif option == "dd": + print("You chose
- display database") + print(get_db_helper()) + sleep(2) + break + elif option == "di": + print("You chose - display (outstation) info") + print(get_config_helper()) + sleep(3) + break + elif option == "cr": + print("You chose - config then restart outstation") + print(f"current self.volttron_config is {get_config_helper()}") + print( + "Type in , then hit ENTER. e.g., `20000`." + "(Note: In this script, only support port configuration.)") + # input_str = input_prompt() + input_str = input() + try: + # set_volttron_config + port_val = int(input_str) + method = Dnp3OutstationAgent.update_outstation + peer_method = method.__name__ + response = a.vip.rpc.call(peer, peer_method, port=port_val).get(timeout=10) + print("SUCCESS.", get_config_helper()) + sleep(2) + except Exception as e: + print(f"your input string '{input_str}'") + print(e) + break + else: + print(f"ERROR- your input `{option}` is not one of the following.") + sleep(1) + break + + _log.debug('Exiting.') + # outstation_application.shutdown() + # outstation_application.shutdown() + + +if __name__ == '__main__': + main() diff --git a/services/core/DNP3Agent/dnp3/mesa/__init__.py b/services/core/DNP3OutstationAgent/dnp3_outstation_agent/__init__.py similarity index 100% rename from services/core/DNP3Agent/dnp3/mesa/__init__.py rename to services/core/DNP3OutstationAgent/dnp3_outstation_agent/__init__.py diff --git a/services/core/DNP3OutstationAgent/dnp3_outstation_agent/agent.py b/services/core/DNP3OutstationAgent/dnp3_outstation_agent/agent.py new file mode 100644 index 0000000000..9afb392e23 --- /dev/null +++ b/services/core/DNP3OutstationAgent/dnp3_outstation_agent/agent.py @@ -0,0 +1,567 @@ +""" +Agent documentation goes here. +""" + +__docformat__ = 'reStructuredText' + +import logging +import sys +from volttron.platform.agent import utils +from volttron.platform.vip.agent import Agent, Core, RPC + +# from dnp3_python.dnp3station.outstation import MyOutStation as MyOutStationNew +from dnp3_python.dnp3station.outstation_new import MyOutStationNew +from pydnp3 import opendnp3 +from typing import Dict + + + +_log = logging.getLogger("Dnp3-agent") +utils.setup_logging() +__version__ = "0.2.0" + +_log.level=logging.DEBUG +_log.addHandler(logging.StreamHandler(sys.stdout)) # Note: redirect stdout from dnp3 lib + + +# def agent_main(config_path, **kwargs): +# """ +# Parses the Agent configuration and returns an instance of +# the agent created using that configuration. +# +# Note: config_path is by convention under .volttron home path, called config, e.g. +# /home/kefei/.volttron/agents/6745e0ef-b500-495a-a6e8-120ec0ead4fd/testeragent-0.5/testeragent-0.5.dist-info/config +# +# :param config_path: Path to a configuration file. +# :type config_path: str +# :returns: Tester +# :rtype: Dnp3Agent +# """ +# # _log.info(f"======config_path {config_path}") +# # Note: config_path is by convention under .volttron home path, called config, e.g. +# # /home/kefei/.volttron/agents/6745e0ef-b500-495a-a6e8-120ec0ead4fd/testeragent-0.5/testeragent-0.5.dist-info/config +# # Note: the config file is attached when running `python scripts/install-agent.py -c TestAgent/config` +# # NOte: the config file attached in this way will not appear in the config store. +# # (Need to explicitly using `vctl config store`) +# try: +# config: dict = utils.load_config(config_path) +# except Exception as e: +# _log.info(e) +# config = {} +# +# if not config: +# _log.info("Using Agent defaults for starting configuration.") +# +# setting1 = int(config.get('setting1', 1)) +# setting2 = config.get('setting2', "some/random/topic") +# +# return Dnp3Agent(config, **kwargs) + + +class Dnp3Agent(Agent): + """This is class is a subclass of the Volttron Agent; + This agent is an implementation of a DNP3 outstation; + The agent overrides @Core.receiver methods to modify agent life cycle behavior; + The agent exposes @RPC.export as public interface utilizing RPC calls. + """ + + def __init__(self, config_path: str, **kwargs) -> None: + super(Dnp3Agent, self).__init__(**kwargs) + + # default_config, mainly for developing and testing purposes. + default_config: dict = {'outstation_ip': '0.0.0.0', 'port': 20000, 'master_id': 2, 'outstation_id': 1} + # agent configuration using volttron config framework + # self._dnp3_outstation_config = default_config + config_from_path = self._parse_config(config_path) + + # TODO: improve this logic by refactoring out the MyOutstationNew init, + # and add config from "config store" + try: + _log.info("Using config_from_path {config_from_path}") + self._dnp3_outstation_config = config_from_path + self.outstation_application = MyOutStationNew(**self._dnp3_outstation_config) + except Exception as e: + _log.error(e) + _log.info(f"Failed to use config_from_path {config_from_path}" + f"Using default_config {default_config}") + self._dnp3_outstation_config = default_config + self.outstation_application = MyOutStationNew(**self._dnp3_outstation_config) + + # SubSystem/ConfigStore + self.vip.config.set_default("config", default_config) + self.vip.config.subscribe( + self._config_callback_dummy, # TODO: cleanup: used to be _configure_ven_client + actions=["NEW", "UPDATE"], + pattern="config", + ) # TODO: understand what vip.config.subscribe does + + @property + def dnp3_outstation_config(self): + return self._dnp3_outstation_config + + @dnp3_outstation_config.setter + def dnp3_outstation_config(self, config: dict): + # TODO: add validation + self._dnp3_outstation_config = config + + def _config_callback_dummy(self, config_name: str, action: str, + contents: Dict) -> None: + pass + + @Core.receiver("onstart") + def onstart(self, sender, **kwargs): + """ + This is method is called once the Agent has successfully connected to the platform. + This is a good place to setup subscriptions if they are not dynamic or + do any other startup activities that require a connection to the message bus. + Called after any configurations methods that are called at startup. + Usually not needed if using the configuration store. + """ + + # for dnp3 outstation + self.outstation_application.start() + + # Example publish to pubsub + # self.vip.pubsub.publish('pubsub', "some/random/topic", message="HI!") + # + # # Example RPC call + # # self.vip.rpc.call("some_agent", "some_method", arg1, arg2) + # pass + # self._create_subscriptions(self.setting2) + + # ***************** Helper methods ******************** + def _parse_config(self, config_path: str) -> Dict: + """Parses the agent's configuration file. + + :param config_path: The path to the configuration file + :return: The configuration + """ + # TODO: added capability to configuration based on tabular config file (e.g., csv) + try: + config = utils.load_config(config_path) + except NameError as err: + _log.exception(err) + raise err + except Exception as err: + _log.error("Error loading configuration: {}".format(err)) + config = {} + # print(f"============= def _parse_config config {config}") + if not config: + raise Exception("Configuration cannot be empty.") + return config + + @RPC.export + def rpc_dummy(self) -> str: + """ + For testing rpc call + """ + return "This is a dummy rpc call" + + @RPC.export + def reset_outstation(self): + """update`self._dnp3_outstation_config`, then init a new outstation. + For post-configuration and immediately take effect. + Note: will start a new outstation instance and the old database data will lose""" + # self.dnp3_outstation_config(**kwargs) + # TODO: this method might be refactored as internal helper method for `update_outstation` + try: + self.outstation_application.shutdown() + outstation_app_new = MyOutStationNew(**self.dnp3_outstation_config) + self.outstation_application = outstation_app_new + self.outstation_application.start() + _log.info(f"Outstation has restarted") + except Exception as e: + _log.error(e) + + @RPC.export + def display_outstation_db(self) -> dict: + """expose db""" + return self.outstation_application.db_handler.db + + @RPC.export + def get_outstation_config(self) -> dict: + """expose get_config""" + return self.outstation_application.get_config() + + @RPC.export + def is_outstation_connected(self) -> bool: + """expose is_connected, note: status, property""" + return self.outstation_application.is_connected + + @RPC.export + def apply_update_analog_input(self, val: float, index: int) -> dict: + """public interface to update analog-input point value + val: float + index: int, point index + """ + if not isinstance(val, float): + raise f"val of type(val) should be float" + self.outstation_application.apply_update(opendnp3.Analog(value=val), index) + _log.debug(f"Updated outstation analog-input index: {index}, val: {val}") + + return self.outstation_application.db_handler.db + + @RPC.export + def apply_update_analog_output(self, val: float, index: int) -> dict: + """public interface to update analog-output point value + val: float + index: int, point index + """ + + if not isinstance(val, float): + raise f"val of type(val) should be float" + self.outstation_application.apply_update(opendnp3.AnalogOutputStatus(value=val), index) + _log.debug(f"Updated outstation analog-output index: {index}, val: {val}") + + return self.outstation_application.db_handler.db + + @RPC.export + def apply_update_binary_input(self, val: bool, index: int): + """public interface to update binary-input point value + val: bool + index: int, point index + """ + if not isinstance(val, bool): + raise f"val of type(val) should be bool" + self.outstation_application.apply_update(opendnp3.Binary(value=val), index) + _log.debug(f"Updated outstation binary-input index: {index}, val: {val}") + + return self.outstation_application.db_handler.db + + @RPC.export + def apply_update_binary_output(self, val: bool, index: int): + """public interface to update binary-output point value + val: bool + index: int, point index + """ + if not isinstance(val, bool): + raise f"val of type(val) should be bool" + self.outstation_application.apply_update(opendnp3.BinaryOutputStatus(value=val), index) + _log.debug(f"Updated outstation binary-output index: {index}, val: {val}") + + return self.outstation_application.db_handler.db + + @RPC.export + def update_outstation(self, + outstation_ip: str = None, + port: int = None, + master_id: int = None, + outstation_id: int = None, + **kwargs): + """ + Update dnp3 outstation config and restart the application to take effect. By default, + {'outstation_ip': '0.0.0.0', 'port': 20000, 'master_id': 2, 'outstation_id': 1} + """ + config = self._dnp3_outstation_config.copy() + for kwarg in [{"outstation_ip": outstation_ip}, + {"port": port}, + {"master_id": master_id}, {"outstation_id": outstation_id}]: + if list(kwarg.values())[0] is not None: + config.update(kwarg) + self._dnp3_outstation_config = config + self.reset_outstation() + +# class Dnp3Agent(Agent): +# """ +# Dnp3 agent mainly to represent a dnp3 outstation +# """ +# +# def __init__(self, setting1={}, setting2="some/random/topic", **kwargs): +# # TODO: clean-up the bizarre signature. Note: may need to reinstall the agent for testing. +# super(Dnp3Agent, self).__init__(**kwargs) +# _log.debug("vip_identity: " + self.core.identity) # Note: consistent with IDENTITY in `vctl status` +# +# +# # self.setting1 = setting1 +# # self.setting2 = setting2 +# config_when_installed = setting1 +# # TODO: new-feature: load_config from config store +# # config_at_configstore = +# +# self.default_config = {'outstation_ip': '0.0.0.0', 'port': 20000, +# 'master_id': 2, 'outstation_id': 1} +# # agent configuration using volttron config framework +# # get_volttron_cofig, set_volltron_config +# self._volttron_config: dict +# +# # for dnp3 features +# try: +# self.outstation_application = MyOutStation(**config_when_installed) +# _log.info(f"init dnp3 outstation with {config_when_installed}") +# self._volttron_config = config_when_installed +# except Exception as e: +# _log.error(e) +# self.outstation_application = MyOutStation(**self.default_config) +# _log.info(f"init dnp3 outstation with {self.default_config}") +# self._volttron_config = self.default_config +# # self.outstation_application.start() # moved to onstart +# +# # Set a default configuration to ensure that self.configure is called immediately to setup +# # the agent. +# self.vip.config.set_default(config_name="default-config", contents=self.default_config) +# self.vip.config.set_default(config_name="_volttron_config", contents=self._volttron_config) +# # Hook self.configure up to changes to the configuration file "config". +# self.vip.config.subscribe(self.configure, actions=["NEW", "UPDATE"], pattern="config") +# +# def _get_volttron_config(self): +# return self._volttron_config +# +# def _set_volttron_config(self, **kwargs): +# """set self._volttron_config using **kwargs. +# EXAMPLE +# self.default_config = {'outstation_ip': '0.0.0.0', 'port': 21000, +# 'master_id': 2, 'outstation_id': 1} +# set_volttron_config(port=30000, unused_key="unused") +# # outcome +# self.default_config = {'outstation_ip': '0.0.0.0', 'port': 30000, +# 'master_id': 2, 'outstation_id': 1, +# 'unused_key': 'unused'} +# """ +# self._volttron_config.update(kwargs) +# _log.info(f"Updated self._volttron_config to {self._volttron_config}") +# return {"_volttron_config": self._get_volttron_config()} +# +# @RPC.export +# def outstation_reset(self, **kwargs): +# """update`self._volttron_config`, then init a new outstation. +# +# For post-configuration and immediately take effect. +# Note: will start a new outstation instance and the old database data will lose""" +# self._set_volttron_config(**kwargs) +# try: +# outstation_app_new = MyOutStation(**self._volttron_config) +# self.outstation_application.shutdown() +# self.outstation_application = outstation_app_new +# self.outstation_application.start() +# except Exception as e: +# _log.error(e) +# +# @RPC.export +# def outstation_get_db(self): +# """expose db""" +# return self.outstation_application.db_handler.db +# +# @RPC.export +# def outstation_get_config(self): +# """expose get_config""" +# return self.outstation_application.get_config() +# +# @RPC.export +# def outstation_get_is_connected(self): +# """expose is_connected, note: status, property""" +# return self.outstation_application.is_connected +# +# @RPC.export +# def outstation_apply_update_analog_input(self, val, index): +# """public interface to update analog-input point value +# +# val: float +# index: int, point index +# """ +# if not isinstance(val, float): +# raise f"val of type(val) should be float" +# self.outstation_application.apply_update(opendnp3.Analog(value=val), index) +# _log.debug(f"Updated outstation analog-input index: {index}, val: {val}") +# +# return self.outstation_application.db_handler.db +# +# @RPC.export +# def outstation_apply_update_analog_output(self, val, index): +# """public interface to update analog-output point value +# +# val: float +# index: int, point index +# """ +# +# if not isinstance(val, float): +# raise f"val of type(val) should be float" +# self.outstation_application.apply_update(opendnp3.AnalogOutputStatus(value=val), index) +# _log.debug(f"Updated outstation analog-output index: {index}, val: {val}") +# +# return self.outstation_application.db_handler.db +# +# @RPC.export +# def outstation_apply_update_binary_input(self, val, index): +# """public interface to update binary-input point value +# +# val: bool +# index: int, point index +# """ +# if not isinstance(val, bool): +# raise f"val of type(val) should be bool" +# self.outstation_application.apply_update(opendnp3.Binary(value=val), index) +# _log.debug(f"Updated outstation binary-input index: {index}, val: {val}") +# +# return self.outstation_application.db_handler.db +# +# @RPC.export +# def outstation_apply_update_binary_output(self, val, index): +# """public interface to update binary-output point value +# +# val: bool +# index: int, point index +# """ +# if not isinstance(val, bool): +# raise f"val of type(val) should be bool" +# self.outstation_application.apply_update(opendnp3.BinaryOutputStatus(value=val), index) +# _log.debug(f"Updated outstation binary-output index: {index}, val: {val}") +# +# return self.outstation_application.db_handler.db +# +# @RPC.export +# def outstation_display_db(self): +# return self.outstation_application.db_handler.db +# +# def configure(self, config_name, action, contents): +# """ +# # TODO: clean-up this bizarre method +# """ +# config = self.default_config.copy() +# config.update(contents) +# +# _log.debug("Configuring Agent") +# +# try: +# setting1 = int(config["setting1"]) +# setting2 = str(config["setting2"]) +# except ValueError as e: +# _log.error("ERROR PROCESSING CONFIGURATION: {}".format(e)) +# return +# +# self.setting1 = setting1 +# self.setting2 = setting2 +# +# self._create_subscriptions(self.setting2) +# +# def _create_subscriptions(self, topic): +# """ +# Unsubscribe from all pub/sub topics and create a subscription to a topic in the configuration which triggers +# the _handle_publish callback +# """ +# self.vip.pubsub.unsubscribe("pubsub", None, None) +# +# topic = "some/topic" +# self.vip.pubsub.subscribe(peer='pubsub', +# prefix=topic, +# callback=self._handle_publish) +# +# def _handle_publish(self, peer, sender, bus, topic, headers, message): +# """ +# Callback triggered by the subscription setup using the topic from the agent's config file +# """ +# _log.debug(f" ++++++handleer++++++++++++++++++++++++++" +# f"peer {peer}, sender {sender}, bus {bus}, topic {topic}, " +# f"headers {headers}, message {message}") +# +# @Core.receiver("onstart") +# def onstart(self, sender, **kwargs): +# """ +# This is method is called once the Agent has successfully connected to the platform. +# This is a good place to setup subscriptions if they are not dynamic or +# do any other startup activities that require a connection to the message bus. +# Called after any configurations methods that are called at startup. +# +# Usually not needed if using the configuration store. +# """ +# +# # for dnp3 outstation +# self.outstation_application.start() +# +# # Example publish to pubsub +# # self.vip.pubsub.publish('pubsub', "some/random/topic", message="HI!") +# # +# # # Example RPC call +# # # self.vip.rpc.call("some_agent", "some_method", arg1, arg2) +# # pass +# # self._create_subscriptions(self.setting2) +# +# +# @Core.receiver("onstop") +# def onstop(self, sender, **kwargs): +# """ +# This method is called when the Agent is about to shutdown, but before it disconnects from +# the message bus. +# """ +# pass +# self.outstation_application.shutdown() +# +# # @RPC.export +# # def rpc_demo_load_config(self): +# # """ +# # RPC method +# # +# # May be called from another agent via self.core.rpc.call +# # """ +# # try: +# # config = utils.load_config("/home/kefei/project-local/volttron/TestAgent/config") +# # except Exception: +# # config = {} +# # return config +# +# # @RPC.export +# # def rpc_demo_config_list_set_get(self): +# # """ +# # RPC method +# # +# # May be called from another agent via self.core.rpc.call +# # """ +# # default_config = {"setting1": "setting1-xxxxxxxxx", +# # "setting2": "setting2-xxxxxxxxx"} +# # +# # # Set a default configuration to ensure that self.configure is called immediately to setup +# # # the agent. +# # # self.vip.config.set_default("config", default_config) # set_default can only be used before onstart +# # self.vip.config.set(config_name="config_2", contents=default_config, +# # trigger_callback=False, send_update=True) +# # get_result = [ +# # self.vip.config.get(config) for config in self.vip.config.list() +# # ] +# # return self.vip.config.list(), get_result +# +# # @RPC.export +# # def rpc_demo_config_set_default(self): +# # """ +# # RPC method +# # +# # May be called from another agent via self.core.rpc.call +# # """ +# # default_config = {"setting1": "setting1-xxxxxxxxx", +# # "setting2": "setting2-xxxxxxxxx"} +# # +# # # Set a default configuration to ensure that self.configure is called immediately to setup +# # # the agent. +# # self.vip.config.set_default("config", default_config) +# # return self.vip.config.list() +# # # # Hook self.configure up to changes to the configuration file "config". +# # # self.vip.config.subscribe(self.configure, actions=["NEW", "UPDATE"], pattern="config") +# +# # @RPC.export +# # def rpc_demo_pubsub(self): +# # """ +# # RPC method +# # +# # May be called from another agent via self.core.rpc.call +# # """ +# # +# # # pubsub_list = self.vip.pubsub.list('pubsub', 'some/') +# # # list(self, peer, prefix='', bus='', subscribed=True, reverse=False, all_platforms=False) +# # # # return pubsub_list +# # self.vip.pubsub.publish('pubsub', 'some/topic/', message="+++++++++++++++++++++++++ something something") +# # # self.vip.pubsub.subscribe('pubsub', 'some/topic/', callable=self._handle_publish) +# # # return pubsub_list +# # # # Hook self.configure up to changes to the configuration file "config". +# # # self.vip.config.subscribe(self.configure, actions=["NEW", "UPDATE"], pattern="config") + + +def main(): + """Main method called to start the agent.""" + utils.vip_main(Dnp3Agent, + version=__version__) + + +if __name__ == '__main__': + # Entry point for script + try: + sys.exit(main()) + except KeyboardInterrupt: + pass diff --git a/services/core/DNP3OutstationAgent/example-config.json b/services/core/DNP3OutstationAgent/example-config.json new file mode 100644 index 0000000000..567306a8e3 --- /dev/null +++ b/services/core/DNP3OutstationAgent/example-config.json @@ -0,0 +1,4 @@ +{'outstation_ip': '0.0.0.0', +'port': 20000, +'master_id': 2, +'outstation_id': 1} diff --git a/services/core/DNP3OutstationAgent/requirements.txt b/services/core/DNP3OutstationAgent/requirements.txt new file mode 100644 index 0000000000..2a3adaaaae --- /dev/null +++ b/services/core/DNP3OutstationAgent/requirements.txt @@ -0,0 +1 @@ +dnp3-python==0.2.3b3 diff --git a/services/core/DNP3OutstationAgent/setup.py b/services/core/DNP3OutstationAgent/setup.py new file mode 100644 index 0000000000..b96cd42d10 --- /dev/null +++ b/services/core/DNP3OutstationAgent/setup.py @@ -0,0 +1,29 @@ +from setuptools import setup, find_packages + +MAIN_MODULE = 'agent' + +# Find the agent package that contains the main module +packages = find_packages('.') +agent_package = 'dnp3_outstation_agent' + +# Find the version number from the main module +agent_module = agent_package + '.' + MAIN_MODULE +_temp = __import__(agent_module, globals(), locals(), ['__version__'], 0) +__version__ = _temp.__version__ + +# Setup +setup( + name=agent_package + 'agent', + version=__version__, + author="VOLTTRON team", + author_email="volttron@pnl.gov", + url="http:something", + description="Dnp3 agent as an outstation", + install_requires=['volttron'], + packages=packages, + entry_points={ + 'setuptools.installation': [ + 'eggsecutable = ' + agent_module + ':main', + ] + } +) diff --git a/services/core/DNP3OutstationAgent/tests/test_dnp3_agent.py b/services/core/DNP3OutstationAgent/tests/test_dnp3_agent.py new file mode 100644 index 0000000000..f7b4fa266b --- /dev/null +++ b/services/core/DNP3OutstationAgent/tests/test_dnp3_agent.py @@ -0,0 +1,244 @@ +""" +This test suits focus on the exposed RPC calls. +It utilizes a vip agent to evoke the RPC calls. +The volltron instance and dnp3-agent is start manually. +Note: several fixtures are used + volttron_platform_wrapper + vip_agent + dnp3_outstation_agent +""" +import pathlib + +import gevent +import pytest +import os +import datetime +# from dnp3_outstation.agent import Dnp3OutstationAgent +from services.core.DNP3OutstationAgent.dnp3_outstation_agent.agent import Dnp3Agent as Dnp3OutstationAgent +from dnp3_python.dnp3station.outstation_new import MyOutStationNew +import random +import subprocess +import logging + +logging_logger = logging.getLogger(__name__) + +dnp3_vip_identity = "dnp3_outstation" + + +# @pytest.fixture(scope="module") +# def volttron_home(): +# """ +# VOLTTRON_HOME environment variable suggested to setup at pytest.ini [env] +# """ +# volttron_home: str = os.getenv("VOLTTRON_HOME") +# assert volttron_home +# return volttron_home +# +# +# def test_volttron_home_fixture(volttron_home): +# assert volttron_home +# print(volttron_home) + + +def test_testing_file_path(): + parent_path = os.getcwd() + dnp3_agent_config_path = os.path.join(parent_path, "dnp3-outstation-config.json") + # print(dnp3_agent_config_path) + logging_logger.info(f"test_testing_file_path {dnp3_agent_config_path}") + + +def test_volttron_instance_fixture(volttron_instance): + print(volttron_instance) + logging_logger.info(f"=========== volttron_instance_new.volttron_home: {volttron_instance.volttron_home}") + logging_logger.info(f"=========== volttron_instance_new.skip_cleanup: {volttron_instance.skip_cleanup}") + logging_logger.info(f"=========== volttron_instance_new.vip_address: {volttron_instance.vip_address}") + + +@pytest.fixture(scope="module") +def vip_agent(volttron_instance): + # build a vip agent + a = volttron_instance.build_agent() + print(a) + return a + + +def test_vip_agent_fixture(vip_agent): + print(vip_agent) + logging_logger.info(f"=========== vip_agent: {vip_agent}") + logging_logger.info(f"=========== vip_agent.core.identity: {vip_agent.core.identity}") + logging_logger.info(f"=========== vip_agent.vip.peerlist().get(): {vip_agent.vip.peerlist().get()}") + + +@pytest.fixture(scope="module") +def dnp3_outstation_agent(volttron_instance) -> dict: + """ + Install and start a dnp3-outstation-agent, return its vip-identity + """ + # install a dnp3-outstation-agent + # TODO: improve the following hacky path resolver + parent_path = pathlib.Path(__file__) + dnp3_outstation_package_path = pathlib.Path(parent_path).parent.parent + dnp3_agent_config_path = str(os.path.join(parent_path, "dnp3-outstation-config.json")) + config = { + "outstation_ip": "0.0.0.0", + "master_id": 2, + "outstation_id": 1, + "port": 20000 + } + agent_vip_id = dnp3_vip_identity + uuid = volttron_instance.install_agent( + agent_dir=dnp3_outstation_package_path, + # agent_dir="volttron-dnp3-outastion", + config_file=config, + start=False, # Note: for some reason, need to set to False, then start + vip_identity=agent_vip_id) + # start agent with retry + # pid = retry_call(volttron_instance.start_agent, f_kwargs=dict(agent_uuid=uuid), max_retries=5, delay_s=2, + # wait_before_call_s=2) + + # # check if running with retry + # retry_call(volttron_instance.is_agent_running, f_kwargs=dict(agent_uuid=uuid), max_retries=5, delay_s=2, + # wait_before_call_s=2) + gevent.sleep(5) + pid = volttron_instance.start_agent(uuid) + gevent.sleep(5) + logging_logger.info( + f"=========== volttron_instance.is_agent_running(uuid): {volttron_instance.is_agent_running(uuid)}") + # TODO: get retry_call back + return {"uuid": uuid, "pid": pid} + + +def test_install_dnp3_outstation_agent_fixture(dnp3_outstation_agent, vip_agent, volttron_instance): + puid = dnp3_outstation_agent + print(puid) + logging_logger.info(f"=========== dnp3_outstation_agent ids: {dnp3_outstation_agent}") + logging_logger.info(f"=========== vip_agent.vip.peerlist().get(): {vip_agent.vip.peerlist().get()}") + logging_logger.info(f"=========== volttron_instance_new.is_agent_running(puid): " + f"{volttron_instance.is_agent_running(dnp3_outstation_agent['uuid'])}") + + +def test_dummy(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.rpc_dummy + peer_method = method.__name__ # "rpc_dummy" + rs = vip_agent.vip.rpc.call(peer, peer_method).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + + +def test_outstation_reset(vip_agent, dnp3_outstation_agent): + + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.reset_outstation + peer_method = method.__name__ # "reset_outstation" + # note: reset_outstation returns None, check if raise or time out instead + try: + rs = vip_agent.vip.rpc.call(peer, peer_method).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + except BaseException as e: + assert False + + +def test_outstation_get_db(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.display_outstation_db + peer_method = method.__name__ # "display_outstation_db" + rs = vip_agent.vip.rpc.call(peer, peer_method).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + assert rs == { + 'Analog': {'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, + '9': None}, + 'AnalogOutputStatus': {'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, + '8': None, '9': None}, + 'Binary': {'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, '8': None, + '9': None}, + 'BinaryOutputStatus': {'0': None, '1': None, '2': None, '3': None, '4': None, '5': None, '6': None, '7': None, + '8': None, '9': None}} + + +def test_outstation_get_config(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.get_outstation_config + peer_method = method.__name__ # "get_outstation_config" + rs = vip_agent.vip.rpc.call(peer, peer_method).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + assert rs == {'outstation_ip_str': '0.0.0.0', 'port': 20000, 'masterstation_id_int': 2, 'outstation_id_int': 1} + + +def test_outstation_is_connected(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.is_outstation_connected + peer_method = method.__name__ # "is_outstation_connected" + rs = vip_agent.vip.rpc.call(peer, peer_method).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + assert rs in [True, False] + + +def test_outstation_apply_update_analog_input(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.apply_update_analog_input + peer_method = method.__name__ # "apply_update_analog_input" + val, index = random.random(), random.choice(range(5)) + print(f"val: {val}, index: {index}") + rs = vip_agent.vip.rpc.call(peer, peer_method, val, index).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + + # verify + val_new = rs.get("Analog").get(str(index)) + assert val_new == val + + +def test_outstation_apply_update_analog_output(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.apply_update_analog_output + peer_method = method.__name__ # "apply_update_analog_output" + val, index = random.random(), random.choice(range(5)) + print(f"val: {val}, index: {index}") + rs = vip_agent.vip.rpc.call(peer, peer_method, val, index).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + + # verify + val_new = rs.get("AnalogOutputStatus").get(str(index)) + assert val_new == val + + +def test_outstation_apply_update_binary_input(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.apply_update_binary_input + peer_method = method.__name__ # "apply_update_binary_input" + val, index = random.choice([True, False]), random.choice(range(5)) + print(f"val: {val}, index: {index}") + rs = vip_agent.vip.rpc.call(peer, peer_method, val, index).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + + # verify + val_new = rs.get("Binary").get(str(index)) + assert val_new == val + + +def test_outstation_apply_update_binary_output(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.apply_update_binary_output + peer_method = method.__name__ # "apply_update_binary_output" + val, index = random.choice([True, False]), random.choice(range(5)) + print(f"val: {val}, index: {index}") + rs = vip_agent.vip.rpc.call(peer, peer_method, val, index).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + + # verify + val_new = rs.get("BinaryOutputStatus").get(str(index)) + assert val_new == val + + +def test_outstation_update_config_with_restart(vip_agent, dnp3_outstation_agent): + peer = dnp3_vip_identity + method = Dnp3OutstationAgent.update_outstation + peer_method = method.__name__ # "update_outstation" + port_to_set = 20001 + rs = vip_agent.vip.rpc.call(peer, peer_method, port=port_to_set).get(timeout=5) + print(datetime.datetime.now(), "rs: ", rs) + + # verify + rs = vip_agent.vip.rpc.call(peer, "get_outstation_config").get(timeout=5) + port_new = rs.get("port") + # print(f"========= port_new {port_new}") + assert port_new == port_to_set diff --git a/services/core/DataMover/datamover/agent.py b/services/core/DataMover/datamover/agent.py index e1507c15c1..e5dde84b1b 100755 --- a/services/core/DataMover/datamover/agent.py +++ b/services/core/DataMover/datamover/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime @@ -79,15 +65,15 @@ class DataMover(BaseHistorian): def __init__(self, destination_vip, destination_serverkey, destination_historian_identity=PLATFORM_HISTORIAN, remote_identity=None, **kwargs): """ - :param destination_vip: vip address of the destination volttron + :param destination_vip: vip address of the destination volttron instance :param destination_serverkey: public key of the destination server - :param services_topic_list: subset of topics that are inherently - supported by base historian. Default is device, analysis, logger, + :param services_topic_list: subset of topics that are inherently + supported by base historian. Default is device, analysis, logger, and record topics - :param custom_topic_list: any additional topics this historian + :param custom_topic_list: any additional topics this historian should subscribe to. - :param destination_historian_identity: vip identity of the + :param destination_historian_identity: vip identity of the destination historian. default is 'platform.historian' :param destination_instance_name: instance name of destination server :param kwargs: additional arguments to be passed along to parent class diff --git a/services/core/DataMover/setup.py b/services/core/DataMover/setup.py index 65bf2b0a14..e671e235b2 100644 --- a/services/core/DataMover/setup.py +++ b/services/core/DataMover/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from setuptools import setup, find_packages diff --git a/services/core/DataMover/tests/test_datamover.py b/services/core/DataMover/tests/test_datamover.py index 581a1094bd..45ac3dedd7 100644 --- a/services/core/DataMover/tests/test_datamover.py +++ b/services/core/DataMover/tests/test_datamover.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -204,10 +190,10 @@ def test_devices_topic(publish_agent, query_agent): count=20, order="LAST_TO_FIRST").get(timeout=10) - assert (len(result['values']) == 1) + assert len(result['values']) == 1 (time1_date, time1_time) = time1.split("T") assert (result['values'][0][0] == time1_date + 'T' + time1_time + '+00:00') - assert (result['values'][0][1] == approx(oat_reading)) + assert result['values'][0][1] == approx(oat_reading) assert set(result['metadata'].items()) == set(float_meta.items()) @@ -367,12 +353,12 @@ def test_analysis_topic(publish_agent, query_agent): start=now, order="LAST_TO_FIRST").get(timeout=10) print('Query Result', result) - assert (len(result['values']) == 1) + assert len(result['values']) == 1 (now_date, now_time) = now.split("T") if now_time[-1:] == 'Z': now_time = now_time[:-1] - assert (result['values'][0][0] == now_date + 'T' + now_time + '+00:00') - assert (result['values'][0][1] == approx(mixed_reading)) + assert result['values'][0][0] == now_date + 'T' + now_time + '+00:00' + assert result['values'][0][1] == approx(mixed_reading) @pytest.mark.historian @@ -430,8 +416,8 @@ def test_analysis_topic_no_header(publish_agent, query_agent): start=now, order="LAST_TO_FIRST").get(timeout=10) print('Query Result', result) - assert (len(result['values']) == 1) - assert (result['values'][0][1] == approx(mixed_reading)) + assert len(result['values']) == 1 + assert result['values'][0][1] == approx(mixed_reading) @pytest.mark.historian @@ -491,8 +477,8 @@ def test_log_topic(publish_agent, query_agent): topic="datalogger/PNNL/BUILDING1_ANON/Device/MixedAirTemperature", order="LAST_TO_FIRST").get(timeout=10) print('Query Result', result) - assert (len(result['values']) == 1) - assert (result['values'][0][1] == approx(mixed_reading)) + assert len(result['values']) == 1 + assert result['values'][0][1] == approx(mixed_reading) @pytest.mark.historian @@ -539,15 +525,15 @@ def test_log_topic_no_header(publish_agent, query_agent): start=current_time, order="LAST_TO_FIRST").get(timeout=10) print('Query Result', result) - assert (len(result['values']) == 1) - assert (result['values'][0][1] == approx(mixed_reading)) + assert len(result['values']) == 1 + assert result['values'][0][1] == approx(mixed_reading) @pytest.mark.historian @pytest.mark.forwarder def test_old_config(volttron_instances, forwarder): """ - Test adding 'agentid' and 'identity' to config. identity should be + Test adding 'agentid' and 'identity' to config. identity should be supported with "deprecated warning" and "agentid" should get ignored with a warning message """ @@ -566,24 +552,3 @@ def test_old_config(volttron_instances, forwarder): start=True) print("data_mover agent id: ", uuid) - - -@pytest.mark.historian -@pytest.mark.forwarder -def test_default_config(volttron_instances): - """ - Test the default configuration file included with the agent - """ - publish_agent = volttron_instance1.build_agent(identity="test_agent") - gevent.sleep(1) - - config_path = os.path.join(get_services_core("DataMover"), "config") - with open(config_path, "r") as config_file: - config_json = json.load(config_file) - assert isinstance(config_json, dict) - volttron_instance1.install_agent( - agent_dir=get_services_core("DataMover"), - config_file=config_json, - start=True, - vip_identity="health_test") - assert publish_agent.vip.rpc.call("health_test", "health.get_status").get(timeout=10).get('status') == STATUS_GOOD diff --git a/services/core/ForwardHistorian/forwarder/agent.py b/services/core/ForwardHistorian/forwarder/agent.py index a2f4e39a35..f3904ebc28 100644 --- a/services/core/ForwardHistorian/forwarder/agent.py +++ b/services/core/ForwardHistorian/forwarder/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime diff --git a/services/core/ForwardHistorian/setup.py b/services/core/ForwardHistorian/setup.py index 65bf2b0a14..e671e235b2 100644 --- a/services/core/ForwardHistorian/setup.py +++ b/services/core/ForwardHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from setuptools import setup, find_packages diff --git a/services/core/ForwardHistorian/tests/test_forward_historian.py b/services/core/ForwardHistorian/tests/test_forward_historian.py index 668ff9b98f..8ca457107f 100644 --- a/services/core/ForwardHistorian/tests/test_forward_historian.py +++ b/services/core/ForwardHistorian/tests/test_forward_historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import random @@ -217,7 +203,7 @@ def test_devices_topic(publish_agent, query_agent): assert (len(result['values']) == 1) (time1_date, time1_time) = time1.split("T") assert (result['values'][0][0] == time1_date + 'T' + time1_time + '+00:00') - assert (result['values'][0][1] == approx(oat_reading)) + assert result['values'][0][1] == approx(oat_reading) assert set(result['metadata'].items()) == set(float_meta.items()) @@ -283,8 +269,8 @@ def test_analysis_topic(publish_agent, query_agent): (now_date, now_time) = now.split("T") if now_time[-1:] == 'Z': now_time = now_time[:-1] - assert (result['values'][0][0] == now_date + 'T' + now_time + '+00:00') - assert (result['values'][0][1] == approx(mixed_reading)) + assert result['values'][0][0] == now_date + 'T' + now_time + '+00:00' + assert result['values'][0][1] == approx(mixed_reading) @pytest.mark.historian @@ -342,8 +328,8 @@ def test_analysis_topic_no_header(publish_agent, query_agent): start=now, order="LAST_TO_FIRST").get(timeout=10) print('Query Result', result) - assert (len(result['values']) == 1) - assert (result['values'][0][1] == approx(mixed_reading)) + assert len(result['values']) == 1 + assert result['values'][0][1] == approx(mixed_reading) @pytest.mark.historian @@ -404,8 +390,8 @@ def test_log_topic(publish_agent, query_agent): topic="datalogger/PNNL/BUILDING1_ANON/Device/MixedAirTemperature", order="LAST_TO_FIRST").get(timeout=10) print('Query Result', result) - assert (len(result['values']) == 1) - assert (result['values'][0][1] == approx(mixed_reading)) + assert len(result['values']) == 1 + assert result['values'][0][1] == approx(mixed_reading) @pytest.mark.historian @@ -452,8 +438,8 @@ def test_log_topic_no_header(publish_agent, query_agent): start=current_time, order="LAST_TO_FIRST").get(timeout=10) print('Query Result', result) - assert (len(result['values']) == 1) - assert (result['values'][0][1] == approx(mixed_reading)) + assert len(result['values']) == 1 + assert result['values'][0][1] == approx(mixed_reading) @pytest.mark.historian @@ -549,7 +535,7 @@ def test_old_config(volttron_instances, forwarder): # gevent.sleep(1) # wait for topic to be forwarded and callback to happen # # # assert query_agent.callback.call_count == 1 -# print ('call args ', query_agent.callback.call_args_list) +# print('call args ', query_agent.callback.call_args_list) # # assert query_agent.callback.call_args[0][1] == 'platform.actuator' # assert query_agent.callback.call_args[0][3] == \ # topics.ACTUATOR_SCHEDULE_RESULT @@ -737,5 +723,5 @@ def test_default_config(volttron_instances, query_agent): assert (len(result['values']) == 1) (time1_date, time1_time) = time1.split("T") assert (result['values'][0][0] == time1_date + 'T' + time1_time + '+00:00') - assert (result['values'][0][1] == approx(oat_reading)) + assert result['values'][0][1] == approx(oat_reading) assert set(result['metadata'].items()) == set(float_meta.items()) diff --git a/services/core/ForwardHistorian/tests/test_forwarder_reconnections.py b/services/core/ForwardHistorian/tests/test_forwarder_reconnections.py index 04f05357a0..cdc4013bb9 100644 --- a/services/core/ForwardHistorian/tests/test_forwarder_reconnections.py +++ b/services/core/ForwardHistorian/tests/test_forwarder_reconnections.py @@ -112,8 +112,6 @@ def _device_capture(peer, sender, bus, topic, headers, message): pub_listener.core.stop() - - def test_target_shutdown(setup_instances): inst_forward, inst_target = setup_instances @@ -160,21 +158,22 @@ def _device_capture(peer, sender, bus, topic, headers, message): inst_target.restart_platform() assert inst_target.is_running() - + gevent.sleep(3) pub_listener = inst_target.build_agent() pub_listener.vip.pubsub.subscribe(peer="pubsub", prefix="devices", callback=_device_capture) - gevent.sleep(0.1) + gevent.sleep(3) all_topic = 'devices/campus/building/all' headers, message = publish_device_messages(inst_forward, all_topic=all_topic) + gevent.sleep(3) validate_published_device_data(headers, message, pubsub_retrieved[0][1], pubsub_retrieved[0][2]) def test_can_pause_publishing(setup_instances): - pass \ No newline at end of file + pass diff --git a/services/core/ForwardHistorian/tests/test_multi_messagebus_forwarder.py b/services/core/ForwardHistorian/tests/test_multi_messagebus_forwarder.py index 1f8eb55d96..5ae51eea90 100644 --- a/services/core/ForwardHistorian/tests/test_multi_messagebus_forwarder.py +++ b/services/core/ForwardHistorian/tests/test_multi_messagebus_forwarder.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest @@ -136,6 +122,7 @@ def test_multi_messagebus_forwarder(multi_messagebus_forwarder): assert subscriber_agent.analysis_callback.call_count == 5 +@pytest.mark.timeout(600) @pytest.mark.forwarder def test_multi_messagebus_custom_topic_forwarder(multi_messagebus_forwarder): """ @@ -169,6 +156,7 @@ def test_multi_messagebus_custom_topic_forwarder(multi_messagebus_forwarder): assert subscriber_agent.callback.call_count == 5 +@pytest.mark.timeout(600) @pytest.mark.forwarder def test_multi_messagebus_forwarder_reconnection(multi_messagebus_forwarder): """ @@ -212,4 +200,3 @@ def test_multi_messagebus_forwarder_reconnection(multi_messagebus_forwarder): gevent.sleep(3) assert subscriber_agent.callback.call_count == 3 - diff --git a/services/core/IEEE2030_5Agent/IDENTITY b/services/core/IEEE2030_5Agent/IDENTITY deleted file mode 100644 index e722eb9048..0000000000 --- a/services/core/IEEE2030_5Agent/IDENTITY +++ /dev/null @@ -1 +0,0 @@ -IEEE2030_5agent diff --git a/services/core/IEEE2030_5Agent/IEEE2030_5/__init__.py b/services/core/IEEE2030_5Agent/IEEE2030_5/__init__.py deleted file mode 100644 index e6ebd475e7..0000000000 --- a/services/core/IEEE2030_5Agent/IEEE2030_5/__init__.py +++ /dev/null @@ -1,87 +0,0 @@ -from collections import namedtuple - -STOR_UNKNOWN = -1 -STOR_DISCONNECTED = 1 -STOR_CONNECTED = 5 - -CONTROL_MODE_LOCAL = 0 -CONTROL_MODE_REMOTE = 1 - -INVERTER_STATUS_UNKNOWN = -1 -INVERTER_NORMAL = 0 -INVERTER_OFF = 1 -INVERTER_STARTING = 3 -INVERTER_FORCED_POWER_REDUCTION = 5 -INVERTER_FAULT = 7 -INVERTER_CELL_BALANCING = 10 - -MRID_SUFFIX_FUNCTION_SET_ASSIGNMENT = 3 -MRID_SUFFIX_DER_PROGRAM = 4 -MRID_SUFFIX_DER_CONTROL = 5 - -EVENT_STATUS_SCHEDULE = 0 -EVENT_STATUS_ACTIVE = 1 -EVENT_STATUS_CANCELLED = 2 -EVENT_STATUS_CANCELLED_RANDOM = 3 -EVENT_STATUS_SUPERCEDED = 4 - -QUALITY_NTP = 3 - -STATUS_CODES = { - 200: '200 OK', - 201: '201 Created', - 204: '204 No Content', - 500: '500 Internal Error', -} -XML_HEADERS = [("Content-Type", "application/sep+xml")] -CREATED_HEADERS = [("Content-Length", "0")] - -Endpoint = namedtuple('Endpoint', ['url', 'callback']) -IEEE2030_5_ENDPOINTS = { - "dcap": Endpoint(url="/dcap", callback='dcap'), - "tm": Endpoint(url="/dcap/tm", callback='tm'), - "sdev": Endpoint(url="/dcap/sdev", callback='sdev'), - "edev-list": Endpoint(url="/dcap/edev", callback='edev_list'), - - "sdev-di": Endpoint(url="/dcap/sdev/di", callback='sdev_di'), - "sdev-log": Endpoint(url="/dcap/sdev/log", callback='sdev_log'), - - "mup-list": Endpoint(url="/dcap/mup", callback='mup_list'), -} -IEEE2030_5_MUP_ENDPOINTS = { - "mup": Endpoint(url="/dcap/mup/{}", callback='mup'), -} -IEEE2030_5_EDEV_ENDPOINTS = { - "edev": Endpoint(url="/dcap/edev/{}", callback='edev'), - "reg": Endpoint(url="/dcap/edev/{}/reg", callback='edev_reg'), - "di": Endpoint(url="/dcap/edev/{}/di", callback='edev_di'), - "dstat": Endpoint(url="/dcap/edev/{}/dstat", callback='edev_dstat'), - "ps": Endpoint(url="/dcap/edev/{}/ps", callback='edev_ps'), - "der-list": Endpoint(url="/dcap/edev/{}/der", callback='edev_der_list'), - - "derp-list": Endpoint(url="/dcap/edev/{}/derp", callback='edev_derp_list'), - "derp": Endpoint(url="/dcap/edev/{}/derp/1", callback='edev_derp'), - - "der": Endpoint(url="/dcap/edev/{}/der/1", callback='edev_der'), - "dera": Endpoint(url="/dcap/edev/{}/der/1/dera", callback='edev_dera'), - "dercap": Endpoint(url="/dcap/edev/{}/der/1/dercap", callback='edev_dercap'), - "derg": Endpoint(url="/dcap/edev/{}/der/1/derg", callback='edev_derg'), - "ders": Endpoint(url="/dcap/edev/{}/der/1/ders", callback='edev_ders'), - - "derc-list": Endpoint(url="/dcap/edev/{}/derc", callback='edev_derc_list'), - "derc": Endpoint(url="/dcap/edev/{}/derc/1", callback='edev_derc'), - - "fsa-list": Endpoint(url="/dcap/edev/{}/fsa", callback='edev_fsa_list'), - "fsa": Endpoint(url="/dcap/edev/{}/fsa/0", callback='edev_fsa'), -} - -RESOURCE_MAPPING = { - "DeviceInformation": "device_information", - "MirrorMeterReading": "mup", - "DERStatus": "der_status", - "DERControl": "der_control", - "DERCapability": "der_capability", - "DERSettings": "der_settings", - "DERAvailability": "der_availability", - "PowerStatus": "power_status", -} diff --git a/services/core/IEEE2030_5Agent/IEEE2030_5/agent.py b/services/core/IEEE2030_5Agent/IEEE2030_5/agent.py deleted file mode 100644 index 332834b2e3..0000000000 --- a/services/core/IEEE2030_5Agent/IEEE2030_5/agent.py +++ /dev/null @@ -1,564 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2020, Battelle Memorial Institute. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 -# }}} - -from .end_device import EndDevice, MUP, IEEE2030_5Renderer, IEEE2030_5Time -from datetime import datetime, timedelta -from volttron.platform.agent import utils -from volttron.platform.vip.agent import Agent, Core, RPC -import IEEE2030_5 -import base64 -import logging -import pytz -import sys -from . import xsd_models - -utils.setup_logging() -_log = logging.getLogger(__name__) -__version__ = '1.0' - - -class IEEE2030_5Exception(Exception): - pass - - -def IEEE2030_5_agent(config_path, **kwargs): - """Parses the IEEE2030_5 Agent configuration and returns an instance of - the agent created using that configuation. - - :param config_path: Path to a configuation file. - - :type config_path: str - :returns: IEEE 2030.5 Agent - :rtype: IEEE2030_5Agent - """ - try: - config = utils.load_config(config_path) - except Exception: - config = {} - - if not config: - _log.info("Using IEEE 2030.5 Agent defaults for starting configuration.") - - devices = config.get('devices', []) # To add devices, include them in a config file - # This default should be overridden in config file - IEEE2030_5_server_sfdi = config.get('IEEE2030_5_server_sfdi', 'foo') - # This default should be overridden in config file - IEEE2030_5_server_lfdi = config.get('IEEE2030_5_server_lfdi', 'bar') - load_shed_device_category = config.get('load_shed_device_category', '0020') - timezone = config.get('timezone', 'America/Los_Angeles') - - return IEEE2030_5Agent(devices, - IEEE2030_5_server_sfdi, - IEEE2030_5_server_lfdi, - load_shed_device_category, - timezone, - **kwargs) - - -class IEEE2030_5Agent(Agent): - """ - Agent that handles IEEE 2030.5 communication. - - IEEE2030_5Agent uses the VOLTTRON web service to communicate with IEEE 2030.5 end devices. - End device configuration is outlined in the agent config file. - - IEEE 2030.5 data is exposed via get_point(), get_points() and set_point() calls. - A IEEE 2030.5 device driver (IEEE2030_5.py under PlatformDriverAgent) can be configured, - which gets and sets data by sending RPCs to this agent. - - For further information about this subsystem, please see the VOLTTRON - IEEE 2030.5 DER Support specification, which is located in VOLTTRON readthedocs - under specifications/IEEE2030_5_agent.html. - - This agent can be installed as follows: - export IEEE2030_5_ROOT=$VOLTTRON_ROOT/services/core/IEEE2030_5Agent - cd $VOLTTRON_ROOT - python scripts/install-agent.py -s $IEEE2030_5_ROOT -i IEEE2030_5agent -c $IEEE2030_5_ROOT/config - -t IEEE2030_5agent -f - """ - - def __init__(self, device_config=[], IEEE2030_5_server_sfdi='foo', IEEE2030_5_server_lfdi='bar', - load_shed_device_category='0020', timezone='America/Los_Angeles', **kwargs): - super(IEEE2030_5Agent, self).__init__(enable_web=True, **kwargs) - - self.device_config = device_config - self.IEEE2030_5_server_sfdi = IEEE2030_5_server_sfdi - self.IEEE2030_5_server_lfdi = IEEE2030_5_server_lfdi - self.load_shed_device_category = load_shed_device_category - self.timezone = timezone - self.devices = {} - - self.default_config = {"devices": device_config, - "IEEE2030_5_server_sfdi": IEEE2030_5_server_sfdi, - "IEEE2030_5_server_lfdi": IEEE2030_5_server_lfdi, - "load_shed_device_category": load_shed_device_category, - "timezone": timezone} - self.vip.config.set_default("config", self.default_config) - self.devices = self.register_devices(device_config) - self.mups = [] - - self.vip.config.subscribe(self.configure, actions=["NEW", "UPDATE"], pattern="config") - - def configure(self, configure, actions, contents): - config = self.default_config.copy() - config.update(contents) - _log.debug("Configuring IEEE 2030.5 Agent") - - self.device_config = config["devices"] - self.IEEE2030_5_server_sfdi = config["IEEE2030_5_server_sfdi"] - self.IEEE2030_5_server_lfdi = config["IEEE2030_5_server_lfdi"] - self.load_shed_device_category = config["load_shed_device_category"] - self.timezone = config["timezone"] - self.devices = self.register_devices(self.device_config) - self.register_endpoints(self) - - @Core.receiver('onstart') - def register_endpoints(self, sender): - """ Register HTTP endpoints. - - Registers all IEEE 2030.5 related endpoints. Endpoints are defined in the end_device.py file. - """ - # _log.debug("Deregistering Endpoints: {}".format(self.__class__.__name__)) - for endpoint in self.vip.web._endpoints: - try: - split_path = endpoint.split('/') - if split_path[2] == 'edev' and int(split_path[3]): - if int(split_path[3]) not in self.devices.keys(): - pass - # If code is ever introduced to unregister an endpoint, do so here! - # self.vip.web.unregister_endpoint(endpoint) - except (IndexError, ValueError): - pass - - _log.debug("Registering Endpoints: {}".format(self.__class__.__name__)) - for _, endpoint in IEEE2030_5.IEEE2030_5_ENDPOINTS.items(): - if endpoint.url not in self.vip.web._endpoints: - self.vip.web.register_endpoint(endpoint.url, getattr(self, endpoint.callback), "raw") - for device_id, device in self.devices.items(): - for _, endpoint in IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS.items(): - if endpoint.url.format(device_id) not in self.vip.web._endpoints: - self.vip.web.register_endpoint(endpoint.url.format(device_id), - getattr(self, endpoint.callback), "raw") - - def register_devices(self, devices): - """ Register IEEE 2030.5 end devices. - - :param devices: End devices from agent config file. - :type devices: List - - :return: Dictionary of EndDevice objects keyed by ID. - """ - _log.debug("Loading Devices: {}".format(self.__class__.__name__)) - end_devices = self.devices - for device in devices: - if device['sfdi'] not in [k.sfdi for k in end_devices.values()]: - d = EndDevice(sfdi=device["sfdi"], - lfdi=device["lfdi"], - load_shed_device_category=device["load_shed_device_category"], - pin_code=device["pin_code"]) - end_devices[d.id] = d - else: - d = self.get_end_device(sfdi=device['sfdi']) - d.lfdi = device['lfdi'] - d.load_shed_device_category = device['load_shed_device_category'] - d.pin_code = device['pin_code'] - - old_indices = [] - for index, d in end_devices.items(): - if d.sfdi not in [device['sfdi'] for device in devices]: - old_indices.append(index) - for i in old_indices: - end_devices.pop(i) - return end_devices - - def get_end_device(self, path=None, sfdi=None, lfdi=None): - """ Helper function to return end device object. - - Only one of path or sfdi should be used for End Device lookup - - :param path: Path Info of HTTP endpoint request - :param sfdi: SFDI of end device - :param lfdi: LFDI of end device - :return: EndDevice object - """ - if path: - end_device_id = path.split('/')[3] - try: - device = self.devices[int(end_device_id)] - return device - except KeyError: - raise IEEE2030_5Exception("Invalid end device requested") - else: - end_device = None - for device in self.devices.values(): - if device.sfdi == sfdi or device.lfdi == lfdi: - end_device = device - if end_device is None: - raise IEEE2030_5Exception("Invalid end device requested") - return end_device - - def process_edev(self, env, data, xsd_type, attr_name): - """ Process HTTP requests and prepare response - - :param env: Request Environment variables - :param data: Request data - :param xsd_type: XSD object type request represents - :param attr_name: Attribute of EndDevice object that corresponds to the XSD Object - :return: Tuple of (Status Code, Response Data, Headers) - """ - device = self.get_end_device(env['PATH_INFO']) - if env['REQUEST_METHOD'] in ('POST', 'PUT'): - obj = xsd_models.parseString(data, silence=True) - if type(obj) == xsd_type: - setattr(device, attr_name, obj) - return [IEEE2030_5.STATUS_CODES[204], '', IEEE2030_5.CREATED_HEADERS] - else: - _log.warning("Bad XML input for HTTP Endpoint.") - return [IEEE2030_5.STATUS_CODES[500], '', IEEE2030_5.XML_HEADERS] - else: - return IEEE2030_5Agent.prep_200_response({'received_data': data, 'result': getattr(device, attr_name)}) - - @staticmethod - def add_meter_readings(mup, meter_readings): - """ Update/Create Meter Readings for MUP based on existance. - - If Meter Reading already exists, send an update. If it does not, create new Meter Reading for MUP. - - :param mup: MUP object - :param meter_readings: List of incoming Meter Readings to insert into MUP object. - :return: None - """ - for meter_reading in meter_readings: - flag = True - for index, xsd in enumerate(mup.mup_xsd.get_MirrorMeterReading()): - if meter_reading.description == mup.mup_xsd.get_MirrorMeterReading()[index].description: - mup.mup_xsd.replace_MirrorMeterReading_at(index, meter_reading) - flag = False - if flag: - mup.mup_xsd.add_MirrorMeterReading(meter_reading) - - @staticmethod - def prep_200_response(render_dict): - """Helper function to prep standard 200 responses with XML formatted data - - :param render_dict: dictionary to render into XML serializable string - - :return: Tuple of (Status Code, Response Data, Headers) - """ - return (IEEE2030_5.STATUS_CODES[200], - base64.b64encode(IEEE2030_5Renderer.render(render_dict)).decode('ascii'), - IEEE2030_5.XML_HEADERS) - - @RPC.export - def get_point(self, sfdi, point_name): - _log.debug("EndDevice {0}: Getting value for {1}".format(sfdi, point_name)) - end_device = self.get_end_device(sfdi=sfdi) - try: - point_definition = end_device.mappings[point_name] - return end_device.field_value(point_definition['IEEE 2030.5 Resource Name'], - point_definition['IEEE 2030.5 Field Name']) - except KeyError: - raise IEEE2030_5Exception("{0} not a configured point name.".format(point_name)) - - @RPC.export - def get_points(self, sfdi): - _log.debug("EndDevice {0}: Getting all configured point values".format(sfdi)) - end_device = self.get_end_device(sfdi=sfdi) - try: - end_device_points = {} - for volttron_point_name, point_definition in end_device.mappings.items(): - field_value = end_device.field_value(point_definition['IEEE 2030.5 Resource Name'], - point_definition['IEEE 2030.5 Field Name']) - end_device_points[volttron_point_name] = field_value - return end_device_points - except Exception as e: - raise IEEE2030_5Exception(e) - - @RPC.export - def set_point(self, sfdi, point_name, value): - _log.debug("EndDevice {0}: Setting {1} to {2}".format(sfdi, point_name, value)) - end_device = self.get_end_device(sfdi=sfdi) - try: - setattr(end_device, point_name, value) - except Exception as e: - raise IEEE2030_5Exception(e) - - @RPC.export - def config_points(self, sfdi, point_map): - _log.debug("EndDevice {0}: Configuring points: {1}".format(sfdi, point_map)) - end_device = self.get_end_device(sfdi=sfdi) - end_device.mappings = point_map - - ########################################################################## - # The following methods are callback functions for IEEE 2030.5 Endpoints # - ########################################################################## - - def dcap(self, env, data): - dcap = xsd_models.DeviceCapability( - EndDeviceListLink=xsd_models.EndDeviceListLink(), - MirrorUsagePointListLink=xsd_models.MirrorUsagePointListLink(), - SelfDeviceLink=xsd_models.SelfDeviceLink() - ) - dcap.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["dcap"].url) - - dcap.EndDeviceListLink.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["edev-list"].url) - dcap.SelfDeviceLink.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["sdev"].url) - - dcap.TimeLink = xsd_models.TimeLink() - dcap.TimeLink.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["tm"].url) - - dcap.MirrorUsagePointListLink.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["mup-list"].url) - - return IEEE2030_5Agent.prep_200_response({"result": dcap}) - - def sdev(self, env, data): - sdev = xsd_models.SelfDevice() - sdev.sFDI = xsd_models.SFDIType(valueOf_=int(self.IEEE2030_5_server_sfdi)) - sdev.loadShedDeviceCategory = xsd_models.DeviceCategoryType(valueOf_=self.load_shed_device_category) - sdev.DeviceInformationLink = xsd_models.DeviceInformationLink() - sdev.DeviceInformationLink.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["sdev-di"].url) - sdev.LogEventListLink = xsd_models.LogEventListLink() - sdev.LogEventListLink.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["sdev-log"].url) - sdev.LogEventListLink.set_all(1) - return IEEE2030_5Agent.prep_200_response({"result": sdev}) - - def sdev_di(self, env, data): - sep_device_information = xsd_models.DeviceInformation(lFDI=self.IEEE2030_5_server_lfdi) - return IEEE2030_5Agent.prep_200_response({"result": sep_device_information}) - - def sdev_log(self, env, data): - sep_log_event_list = xsd_models.LogEventList() - return IEEE2030_5Agent.prep_200_response({"result": sep_log_event_list}) - - def tm(self, env, data): - now_utc = datetime.utcnow().replace(tzinfo=pytz.utc) - local_tz = pytz.timezone(self.timezone) - now_local = datetime.now().replace(tzinfo=local_tz) - - start_dst_utc, end_dst_utc = [dt for dt in local_tz._utc_transition_times if dt.year == now_local.year] - - utc_offset = local_tz.utcoffset(start_dst_utc - timedelta(days=1)) - dst_offset = local_tz.utcoffset(start_dst_utc + timedelta(days=1)) - utc_offset - local_but_utc = datetime.now().replace(tzinfo=pytz.utc) - - tm = xsd_models.Time( - currentTime=IEEE2030_5Time(now_utc), - dstEndTime=IEEE2030_5Time(end_dst_utc.replace(tzinfo=pytz.utc)), - dstOffset=xsd_models.TimeOffsetType(valueOf_=int(dst_offset.total_seconds())), - dstStartTime=IEEE2030_5Time(start_dst_utc.replace(tzinfo=pytz.utc)), - localTime=IEEE2030_5Time(local_but_utc), - quality=IEEE2030_5.QUALITY_NTP, - tzOffset=xsd_models.TimeOffsetType(valueOf_=int(utc_offset.total_seconds())) - ) - tm.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["tm"].url) - return IEEE2030_5Agent.prep_200_response({"result": tm}) - - def edev_list(self, env, data): - device_list = xsd_models.EndDeviceList() - start, limit = parse_list_query(env['QUERY_STRING'].encode('ascii', 'ignore'), len(self.devices)) - - for i in range(start, limit): - device_list.add_EndDevice(self.devices[i].end_device) - - device_list.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["edev-list"].url) - device_list.set_results(max(0, len(range(start, limit)))) - device_list.set_all(len(self.devices)) - - return IEEE2030_5Agent.prep_200_response({'received_data': data, 'result': device_list}) - - def edev(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.EndDevice, attr_name="end_device") - - def edev_di(self, env, data): - return self.process_edev(env=env, data=data, - xsd_type=xsd_models.DeviceInformation, attr_name="device_information") - - def edev_dstat(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.DeviceStatus, attr_name="device_status") - - def edev_fsa_list(self, env, data): - device = self.get_end_device(env['PATH_INFO']) - fsa_list = xsd_models.FunctionSetAssignmentsList() - fsa_list.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS["fsa-list"].url.format(device.id)) - fsa_list.add_FunctionSetAssignments(device.function_set_assignments) - fsa_list.set_all(1) - fsa_list.set_results(1) - return IEEE2030_5Agent.prep_200_response({"result": fsa_list}) - - def edev_fsa(self, env, data): - return self.process_edev(env=env, data=data, - xsd_type=xsd_models.FunctionSetAssignments, attr_name="function_set_assignments") - - def edev_ps(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.PowerStatus, attr_name="power_status") - - def edev_reg(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.Registration, attr_name="registration") - - def edev_der_list(self, env, data): - device = self.get_end_device(env['PATH_INFO']) - der_list = xsd_models.DERList() - der_list.set_all(1) - der_list.set_results(1) - der_list.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS["der-list"].url.format(device.id)) - der_list.add_DER(device.der) - return IEEE2030_5Agent.prep_200_response({"result": der_list}) - - def edev_der(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.DER, attr_name="der") - - def edev_dera(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.DERAvailability, attr_name="der_availability") - - def edev_derc_list(self, env, data): - device = self.get_end_device(env['PATH_INFO']) - derc_list = xsd_models.DERControlList() - derc_list.set_all(1) - derc_list.set_results(1) - derc_list.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS["derc-list"].url.format(device.id)) - derc_list.add_DERControl(device.der_control_xsd_object()) - return IEEE2030_5Agent.prep_200_response({"result": derc_list}) - - def edev_derc(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.DERControl, attr_name="der_control") - - def edev_dercap(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.DERCapability, attr_name="der_capability") - - def edev_derg(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.DERSettings, attr_name="der_settings") - - def edev_derp_list(self, env, data): - device = self.get_end_device(env['PATH_INFO']) - derp_list = xsd_models.DERProgramList() - derp_list.set_all(1) - derp_list.set_results(1) - derp_list.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS["derp-list"].url.format(device.id)) - derp_list.add_DERProgram(device.der_program) - return IEEE2030_5Agent.prep_200_response({"result": derp_list}) - - def edev_derp(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.DERProgram, attr_name="der_program") - - def edev_ders(self, env, data): - return self.process_edev(env=env, data=data, xsd_type=xsd_models.DERStatus, attr_name="der_status") - - def mup_list(self, env, data): - if env['REQUEST_METHOD'] in ('POST', 'PUT'): - endpoint = IEEE2030_5.IEEE2030_5_MUP_ENDPOINTS["mup"] - mup = xsd_models.parseString(data, silence=True) - device = self.get_end_device(lfdi=mup.get_deviceLFDI()) - if device.mup is None: - m = MUP(mup) - m.mup_xsd.set_href(endpoint.url.format(m.id)) - device.mup = m - self.mups.append(m) - if endpoint.url.format(m.id) not in self.vip.web._endpoints: - self.vip.web.register_endpoint(endpoint.url.format(m.id), getattr(self, endpoint.callback), "raw") - else: - IEEE2030_5Agent.add_meter_readings(device.mup, mup.get_MirrorMeterReading()) - - return [IEEE2030_5.STATUS_CODES[201], - '', - IEEE2030_5.XML_HEADERS+[("Location", endpoint.url.format(device.mup.id))]] - - else: - mup_list = xsd_models.MirrorUsagePointList() - - start, limit = parse_list_query(env['QUERY_STRING'].encode('ascii', 'ignore'), len(self.mups)) - - for i in range(start, limit): - mup_list.add_MirrorUsagePoint(self.mups[i].mup_xsd) - - mup_list.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["mup-list"].url) - mup_list.set_results(max(0, len(range(start, limit)))) - mup_list.set_all(len(self.mups)) - - return IEEE2030_5Agent.prep_200_response({"result": mup_list}) - - def mup(self, env, data): - mup_id = env['PATH_INFO'].split('/')[3] - mup = self.mups[int(mup_id)] - if env['REQUEST_METHOD'] in ('POST', 'PUT'): - device = self.get_end_device(lfdi=mup.mup_xsd.get_deviceLFDI()) - obj = xsd_models.parseString(data, silence=True) - if type(obj) == xsd_models.MirrorUsagePoint: - readings = obj.get_MirrorMeterReading() - elif type(obj) == xsd_models.MirrorMeterReading: - readings = [obj] - else: - _log.warning("Bad XML input for HTTP Endpoint.") - return [IEEE2030_5.STATUS_CODES[500], '', IEEE2030_5.XML_HEADERS] - IEEE2030_5Agent.add_meter_readings(device.mup, readings) - - return [IEEE2030_5.STATUS_CODES[201], - '', - IEEE2030_5.XML_HEADERS + [ - ("Location", IEEE2030_5.IEEE2030_5_MUP_ENDPOINTS["mup"].url.format(mup.id))]] - else: - xsd_object = getattr(mup, 'mup_xsd') - return IEEE2030_5Agent.prep_200_response({'received_data': data, 'result': xsd_object}) - - -def parse_list_query(query, length): - """Parses the IEEE 2030.5 query string parameters associated with list resources. - - There is some defensive code here to avoid errors on negative numbers. - - :param query: The request QUERY PARAMS dictionary - :param length: Length of the list - :return: (start index 0 based, limit) - xrange style - """ - params = {a[0]: a[1] for a in [x.split('=') for x in query.split("&")]} if len(query) > 0 else {} - start = max(0, int(params.get('s', '0'))) - limit = max(0, min(length, start + int(params.get('l', '255')))) - return start, limit - - -def main(): - """Main method called to start the agent.""" - utils.vip_main(IEEE2030_5_agent, identity='IEEE2030_5agent', - version=__version__) - - -if __name__ == '__main__': - # Entry point for script - try: - sys.exit(main()) - except KeyboardInterrupt: - pass diff --git a/services/core/IEEE2030_5Agent/IEEE2030_5/end_device.py b/services/core/IEEE2030_5Agent/IEEE2030_5/end_device.py deleted file mode 100644 index 5bd6f3ae49..0000000000 --- a/services/core/IEEE2030_5Agent/IEEE2030_5/end_device.py +++ /dev/null @@ -1,441 +0,0 @@ -# }}} - -from datetime import datetime, timedelta -import IEEE2030_5 -import calendar -import logging -import pytz -import io -import time -from . import xsd_models -from volttron.platform.agent import utils - -utils.setup_logging() -_log = logging.getLogger(__name__) - - -class EndDevice: - """ Object representing an End Device in IEEE 2030.5 - - End Devices talk with the IEEE 2030.5 Agent over HTTP using XML formatting. This End Device representation stores - configuration information about the End Device and exports that information as XSD Objects when various - endpoint urls are queried. - """ - enddevice_id = 0 - - def __init__(self, sfdi, lfdi, load_shed_device_category, pin_code): - """Representation of End Device object. - - :param sfdi: Short Form Device Identifier - :param lfdi: Long Form Device Identifier - :param load_shed_device_category: Load Shed Device Category - :param pin_code: Pin Code - """ - - # Basic Device Configurations - self.sfdi = sfdi - self.lfdi = lfdi - self.loadShedDeviceCategory = load_shed_device_category - self.pinCode = pin_code - self.registeredOn = datetime.utcnow().replace(tzinfo=pytz.utc) - - # Global Device ID. Updates as End Devices are registered. - self.id = EndDevice.enddevice_id - EndDevice.enddevice_id += 1 - - self.mappings = {} - - # IEEE 2030.5 Resource Initialization - self._end_device = xsd_models.EndDevice( - FunctionSetAssignmentsListLink=xsd_models.FunctionSetAssignmentsListLink(), - RegistrationLink=xsd_models.RegistrationLink(), - ) - self._end_device.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['edev'].url.format(self.id)) - self._end_device.sFDI = xsd_models.SFDIType(valueOf_=self.sfdi) - self._end_device.loadShedDeviceCategory = xsd_models.DeviceCategoryType(valueOf_=self.loadShedDeviceCategory) - self._end_device.FunctionSetAssignmentsListLink.\ - set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['fsa-list'].url.format(self.id)) - self._end_device.FunctionSetAssignmentsListLink.set_all(1) - self._end_device.RegistrationLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['reg'].url.format(self.id)) - self._end_device.DeviceInformationLink = xsd_models.DeviceInformationLink() - self._end_device.DeviceInformationLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['di'].url.format(self.id)) - self._end_device.DeviceStatusLink = xsd_models.DeviceStatus() - self._end_device.DeviceStatusLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['dstat'].url.format(self.id)) - self._end_device.PowerStatusLink = xsd_models.PowerStatusLink() - self._end_device.PowerStatusLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['ps'].url.format(self.id)) - self._end_device.DERListLink = xsd_models.DERListLink() - self._end_device.DERListLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['der-list'].url.format(self.id)) - self._end_device.DERListLink.set_all(1) - - self._device_information = xsd_models.DeviceInformation() - self._device_status = xsd_models.DeviceStatus() - self._power_status = xsd_models.PowerStatus() - - self._function_set_assignments = xsd_models.FunctionSetAssignments( - subscribable='0', - mRID=xsd_models.mRIDType(valueOf_=mrid_helper(self.id, IEEE2030_5.MRID_SUFFIX_FUNCTION_SET_ASSIGNMENT)), - description="FSA", - ) - self._function_set_assignments.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS["fsa"].url.format(self.id)) - self._function_set_assignments.DERProgramListLink = xsd_models.DERProgramListLink() - self._function_set_assignments.DERProgramListLink.\ - set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS["derp-list"].url.format(self.id)) - self._function_set_assignments.DERProgramListLink.set_all(1) - self._function_set_assignments.TimeLink = xsd_models.TimeLink() - self._function_set_assignments.TimeLink.set_href(IEEE2030_5.IEEE2030_5_ENDPOINTS["tm"].url) - - self._registration = xsd_models.Registration( - dateTimeRegistered=IEEE2030_5Time(self.registeredOn), - pIN=xsd_models.PINType(valueOf_=int(self.pinCode))) - self._registration.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['reg'].url.format(self.id)) - - self._der = xsd_models.DER( - AssociatedDERProgramListLink=xsd_models.AssociatedDERProgramListLink(), - CurrentDERProgramLink=xsd_models.CurrentDERProgramLink(), - DERAvailabilityLink=xsd_models.DERAvailabilityLink(), - DERCapabilityLink=xsd_models.DERCapabilityLink(), - DERSettingsLink=xsd_models.DERSettingsLink(), - DERStatusLink=xsd_models.DERStatusLink() - ) - self._der.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['der'].url.format(self.id)) - self._der.AssociatedDERProgramListLink.set_href( - IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['derp-list'].url.format(self.id)) - self._der.AssociatedDERProgramListLink.set_all(1) - self._der.CurrentDERProgramLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['derp'].url.format(self.id)) - self._der.DERAvailabilityLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['dera'].url.format(self.id)) - self._der.DERCapabilityLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['dercap'].url.format(self.id)) - self._der.DERSettingsLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['derg'].url.format(self.id)) - self._der.DERStatusLink.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['ders'].url.format(self.id)) - - self._der_program = xsd_models.DERProgram( - DERControlListLink=xsd_models.DERControlListLink(), - primacy=xsd_models.PrimacyType(valueOf_=1) - ) - self._der_program.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['derp'].url.format(self.id)) - self._der_program.set_mRID( - xsd_models.mRIDType(valueOf_=mrid_helper(self.id, IEEE2030_5.MRID_SUFFIX_DER_PROGRAM))) - self._der_program.set_version(xsd_models.VersionType(valueOf_='0')) - self._der_program.set_description("DER Program") - self._der_program.DERControlListLink.set_href( - IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['derc-list'].url.format(self.id)) - self._der_program.DERControlListLink.set_all(1) - - self._der_settings = xsd_models.DERSettings() - self._der_capability = xsd_models.DERCapability() - self._der_status = xsd_models.DERStatus() - self._der_availability = xsd_models.DERAvailability() - - self._der_control = xsd_models.DERControl(DERControlBase=xsd_models.DERControlBase()) - self._der_control.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['derc'].url.format(self.id)) - self._der_control.set_description("DER Control") - - self._mup = None - - def meter_reading_helper(self, attr_name): - """ Helper method for attributes that use meter readings - - :param attr_name: Name of SunSpec attribute - :return: Value of IEEE 2030.5 Meter Reading correlated with SunSpec attribute - """ - if self.mup is not None: - for reading in self.mup.mup_xsd.get_MirrorMeterReading(): - if reading.get_description() == attr_name: - power_of_ten = reading.get_ReadingType() - value = reading.get_Reading().get_value() - return float(value) * pow(10, int(power_of_ten.get_powerOfTenMultiplier().get_valueOf_())) \ - if power_of_ten is not None else float(value) - return None - - ##################################################################### - # Currently WChaMax is the only SunSpec register we support # - # writing to. Because of the way IEEE 2030.5 is set up, we can read # - # any register by giving it a proper IEEE 2030.5 resource and field # - # but writing to registers will require special agent config # - ##################################################################### - - def b124_WChaMax(self, value): - now = datetime.utcnow().replace(tzinfo=pytz.utc) - mrid = mrid_helper(self.id, int(time.mktime(now.timetuple()))) - self.der_control.get_DERControlBase().set_opModFixedFlow(xsd_models.SignedPerCent(valueOf_=value)) - self.der_control.set_mRID(xsd_models.mRIDType(valueOf_=mrid)) - self.der_control.set_creationTime(IEEE2030_5Time(now)) - self.der_control.set_EventStatus(xsd_models.EventStatus( - currentStatus=IEEE2030_5.EVENT_STATUS_ACTIVE, - dateTime=IEEE2030_5Time(now), - potentiallySuperseded=True, - potentiallySupersededTime=IEEE2030_5Time(now), - reason="Dispatch" - )) - self.der_control.set_interval(xsd_models.DateTimeInterval(duration=3600 * 24, start=IEEE2030_5Time(now))) - - def field_value(self, resource, field): - """ Given a IEEE 2030.5 field name, return the value of that field. - :param resource: IEEE 2030.5 resource name - :param field: IEEE 2030.5 field name (may be dotted notation if a nested field) - :return: field value - """ - - # Special Corner cases that exist outside of official IEEE 2030.5 fields - if field == 'sFDI': - return self.sfdi - elif field == 'SOC': - _log.debug('Calculating DERAvailability.soc...') - if self.field_value("DERAvailability", "availabilityDuration") is not None and \ - self.field_value("DERSettings", "setMaxChargeRate") is not None: - duration = self.field_value("DERAvailability", "availabilityDuration") / 3600.0 - max_charge = self.field_value("DERSettings", "setMaxChargeRate") - soc = duration * max_charge - else: - soc = None - return soc - - # Translate from IEEE 2030.5 resource (DeviceInformation) to EndDevice attribute (device_information) - converted_resource = IEEE2030_5.RESOURCE_MAPPING[resource] - if hasattr(self, converted_resource): - IEEE2030_5_resource = getattr(self, converted_resource) - else: - raise AttributeError("{} is not a valid IEEE 2030.5 Resource".format(resource)) - - # MUPs have special case handling - if converted_resource == "mup": - return self.meter_reading_helper(field) - - IEEE2030_5_field = self.get_field(IEEE2030_5_resource, field) - if hasattr(IEEE2030_5_field, 'value'): - field_value = IEEE2030_5_field.value - if hasattr(IEEE2030_5_field, 'multiplier') and type(IEEE2030_5_field.multiplier) == \ - xsd_models.PowerOfTenMultiplierType: - field_value = float(field_value) * pow(10, int(IEEE2030_5_field.multiplier.get_valueOf_())) - elif type(field_value) == xsd_models.PerCent: - field_value = int(field_value.get_valueOf_()) / 100.0 - else: - # Depending on field choice, this could be a nested xsd model, not JSON serializable. - pass - else: - field_value = IEEE2030_5_field - - return field_value - - @staticmethod - def get_field(resource, field): - """ Recursive helper method to retrieve field from IEEE 2030.5 resource - - If IEEE 2030.5 fields have not been defined, this method will return None - - :param resource: IEEE 2030.5 resource (xsd_models object) - :param field: IEEE 2030.5 field name - :return: value of field - """ - fields = field.split('.', 1) - if len(fields) == 1: - IEEE2030_5_field = getattr(resource, field, None) - else: - meta_field = getattr(resource, fields[0], None) - IEEE2030_5_field = EndDevice.get_field(meta_field, fields[1]) if meta_field else None - return IEEE2030_5_field - - ############################################################ - # XSD Object representation methods. # - # These objects represent various IEEE2030_5 Resources. # - # These Resource objects mirror HTTP request GET and POSTS # - ############################################################ - - @property - def end_device(self): - return self._end_device - - @property - def device_information(self): - return self._device_information - - @device_information.setter - def device_information(self, value): - self._device_information = value - self._device_information.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['di'].url.format(self.id)) - - @property - def device_status(self): - return self._device_status - - @device_status.setter - def device_status(self, value): - self._device_status = value - self._device_status.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['dstat'].url.format(self.id)) - - @property - def function_set_assignments(self): - return self._function_set_assignments - - @property - def power_status(self): - return self._power_status - - @power_status.setter - def power_status(self, value): - self._power_status = value - self._power_status.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['ps'].url.format(self.id)) - - @property - def registration(self): - return self._registration - - @property - def der(self): - return self._der - - @property - def der_program(self): - return self._der_program - - @property - def der_control(self): - return self._der_control - - @property - def der_availability(self): - return self._der_availability - - @der_availability.setter - def der_availability(self, value): - self._der_availability = value - self._der_availability.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['dera'].url.format(self.id)) - - @property - def der_capability(self): - return self._der_capability - - @der_capability.setter - def der_capability(self, value): - self._der_capability = value - self._der_capability.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['dercap'].url.format(self.id)) - - @property - def der_status(self): - return self._der_status - - @der_status.setter - def der_status(self, value): - self._der_status = value - self._der_status.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['ders'].url.format(self.id)) - - @property - def der_settings(self): - return self._der_settings - - @der_settings.setter - def der_settings(self, value): - self._der_settings = value - self._der_settings.set_href(IEEE2030_5.IEEE2030_5_EDEV_ENDPOINTS['derg'].url.format(self.id)) - - @property - def mup(self): - return self._mup - - @mup.setter - def mup(self, value): - self._mup = value - - -class MUP: - """ Object representing an MUP in IEEE2030_5 """ - mup_id = 0 - - def __init__(self, xsd): - self.id = MUP.mup_id - MUP.mup_id += 1 - self.mup_xsd = xsd - - -class IEEE2030_5Renderer: - """ Takes IEEE 2030.5 Type objects and renders them as XML formatted data for HTTP response. """ - - media_type = 'application/sep+xml' - - @staticmethod - def export(xsd_object, make_pretty=True): - """Export IEEE 2030.5 object into serializable XML - - :param xsd_object: IEEE 2030.5 object to export - :param make_pretty: Boolean value determining whether or not to use newline characters between XML elements. - - :return: String of XML serialized data. - """ - buff = io.StringIO() - xsd_object.export( - buff, - 1, - namespacedef_='xmlns="http://zigbee.org/sep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"', - pretty_print=make_pretty - ) - return buff.getvalue() - - @staticmethod - def render(data): - """ Wrapper function around the export method. - - :param data: XSD object to render. Empty string if data does not come in correctly. - :return: Formatted XML string. - """ - if data is None: - return '' - - if 'rendered_result' not in data: - if 'result' not in data: - data['rendered_result'] = '' - else: - make_pretty = True - data['rendered_result'] = IEEE2030_5Renderer.export(data['result'], make_pretty) - - return data['rendered_result'] - - -class IEEE2030_5Parser: - """ Takes XML formatted string and renders it as an XSD object. """ - media_type = 'application/sep+xml' - - @staticmethod - def parse(stream): - """ Parses the incoming bytestream as XML and returns the resulting data. """ - return xsd_models.parseString(stream, silence=True) - - -def mrid_helper(edev_pk, resource_suffix): - """ Helper method to create universally unique ID for any resource object - - :param edev_pk: Primary Key of End Device object - :param resource_suffix: Suffix to add to hash to create unique ID - :return: UUID (MRID) value. (In hex-decimal) - """ - hex_string = hex(int(edev_pk)*10000000000000+resource_suffix*100)[2:].upper() - if hex_string.endswith('L'): - hex_string = hex_string[:-1] - if (len(hex_string)) % 2 == 1: - hex_string = "0{0}".format(hex_string) - return hex_string - - -def IEEE2030_5Time(dt_obj, local=False): - """ Return a proper IEEE2030_5 TimeType object for the dt_obj passed in. - - From IEEE 2030.5 spec: - TimeType Object (Int64) - Time is a signed 64 bit value representing the number of seconds - since 0 hours, 0 minutes, 0 seconds, on the 1st of January, 1970, - in UTC, not counting leap seconds. - - :param dt_obj: Datetime object to convert to IEEE2030_5 TimeType object. - :param local: dt_obj is in UTC or Local time. Default to UTC time. - :return: Time XSD object - :raises: If utc_dt_obj is not UTC - """ - - if dt_obj.tzinfo is None: - raise Exception("IEEE 2030.5 times should be timezone aware UTC or local") - - if dt_obj.utcoffset() != timedelta(0) and not local: - raise Exception("IEEE 2030.5 TimeType should be based on UTC") - - if local: - return xsd_models.TimeType(valueOf_=int(time.mktime(dt_obj.timetuple()))) - else: - return xsd_models.TimeType(valueOf_=int(calendar.timegm(dt_obj.timetuple()))) diff --git a/services/core/IEEE2030_5Agent/IEEE2030_5/xsd_models.py b/services/core/IEEE2030_5Agent/IEEE2030_5/xsd_models.py deleted file mode 100644 index 8d76e5a883..0000000000 --- a/services/core/IEEE2030_5Agent/IEEE2030_5/xsd_models.py +++ /dev/null @@ -1,35078 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Generated Sat Oct 11 16:09:18 2014 by generateDS.py version 2.13a. -# -# Command line options: -# ('-o', 'xsd_models.py') -# -# Command line arguments: -# sep.xsd -# -# Command line: -# generateDS.py -o "xsd_models.py" sep.xsd -# -# Current working directory (os.getcwd()): -# sep2 -# - -import sys -import getopt -import re as re_ -import base64 -import datetime as datetime_ - -etree_ = None -Verbose_import_ = False -( - XMLParser_import_none, XMLParser_import_lxml, - XMLParser_import_elementtree -) = list(range(3)) -XMLParser_import_library = None -try: - # lxml - from lxml import etree as etree_ - XMLParser_import_library = XMLParser_import_lxml - if Verbose_import_: - print("running with lxml.etree") -except ImportError: - try: - # cElementTree from Python 2.5+ - import xml.etree.cElementTree as etree_ - XMLParser_import_library = XMLParser_import_elementtree - if Verbose_import_: - print("running with cElementTree on Python 2.5+") - except ImportError: - try: - # ElementTree from Python 2.5+ - import xml.etree.ElementTree as etree_ - XMLParser_import_library = XMLParser_import_elementtree - if Verbose_import_: - print("running with ElementTree on Python 2.5+") - except ImportError: - try: - # normal cElementTree install - import cElementTree as etree_ - XMLParser_import_library = XMLParser_import_elementtree - if Verbose_import_: - print("running with cElementTree") - except ImportError: - try: - # normal ElementTree install - import elementtree.ElementTree as etree_ - XMLParser_import_library = XMLParser_import_elementtree - if Verbose_import_: - print("running with ElementTree") - except ImportError: - raise ImportError( - "Failed to import ElementTree from any known place") - - -def parsexml_(*args, **kwargs): - if (XMLParser_import_library == XMLParser_import_lxml and - 'parser' not in kwargs): - # Use the lxml ElementTree compatible parser so that, e.g., - # we ignore comments. - kwargs['parser'] = etree_.ETCompatXMLParser() - doc = etree_.parse(*args, **kwargs) - return doc - -# -# User methods -# -# Calls to the methods in these classes are generated by generateDS.py. -# You can replace these methods by re-implementing the following class -# in a module named generatedssuper.py. - -try: - from generatedssuper import GeneratedsSuper -except ImportError as exp: - - class GeneratedsSuper: - tzoff_pattern = re_.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') - class _FixedOffsetTZ(datetime_.tzinfo): - def __init__(self, offset, name): #pylint: disable=super-init-not-called - self.__offset = datetime_.timedelta(minutes=offset) - self.__name = name - def utcoffset(self, dt): - return self.__offset - def tzname(self, dt): - return self.__name - def dst(self, dt): - return None - def gds_format_string(self, input_data, input_name=''): - return input_data - def gds_validate_string(self, input_data, node, input_name=''): - if not input_data: - return '' - else: - return input_data - def gds_format_base64(self, input_data, input_name=''): - return base64.b64encode(input_data) - def gds_validate_base64(self, input_data, node, input_name=''): - return input_data - def gds_format_integer(self, input_data, input_name=''): - return '%d' % input_data - def gds_validate_integer(self, input_data, node, input_name=''): - return input_data - def gds_format_integer_list(self, input_data, input_name=''): - return '%s' % input_data - def gds_validate_integer_list(self, input_data, node, input_name=''): - values = input_data.split() - for value in values: - try: - float(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of integers') - return input_data - def gds_format_float(self, input_data, input_name=''): - return ('%.15f' % input_data).rstrip('0') - def gds_validate_float(self, input_data, node, input_name=''): - return input_data - def gds_format_float_list(self, input_data, input_name=''): - return '%s' % input_data - def gds_validate_float_list(self, input_data, node, input_name=''): - values = input_data.split() - for value in values: - try: - float(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of floats') - return input_data - def gds_format_double(self, input_data, input_name=''): - return '%e' % input_data - def gds_validate_double(self, input_data, node, input_name=''): - return input_data - def gds_format_double_list(self, input_data, input_name=''): - return '%s' % input_data - def gds_validate_double_list(self, input_data, node, input_name=''): - values = input_data.split() - for value in values: - try: - float(value) - except (TypeError, ValueError): - raise_parse_error(node, 'Requires sequence of doubles') - return input_data - def gds_format_boolean(self, input_data, input_name=''): - return ('%s' % input_data).lower() - def gds_validate_boolean(self, input_data, node, input_name=''): - return input_data - def gds_format_boolean_list(self, input_data, input_name=''): - return '%s' % input_data - def gds_validate_boolean_list(self, input_data, node, input_name=''): - values = input_data.split() - for value in values: - if value not in ('true', '1', 'false', '0', ): - raise_parse_error( - node, - 'Requires sequence of booleans ' - '("true", "1", "false", "0")') - return input_data - def gds_validate_datetime(self, input_data, node, input_name=''): - return input_data - def gds_format_datetime(self, input_data, input_name=''): - if input_data.microsecond == 0: - _svalue = '%04d-%02d-%02dT%02d:%02d:%02d' % ( - input_data.year, - input_data.month, - input_data.day, - input_data.hour, - input_data.minute, - input_data.second, - ) - else: - _svalue = '%04d-%02d-%02dT%02d:%02d:%02d.%s' % ( - input_data.year, - input_data.month, - input_data.day, - input_data.hour, - input_data.minute, - input_data.second, - ('%f' % (float(input_data.microsecond) / 1000000))[2:], - ) - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - return _svalue - @classmethod - def gds_parse_datetime(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - time_parts = input_data.split('.') - if len(time_parts) > 1: - micro_seconds = int(float('0.' + time_parts[1]) * 1000000) - input_data = '%s.%s' % (time_parts[0], micro_seconds, ) - dt = datetime_.datetime.strptime( - input_data, '%Y-%m-%dT%H:%M:%S.%f') - else: - dt = datetime_.datetime.strptime( - input_data, '%Y-%m-%dT%H:%M:%S') - dt = dt.replace(tzinfo=tz) - return dt - def gds_validate_date(self, input_data, node, input_name=''): - return input_data - def gds_format_date(self, input_data, input_name=''): - _svalue = '%04d-%02d-%02d' % ( - input_data.year, - input_data.month, - input_data.day, - ) - try: - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - except AttributeError: - pass - return _svalue - @classmethod - def gds_parse_date(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - dt = datetime_.datetime.strptime(input_data, '%Y-%m-%d') - dt = dt.replace(tzinfo=tz) - return dt.date() - def gds_validate_time(self, input_data, node, input_name=''): - return input_data - def gds_format_time(self, input_data, input_name=''): - if input_data.microsecond == 0: - _svalue = '%02d:%02d:%02d' % ( - input_data.hour, - input_data.minute, - input_data.second, - ) - else: - _svalue = '%02d:%02d:%02d.%s' % ( - input_data.hour, - input_data.minute, - input_data.second, - ('%f' % (float(input_data.microsecond) / 1000000))[2:], - ) - if input_data.tzinfo is not None: - tzoff = input_data.tzinfo.utcoffset(input_data) - if tzoff is not None: - total_seconds = tzoff.seconds + (86400 * tzoff.days) - if total_seconds == 0: - _svalue += 'Z' - else: - if total_seconds < 0: - _svalue += '-' - total_seconds *= -1 - else: - _svalue += '+' - hours = total_seconds // 3600 - minutes = (total_seconds - (hours * 3600)) // 60 - _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) - return _svalue - @classmethod - def gds_parse_time(cls, input_data): - tz = None - if input_data[-1] == 'Z': - tz = GeneratedsSuper._FixedOffsetTZ(0, 'UTC') - input_data = input_data[:-1] - else: - results = GeneratedsSuper.tzoff_pattern.search(input_data) - if results is not None: - tzoff_parts = results.group(2).split(':') - tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) - if results.group(1) == '-': - tzoff *= -1 - tz = GeneratedsSuper._FixedOffsetTZ( - tzoff, results.group(0)) - input_data = input_data[:-6] - if len(input_data.split('.')) > 1: - dt = datetime_.datetime.strptime(input_data, '%H:%M:%S.%f') - else: - dt = datetime_.datetime.strptime(input_data, '%H:%M:%S') - dt = dt.replace(tzinfo=tz) - return dt.time() - def gds_str_lower(self, instring): - return instring.lower() - def get_path_(self, node): - path_list = [] - self.get_path_list_(node, path_list) - path_list.reverse() - path = '/'.join(path_list) - return path - Tag_strip_pattern_ = re_.compile(r'\{.*\}') - def get_path_list_(self, node, path_list): - if node is None: - return - tag = GeneratedsSuper.Tag_strip_pattern_.sub('', node.tag) - if tag: - path_list.append(tag) - self.get_path_list_(node.getparent(), path_list) - def get_class_obj_(self, node, default_class=None): - class_obj1 = default_class - if 'xsi' in node.nsmap: - classname = node.get('{%s}type' % node.nsmap['xsi']) - if classname is not None: - names = classname.split(':') - if len(names) == 2: - classname = names[1] - class_obj2 = globals().get(classname) - if class_obj2 is not None: - class_obj1 = class_obj2 - return class_obj1 - def gds_build_any(self, node, type_name=None): - return None - @classmethod - def gds_reverse_node_mapping(cls, mapping): - return dict(((v, k) for k, v in mapping.items())) - - -# -# If you have installed IPython you can uncomment and use the following. -# IPython is available from http://ipython.scipy.org/. -# - -## from IPython.Shell import IPShellEmbed -## args = '' -## ipshell = IPShellEmbed(args, -## banner = 'Dropping into IPython', -## exit_msg = 'Leaving Interpreter, back to program.') - -# Then use the following line where and when you want to drop into the -# IPython shell: -# ipshell(' -- Entering ipshell.\nHit Ctrl-D to exit') - -# -# Globals -# - -ExternalEncoding = 'ascii' -Tag_pattern_ = re_.compile(r'({.*})?(.*)') -String_cleanup_pat_ = re_.compile(r"[\n\r\s]+") -Namespace_extract_pat_ = re_.compile(r'{(.*)}(.*)') - -# -# Support/utility functions. -# - - -def showIndent(outfile, level, pretty_print=True): - if pretty_print: - for idx in range(level): - outfile.write(' ') - - -def quote_xml(inStr): - if not inStr: - return '' - s1 = (isinstance(inStr, str) and inStr or - '%s' % inStr) - s1 = s1.replace('&', '&') - s1 = s1.replace('<', '<') - s1 = s1.replace('>', '>') - return s1 - - -def quote_attrib(inStr): - s1 = (isinstance(inStr, str) and inStr or - '%s' % inStr) - s1 = s1.replace('&', '&') - s1 = s1.replace('<', '<') - s1 = s1.replace('>', '>') - if '"' in s1: - if "'" in s1: - s1 = '"%s"' % s1.replace('"', """) - else: - s1 = "'%s'" % s1 - else: - s1 = '"%s"' % s1 - return s1 - - -def quote_python(inStr): - s1 = inStr - if s1.find("'") == -1: - if s1.find('\n') == -1: - return "'%s'" % s1 - else: - return "'''%s'''" % s1 - else: - if s1.find('"') != -1: - s1 = s1.replace('"', '\\"') - if s1.find('\n') == -1: - return '"%s"' % s1 - else: - return '"""%s"""' % s1 - - -def get_all_text_(node): - if node.text is not None: - text = node.text - else: - text = '' - for child in node: - if child.tail is not None: - text += child.tail - return text - - -def find_attr_value_(attr_name, node): - attrs = node.attrib - attr_parts = attr_name.split(':') - value = None - if len(attr_parts) == 1: - value = attrs.get(attr_name) - elif len(attr_parts) == 2: - prefix, name = attr_parts - namespace = node.nsmap.get(prefix) - if namespace is not None: - value = attrs.get('{%s}%s' % (namespace, name, )) - return value - - -class GDSParseError(Exception): - pass - - -def raise_parse_error(node, msg): - if XMLParser_import_library == XMLParser_import_lxml: - msg = '%s (element %s/line %d)' % ( - msg, node.tag, node.sourceline, ) - else: - msg = '%s (element %s)' % (msg, node.tag, ) - raise GDSParseError(msg) - - -class MixedContainer: - # Constants for category: - CategoryNone = 0 - CategoryText = 1 - CategorySimple = 2 - CategoryComplex = 3 - # Constants for content_type: - TypeNone = 0 - TypeText = 1 - TypeString = 2 - TypeInteger = 3 - TypeFloat = 4 - TypeDecimal = 5 - TypeDouble = 6 - TypeBoolean = 7 - TypeBase64 = 8 - def __init__(self, category, content_type, name, value): - self.category = category - self.content_type = content_type - self.name = name - self.value = value - def getCategory(self): - return self.category - def getContenttype(self, content_type): - return self.content_type - def getValue(self): - return self.value - def getName(self): - return self.name - def export(self, outfile, level, name, namespace, pretty_print=True): - if self.category == MixedContainer.CategoryText: - # Prevent exporting empty content as empty lines. - if self.value.strip(): - outfile.write(self.value) - elif self.category == MixedContainer.CategorySimple: - self.exportSimple(outfile, level, name) - else: # category == MixedContainer.CategoryComplex - self.value.export(outfile, level, namespace, name, pretty_print) - def exportSimple(self, outfile, level, name): - if self.content_type == MixedContainer.TypeString: - outfile.write('<%s>%s' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeInteger or \ - self.content_type == MixedContainer.TypeBoolean: - outfile.write('<%s>%d' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeFloat or \ - self.content_type == MixedContainer.TypeDecimal: - outfile.write('<%s>%f' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeDouble: - outfile.write('<%s>%g' % ( - self.name, self.value, self.name)) - elif self.content_type == MixedContainer.TypeBase64: - outfile.write('<%s>%s' % ( - self.name, base64.b64encode(self.value), self.name)) - def to_etree(self, element): - if self.category == MixedContainer.CategoryText: - # Prevent exporting empty content as empty lines. - if self.value.strip(): - if len(element) > 0: - if element[-1].tail is None: - element[-1].tail = self.value - else: - element[-1].tail += self.value - else: - if element.text is None: - element.text = self.value - else: - element.text += self.value - elif self.category == MixedContainer.CategorySimple: - subelement = etree_.SubElement(element, '%s' % self.name) - subelement.text = self.to_etree_simple() - else: # category == MixedContainer.CategoryComplex - self.value.to_etree(element) - def to_etree_simple(self): - if self.content_type == MixedContainer.TypeString: - text = self.value - elif (self.content_type == MixedContainer.TypeInteger or - self.content_type == MixedContainer.TypeBoolean): - text = '%d' % self.value - elif (self.content_type == MixedContainer.TypeFloat or - self.content_type == MixedContainer.TypeDecimal): - text = '%f' % self.value - elif self.content_type == MixedContainer.TypeDouble: - text = '%g' % self.value - elif self.content_type == MixedContainer.TypeBase64: - text = '%s' % base64.b64encode(self.value) - return text - def exportLiteral(self, outfile, level, name): - if self.category == MixedContainer.CategoryText: - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( - self.category, self.content_type, self.name, self.value)) - elif self.category == MixedContainer.CategorySimple: - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s", "%s"),\n' % ( - self.category, self.content_type, self.name, self.value)) - else: # category == MixedContainer.CategoryComplex - showIndent(outfile, level) - outfile.write( - 'model_.MixedContainer(%d, %d, "%s",\n' % ( - self.category, self.content_type, self.name,)) - self.value.exportLiteral(outfile, level + 1) - showIndent(outfile, level) - outfile.write(')\n') - - -class MemberSpec_: - def __init__(self, name='', data_type='', container=0): - self.name = name - self.data_type = data_type - self.container = container - def set_name(self, name): self.name = name - def get_name(self): return self.name - def set_data_type(self, data_type): self.data_type = data_type - def get_data_type_chain(self): return self.data_type - def get_data_type(self): - if isinstance(self.data_type, list): - if len(self.data_type) > 0: - return self.data_type[-1] - else: - return 'xs:string' - else: - return self.data_type - def set_container(self, container): self.container = container - def get_container(self): return self.container - - -def _cast(typ, value): - if typ is None or value is None: - return value - return typ(value) - -# -# Data representation classes. -# - - -class Temperature(GeneratedsSuper): - """Specification of a temperature.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, subject=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.subject = subject - self.value = value - def factory(*args_, **kwargs_): - if Temperature.subclass: - return Temperature.subclass(*args_, **kwargs_) - else: - return Temperature(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_subject(self): return self.subject - def set_subject(self, subject): self.subject = subject - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_Int16(self, value): - # Validate type Int16, a restriction on xs:short. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.subject is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Temperature', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Temperature') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Temperature', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Temperature'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='Temperature', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.subject is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssubject>%s%s' % (namespace_, self.gds_format_integer(self.subject, input_name='subject'), namespace_, eol_)) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Temperature'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.subject is not None: - showIndent(outfile, level) - outfile.write('subject=%d,\n' % self.subject) - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'subject': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'subject') - self.subject = ival_ - self.validate_UInt8(self.subject) # validate type UInt8 - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int16(self.value) # validate type Int16 -# end class Temperature - - -class Condition(GeneratedsSuper): - """Indicates a condition that must be satisfied for the Notification to - be triggered.""" - subclass = None - superclass = None - def __init__(self, attributeIdentifier=None, lowerThreshold=None, upperThreshold=None): - self.original_tagname_ = None - self.attributeIdentifier = attributeIdentifier - self.lowerThreshold = lowerThreshold - self.upperThreshold = upperThreshold - def factory(*args_, **kwargs_): - if Condition.subclass: - return Condition.subclass(*args_, **kwargs_) - else: - return Condition(*args_, **kwargs_) - factory = staticmethod(factory) - def get_attributeIdentifier(self): return self.attributeIdentifier - def set_attributeIdentifier(self, attributeIdentifier): self.attributeIdentifier = attributeIdentifier - def get_lowerThreshold(self): return self.lowerThreshold - def set_lowerThreshold(self, lowerThreshold): self.lowerThreshold = lowerThreshold - def get_upperThreshold(self): return self.upperThreshold - def set_upperThreshold(self, upperThreshold): self.upperThreshold = upperThreshold - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_Int48(self, value): - # Validate type Int48, a restriction on xs:long. - pass - def hasContent_(self): - if ( - self.attributeIdentifier is not None or - self.lowerThreshold is not None or - self.upperThreshold is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Condition', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Condition') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Condition', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Condition'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='Condition', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.attributeIdentifier is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sattributeIdentifier>%s%s' % (namespace_, self.gds_format_integer(self.attributeIdentifier, input_name='attributeIdentifier'), namespace_, eol_)) - if self.lowerThreshold is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slowerThreshold>%s%s' % (namespace_, self.gds_format_integer(self.lowerThreshold, input_name='lowerThreshold'), namespace_, eol_)) - if self.upperThreshold is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%supperThreshold>%s%s' % (namespace_, self.gds_format_integer(self.upperThreshold, input_name='upperThreshold'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Condition'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.attributeIdentifier is not None: - showIndent(outfile, level) - outfile.write('attributeIdentifier=%d,\n' % self.attributeIdentifier) - if self.lowerThreshold is not None: - showIndent(outfile, level) - outfile.write('lowerThreshold=%d,\n' % self.lowerThreshold) - if self.upperThreshold is not None: - showIndent(outfile, level) - outfile.write('upperThreshold=%d,\n' % self.upperThreshold) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'attributeIdentifier': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'attributeIdentifier') - self.attributeIdentifier = ival_ - self.validate_UInt8(self.attributeIdentifier) # validate type UInt8 - elif nodeName_ == 'lowerThreshold': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'lowerThreshold') - self.lowerThreshold = ival_ - self.validate_Int48(self.lowerThreshold) # validate type Int48 - elif nodeName_ == 'upperThreshold': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'upperThreshold') - self.upperThreshold = ival_ - self.validate_Int48(self.upperThreshold) # validate type Int48 -# end class Condition - - -class AppliedTargetReduction(GeneratedsSuper): - """Specifies the value of the TargetReduction applied by the device.""" - subclass = None - superclass = None - def __init__(self, type_=None, value=None): - self.original_tagname_ = None - self.type_ = type_ - self.value = value - def factory(*args_, **kwargs_): - if AppliedTargetReduction.subclass: - return AppliedTargetReduction.subclass(*args_, **kwargs_) - else: - return AppliedTargetReduction(*args_, **kwargs_) - factory = staticmethod(factory) - def get_type(self): return self.type_ - def set_type(self, type_): self.type_ = type_ - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.type_ is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AppliedTargetReduction', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AppliedTargetReduction') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AppliedTargetReduction', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AppliedTargetReduction'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='AppliedTargetReduction', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.type_ is not None: - self.type_.export(outfile, level, namespace_, name_='type', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='AppliedTargetReduction'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.type_ is not None: - showIndent(outfile, level) - outfile.write('type_=model_.UnitType(\n') - self.type_.exportLiteral(outfile, level, name_='type') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'type': - obj_ = UnitType.factory() - obj_.build(child_) - self.type_ = obj_ - obj_.original_tagname_ = 'type' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt16(self.value) # validate type UInt16 -# end class AppliedTargetReduction - - -class DRLCCapabilities(GeneratedsSuper): - """Contains information about the static capabilities of the device, to - allow service providers to know what types of functions are - supported, what the normal operating ranges and limits are, and - other similar information, in order to provide better - suggestions of applicable programs to receive the maximum - benefit.""" - subclass = None - superclass = None - def __init__(self, averageEnergy=None, maxDemand=None, optionsImplemented=None): - self.original_tagname_ = None - self.averageEnergy = averageEnergy - self.maxDemand = maxDemand - self.optionsImplemented = optionsImplemented - def factory(*args_, **kwargs_): - if DRLCCapabilities.subclass: - return DRLCCapabilities.subclass(*args_, **kwargs_) - else: - return DRLCCapabilities(*args_, **kwargs_) - factory = staticmethod(factory) - def get_averageEnergy(self): return self.averageEnergy - def set_averageEnergy(self, averageEnergy): self.averageEnergy = averageEnergy - def get_maxDemand(self): return self.maxDemand - def set_maxDemand(self, maxDemand): self.maxDemand = maxDemand - def get_optionsImplemented(self): return self.optionsImplemented - def set_optionsImplemented(self, optionsImplemented): self.optionsImplemented = optionsImplemented - def validate_HexBinary32(self, value): - # Validate type HexBinary32, a restriction on xs:hexBinary. - pass - def hasContent_(self): - if ( - self.averageEnergy is not None or - self.maxDemand is not None or - self.optionsImplemented is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DRLCCapabilities', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DRLCCapabilities') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DRLCCapabilities', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DRLCCapabilities'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DRLCCapabilities', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.averageEnergy is not None: - self.averageEnergy.export(outfile, level, namespace_, name_='averageEnergy', pretty_print=pretty_print) - if self.maxDemand is not None: - self.maxDemand.export(outfile, level, namespace_, name_='maxDemand', pretty_print=pretty_print) - if self.optionsImplemented is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%soptionsImplemented>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.optionsImplemented).encode(ExternalEncoding), input_name='optionsImplemented'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='DRLCCapabilities'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.averageEnergy is not None: - showIndent(outfile, level) - outfile.write('averageEnergy=model_.RealEnergy(\n') - self.averageEnergy.exportLiteral(outfile, level, name_='averageEnergy') - showIndent(outfile, level) - outfile.write('),\n') - if self.maxDemand is not None: - showIndent(outfile, level) - outfile.write('maxDemand=model_.ActivePower(\n') - self.maxDemand.exportLiteral(outfile, level, name_='maxDemand') - showIndent(outfile, level) - outfile.write('),\n') - if self.optionsImplemented is not None: - showIndent(outfile, level) - outfile.write('optionsImplemented=%s,\n' % quote_python(self.optionsImplemented).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'averageEnergy': - obj_ = RealEnergy.factory() - obj_.build(child_) - self.averageEnergy = obj_ - obj_.original_tagname_ = 'averageEnergy' - elif nodeName_ == 'maxDemand': - obj_ = ActivePower.factory() - obj_.build(child_) - self.maxDemand = obj_ - obj_.original_tagname_ = 'maxDemand' - elif nodeName_ == 'optionsImplemented': - optionsImplemented_ = child_.text - optionsImplemented_ = self.gds_validate_string(optionsImplemented_, node, 'optionsImplemented') - self.optionsImplemented = optionsImplemented_ - self.validate_HexBinary32(self.optionsImplemented) # validate type HexBinary32 -# end class DRLCCapabilities - - -class PowerSourceType(GeneratedsSuper): - """0 - none 1 - mains 2 - battery 3 - local generation 4 - emergency 5 - - unknown All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PowerSourceType.subclass: - return PowerSourceType.subclass(*args_, **kwargs_) - else: - return PowerSourceType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PowerSourceType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PowerSourceType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PowerSourceType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PowerSourceType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PowerSourceType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PowerSourceType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PowerSourceType - - -class PEVInfo(GeneratedsSuper): - """Contains attributes that can be exposed by PEVs and other devices - that have charging requirements.""" - subclass = None - superclass = None - def __init__(self, chargingPowerNow=None, energyRequestNow=None, maxForwardPower=None, minimumChargingDuration=None, targetStateOfCharge=None, timeChargeIsNeeded=None, timeChargingStatusPEV=None): - self.original_tagname_ = None - self.chargingPowerNow = chargingPowerNow - self.energyRequestNow = energyRequestNow - self.maxForwardPower = maxForwardPower - self.minimumChargingDuration = minimumChargingDuration - self.targetStateOfCharge = targetStateOfCharge - self.timeChargeIsNeeded = timeChargeIsNeeded - self.timeChargingStatusPEV = timeChargingStatusPEV - def factory(*args_, **kwargs_): - if PEVInfo.subclass: - return PEVInfo.subclass(*args_, **kwargs_) - else: - return PEVInfo(*args_, **kwargs_) - factory = staticmethod(factory) - def get_chargingPowerNow(self): return self.chargingPowerNow - def set_chargingPowerNow(self, chargingPowerNow): self.chargingPowerNow = chargingPowerNow - def get_energyRequestNow(self): return self.energyRequestNow - def set_energyRequestNow(self, energyRequestNow): self.energyRequestNow = energyRequestNow - def get_maxForwardPower(self): return self.maxForwardPower - def set_maxForwardPower(self, maxForwardPower): self.maxForwardPower = maxForwardPower - def get_minimumChargingDuration(self): return self.minimumChargingDuration - def set_minimumChargingDuration(self, minimumChargingDuration): self.minimumChargingDuration = minimumChargingDuration - def get_targetStateOfCharge(self): return self.targetStateOfCharge - def set_targetStateOfCharge(self, targetStateOfCharge): self.targetStateOfCharge = targetStateOfCharge - def get_timeChargeIsNeeded(self): return self.timeChargeIsNeeded - def set_timeChargeIsNeeded(self, timeChargeIsNeeded): self.timeChargeIsNeeded = timeChargeIsNeeded - def get_timeChargingStatusPEV(self): return self.timeChargingStatusPEV - def set_timeChargingStatusPEV(self, timeChargingStatusPEV): self.timeChargingStatusPEV = timeChargingStatusPEV - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def hasContent_(self): - if ( - self.chargingPowerNow is not None or - self.energyRequestNow is not None or - self.maxForwardPower is not None or - self.minimumChargingDuration is not None or - self.targetStateOfCharge is not None or - self.timeChargeIsNeeded is not None or - self.timeChargingStatusPEV is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PEVInfo', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PEVInfo') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PEVInfo', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PEVInfo'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PEVInfo', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.chargingPowerNow is not None: - self.chargingPowerNow.export(outfile, level, namespace_, name_='chargingPowerNow', pretty_print=pretty_print) - if self.energyRequestNow is not None: - self.energyRequestNow.export(outfile, level, namespace_, name_='energyRequestNow', pretty_print=pretty_print) - if self.maxForwardPower is not None: - self.maxForwardPower.export(outfile, level, namespace_, name_='maxForwardPower', pretty_print=pretty_print) - if self.minimumChargingDuration is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sminimumChargingDuration>%s%s' % (namespace_, self.gds_format_integer(self.minimumChargingDuration, input_name='minimumChargingDuration'), namespace_, eol_)) - if self.targetStateOfCharge is not None: - self.targetStateOfCharge.export(outfile, level, namespace_, name_='targetStateOfCharge', pretty_print=pretty_print) - if self.timeChargeIsNeeded is not None: - self.timeChargeIsNeeded.export(outfile, level, namespace_, name_='timeChargeIsNeeded', pretty_print=pretty_print) - if self.timeChargingStatusPEV is not None: - self.timeChargingStatusPEV.export(outfile, level, namespace_, name_='timeChargingStatusPEV', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='PEVInfo'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.chargingPowerNow is not None: - showIndent(outfile, level) - outfile.write('chargingPowerNow=model_.ActivePower(\n') - self.chargingPowerNow.exportLiteral(outfile, level, name_='chargingPowerNow') - showIndent(outfile, level) - outfile.write('),\n') - if self.energyRequestNow is not None: - showIndent(outfile, level) - outfile.write('energyRequestNow=model_.RealEnergy(\n') - self.energyRequestNow.exportLiteral(outfile, level, name_='energyRequestNow') - showIndent(outfile, level) - outfile.write('),\n') - if self.maxForwardPower is not None: - showIndent(outfile, level) - outfile.write('maxForwardPower=model_.ActivePower(\n') - self.maxForwardPower.exportLiteral(outfile, level, name_='maxForwardPower') - showIndent(outfile, level) - outfile.write('),\n') - if self.minimumChargingDuration is not None: - showIndent(outfile, level) - outfile.write('minimumChargingDuration=%d,\n' % self.minimumChargingDuration) - if self.targetStateOfCharge is not None: - showIndent(outfile, level) - outfile.write('targetStateOfCharge=model_.PerCent(\n') - self.targetStateOfCharge.exportLiteral(outfile, level, name_='targetStateOfCharge') - showIndent(outfile, level) - outfile.write('),\n') - if self.timeChargeIsNeeded is not None: - showIndent(outfile, level) - outfile.write('timeChargeIsNeeded=model_.TimeType(\n') - self.timeChargeIsNeeded.exportLiteral(outfile, level, name_='timeChargeIsNeeded') - showIndent(outfile, level) - outfile.write('),\n') - if self.timeChargingStatusPEV is not None: - showIndent(outfile, level) - outfile.write('timeChargingStatusPEV=model_.TimeType(\n') - self.timeChargingStatusPEV.exportLiteral(outfile, level, name_='timeChargingStatusPEV') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'chargingPowerNow': - obj_ = ActivePower.factory() - obj_.build(child_) - self.chargingPowerNow = obj_ - obj_.original_tagname_ = 'chargingPowerNow' - elif nodeName_ == 'energyRequestNow': - obj_ = RealEnergy.factory() - obj_.build(child_) - self.energyRequestNow = obj_ - obj_.original_tagname_ = 'energyRequestNow' - elif nodeName_ == 'maxForwardPower': - obj_ = ActivePower.factory() - obj_.build(child_) - self.maxForwardPower = obj_ - obj_.original_tagname_ = 'maxForwardPower' - elif nodeName_ == 'minimumChargingDuration': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'minimumChargingDuration') - self.minimumChargingDuration = ival_ - self.validate_UInt32(self.minimumChargingDuration) # validate type UInt32 - elif nodeName_ == 'targetStateOfCharge': - obj_ = PerCent.factory() - obj_.build(child_) - self.targetStateOfCharge = obj_ - obj_.original_tagname_ = 'targetStateOfCharge' - elif nodeName_ == 'timeChargeIsNeeded': - obj_ = TimeType.factory() - obj_.build(child_) - self.timeChargeIsNeeded = obj_ - obj_.original_tagname_ = 'timeChargeIsNeeded' - elif nodeName_ == 'timeChargingStatusPEV': - obj_ = TimeType.factory() - obj_.build(child_) - self.timeChargingStatusPEV = obj_ - obj_.original_tagname_ = 'timeChargingStatusPEV' -# end class PEVInfo - - -class IEEE_802_15_4(GeneratedsSuper): - """Contains 802.15.4 link layer specific attributes.""" - subclass = None - superclass = None - def __init__(self, capabilityInfo=None, NeighborListLink=None, shortAddress=None): - self.original_tagname_ = None - self.capabilityInfo = capabilityInfo - self.NeighborListLink = NeighborListLink - self.shortAddress = shortAddress - def factory(*args_, **kwargs_): - if IEEE_802_15_4.subclass: - return IEEE_802_15_4.subclass(*args_, **kwargs_) - else: - return IEEE_802_15_4(*args_, **kwargs_) - factory = staticmethod(factory) - def get_capabilityInfo(self): return self.capabilityInfo - def set_capabilityInfo(self, capabilityInfo): self.capabilityInfo = capabilityInfo - def get_NeighborListLink(self): return self.NeighborListLink - def set_NeighborListLink(self, NeighborListLink): self.NeighborListLink = NeighborListLink - def get_shortAddress(self): return self.shortAddress - def set_shortAddress(self, shortAddress): self.shortAddress = shortAddress - def validate_HexBinary8(self, value): - # Validate type HexBinary8, a restriction on xs:hexBinary. - pass - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.capabilityInfo is not None or - self.NeighborListLink is not None or - self.shortAddress is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='IEEE_802_15_4', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='IEEE_802_15_4') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='IEEE_802_15_4', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='IEEE_802_15_4'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='IEEE_802_15_4', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.capabilityInfo is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%scapabilityInfo>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.capabilityInfo).encode(ExternalEncoding), input_name='capabilityInfo'), namespace_, eol_)) - if self.NeighborListLink is not None: - self.NeighborListLink.export(outfile, level, namespace_, name_='NeighborListLink', pretty_print=pretty_print) - if self.shortAddress is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sshortAddress>%s%s' % (namespace_, self.gds_format_integer(self.shortAddress, input_name='shortAddress'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='IEEE_802_15_4'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.capabilityInfo is not None: - showIndent(outfile, level) - outfile.write('capabilityInfo=%s,\n' % quote_python(self.capabilityInfo).encode(ExternalEncoding)) - if self.NeighborListLink is not None: - showIndent(outfile, level) - outfile.write('NeighborListLink=model_.NeighborListLink(\n') - self.NeighborListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.shortAddress is not None: - showIndent(outfile, level) - outfile.write('shortAddress=%d,\n' % self.shortAddress) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'capabilityInfo': - capabilityInfo_ = child_.text - capabilityInfo_ = self.gds_validate_string(capabilityInfo_, node, 'capabilityInfo') - self.capabilityInfo = capabilityInfo_ - self.validate_HexBinary8(self.capabilityInfo) # validate type HexBinary8 - elif nodeName_ == 'NeighborListLink': - obj_ = NeighborListLink.factory() - obj_.build(child_) - self.NeighborListLink = obj_ - obj_.original_tagname_ = 'NeighborListLink' - elif nodeName_ == 'shortAddress': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'shortAddress') - self.shortAddress = ival_ - self.validate_UInt16(self.shortAddress) # validate type UInt16 -# end class IEEE_802_15_4 - - -class loWPAN(GeneratedsSuper): - """Contains information specific to 6LoWPAN.""" - subclass = None - superclass = None - def __init__(self, octetsRx=None, octetsTx=None, packetsRx=None, packetsTx=None, rxFragError=None): - self.original_tagname_ = None - self.octetsRx = octetsRx - self.octetsTx = octetsTx - self.packetsRx = packetsRx - self.packetsTx = packetsTx - self.rxFragError = rxFragError - def factory(*args_, **kwargs_): - if loWPAN.subclass: - return loWPAN.subclass(*args_, **kwargs_) - else: - return loWPAN(*args_, **kwargs_) - factory = staticmethod(factory) - def get_octetsRx(self): return self.octetsRx - def set_octetsRx(self, octetsRx): self.octetsRx = octetsRx - def get_octetsTx(self): return self.octetsTx - def set_octetsTx(self, octetsTx): self.octetsTx = octetsTx - def get_packetsRx(self): return self.packetsRx - def set_packetsRx(self, packetsRx): self.packetsRx = packetsRx - def get_packetsTx(self): return self.packetsTx - def set_packetsTx(self, packetsTx): self.packetsTx = packetsTx - def get_rxFragError(self): return self.rxFragError - def set_rxFragError(self, rxFragError): self.rxFragError = rxFragError - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def hasContent_(self): - if ( - self.octetsRx is not None or - self.octetsTx is not None or - self.packetsRx is not None or - self.packetsTx is not None or - self.rxFragError is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='loWPAN', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='loWPAN') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='loWPAN', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='loWPAN'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='loWPAN', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.octetsRx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%soctetsRx>%s%s' % (namespace_, self.gds_format_integer(self.octetsRx, input_name='octetsRx'), namespace_, eol_)) - if self.octetsTx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%soctetsTx>%s%s' % (namespace_, self.gds_format_integer(self.octetsTx, input_name='octetsTx'), namespace_, eol_)) - if self.packetsRx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%spacketsRx>%s%s' % (namespace_, self.gds_format_integer(self.packetsRx, input_name='packetsRx'), namespace_, eol_)) - if self.packetsTx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%spacketsTx>%s%s' % (namespace_, self.gds_format_integer(self.packetsTx, input_name='packetsTx'), namespace_, eol_)) - if self.rxFragError is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srxFragError>%s%s' % (namespace_, self.gds_format_integer(self.rxFragError, input_name='rxFragError'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='loWPAN'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.octetsRx is not None: - showIndent(outfile, level) - outfile.write('octetsRx=%d,\n' % self.octetsRx) - if self.octetsTx is not None: - showIndent(outfile, level) - outfile.write('octetsTx=%d,\n' % self.octetsTx) - if self.packetsRx is not None: - showIndent(outfile, level) - outfile.write('packetsRx=%d,\n' % self.packetsRx) - if self.packetsTx is not None: - showIndent(outfile, level) - outfile.write('packetsTx=%d,\n' % self.packetsTx) - if self.rxFragError is not None: - showIndent(outfile, level) - outfile.write('rxFragError=%d,\n' % self.rxFragError) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'octetsRx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'octetsRx') - self.octetsRx = ival_ - self.validate_UInt32(self.octetsRx) # validate type UInt32 - elif nodeName_ == 'octetsTx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'octetsTx') - self.octetsTx = ival_ - self.validate_UInt32(self.octetsTx) # validate type UInt32 - elif nodeName_ == 'packetsRx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'packetsRx') - self.packetsRx = ival_ - self.validate_UInt32(self.packetsRx) # validate type UInt32 - elif nodeName_ == 'packetsTx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'packetsTx') - self.packetsTx = ival_ - self.validate_UInt32(self.packetsTx) # validate type UInt32 - elif nodeName_ == 'rxFragError': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'rxFragError') - self.rxFragError = ival_ - self.validate_UInt32(self.rxFragError) # validate type UInt32 -# end class loWPAN - - -class PowerConfiguration(GeneratedsSuper): - """Contains configuration related to the device's power sources""" - subclass = None - superclass = None - def __init__(self, batteryInstallTime=None, lowChargeThreshold=None): - self.original_tagname_ = None - self.batteryInstallTime = batteryInstallTime - self.lowChargeThreshold = lowChargeThreshold - def factory(*args_, **kwargs_): - if PowerConfiguration.subclass: - return PowerConfiguration.subclass(*args_, **kwargs_) - else: - return PowerConfiguration(*args_, **kwargs_) - factory = staticmethod(factory) - def get_batteryInstallTime(self): return self.batteryInstallTime - def set_batteryInstallTime(self, batteryInstallTime): self.batteryInstallTime = batteryInstallTime - def get_lowChargeThreshold(self): return self.lowChargeThreshold - def set_lowChargeThreshold(self, lowChargeThreshold): self.lowChargeThreshold = lowChargeThreshold - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def hasContent_(self): - if ( - self.batteryInstallTime is not None or - self.lowChargeThreshold is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PowerConfiguration', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PowerConfiguration') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PowerConfiguration', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PowerConfiguration'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PowerConfiguration', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.batteryInstallTime is not None: - self.batteryInstallTime.export(outfile, level, namespace_, name_='batteryInstallTime', pretty_print=pretty_print) - if self.lowChargeThreshold is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slowChargeThreshold>%s%s' % (namespace_, self.gds_format_integer(self.lowChargeThreshold, input_name='lowChargeThreshold'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='PowerConfiguration'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.batteryInstallTime is not None: - showIndent(outfile, level) - outfile.write('batteryInstallTime=model_.TimeType(\n') - self.batteryInstallTime.exportLiteral(outfile, level, name_='batteryInstallTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.lowChargeThreshold is not None: - showIndent(outfile, level) - outfile.write('lowChargeThreshold=%d,\n' % self.lowChargeThreshold) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'batteryInstallTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.batteryInstallTime = obj_ - obj_.original_tagname_ = 'batteryInstallTime' - elif nodeName_ == 'lowChargeThreshold': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'lowChargeThreshold') - self.lowChargeThreshold = ival_ - self.validate_UInt32(self.lowChargeThreshold) # validate type UInt32 -# end class PowerConfiguration - - -class TimeConfiguration(GeneratedsSuper): - """Contains attributes related to the configuration of the time - service.""" - subclass = None - superclass = None - def __init__(self, dstEndRule=None, dstOffset=None, dstStartRule=None, tzOffset=None): - self.original_tagname_ = None - self.dstEndRule = dstEndRule - self.dstOffset = dstOffset - self.dstStartRule = dstStartRule - self.tzOffset = tzOffset - def factory(*args_, **kwargs_): - if TimeConfiguration.subclass: - return TimeConfiguration.subclass(*args_, **kwargs_) - else: - return TimeConfiguration(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dstEndRule(self): return self.dstEndRule - def set_dstEndRule(self, dstEndRule): self.dstEndRule = dstEndRule - def get_dstOffset(self): return self.dstOffset - def set_dstOffset(self, dstOffset): self.dstOffset = dstOffset - def get_dstStartRule(self): return self.dstStartRule - def set_dstStartRule(self, dstStartRule): self.dstStartRule = dstStartRule - def get_tzOffset(self): return self.tzOffset - def set_tzOffset(self, tzOffset): self.tzOffset = tzOffset - def hasContent_(self): - if ( - self.dstEndRule is not None or - self.dstOffset is not None or - self.dstStartRule is not None or - self.tzOffset is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TimeConfiguration', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TimeConfiguration') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TimeConfiguration', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TimeConfiguration'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='TimeConfiguration', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dstEndRule is not None: - self.dstEndRule.export(outfile, level, namespace_, name_='dstEndRule', pretty_print=pretty_print) - if self.dstOffset is not None: - self.dstOffset.export(outfile, level, namespace_, name_='dstOffset', pretty_print=pretty_print) - if self.dstStartRule is not None: - self.dstStartRule.export(outfile, level, namespace_, name_='dstStartRule', pretty_print=pretty_print) - if self.tzOffset is not None: - self.tzOffset.export(outfile, level, namespace_, name_='tzOffset', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='TimeConfiguration'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dstEndRule is not None: - showIndent(outfile, level) - outfile.write('dstEndRule=model_.DstRuleType(\n') - self.dstEndRule.exportLiteral(outfile, level, name_='dstEndRule') - showIndent(outfile, level) - outfile.write('),\n') - if self.dstOffset is not None: - showIndent(outfile, level) - outfile.write('dstOffset=model_.TimeOffsetType(\n') - self.dstOffset.exportLiteral(outfile, level, name_='dstOffset') - showIndent(outfile, level) - outfile.write('),\n') - if self.dstStartRule is not None: - showIndent(outfile, level) - outfile.write('dstStartRule=model_.DstRuleType(\n') - self.dstStartRule.exportLiteral(outfile, level, name_='dstStartRule') - showIndent(outfile, level) - outfile.write('),\n') - if self.tzOffset is not None: - showIndent(outfile, level) - outfile.write('tzOffset=model_.TimeOffsetType(\n') - self.tzOffset.exportLiteral(outfile, level, name_='tzOffset') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dstEndRule': - obj_ = DstRuleType.factory() - obj_.build(child_) - self.dstEndRule = obj_ - obj_.original_tagname_ = 'dstEndRule' - elif nodeName_ == 'dstOffset': - obj_ = TimeOffsetType.factory() - obj_.build(child_) - self.dstOffset = obj_ - obj_.original_tagname_ = 'dstOffset' - elif nodeName_ == 'dstStartRule': - obj_ = DstRuleType.factory() - obj_.build(child_) - self.dstStartRule = obj_ - obj_.original_tagname_ = 'dstStartRule' - elif nodeName_ == 'tzOffset': - obj_ = TimeOffsetType.factory() - obj_.build(child_) - self.tzOffset = obj_ - obj_.original_tagname_ = 'tzOffset' -# end class TimeConfiguration - - -class ApplianceLoadReduction(GeneratedsSuper): - """The ApplianceLoadReduction object is used by a Demand Response - service provider to provide signals for ENERGY STAR compliant - appliances. See the definition of ApplianceLoadReductionType for - more information.""" - subclass = None - superclass = None - def __init__(self, type_=None): - self.original_tagname_ = None - self.type_ = type_ - def factory(*args_, **kwargs_): - if ApplianceLoadReduction.subclass: - return ApplianceLoadReduction.subclass(*args_, **kwargs_) - else: - return ApplianceLoadReduction(*args_, **kwargs_) - factory = staticmethod(factory) - def get_type(self): return self.type_ - def set_type(self, type_): self.type_ = type_ - def hasContent_(self): - if ( - self.type_ is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ApplianceLoadReduction', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ApplianceLoadReduction') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ApplianceLoadReduction', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ApplianceLoadReduction'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ApplianceLoadReduction', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.type_ is not None: - self.type_.export(outfile, level, namespace_, name_='type', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ApplianceLoadReduction'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.type_ is not None: - showIndent(outfile, level) - outfile.write('type_=model_.ApplianceLoadReductionType(\n') - self.type_.exportLiteral(outfile, level, name_='type') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'type': - obj_ = ApplianceLoadReductionType.factory() - obj_.build(child_) - self.type_ = obj_ - obj_.original_tagname_ = 'type' -# end class ApplianceLoadReduction - - -class DutyCycle(GeneratedsSuper): - """Duty cycle control is a device specific issue and is managed by the - device. The duty cycle of the device under control should span - the shortest practical time period in accordance with the nature - of the device under control and the intent of the request for - demand reduction. The default factory setting SHOULD be three - minutes for each 10% of duty cycle. This indicates that the - default time period over which a duty cycle is applied is 30 - minutes, meaning a 10% duty cycle would cause a device to be ON - for 3 minutes. The “off state” SHALL precede the “on - state”.""" - subclass = None - superclass = None - def __init__(self, normalValue=None): - self.original_tagname_ = None - self.normalValue = normalValue - def factory(*args_, **kwargs_): - if DutyCycle.subclass: - return DutyCycle.subclass(*args_, **kwargs_) - else: - return DutyCycle(*args_, **kwargs_) - factory = staticmethod(factory) - def get_normalValue(self): return self.normalValue - def set_normalValue(self, normalValue): self.normalValue = normalValue - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.normalValue is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DutyCycle', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DutyCycle') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DutyCycle', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DutyCycle'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DutyCycle', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.normalValue is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%snormalValue>%s%s' % (namespace_, self.gds_format_integer(self.normalValue, input_name='normalValue'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='DutyCycle'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.normalValue is not None: - showIndent(outfile, level) - outfile.write('normalValue=%d,\n' % self.normalValue) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'normalValue': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'normalValue') - self.normalValue = ival_ - self.validate_UInt8(self.normalValue) # validate type UInt8 -# end class DutyCycle - - -class Offset(GeneratedsSuper): - """If a temperature offset is sent that causes the heating or cooling - temperature set point to exceed the limit boundaries that are - programmed into the device, the device SHALL respond by setting - the temperature at the limit. If an EDC is being targeted at - multiple devices or to a device that controls multiple devices - (e.g., EMS), it can provide multiple Offset types within one - EDC. For events with multiple Offset types, a client SHALL - select the Offset that best fits their operating function. - Alternatively, an event with a single Offset type can be - targeted at an EMS in order to request a percentage load - reduction on the average energy usage of the entire premise. An - EMS SHOULD use the Metering function set to determine the - initial load in the premise, reduce energy consumption by - controlling devices at its disposal, and at the conclusion of - the event, once again use the Metering function set to determine - if the desired load reduction was achieved.""" - subclass = None - superclass = None - def __init__(self, coolingOffset=None, heatingOffset=None, loadAdjustmentPercentageOffset=None): - self.original_tagname_ = None - self.coolingOffset = coolingOffset - self.heatingOffset = heatingOffset - self.loadAdjustmentPercentageOffset = loadAdjustmentPercentageOffset - def factory(*args_, **kwargs_): - if Offset.subclass: - return Offset.subclass(*args_, **kwargs_) - else: - return Offset(*args_, **kwargs_) - factory = staticmethod(factory) - def get_coolingOffset(self): return self.coolingOffset - def set_coolingOffset(self, coolingOffset): self.coolingOffset = coolingOffset - def get_heatingOffset(self): return self.heatingOffset - def set_heatingOffset(self, heatingOffset): self.heatingOffset = heatingOffset - def get_loadAdjustmentPercentageOffset(self): return self.loadAdjustmentPercentageOffset - def set_loadAdjustmentPercentageOffset(self, loadAdjustmentPercentageOffset): self.loadAdjustmentPercentageOffset = loadAdjustmentPercentageOffset - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.coolingOffset is not None or - self.heatingOffset is not None or - self.loadAdjustmentPercentageOffset is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Offset', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Offset') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Offset', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Offset'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='Offset', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.coolingOffset is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%scoolingOffset>%s%s' % (namespace_, self.gds_format_integer(self.coolingOffset, input_name='coolingOffset'), namespace_, eol_)) - if self.heatingOffset is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sheatingOffset>%s%s' % (namespace_, self.gds_format_integer(self.heatingOffset, input_name='heatingOffset'), namespace_, eol_)) - if self.loadAdjustmentPercentageOffset is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sloadAdjustmentPercentageOffset>%s%s' % (namespace_, self.gds_format_integer(self.loadAdjustmentPercentageOffset, input_name='loadAdjustmentPercentageOffset'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Offset'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.coolingOffset is not None: - showIndent(outfile, level) - outfile.write('coolingOffset=%d,\n' % self.coolingOffset) - if self.heatingOffset is not None: - showIndent(outfile, level) - outfile.write('heatingOffset=%d,\n' % self.heatingOffset) - if self.loadAdjustmentPercentageOffset is not None: - showIndent(outfile, level) - outfile.write('loadAdjustmentPercentageOffset=%d,\n' % self.loadAdjustmentPercentageOffset) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'coolingOffset': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'coolingOffset') - self.coolingOffset = ival_ - self.validate_UInt8(self.coolingOffset) # validate type UInt8 - elif nodeName_ == 'heatingOffset': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'heatingOffset') - self.heatingOffset = ival_ - self.validate_UInt8(self.heatingOffset) # validate type UInt8 - elif nodeName_ == 'loadAdjustmentPercentageOffset': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'loadAdjustmentPercentageOffset') - self.loadAdjustmentPercentageOffset = ival_ - self.validate_UInt8(self.loadAdjustmentPercentageOffset) # validate type UInt8 -# end class Offset - - -class SetPoint(GeneratedsSuper): - """The SetPoint object is used to apply specific temperature set points - to a temperature control device. The values of the - heatingSetpoint and coolingSetpoint attributes SHALL be - calculated as follows: Cooling/Heating Temperature Set Point / - 100 = temperature in degrees Celsius where -273.15°C <= - temperature <= 327.67°C, corresponding to a Cooling and/or - Heating Temperature Set Point. The maximum resolution this - format allows is 0.01°C. The field not present in a Response - indicates that this field has not been used by the end device. - If a temperature is sent that exceeds the temperature limit - boundaries that are programmed into the device, the device SHALL - respond by setting the temperature at the limit.""" - subclass = None - superclass = None - def __init__(self, coolingSetpoint=None, heatingSetpoint=None): - self.original_tagname_ = None - self.coolingSetpoint = coolingSetpoint - self.heatingSetpoint = heatingSetpoint - def factory(*args_, **kwargs_): - if SetPoint.subclass: - return SetPoint.subclass(*args_, **kwargs_) - else: - return SetPoint(*args_, **kwargs_) - factory = staticmethod(factory) - def get_coolingSetpoint(self): return self.coolingSetpoint - def set_coolingSetpoint(self, coolingSetpoint): self.coolingSetpoint = coolingSetpoint - def get_heatingSetpoint(self): return self.heatingSetpoint - def set_heatingSetpoint(self, heatingSetpoint): self.heatingSetpoint = heatingSetpoint - def validate_Int16(self, value): - # Validate type Int16, a restriction on xs:short. - pass - def hasContent_(self): - if ( - self.coolingSetpoint is not None or - self.heatingSetpoint is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SetPoint', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SetPoint') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SetPoint', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SetPoint'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='SetPoint', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.coolingSetpoint is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%scoolingSetpoint>%s%s' % (namespace_, self.gds_format_integer(self.coolingSetpoint, input_name='coolingSetpoint'), namespace_, eol_)) - if self.heatingSetpoint is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sheatingSetpoint>%s%s' % (namespace_, self.gds_format_integer(self.heatingSetpoint, input_name='heatingSetpoint'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='SetPoint'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.coolingSetpoint is not None: - showIndent(outfile, level) - outfile.write('coolingSetpoint=%d,\n' % self.coolingSetpoint) - if self.heatingSetpoint is not None: - showIndent(outfile, level) - outfile.write('heatingSetpoint=%d,\n' % self.heatingSetpoint) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'coolingSetpoint': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'coolingSetpoint') - self.coolingSetpoint = ival_ - self.validate_Int16(self.coolingSetpoint) # validate type Int16 - elif nodeName_ == 'heatingSetpoint': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'heatingSetpoint') - self.heatingSetpoint = ival_ - self.validate_Int16(self.heatingSetpoint) # validate type Int16 -# end class SetPoint - - -class TargetReduction(GeneratedsSuper): - """The TargetReduction object is used by a Demand Response service - provider to provide a RECOMMENDED threshold that a - device/premises should maintain its consumption below. For - example, a service provider can provide a RECOMMENDED threshold - of some kWh for a 3-hour event. This means that the - device/premises would maintain its consumption below the - specified limit for the specified period.""" - subclass = None - superclass = None - def __init__(self, type_=None, value=None): - self.original_tagname_ = None - self.type_ = type_ - self.value = value - def factory(*args_, **kwargs_): - if TargetReduction.subclass: - return TargetReduction.subclass(*args_, **kwargs_) - else: - return TargetReduction(*args_, **kwargs_) - factory = staticmethod(factory) - def get_type(self): return self.type_ - def set_type(self, type_): self.type_ = type_ - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.type_ is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TargetReduction', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TargetReduction') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TargetReduction', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TargetReduction'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='TargetReduction', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.type_ is not None: - self.type_.export(outfile, level, namespace_, name_='type', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='TargetReduction'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.type_ is not None: - showIndent(outfile, level) - outfile.write('type_=model_.UnitType(\n') - self.type_.exportLiteral(outfile, level, name_='type') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'type': - obj_ = UnitType.factory() - obj_.build(child_) - self.type_ = obj_ - obj_.original_tagname_ = 'type' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt16(self.value) # validate type UInt16 -# end class TargetReduction - - -class CostKindType(GeneratedsSuper): - """0 - Carbon Dioxide emissions, in grams per unit 1 - Sulfur Dioxide - emissions, in grams per unit 2 - Nitrogen Oxides emissions, in - grams per unit 3 - Renewable generation, as a percentage of - overall generation All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if CostKindType.subclass: - return CostKindType.subclass(*args_, **kwargs_) - else: - return CostKindType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CostKindType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CostKindType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='CostKindType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CostKindType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CostKindType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='CostKindType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class CostKindType - - -class EnvironmentalCost(GeneratedsSuper): - """Provides alternative or secondary price information for the relevant - RateComponent. Supports jurisdictions that seek to convey the - environmental price per unit of the specified commodity not - expressed in currency. Implementers and consumers can use this - attribute to prioritize operations of their HAN devices (e.g., - PEV charging during times of high availability of renewable - electricity resources).""" - subclass = None - superclass = None - def __init__(self, amount=None, costKind=None, costLevel=None, numCostLevels=None): - self.original_tagname_ = None - self.amount = amount - self.costKind = costKind - self.costLevel = costLevel - self.numCostLevels = numCostLevels - def factory(*args_, **kwargs_): - if EnvironmentalCost.subclass: - return EnvironmentalCost.subclass(*args_, **kwargs_) - else: - return EnvironmentalCost(*args_, **kwargs_) - factory = staticmethod(factory) - def get_amount(self): return self.amount - def set_amount(self, amount): self.amount = amount - def get_costKind(self): return self.costKind - def set_costKind(self, costKind): self.costKind = costKind - def get_costLevel(self): return self.costLevel - def set_costLevel(self, costLevel): self.costLevel = costLevel - def get_numCostLevels(self): return self.numCostLevels - def set_numCostLevels(self, numCostLevels): self.numCostLevels = numCostLevels - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.amount is not None or - self.costKind is not None or - self.costLevel is not None or - self.numCostLevels is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EnvironmentalCost', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EnvironmentalCost') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EnvironmentalCost', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EnvironmentalCost'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='EnvironmentalCost', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.amount is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%samount>%s%s' % (namespace_, self.gds_format_integer(self.amount, input_name='amount'), namespace_, eol_)) - if self.costKind is not None: - self.costKind.export(outfile, level, namespace_, name_='costKind', pretty_print=pretty_print) - if self.costLevel is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%scostLevel>%s%s' % (namespace_, self.gds_format_integer(self.costLevel, input_name='costLevel'), namespace_, eol_)) - if self.numCostLevels is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%snumCostLevels>%s%s' % (namespace_, self.gds_format_integer(self.numCostLevels, input_name='numCostLevels'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='EnvironmentalCost'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.amount is not None: - showIndent(outfile, level) - outfile.write('amount=%d,\n' % self.amount) - if self.costKind is not None: - showIndent(outfile, level) - outfile.write('costKind=model_.CostKindType(\n') - self.costKind.exportLiteral(outfile, level, name_='costKind') - showIndent(outfile, level) - outfile.write('),\n') - if self.costLevel is not None: - showIndent(outfile, level) - outfile.write('costLevel=%d,\n' % self.costLevel) - if self.numCostLevels is not None: - showIndent(outfile, level) - outfile.write('numCostLevels=%d,\n' % self.numCostLevels) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'amount': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'amount') - self.amount = ival_ - self.validate_UInt32(self.amount) # validate type UInt32 - elif nodeName_ == 'costKind': - obj_ = CostKindType.factory() - obj_.build(child_) - self.costKind = obj_ - obj_.original_tagname_ = 'costKind' - elif nodeName_ == 'costLevel': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'costLevel') - self.costLevel = ival_ - self.validate_UInt8(self.costLevel) # validate type UInt8 - elif nodeName_ == 'numCostLevels': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'numCostLevels') - self.numCostLevels = ival_ - self.validate_UInt8(self.numCostLevels) # validate type UInt8 -# end class EnvironmentalCost - - -class PriorityType(GeneratedsSuper): - """Indicates the priority of a message: 0 - Low 1 - Normal 2 - High 3 - - Critical All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PriorityType.subclass: - return PriorityType.subclass(*args_, **kwargs_) - else: - return PriorityType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PriorityType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PriorityType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PriorityType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PriorityType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PriorityType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PriorityType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PriorityType - - -class Charge(GeneratedsSuper): - """Charges contain charges on a customer bill. These could be items - like taxes, levies, surcharges, rebates, or others. This is - meant to allow the HAN device to retrieve enough information to - be able to reconstruct an estimate of what the total bill would - look like. Providers can provide line item billing, including - multiple charge kinds (e.g. taxes, surcharges) at whatever - granularity desired, using as many Charges as desired during a - billing period. There can also be any number of Charges - associated with different ReadingTypes to distinguish between - TOU tiers, consumption blocks, or demand charges.""" - subclass = None - superclass = None - def __init__(self, description=None, kind=None, value=None): - self.original_tagname_ = None - self.description = description - self.kind = kind - self.value = value - def factory(*args_, **kwargs_): - if Charge.subclass: - return Charge.subclass(*args_, **kwargs_) - else: - return Charge(*args_, **kwargs_) - factory = staticmethod(factory) - def get_description(self): return self.description - def set_description(self, description): self.description = description - def get_kind(self): return self.kind - def set_kind(self, kind): self.kind = kind - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_String20(self, value): - # Validate type String20, a restriction on xs:string. - pass - def validate_Int32(self, value): - # Validate type Int32, a restriction on xs:int. - pass - def hasContent_(self): - if ( - self.description is not None or - self.kind is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Charge', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Charge') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Charge', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Charge'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='Charge', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.description is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdescription>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.description).encode(ExternalEncoding), input_name='description'), namespace_, eol_)) - if self.kind is not None: - self.kind.export(outfile, level, namespace_, name_='kind', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Charge'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.description is not None: - showIndent(outfile, level) - outfile.write('description=%s,\n' % quote_python(self.description).encode(ExternalEncoding)) - if self.kind is not None: - showIndent(outfile, level) - outfile.write('kind=model_.ChargeKind(\n') - self.kind.exportLiteral(outfile, level, name_='kind') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'description': - description_ = child_.text - description_ = self.gds_validate_string(description_, node, 'description') - self.description = description_ - self.validate_String20(self.description) # validate type String20 - elif nodeName_ == 'kind': - obj_ = ChargeKind.factory() - obj_.build(child_) - self.kind = obj_ - obj_.original_tagname_ = 'kind' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int32(self.value) # validate type Int32 -# end class Charge - - -class ChargeKind(GeneratedsSuper): - """Kind of charge. 0 - Consumption Charge 1 - Rebate 2 - Auxiliary - Charge 3 - Demand Charge 4 - Tax Charge""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if ChargeKind.subclass: - return ChargeKind.subclass(*args_, **kwargs_) - else: - return ChargeKind(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ChargeKind', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ChargeKind') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='ChargeKind', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ChargeKind'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ChargeKind', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='ChargeKind'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class ChargeKind - - -class AccountingUnit(GeneratedsSuper): - """Unit for accounting; use either 'energyUnit' or 'currencyUnit' to - specify the unit for 'value'.""" - subclass = None - superclass = None - def __init__(self, energyUnit=None, monetaryUnit=None, multiplier=None, value=None): - self.original_tagname_ = None - self.energyUnit = energyUnit - self.monetaryUnit = monetaryUnit - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if AccountingUnit.subclass: - return AccountingUnit.subclass(*args_, **kwargs_) - else: - return AccountingUnit(*args_, **kwargs_) - factory = staticmethod(factory) - def get_energyUnit(self): return self.energyUnit - def set_energyUnit(self, energyUnit): self.energyUnit = energyUnit - def get_monetaryUnit(self): return self.monetaryUnit - def set_monetaryUnit(self, monetaryUnit): self.monetaryUnit = monetaryUnit - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_Int32(self, value): - # Validate type Int32, a restriction on xs:int. - pass - def hasContent_(self): - if ( - self.energyUnit is not None or - self.monetaryUnit is not None or - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AccountingUnit', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AccountingUnit') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AccountingUnit', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AccountingUnit'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='AccountingUnit', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.energyUnit is not None: - self.energyUnit.export(outfile, level, namespace_, name_='energyUnit', pretty_print=pretty_print) - if self.monetaryUnit is not None: - self.monetaryUnit.export(outfile, level, namespace_, name_='monetaryUnit', pretty_print=pretty_print) - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='AccountingUnit'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.energyUnit is not None: - showIndent(outfile, level) - outfile.write('energyUnit=model_.RealEnergy(\n') - self.energyUnit.exportLiteral(outfile, level, name_='energyUnit') - showIndent(outfile, level) - outfile.write('),\n') - if self.monetaryUnit is not None: - showIndent(outfile, level) - outfile.write('monetaryUnit=model_.CurrencyCode(\n') - self.monetaryUnit.exportLiteral(outfile, level, name_='monetaryUnit') - showIndent(outfile, level) - outfile.write('),\n') - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'energyUnit': - obj_ = RealEnergy.factory() - obj_.build(child_) - self.energyUnit = obj_ - obj_.original_tagname_ = 'energyUnit' - elif nodeName_ == 'monetaryUnit': - obj_ = CurrencyCode.factory() - obj_.build(child_) - self.monetaryUnit = obj_ - obj_.original_tagname_ = 'monetaryUnit' - elif nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int32(self.value) # validate type Int32 -# end class AccountingUnit - - -class PrepayModeType(GeneratedsSuper): - """0 - Central Wallet 1 - ESI 2 - Local 3 - Credit All other values - reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PrepayModeType.subclass: - return PrepayModeType.subclass(*args_, **kwargs_) - else: - return PrepayModeType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PrepayModeType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PrepayModeType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PrepayModeType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PrepayModeType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PrepayModeType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PrepayModeType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PrepayModeType - - -class ServiceChange(GeneratedsSuper): - """Specifies a change to the service status.""" - subclass = None - superclass = None - def __init__(self, newStatus=None, startTime=None): - self.original_tagname_ = None - self.newStatus = newStatus - self.startTime = startTime - def factory(*args_, **kwargs_): - if ServiceChange.subclass: - return ServiceChange.subclass(*args_, **kwargs_) - else: - return ServiceChange(*args_, **kwargs_) - factory = staticmethod(factory) - def get_newStatus(self): return self.newStatus - def set_newStatus(self, newStatus): self.newStatus = newStatus - def get_startTime(self): return self.startTime - def set_startTime(self, startTime): self.startTime = startTime - def hasContent_(self): - if ( - self.newStatus is not None or - self.startTime is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ServiceChange', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceChange') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ServiceChange', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ServiceChange'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ServiceChange', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.newStatus is not None: - self.newStatus.export(outfile, level, namespace_, name_='newStatus', pretty_print=pretty_print) - if self.startTime is not None: - self.startTime.export(outfile, level, namespace_, name_='startTime', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ServiceChange'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.newStatus is not None: - showIndent(outfile, level) - outfile.write('newStatus=model_.ServiceStatusType(\n') - self.newStatus.exportLiteral(outfile, level, name_='newStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.startTime is not None: - showIndent(outfile, level) - outfile.write('startTime=model_.TimeType(\n') - self.startTime.exportLiteral(outfile, level, name_='startTime') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'newStatus': - obj_ = ServiceStatusType.factory() - obj_.build(child_) - self.newStatus = obj_ - obj_.original_tagname_ = 'newStatus' - elif nodeName_ == 'startTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.startTime = obj_ - obj_.original_tagname_ = 'startTime' -# end class ServiceChange - - -class CreditStatusType(GeneratedsSuper): - """0 - Credit Ok 1 - Credit Low 2 - Credit Exhausted 3 - Credit - Negative All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if CreditStatusType.subclass: - return CreditStatusType.subclass(*args_, **kwargs_) - else: - return CreditStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CreditStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CreditStatusType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='CreditStatusType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CreditStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CreditStatusType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='CreditStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class CreditStatusType - - -class CreditTypeType(GeneratedsSuper): - """0 - Regular 1 - Emergency 2 - Regular, then Emergency 3 - Emergency, - then Regular All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if CreditTypeType.subclass: - return CreditTypeType.subclass(*args_, **kwargs_) - else: - return CreditTypeType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CreditTypeType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CreditTypeType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='CreditTypeType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CreditTypeType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CreditTypeType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='CreditTypeType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class CreditTypeType - - -class CreditTypeChange(GeneratedsSuper): - """Specifies a change to the credit type.""" - subclass = None - superclass = None - def __init__(self, newType=None, startTime=None): - self.original_tagname_ = None - self.newType = newType - self.startTime = startTime - def factory(*args_, **kwargs_): - if CreditTypeChange.subclass: - return CreditTypeChange.subclass(*args_, **kwargs_) - else: - return CreditTypeChange(*args_, **kwargs_) - factory = staticmethod(factory) - def get_newType(self): return self.newType - def set_newType(self, newType): self.newType = newType - def get_startTime(self): return self.startTime - def set_startTime(self, startTime): self.startTime = startTime - def hasContent_(self): - if ( - self.newType is not None or - self.startTime is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CreditTypeChange', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CreditTypeChange') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CreditTypeChange', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CreditTypeChange'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CreditTypeChange', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.newType is not None: - self.newType.export(outfile, level, namespace_, name_='newType', pretty_print=pretty_print) - if self.startTime is not None: - self.startTime.export(outfile, level, namespace_, name_='startTime', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='CreditTypeChange'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.newType is not None: - showIndent(outfile, level) - outfile.write('newType=model_.CreditTypeType(\n') - self.newType.exportLiteral(outfile, level, name_='newType') - showIndent(outfile, level) - outfile.write('),\n') - if self.startTime is not None: - showIndent(outfile, level) - outfile.write('startTime=model_.TimeType(\n') - self.startTime.exportLiteral(outfile, level, name_='startTime') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'newType': - obj_ = CreditTypeType.factory() - obj_.build(child_) - self.newType = obj_ - obj_.original_tagname_ = 'newType' - elif nodeName_ == 'startTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.startTime = obj_ - obj_.original_tagname_ = 'startTime' -# end class CreditTypeChange - - -class ServiceStatusType(GeneratedsSuper): - """0 - Connected 1 - Disconnected 2 - Armed for Connect 3 - Armed for - Disconnect 4 - No Contactor 5 - Load Limited All other values - reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if ServiceStatusType.subclass: - return ServiceStatusType.subclass(*args_, **kwargs_) - else: - return ServiceStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ServiceStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceStatusType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='ServiceStatusType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ServiceStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ServiceStatusType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='ServiceStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class ServiceStatusType - - -class RequestStatus(GeneratedsSuper): - """The RequestStatus object is used to indicate the current status of a - Flow Reservation Request.""" - subclass = None - superclass = None - def __init__(self, dateTime=None, requestStatus=None): - self.original_tagname_ = None - self.dateTime = dateTime - self.requestStatus = requestStatus - def factory(*args_, **kwargs_): - if RequestStatus.subclass: - return RequestStatus.subclass(*args_, **kwargs_) - else: - return RequestStatus(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_requestStatus(self): return self.requestStatus - def set_requestStatus(self, requestStatus): self.requestStatus = requestStatus - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.dateTime is not None or - self.requestStatus is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RequestStatus', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RequestStatus') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RequestStatus', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RequestStatus'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='RequestStatus', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.requestStatus is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srequestStatus>%s%s' % (namespace_, self.gds_format_integer(self.requestStatus, input_name='requestStatus'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='RequestStatus'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.requestStatus is not None: - showIndent(outfile, level) - outfile.write('requestStatus=%d,\n' % self.requestStatus) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'requestStatus': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'requestStatus') - self.requestStatus = ival_ - self.validate_UInt8(self.requestStatus) # validate type UInt8 -# end class RequestStatus - - -class DERType(GeneratedsSuper): - """0 - Not applicable / Unknown 1 - Virtual or mixed DER 2 - - Reciprocating engine 3 - Fuel cell 4 - Photovoltaic system 5 - - Combined heat and power 80 - Storage (immobile) 81 - Electric - vehicle / EVSE 82 - Combined PV and storage All other values - reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if DERType.subclass: - return DERType.subclass(*args_, **kwargs_) - else: - return DERType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DERType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='DERType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class DERType - - -class DERControlBase(GeneratedsSuper): - """Distributed Energy Resource (DER) control values.""" - subclass = None - superclass = None - def __init__(self, opModFixedFlow=None, opModFixedPF=None, opModFixedVAr=None, opModFixedW=None, opModFreqWatt=None, opModHVRT=None, opModLVRT=None, opModVoltVAr=None, opModVoltWatt=None, opModWattPF=None, rampTms=None): - self.original_tagname_ = None - self.opModFixedFlow = opModFixedFlow - self.opModFixedPF = opModFixedPF - self.opModFixedVAr = opModFixedVAr - self.opModFixedW = opModFixedW - self.opModFreqWatt = opModFreqWatt - self.opModHVRT = opModHVRT - self.opModLVRT = opModLVRT - self.opModVoltVAr = opModVoltVAr - self.opModVoltWatt = opModVoltWatt - self.opModWattPF = opModWattPF - self.rampTms = rampTms - def factory(*args_, **kwargs_): - if DERControlBase.subclass: - return DERControlBase.subclass(*args_, **kwargs_) - else: - return DERControlBase(*args_, **kwargs_) - factory = staticmethod(factory) - def get_opModFixedFlow(self): return self.opModFixedFlow - def set_opModFixedFlow(self, opModFixedFlow): self.opModFixedFlow = opModFixedFlow - def get_opModFixedPF(self): return self.opModFixedPF - def set_opModFixedPF(self, opModFixedPF): self.opModFixedPF = opModFixedPF - def get_opModFixedVAr(self): return self.opModFixedVAr - def set_opModFixedVAr(self, opModFixedVAr): self.opModFixedVAr = opModFixedVAr - def get_opModFixedW(self): return self.opModFixedW - def set_opModFixedW(self, opModFixedW): self.opModFixedW = opModFixedW - def get_opModFreqWatt(self): return self.opModFreqWatt - def set_opModFreqWatt(self, opModFreqWatt): self.opModFreqWatt = opModFreqWatt - def get_opModHVRT(self): return self.opModHVRT - def set_opModHVRT(self, opModHVRT): self.opModHVRT = opModHVRT - def get_opModLVRT(self): return self.opModLVRT - def set_opModLVRT(self, opModLVRT): self.opModLVRT = opModLVRT - def get_opModVoltVAr(self): return self.opModVoltVAr - def set_opModVoltVAr(self, opModVoltVAr): self.opModVoltVAr = opModVoltVAr - def get_opModVoltWatt(self): return self.opModVoltWatt - def set_opModVoltWatt(self, opModVoltWatt): self.opModVoltWatt = opModVoltWatt - def get_opModWattPF(self): return self.opModWattPF - def set_opModWattPF(self, opModWattPF): self.opModWattPF = opModWattPF - def get_rampTms(self): return self.rampTms - def set_rampTms(self, rampTms): self.rampTms = rampTms - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.opModFixedFlow is not None or - self.opModFixedPF is not None or - self.opModFixedVAr is not None or - self.opModFixedW is not None or - self.opModFreqWatt is not None or - self.opModHVRT is not None or - self.opModLVRT is not None or - self.opModVoltVAr is not None or - self.opModVoltWatt is not None or - self.opModWattPF is not None or - self.rampTms is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERControlBase', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERControlBase') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERControlBase', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERControlBase'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DERControlBase', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.opModFixedFlow is not None: - self.opModFixedFlow.export(outfile, level, namespace_, name_='opModFixedFlow', pretty_print=pretty_print) - if self.opModFixedPF is not None: - self.opModFixedPF.export(outfile, level, namespace_, name_='opModFixedPF', pretty_print=pretty_print) - if self.opModFixedVAr is not None: - self.opModFixedVAr.export(outfile, level, namespace_, name_='opModFixedVAr', pretty_print=pretty_print) - if self.opModFixedW is not None: - self.opModFixedW.export(outfile, level, namespace_, name_='opModFixedW', pretty_print=pretty_print) - if self.opModFreqWatt is not None: - self.opModFreqWatt.export(outfile, level, namespace_, name_='opModFreqWatt', pretty_print=pretty_print) - if self.opModHVRT is not None: - self.opModHVRT.export(outfile, level, namespace_, name_='opModHVRT', pretty_print=pretty_print) - if self.opModLVRT is not None: - self.opModLVRT.export(outfile, level, namespace_, name_='opModLVRT', pretty_print=pretty_print) - if self.opModVoltVAr is not None: - self.opModVoltVAr.export(outfile, level, namespace_, name_='opModVoltVAr', pretty_print=pretty_print) - if self.opModVoltWatt is not None: - self.opModVoltWatt.export(outfile, level, namespace_, name_='opModVoltWatt', pretty_print=pretty_print) - if self.opModWattPF is not None: - self.opModWattPF.export(outfile, level, namespace_, name_='opModWattPF', pretty_print=pretty_print) - if self.rampTms is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srampTms>%s%s' % (namespace_, self.gds_format_integer(self.rampTms, input_name='rampTms'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='DERControlBase'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.opModFixedFlow is not None: - showIndent(outfile, level) - outfile.write('opModFixedFlow=model_.SignedPerCent(\n') - self.opModFixedFlow.exportLiteral(outfile, level, name_='opModFixedFlow') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModFixedPF is not None: - showIndent(outfile, level) - outfile.write('opModFixedPF=model_.FixedPowerFactor(\n') - self.opModFixedPF.exportLiteral(outfile, level, name_='opModFixedPF') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModFixedVAr is not None: - showIndent(outfile, level) - outfile.write('opModFixedVAr=model_.FixedVAr(\n') - self.opModFixedVAr.exportLiteral(outfile, level, name_='opModFixedVAr') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModFixedW is not None: - showIndent(outfile, level) - outfile.write('opModFixedW=model_.PerCent(\n') - self.opModFixedW.exportLiteral(outfile, level, name_='opModFixedW') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModFreqWatt is not None: - showIndent(outfile, level) - outfile.write('opModFreqWatt=model_.DERCurveLink(\n') - self.opModFreqWatt.exportLiteral(outfile, level, name_='opModFreqWatt') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModHVRT is not None: - showIndent(outfile, level) - outfile.write('opModHVRT=model_.CurvePairType(\n') - self.opModHVRT.exportLiteral(outfile, level, name_='opModHVRT') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModLVRT is not None: - showIndent(outfile, level) - outfile.write('opModLVRT=model_.CurvePairType(\n') - self.opModLVRT.exportLiteral(outfile, level, name_='opModLVRT') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModVoltVAr is not None: - showIndent(outfile, level) - outfile.write('opModVoltVAr=model_.DERCurveLink(\n') - self.opModVoltVAr.exportLiteral(outfile, level, name_='opModVoltVAr') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModVoltWatt is not None: - showIndent(outfile, level) - outfile.write('opModVoltWatt=model_.DERCurveLink(\n') - self.opModVoltWatt.exportLiteral(outfile, level, name_='opModVoltWatt') - showIndent(outfile, level) - outfile.write('),\n') - if self.opModWattPF is not None: - showIndent(outfile, level) - outfile.write('opModWattPF=model_.DERCurveLink(\n') - self.opModWattPF.exportLiteral(outfile, level, name_='opModWattPF') - showIndent(outfile, level) - outfile.write('),\n') - if self.rampTms is not None: - showIndent(outfile, level) - outfile.write('rampTms=%d,\n' % self.rampTms) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'opModFixedFlow': - obj_ = SignedPerCent.factory() - obj_.build(child_) - self.opModFixedFlow = obj_ - obj_.original_tagname_ = 'opModFixedFlow' - elif nodeName_ == 'opModFixedPF': - obj_ = FixedPowerFactor.factory() - obj_.build(child_) - self.opModFixedPF = obj_ - obj_.original_tagname_ = 'opModFixedPF' - elif nodeName_ == 'opModFixedVAr': - obj_ = FixedVAr.factory() - obj_.build(child_) - self.opModFixedVAr = obj_ - obj_.original_tagname_ = 'opModFixedVAr' - elif nodeName_ == 'opModFixedW': - obj_ = PerCent.factory() - obj_.build(child_) - self.opModFixedW = obj_ - obj_.original_tagname_ = 'opModFixedW' - elif nodeName_ == 'opModFreqWatt': - obj_ = DERCurveLink.factory() - obj_.build(child_) - self.opModFreqWatt = obj_ - obj_.original_tagname_ = 'opModFreqWatt' - elif nodeName_ == 'opModHVRT': - obj_ = CurvePairType.factory() - obj_.build(child_) - self.opModHVRT = obj_ - obj_.original_tagname_ = 'opModHVRT' - elif nodeName_ == 'opModLVRT': - obj_ = CurvePairType.factory() - obj_.build(child_) - self.opModLVRT = obj_ - obj_.original_tagname_ = 'opModLVRT' - elif nodeName_ == 'opModVoltVAr': - obj_ = DERCurveLink.factory() - obj_.build(child_) - self.opModVoltVAr = obj_ - obj_.original_tagname_ = 'opModVoltVAr' - elif nodeName_ == 'opModVoltWatt': - obj_ = DERCurveLink.factory() - obj_.build(child_) - self.opModVoltWatt = obj_ - obj_.original_tagname_ = 'opModVoltWatt' - elif nodeName_ == 'opModWattPF': - obj_ = DERCurveLink.factory() - obj_.build(child_) - self.opModWattPF = obj_ - obj_.original_tagname_ = 'opModWattPF' - elif nodeName_ == 'rampTms': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'rampTms') - self.rampTms = ival_ - self.validate_UInt16(self.rampTms) # validate type UInt16 -# end class DERControlBase - - -class DERControlType(GeneratedsSuper): - """Control modes supported by the DER. Bit positions SHALL be defined - as follows: 0 - Volt-VAr Mode 1 - Frequency-Watt Mode 2 - Watt- - PowerFactor Mode 3 - Volt-Watt Mode 4 - Low Voltage Ride Through - Mode 5 - High Voltage Ride Through Mode 6-9 - reserved 10 - - setGenConnect 11 - setStorConnect 12 - Fixed W 13 - Fixed VAr 14 - - Fixed PF 15 - Charge mode 16 - Discharge mode All other values - reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if DERControlType.subclass: - return DERControlType.subclass(*args_, **kwargs_) - else: - return DERControlType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERControlType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERControlType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERControlType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERControlType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DERControlType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='DERControlType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class DERControlType - - -class CurveData(GeneratedsSuper): - """Data point values for defining a curve or schedule""" - subclass = None - superclass = None - def __init__(self, excitation=None, xvalue=None, yvalue=None): - self.original_tagname_ = None - self.excitation = excitation - self.xvalue = xvalue - self.yvalue = yvalue - def factory(*args_, **kwargs_): - if CurveData.subclass: - return CurveData.subclass(*args_, **kwargs_) - else: - return CurveData(*args_, **kwargs_) - factory = staticmethod(factory) - def get_excitation(self): return self.excitation - def set_excitation(self, excitation): self.excitation = excitation - def get_xvalue(self): return self.xvalue - def set_xvalue(self, xvalue): self.xvalue = xvalue - def get_yvalue(self): return self.yvalue - def set_yvalue(self, yvalue): self.yvalue = yvalue - def validate_Int8(self, value): - # Validate type Int8, a restriction on xs:byte. - pass - def validate_Int32(self, value): - # Validate type Int32, a restriction on xs:int. - pass - def hasContent_(self): - if ( - self.excitation is not None or - self.xvalue is not None or - self.yvalue is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CurveData', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CurveData') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CurveData', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CurveData'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CurveData', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.excitation is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sexcitation>%s%s' % (namespace_, self.gds_format_integer(self.excitation, input_name='excitation'), namespace_, eol_)) - if self.xvalue is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sxvalue>%s%s' % (namespace_, self.gds_format_integer(self.xvalue, input_name='xvalue'), namespace_, eol_)) - if self.yvalue is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%syvalue>%s%s' % (namespace_, self.gds_format_integer(self.yvalue, input_name='yvalue'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='CurveData'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.excitation is not None: - showIndent(outfile, level) - outfile.write('excitation=%d,\n' % self.excitation) - if self.xvalue is not None: - showIndent(outfile, level) - outfile.write('xvalue=%d,\n' % self.xvalue) - if self.yvalue is not None: - showIndent(outfile, level) - outfile.write('yvalue=%d,\n' % self.yvalue) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'excitation': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'excitation') - self.excitation = ival_ - self.validate_Int8(self.excitation) # validate type Int8 - elif nodeName_ == 'xvalue': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'xvalue') - self.xvalue = ival_ - self.validate_Int32(self.xvalue) # validate type Int32 - elif nodeName_ == 'yvalue': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'yvalue') - self.yvalue = ival_ - self.validate_Int32(self.yvalue) # validate type Int32 -# end class CurveData - - -class DERCurveType(GeneratedsSuper): - """0 - Volt-VAr Mode 1 - Frequency-Watt Curve Mode 2 - Watt-PowerFactor - Mode 3 - Volt-Watt Mode 4 - Low Voltage Ride Through Mode 5 - - High Voltage Ride Through Mode All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if DERCurveType.subclass: - return DERCurveType.subclass(*args_, **kwargs_) - else: - return DERCurveType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERCurveType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurveType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERCurveType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERCurveType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DERCurveType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='DERCurveType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class DERCurveType - - -class CurvePairType(GeneratedsSuper): - """Specifies a pair of DERCurves.""" - subclass = None - superclass = None - def __init__(self, lowerLimit=None, upperLimit=None): - self.original_tagname_ = None - self.lowerLimit = lowerLimit - self.upperLimit = upperLimit - def factory(*args_, **kwargs_): - if CurvePairType.subclass: - return CurvePairType.subclass(*args_, **kwargs_) - else: - return CurvePairType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_lowerLimit(self): return self.lowerLimit - def set_lowerLimit(self, lowerLimit): self.lowerLimit = lowerLimit - def get_upperLimit(self): return self.upperLimit - def set_upperLimit(self, upperLimit): self.upperLimit = upperLimit - def hasContent_(self): - if ( - self.lowerLimit is not None or - self.upperLimit is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CurvePairType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CurvePairType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CurvePairType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CurvePairType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CurvePairType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.lowerLimit is not None: - self.lowerLimit.export(outfile, level, namespace_, name_='lowerLimit', pretty_print=pretty_print) - if self.upperLimit is not None: - self.upperLimit.export(outfile, level, namespace_, name_='upperLimit', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='CurvePairType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.lowerLimit is not None: - showIndent(outfile, level) - outfile.write('lowerLimit=model_.DERCurveLink(\n') - self.lowerLimit.exportLiteral(outfile, level, name_='lowerLimit') - showIndent(outfile, level) - outfile.write('),\n') - if self.upperLimit is not None: - showIndent(outfile, level) - outfile.write('upperLimit=model_.DERCurveLink(\n') - self.upperLimit.exportLiteral(outfile, level, name_='upperLimit') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'lowerLimit': - obj_ = DERCurveLink.factory() - obj_.build(child_) - self.lowerLimit = obj_ - obj_.original_tagname_ = 'lowerLimit' - elif nodeName_ == 'upperLimit': - obj_ = DERCurveLink.factory() - obj_.build(child_) - self.upperLimit = obj_ - obj_.original_tagname_ = 'upperLimit' -# end class CurvePairType - - -class DERUnitRefType(GeneratedsSuper): - """Specifies context for interpreting percent values: 0 - N/A 1 - - %setMaxW 2 - %setMaxVAr 3 - %statVArAvail 4 - %setEffectiveV 5 - - %setMaxChargeRate 6 - %setMaxDischargeRate All other values - reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if DERUnitRefType.subclass: - return DERUnitRefType.subclass(*args_, **kwargs_) - else: - return DERUnitRefType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERUnitRefType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERUnitRefType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERUnitRefType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERUnitRefType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DERUnitRefType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='DERUnitRefType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class DERUnitRefType - - -class CurrentRMS(GeneratedsSuper): - """Average flow of charge through a conductor.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if CurrentRMS.subclass: - return CurrentRMS.subclass(*args_, **kwargs_) - else: - return CurrentRMS(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CurrentRMS', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CurrentRMS') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CurrentRMS', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CurrentRMS'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CurrentRMS', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='CurrentRMS'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt16(self.value) # validate type UInt16 -# end class CurrentRMS - - -class FixedPointType(GeneratedsSuper): - """Abstract type for specifying a fixed-point value without a given - unit of measure.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if FixedPointType.subclass: - return FixedPointType.subclass(*args_, **kwargs_) - else: - return FixedPointType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_Int16(self, value): - # Validate type Int16, a restriction on xs:short. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FixedPointType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FixedPointType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FixedPointType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FixedPointType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='FixedPointType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='FixedPointType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int16(self.value) # validate type Int16 -# end class FixedPointType - - -class UnsignedFixedPointType(GeneratedsSuper): - """Abstract type for specifying an unsigned fixed-point value without a - given unit of measure.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if UnsignedFixedPointType.subclass: - return UnsignedFixedPointType.subclass(*args_, **kwargs_) - else: - return UnsignedFixedPointType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UnsignedFixedPointType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UnsignedFixedPointType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='UnsignedFixedPointType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UnsignedFixedPointType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='UnsignedFixedPointType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='UnsignedFixedPointType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt16(self.value) # validate type UInt16 -# end class UnsignedFixedPointType - - -class ActivePower(GeneratedsSuper): - """The active (real) power P (in W) is the product of root-mean-square - (RMS) voltage, RMS current, and cos(theta) where theta is the - phase angle of current relative to voltage. It is the primary - measure of the rate of flow of energy.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if ActivePower.subclass: - return ActivePower.subclass(*args_, **kwargs_) - else: - return ActivePower(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_Int16(self, value): - # Validate type Int16, a restriction on xs:short. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActivePower', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActivePower') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActivePower', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActivePower'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ActivePower', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='ActivePower'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int16(self.value) # validate type Int16 -# end class ActivePower - - -class AmpereHour(GeneratedsSuper): - """Available electric charge""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if AmpereHour.subclass: - return AmpereHour.subclass(*args_, **kwargs_) - else: - return AmpereHour(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AmpereHour', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AmpereHour') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AmpereHour', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AmpereHour'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='AmpereHour', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='AmpereHour'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt16(self.value) # validate type UInt16 -# end class AmpereHour - - -class ApparentPower(GeneratedsSuper): - """The apparent power S (in VA) is the product of root mean square - (RMS) voltage and RMS current.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if ApparentPower.subclass: - return ApparentPower.subclass(*args_, **kwargs_) - else: - return ApparentPower(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ApparentPower', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ApparentPower') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ApparentPower', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ApparentPower'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ApparentPower', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='ApparentPower'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt16(self.value) # validate type UInt16 -# end class ApparentPower - - -class ReactivePower(GeneratedsSuper): - """The reactive power Q (in var) is the product of root mean square - (RMS) voltage, RMS current, and sin(theta) where theta is the - phase angle of current relative to voltage.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if ReactivePower.subclass: - return ReactivePower.subclass(*args_, **kwargs_) - else: - return ReactivePower(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_Int16(self, value): - # Validate type Int16, a restriction on xs:short. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReactivePower', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReactivePower') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReactivePower', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReactivePower'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ReactivePower', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='ReactivePower'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int16(self.value) # validate type Int16 -# end class ReactivePower - - -class FixedPowerFactor(GeneratedsSuper): - """Specifies a setpoint for Displacement Power Factor, the ratio - between apparent and active powers at the fundamental frequency - (e.g. 60 Hz).""" - subclass = None - superclass = None - def __init__(self, displacement=None, multiplier=None): - self.original_tagname_ = None - self.displacement = displacement - self.multiplier = multiplier - def factory(*args_, **kwargs_): - if FixedPowerFactor.subclass: - return FixedPowerFactor.subclass(*args_, **kwargs_) - else: - return FixedPowerFactor(*args_, **kwargs_) - factory = staticmethod(factory) - def get_displacement(self): return self.displacement - def set_displacement(self, displacement): self.displacement = displacement - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def validate_Int16(self, value): - # Validate type Int16, a restriction on xs:short. - pass - def hasContent_(self): - if ( - self.displacement is not None or - self.multiplier is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FixedPowerFactor', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FixedPowerFactor') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FixedPowerFactor', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FixedPowerFactor'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='FixedPowerFactor', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.displacement is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdisplacement>%s%s' % (namespace_, self.gds_format_integer(self.displacement, input_name='displacement'), namespace_, eol_)) - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FixedPowerFactor'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.displacement is not None: - showIndent(outfile, level) - outfile.write('displacement=%d,\n' % self.displacement) - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'displacement': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'displacement') - self.displacement = ival_ - self.validate_Int16(self.displacement) # validate type Int16 - elif nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' -# end class FixedPowerFactor - - -class FixedVAr(GeneratedsSuper): - """Specifies a signed setpoint for reactive power.""" - subclass = None - superclass = None - def __init__(self, refType=None, value=None): - self.original_tagname_ = None - self.refType = refType - self.value = value - def factory(*args_, **kwargs_): - if FixedVAr.subclass: - return FixedVAr.subclass(*args_, **kwargs_) - else: - return FixedVAr(*args_, **kwargs_) - factory = staticmethod(factory) - def get_refType(self): return self.refType - def set_refType(self, refType): self.refType = refType - def get_value(self): return self.value - def set_value(self, value): self.value = value - def hasContent_(self): - if ( - self.refType is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FixedVAr', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FixedVAr') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FixedVAr', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FixedVAr'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='FixedVAr', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.refType is not None: - self.refType.export(outfile, level, namespace_, name_='refType', pretty_print=pretty_print) - if self.value is not None: - self.value.export(outfile, level, namespace_, name_='value', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FixedVAr'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.refType is not None: - showIndent(outfile, level) - outfile.write('refType=model_.DERUnitRefType(\n') - self.refType.exportLiteral(outfile, level, name_='refType') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=model_.SignedPerCent(\n') - self.value.exportLiteral(outfile, level, name_='value') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'refType': - obj_ = DERUnitRefType.factory() - obj_.build(child_) - self.refType = obj_ - obj_.original_tagname_ = 'refType' - elif nodeName_ == 'value': - obj_ = SignedPerCent.factory() - obj_.build(child_) - self.value = obj_ - obj_.original_tagname_ = 'value' -# end class FixedVAr - - -class WattHour(GeneratedsSuper): - """Active (real) energy""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if WattHour.subclass: - return WattHour.subclass(*args_, **kwargs_) - else: - return WattHour(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='WattHour', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='WattHour') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='WattHour', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='WattHour'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='WattHour', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='WattHour'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt16(self.value) # validate type UInt16 -# end class WattHour - - -class VoltageRMS(GeneratedsSuper): - """Average electric potential difference between two points.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if VoltageRMS.subclass: - return VoltageRMS.subclass(*args_, **kwargs_) - else: - return VoltageRMS(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='VoltageRMS', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='VoltageRMS') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='VoltageRMS', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='VoltageRMS'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='VoltageRMS', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='VoltageRMS'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt16(self.value) # validate type UInt16 -# end class VoltageRMS - - -class ConnectStatusType(GeneratedsSuper): - """DER ConnectStatus value: 0 - N/A 1 - disconnected_unavail 2 - - disconnected_avail 3 - connected_unavail 4 - connected_avail 5 - - connected_on 6 - test_mode All other values reserved.""" - subclass = None - superclass = None - def __init__(self, dateTime=None, value=None): - self.original_tagname_ = None - self.dateTime = dateTime - self.value = value - def factory(*args_, **kwargs_): - if ConnectStatusType.subclass: - return ConnectStatusType.subclass(*args_, **kwargs_) - else: - return ConnectStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.dateTime is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ConnectStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ConnectStatusType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ConnectStatusType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ConnectStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ConnectStatusType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='ConnectStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt8(self.value) # validate type UInt8 -# end class ConnectStatusType - - -class InverterStatusType(GeneratedsSuper): - """DER InverterStatus value: 0 - N/A 1 - off 2 - sleeping (auto- - shutdown) or DER is at low output power/voltage 3 - starting up - or ON but not producing power 4 - tracking MPPT power point 5 - - forced power reduction/derating 6 - shutting down 7 - one or - more faults exist 8 - standby (service on unit) - DER may be at - high output voltage/power 9 - test mode 10 - as defined in - manufacturer status All other values reserved.""" - subclass = None - superclass = None - def __init__(self, dateTime=None, value=None): - self.original_tagname_ = None - self.dateTime = dateTime - self.value = value - def factory(*args_, **kwargs_): - if InverterStatusType.subclass: - return InverterStatusType.subclass(*args_, **kwargs_) - else: - return InverterStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.dateTime is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='InverterStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='InverterStatusType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='InverterStatusType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='InverterStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='InverterStatusType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='InverterStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt8(self.value) # validate type UInt8 -# end class InverterStatusType - - -class LocalControlModeStatusType(GeneratedsSuper): - """DER LocalControlModeStatus/value: 0 – local control 1 – remote - control All other values reserved.""" - subclass = None - superclass = None - def __init__(self, dateTime=None, value=None): - self.original_tagname_ = None - self.dateTime = dateTime - self.value = value - def factory(*args_, **kwargs_): - if LocalControlModeStatusType.subclass: - return LocalControlModeStatusType.subclass(*args_, **kwargs_) - else: - return LocalControlModeStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.dateTime is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LocalControlModeStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LocalControlModeStatusType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LocalControlModeStatusType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LocalControlModeStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='LocalControlModeStatusType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='LocalControlModeStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt8(self.value) # validate type UInt8 -# end class LocalControlModeStatusType - - -class ManufacturerStatusType(GeneratedsSuper): - """DER ManufacturerStatus/value: String data type""" - subclass = None - superclass = None - def __init__(self, dateTime=None, value=None): - self.original_tagname_ = None - self.dateTime = dateTime - self.value = value - def factory(*args_, **kwargs_): - if ManufacturerStatusType.subclass: - return ManufacturerStatusType.subclass(*args_, **kwargs_) - else: - return ManufacturerStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_String6(self, value): - # Validate type String6, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.dateTime is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ManufacturerStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ManufacturerStatusType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ManufacturerStatusType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ManufacturerStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ManufacturerStatusType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.value).encode(ExternalEncoding), input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='ManufacturerStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%s,\n' % quote_python(self.value).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'value': - value_ = child_.text - value_ = self.gds_validate_string(value_, node, 'value') - self.value = value_ - self.validate_String6(self.value) # validate type String6 -# end class ManufacturerStatusType - - -class OperationalModeStatusType(GeneratedsSuper): - """DER OperationalModeStatus value: 0 - Not applicable / Unknown 1 - - Off 2 - Operational mode 3 - Test mode All other values - reserved.""" - subclass = None - superclass = None - def __init__(self, dateTime=None, value=None): - self.original_tagname_ = None - self.dateTime = dateTime - self.value = value - def factory(*args_, **kwargs_): - if OperationalModeStatusType.subclass: - return OperationalModeStatusType.subclass(*args_, **kwargs_) - else: - return OperationalModeStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.dateTime is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='OperationalModeStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='OperationalModeStatusType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='OperationalModeStatusType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='OperationalModeStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='OperationalModeStatusType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='OperationalModeStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt8(self.value) # validate type UInt8 -# end class OperationalModeStatusType - - -class StateOfChargeStatusType(GeneratedsSuper): - """DER StateOfChargeStatus value: Percent data type""" - subclass = None - superclass = None - def __init__(self, dateTime=None, value=None): - self.original_tagname_ = None - self.dateTime = dateTime - self.value = value - def factory(*args_, **kwargs_): - if StateOfChargeStatusType.subclass: - return StateOfChargeStatusType.subclass(*args_, **kwargs_) - else: - return StateOfChargeStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_value(self): return self.value - def set_value(self, value): self.value = value - def hasContent_(self): - if ( - self.dateTime is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='StateOfChargeStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='StateOfChargeStatusType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='StateOfChargeStatusType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='StateOfChargeStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='StateOfChargeStatusType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.value is not None: - self.value.export(outfile, level, namespace_, name_='value', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='StateOfChargeStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=model_.PerCent(\n') - self.value.exportLiteral(outfile, level, name_='value') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'value': - obj_ = PerCent.factory() - obj_.build(child_) - self.value = obj_ - obj_.original_tagname_ = 'value' -# end class StateOfChargeStatusType - - -class StorageModeStatusType(GeneratedsSuper): - """DER StorageModeStatus value: 0 – storage charging 1 – storage - discharging 2 – storage holding All other values reserved.""" - subclass = None - superclass = None - def __init__(self, dateTime=None, value=None): - self.original_tagname_ = None - self.dateTime = dateTime - self.value = value - def factory(*args_, **kwargs_): - if StorageModeStatusType.subclass: - return StorageModeStatusType.subclass(*args_, **kwargs_) - else: - return StorageModeStatusType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.dateTime is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='StorageModeStatusType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='StorageModeStatusType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='StorageModeStatusType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='StorageModeStatusType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='StorageModeStatusType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='StorageModeStatusType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt8(self.value) # validate type UInt8 -# end class StorageModeStatusType - - -class Link(GeneratedsSuper): - """Links provide a reference, via URI, to another resource.A URI - reference.""" - subclass = None - superclass = None - def __init__(self, href=None): - self.original_tagname_ = None - self.href = _cast(None, href) - def factory(*args_, **kwargs_): - if Link.subclass: - return Link.subclass(*args_, **kwargs_) - else: - return Link(*args_, **kwargs_) - factory = staticmethod(factory) - def get_href(self): return self.href - def set_href(self, href): self.href = href - def hasContent_(self): - if ( - - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Link', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Link') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Link', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Link'): - if self.href is not None and 'href' not in already_processed: - already_processed.add('href') - outfile.write(' href=%s' % (self.gds_format_string(quote_attrib(self.href).encode(ExternalEncoding), input_name='href'), )) - def exportChildren(self, outfile, level, namespace_='', name_='Link', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='Link'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.href is not None and 'href' not in already_processed: - already_processed.add('href') - showIndent(outfile, level) - outfile.write('href="%s",\n' % (self.href,)) - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('href', node) - if value is not None and 'href' not in already_processed: - already_processed.add('href') - self.href = value - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class Link - - -class ListLink(Link): - """ListLinks provide a reference, via URI, to a List.Indicates the - total number of items in the referenced list.""" - subclass = None - superclass = Link - def __init__(self, all=None): - self.original_tagname_ = None - super(ListLink, self).__init__() - self.all = _cast(None, all) - def factory(*args_, **kwargs_): - if ListLink.subclass: - return ListLink.subclass(*args_, **kwargs_) - else: - return ListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def get_all(self): return self.all - def set_all(self, all): self.all = all - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - super(ListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ListLink'): - super(ListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ListLink') - if self.all is not None and 'all' not in already_processed: - already_processed.add('all') - outfile.write(' all=%s' % (quote_attrib(self.all), )) - def exportChildren(self, outfile, level, namespace_='', name_='ListLink', fromsubclass_=False, pretty_print=True): - super(ListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.all is not None and 'all' not in already_processed: - already_processed.add('all') - showIndent(outfile, level) - outfile.write('all=%d,\n' % (self.all,)) - super(ListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('all', node) - if value is not None and 'all' not in already_processed: - already_processed.add('all') - try: - self.all = int(value) - except ValueError as exp: - raise_parse_error(node, 'Bad integer attribute: %s' % exp) - self.validate_UInt16(self.all) # validate type UInt16 - super(ListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ListLink - - -class Resource(GeneratedsSuper): - """A resource is an addressable unit of information, either a - collection (List) or instance of an object (identifiedObject, or - simply, Resource)A reference to the resource address (URI). - Required in a response to a GET, ignored otherwise.""" - subclass = None - superclass = None - def __init__(self, href=None): - self.original_tagname_ = None - self.href = _cast(None, href) - def factory(*args_, **kwargs_): - if Resource.subclass: - return Resource.subclass(*args_, **kwargs_) - else: - return Resource(*args_, **kwargs_) - factory = staticmethod(factory) - def get_href(self): return self.href - def set_href(self, href): self.href = href - def hasContent_(self): - if ( - - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Resource', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Resource') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Resource', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Resource'): - if self.href is not None and 'href' not in already_processed: - already_processed.add('href') - outfile.write(' href=%s' % (self.gds_format_string(quote_attrib(self.href).encode(ExternalEncoding), input_name='href'), )) - def exportChildren(self, outfile, level, namespace_='', name_='Resource', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='Resource'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.href is not None and 'href' not in already_processed: - already_processed.add('href') - showIndent(outfile, level) - outfile.write('href="%s",\n' % (self.href,)) - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('href', node) - if value is not None and 'href' not in already_processed: - already_processed.add('href') - self.href = value - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class Resource - - -class RespondableResource(Resource): - """A Resource to which a Response can be requested.A reference to the - response resource address (URI). Required on a response to a GET - if responseRequired is "true".Indicates whether or not a - response is required upon receipt, creation or update of this - resource. Responses shall be posted to the collection specified - in "replyTo". If the resource has a deviceCategory field, - devices that match one or more of the device types indicated in - deviceCategory SHALL respond according to the rules listed - below. If the category does not match, the device SHALL NOT - respond. If the resource does not have a deviceCategory field, a - device receiving the resource SHALL respond according to the - rules listed below. Value encoded as hex according to the - following bit assignments, any combination is possible. See - Table 10-10 for the list of appropriate Response status codes to - be sent for these purposes. 0 - End device shall indicate that - message was received 1 - End device shall indicate specific - response. 2 - End user / customer response is required. All - other values reserved.""" - subclass = None - superclass = Resource - def __init__(self, replyTo=None, responseRequired='00'): - self.original_tagname_ = None - super(RespondableResource, self).__init__() - self.replyTo = _cast(None, replyTo) - self.responseRequired = _cast(None, responseRequired) - def factory(*args_, **kwargs_): - if RespondableResource.subclass: - return RespondableResource.subclass(*args_, **kwargs_) - else: - return RespondableResource(*args_, **kwargs_) - factory = staticmethod(factory) - def get_replyTo(self): return self.replyTo - def set_replyTo(self, replyTo): self.replyTo = replyTo - def get_responseRequired(self): return self.responseRequired - def set_responseRequired(self, responseRequired): self.responseRequired = responseRequired - def validate_HexBinary8(self, value): - # Validate type HexBinary8, a restriction on xs:hexBinary. - pass - def hasContent_(self): - if ( - super(RespondableResource, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RespondableResource', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RespondableResource') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RespondableResource', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RespondableResource'): - super(RespondableResource, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RespondableResource') - if self.replyTo is not None and 'replyTo' not in already_processed: - already_processed.add('replyTo') - outfile.write(' replyTo=%s' % (self.gds_format_string(quote_attrib(self.replyTo).encode(ExternalEncoding), input_name='replyTo'), )) - if self.responseRequired is not None and 'responseRequired' not in already_processed: - already_processed.add('responseRequired') - outfile.write(' responseRequired=%s' % (quote_attrib(self.responseRequired), )) - def exportChildren(self, outfile, level, namespace_='', name_='RespondableResource', fromsubclass_=False, pretty_print=True): - super(RespondableResource, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='RespondableResource'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.replyTo is not None and 'replyTo' not in already_processed: - already_processed.add('replyTo') - showIndent(outfile, level) - outfile.write('replyTo="%s",\n' % (self.replyTo,)) - if self.responseRequired is not None and 'responseRequired' not in already_processed: - already_processed.add('responseRequired') - showIndent(outfile, level) - outfile.write('responseRequired="%s",\n' % (self.responseRequired,)) - super(RespondableResource, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RespondableResource, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('replyTo', node) - if value is not None and 'replyTo' not in already_processed: - already_processed.add('replyTo') - self.replyTo = value - value = find_attr_value_('responseRequired', node) - if value is not None and 'responseRequired' not in already_processed: - already_processed.add('responseRequired') - self.responseRequired = value - self.validate_HexBinary8(self.responseRequired) # validate type HexBinary8 - super(RespondableResource, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(RespondableResource, self).buildChildren(child_, node, nodeName_, True) - pass -# end class RespondableResource - - -class RespondableSubscribableIdentifiedObject(RespondableResource): - """An IdentifiedObject to which a Response can be requested.Indicates - whether or not subscriptions are supported for this resource, - and whether or not conditional (thresholds) are supported. If - not specified, is "not subscribable" (0).""" - subclass = None - superclass = RespondableResource - def __init__(self, subscribable='0', mRID=None, description=None, version=None): - self.original_tagname_ = None - super(RespondableSubscribableIdentifiedObject, self).__init__() - self.subscribable = _cast(None, subscribable) - self.mRID = mRID - self.description = description - self.version = version - def factory(*args_, **kwargs_): - if RespondableSubscribableIdentifiedObject.subclass: - return RespondableSubscribableIdentifiedObject.subclass(*args_, **kwargs_) - else: - return RespondableSubscribableIdentifiedObject(*args_, **kwargs_) - factory = staticmethod(factory) - def get_mRID(self): return self.mRID - def set_mRID(self, mRID): self.mRID = mRID - def get_description(self): return self.description - def set_description(self, description): self.description = description - def get_version(self): return self.version - def set_version(self, version): self.version = version - def get_subscribable(self): return self.subscribable - def set_subscribable(self, subscribable): self.subscribable = subscribable - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def validate_SubscribableType(self, value): - # Validate type SubscribableType, a restriction on UInt8. - pass - def hasContent_(self): - if ( - self.mRID is not None or - self.description is not None or - self.version is not None or - super(RespondableSubscribableIdentifiedObject, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RespondableSubscribableIdentifiedObject', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RespondableSubscribableIdentifiedObject') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RespondableSubscribableIdentifiedObject', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RespondableSubscribableIdentifiedObject'): - super(RespondableSubscribableIdentifiedObject, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RespondableSubscribableIdentifiedObject') - if self.subscribable is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - outfile.write(' subscribable=%s' % (quote_attrib(self.subscribable), )) - def exportChildren(self, outfile, level, namespace_='', name_='RespondableSubscribableIdentifiedObject', fromsubclass_=False, pretty_print=True): - super(RespondableSubscribableIdentifiedObject, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.mRID is not None: - self.mRID.export(outfile, level, namespace_, name_='mRID', pretty_print=pretty_print) - if self.description is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdescription>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.description).encode(ExternalEncoding), input_name='description'), namespace_, eol_)) - if self.version is not None: - self.version.export(outfile, level, namespace_, name_='version', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='RespondableSubscribableIdentifiedObject'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.subscribable is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - showIndent(outfile, level) - outfile.write('subscribable=%d,\n' % (self.subscribable,)) - super(RespondableSubscribableIdentifiedObject, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RespondableSubscribableIdentifiedObject, self).exportLiteralChildren(outfile, level, name_) - if self.mRID is not None: - showIndent(outfile, level) - outfile.write('mRID=model_.mRIDType(\n') - self.mRID.exportLiteral(outfile, level, name_='mRID') - showIndent(outfile, level) - outfile.write('),\n') - if self.description is not None: - showIndent(outfile, level) - outfile.write('description=%s,\n' % quote_python(self.description).encode(ExternalEncoding)) - if self.version is not None: - showIndent(outfile, level) - outfile.write('version=model_.VersionType(\n') - self.version.exportLiteral(outfile, level, name_='version') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('subscribable', node) - if value is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - self.subscribable = value - self.validate_SubscribableType(self.subscribable) # validate type SubscribableType - super(RespondableSubscribableIdentifiedObject, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'mRID': - obj_ = mRIDType.factory() - obj_.build(child_) - self.mRID = obj_ - obj_.original_tagname_ = 'mRID' - elif nodeName_ == 'description': - description_ = child_.text - description_ = self.gds_validate_string(description_, node, 'description') - self.description = description_ - self.validate_String32(self.description) # validate type String32 - elif nodeName_ == 'version': - obj_ = VersionType.factory() - obj_.build(child_) - self.version = obj_ - obj_.original_tagname_ = 'version' - super(RespondableSubscribableIdentifiedObject, self).buildChildren(child_, node, nodeName_, True) -# end class RespondableSubscribableIdentifiedObject - - -class SubscribableResource(Resource): - """A Resource to which a Subscription can be requested.Indicates - whether or not subscriptions are supported for this resource, - and whether or not conditional (thresholds) are supported. If - not specified, is "not subscribable" (0).""" - subclass = None - superclass = Resource - def __init__(self, subscribable='0'): - self.original_tagname_ = None - super(SubscribableResource, self).__init__() - self.subscribable = _cast(None, subscribable) - def factory(*args_, **kwargs_): - if SubscribableResource.subclass: - return SubscribableResource.subclass(*args_, **kwargs_) - else: - return SubscribableResource(*args_, **kwargs_) - factory = staticmethod(factory) - def get_subscribable(self): return self.subscribable - def set_subscribable(self, subscribable): self.subscribable = subscribable - def validate_SubscribableType(self, value): - # Validate type SubscribableType, a restriction on UInt8. - pass - def hasContent_(self): - if ( - super(SubscribableResource, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SubscribableResource', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SubscribableResource') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SubscribableResource', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SubscribableResource'): - super(SubscribableResource, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SubscribableResource') - if self.subscribable is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - outfile.write(' subscribable=%s' % (quote_attrib(self.subscribable), )) - def exportChildren(self, outfile, level, namespace_='', name_='SubscribableResource', fromsubclass_=False, pretty_print=True): - super(SubscribableResource, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='SubscribableResource'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.subscribable is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - showIndent(outfile, level) - outfile.write('subscribable=%d,\n' % (self.subscribable,)) - super(SubscribableResource, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SubscribableResource, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('subscribable', node) - if value is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - self.subscribable = value - self.validate_SubscribableType(self.subscribable) # validate type SubscribableType - super(SubscribableResource, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(SubscribableResource, self).buildChildren(child_, node, nodeName_, True) - pass -# end class SubscribableResource - - -class Error(GeneratedsSuper): - """Contains information about the nature of an error if a request could - not be completed successfully.""" - subclass = None - superclass = None - def __init__(self, maxRetryDuration=None, reasonCode=None): - self.original_tagname_ = None - self.maxRetryDuration = maxRetryDuration - self.reasonCode = reasonCode - def factory(*args_, **kwargs_): - if Error.subclass: - return Error.subclass(*args_, **kwargs_) - else: - return Error(*args_, **kwargs_) - factory = staticmethod(factory) - def get_maxRetryDuration(self): return self.maxRetryDuration - def set_maxRetryDuration(self, maxRetryDuration): self.maxRetryDuration = maxRetryDuration - def get_reasonCode(self): return self.reasonCode - def set_reasonCode(self, reasonCode): self.reasonCode = reasonCode - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.maxRetryDuration is not None or - self.reasonCode is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Error', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Error') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Error', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Error'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='Error', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.maxRetryDuration is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smaxRetryDuration>%s%s' % (namespace_, self.gds_format_integer(self.maxRetryDuration, input_name='maxRetryDuration'), namespace_, eol_)) - if self.reasonCode is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sreasonCode>%s%s' % (namespace_, self.gds_format_integer(self.reasonCode, input_name='reasonCode'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Error'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.maxRetryDuration is not None: - showIndent(outfile, level) - outfile.write('maxRetryDuration=%d,\n' % self.maxRetryDuration) - if self.reasonCode is not None: - showIndent(outfile, level) - outfile.write('reasonCode=%d,\n' % self.reasonCode) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'maxRetryDuration': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'maxRetryDuration') - self.maxRetryDuration = ival_ - self.validate_UInt16(self.maxRetryDuration) # validate type UInt16 - elif nodeName_ == 'reasonCode': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'reasonCode') - self.reasonCode = ival_ - self.validate_UInt16(self.reasonCode) # validate type UInt16 -# end class Error - - -class Event(RespondableSubscribableIdentifiedObject): - """An Event indicates information that applies to a particular period - of time. Events SHALL be executed relative to the time of the - server, as described in the Time function set section 11.1.""" - subclass = None - superclass = RespondableSubscribableIdentifiedObject - def __init__(self, creationTime=None, EventStatus=None, interval=None): - self.original_tagname_ = None - super(Event, self).__init__() - self.creationTime = creationTime - self.EventStatus = EventStatus - self.interval = interval - def factory(*args_, **kwargs_): - if Event.subclass: - return Event.subclass(*args_, **kwargs_) - else: - return Event(*args_, **kwargs_) - factory = staticmethod(factory) - def get_creationTime(self): return self.creationTime - def set_creationTime(self, creationTime): self.creationTime = creationTime - def get_EventStatus(self): return self.EventStatus - def set_EventStatus(self, EventStatus): self.EventStatus = EventStatus - def get_interval(self): return self.interval - def set_interval(self, interval): self.interval = interval - def hasContent_(self): - if ( - self.creationTime is not None or - self.EventStatus is not None or - self.interval is not None or - super(Event, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Event', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Event') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Event', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Event'): - super(Event, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Event') - def exportChildren(self, outfile, level, namespace_='', name_='Event', fromsubclass_=False, pretty_print=True): - super(Event, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.creationTime is not None: - self.creationTime.export(outfile, level, namespace_, name_='creationTime', pretty_print=pretty_print) - if self.EventStatus is not None: - self.EventStatus.export(outfile, level, namespace_, name_='EventStatus', pretty_print=pretty_print) - if self.interval is not None: - self.interval.export(outfile, level, namespace_, name_='interval', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='Event'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Event, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Event, self).exportLiteralChildren(outfile, level, name_) - if self.creationTime is not None: - showIndent(outfile, level) - outfile.write('creationTime=model_.TimeType(\n') - self.creationTime.exportLiteral(outfile, level, name_='creationTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.EventStatus is not None: - showIndent(outfile, level) - outfile.write('EventStatus=model_.EventStatus(\n') - self.EventStatus.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.interval is not None: - showIndent(outfile, level) - outfile.write('interval=model_.DateTimeInterval(\n') - self.interval.exportLiteral(outfile, level, name_='interval') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Event, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'creationTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.creationTime = obj_ - obj_.original_tagname_ = 'creationTime' - elif nodeName_ == 'EventStatus': - obj_ = EventStatus.factory() - obj_.build(child_) - self.EventStatus = obj_ - obj_.original_tagname_ = 'EventStatus' - elif nodeName_ == 'interval': - obj_ = DateTimeInterval.factory() - obj_.build(child_) - self.interval = obj_ - obj_.original_tagname_ = 'interval' - super(Event, self).buildChildren(child_, node, nodeName_, True) -# end class Event - - -class EventStatus(GeneratedsSuper): - """Current status information relevant to a specific object. The Status - object is used to indicate the current status of an Event. - Devices can read the containing resource (e.g. TextMessage) to - get the most up to date status of the event. Devices can also - subscribe to a specific resource instance to get updates when - any of its attributes change, including the Status object.""" - subclass = None - superclass = None - def __init__(self, currentStatus=None, dateTime=None, potentiallySuperseded=None, potentiallySupersededTime=None, reason=None): - self.original_tagname_ = None - self.currentStatus = currentStatus - self.dateTime = dateTime - self.potentiallySuperseded = potentiallySuperseded - self.potentiallySupersededTime = potentiallySupersededTime - self.reason = reason - def factory(*args_, **kwargs_): - if EventStatus.subclass: - return EventStatus.subclass(*args_, **kwargs_) - else: - return EventStatus(*args_, **kwargs_) - factory = staticmethod(factory) - def get_currentStatus(self): return self.currentStatus - def set_currentStatus(self, currentStatus): self.currentStatus = currentStatus - def get_dateTime(self): return self.dateTime - def set_dateTime(self, dateTime): self.dateTime = dateTime - def get_potentiallySuperseded(self): return self.potentiallySuperseded - def set_potentiallySuperseded(self, potentiallySuperseded): self.potentiallySuperseded = potentiallySuperseded - def get_potentiallySupersededTime(self): return self.potentiallySupersededTime - def set_potentiallySupersededTime(self, potentiallySupersededTime): self.potentiallySupersededTime = potentiallySupersededTime - def get_reason(self): return self.reason - def set_reason(self, reason): self.reason = reason - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_String192(self, value): - # Validate type String192, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.currentStatus is not None or - self.dateTime is not None or - self.potentiallySuperseded is not None or - self.potentiallySupersededTime is not None or - self.reason is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EventStatus', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EventStatus') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EventStatus', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EventStatus'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='EventStatus', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.currentStatus is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%scurrentStatus>%s%s' % (namespace_, self.gds_format_integer(self.currentStatus, input_name='currentStatus'), namespace_, eol_)) - if self.dateTime is not None: - self.dateTime.export(outfile, level, namespace_, name_='dateTime', pretty_print=pretty_print) - if self.potentiallySuperseded is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%spotentiallySuperseded>%s%s' % (namespace_, self.gds_format_boolean(self.potentiallySuperseded, input_name='potentiallySuperseded'), namespace_, eol_)) - if self.potentiallySupersededTime is not None: - self.potentiallySupersededTime.export(outfile, level, namespace_, name_='potentiallySupersededTime', pretty_print=pretty_print) - if self.reason is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sreason>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.reason).encode(ExternalEncoding), input_name='reason'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='EventStatus'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.currentStatus is not None: - showIndent(outfile, level) - outfile.write('currentStatus=%d,\n' % self.currentStatus) - if self.dateTime is not None: - showIndent(outfile, level) - outfile.write('dateTime=model_.TimeType(\n') - self.dateTime.exportLiteral(outfile, level, name_='dateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.potentiallySuperseded is not None: - showIndent(outfile, level) - outfile.write('potentiallySuperseded=%s,\n' % self.potentiallySuperseded) - if self.potentiallySupersededTime is not None: - showIndent(outfile, level) - outfile.write('potentiallySupersededTime=model_.TimeType(\n') - self.potentiallySupersededTime.exportLiteral(outfile, level, name_='potentiallySupersededTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.reason is not None: - showIndent(outfile, level) - outfile.write('reason=%s,\n' % quote_python(self.reason).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'currentStatus': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'currentStatus') - self.currentStatus = ival_ - self.validate_UInt8(self.currentStatus) # validate type UInt8 - elif nodeName_ == 'dateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTime = obj_ - obj_.original_tagname_ = 'dateTime' - elif nodeName_ == 'potentiallySuperseded': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'potentiallySuperseded') - self.potentiallySuperseded = ival_ - elif nodeName_ == 'potentiallySupersededTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.potentiallySupersededTime = obj_ - obj_.original_tagname_ = 'potentiallySupersededTime' - elif nodeName_ == 'reason': - reason_ = child_.text - reason_ = self.gds_validate_string(reason_, node, 'reason') - self.reason = reason_ - self.validate_String192(self.reason) # validate type String192 -# end class EventStatus - - -class RandomizableEvent(Event): - """An Event that can indicate time ranges over which the start time and - duration SHALL be randomized.""" - subclass = None - superclass = Event - def __init__(self, randomizeDuration=None, randomizeStart=None): - self.original_tagname_ = None - super(RandomizableEvent, self).__init__() - self.randomizeDuration = randomizeDuration - self.randomizeStart = randomizeStart - def factory(*args_, **kwargs_): - if RandomizableEvent.subclass: - return RandomizableEvent.subclass(*args_, **kwargs_) - else: - return RandomizableEvent(*args_, **kwargs_) - factory = staticmethod(factory) - def get_randomizeDuration(self): return self.randomizeDuration - def set_randomizeDuration(self, randomizeDuration): self.randomizeDuration = randomizeDuration - def get_randomizeStart(self): return self.randomizeStart - def set_randomizeStart(self, randomizeStart): self.randomizeStart = randomizeStart - def hasContent_(self): - if ( - self.randomizeDuration is not None or - self.randomizeStart is not None or - super(RandomizableEvent, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RandomizableEvent', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RandomizableEvent') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RandomizableEvent', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RandomizableEvent'): - super(RandomizableEvent, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RandomizableEvent') - def exportChildren(self, outfile, level, namespace_='', name_='RandomizableEvent', fromsubclass_=False, pretty_print=True): - super(RandomizableEvent, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.randomizeDuration is not None: - self.randomizeDuration.export(outfile, level, namespace_, name_='randomizeDuration', pretty_print=pretty_print) - if self.randomizeStart is not None: - self.randomizeStart.export(outfile, level, namespace_, name_='randomizeStart', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='RandomizableEvent'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RandomizableEvent, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RandomizableEvent, self).exportLiteralChildren(outfile, level, name_) - if self.randomizeDuration is not None: - showIndent(outfile, level) - outfile.write('randomizeDuration=model_.OneHourRangeType(\n') - self.randomizeDuration.exportLiteral(outfile, level, name_='randomizeDuration') - showIndent(outfile, level) - outfile.write('),\n') - if self.randomizeStart is not None: - showIndent(outfile, level) - outfile.write('randomizeStart=model_.OneHourRangeType(\n') - self.randomizeStart.exportLiteral(outfile, level, name_='randomizeStart') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RandomizableEvent, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'randomizeDuration': - obj_ = OneHourRangeType.factory() - obj_.build(child_) - self.randomizeDuration = obj_ - obj_.original_tagname_ = 'randomizeDuration' - elif nodeName_ == 'randomizeStart': - obj_ = OneHourRangeType.factory() - obj_.build(child_) - self.randomizeStart = obj_ - obj_.original_tagname_ = 'randomizeStart' - super(RandomizableEvent, self).buildChildren(child_, node, nodeName_, True) -# end class RandomizableEvent - - -class AccumulationBehaviourType(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 3 = Cumulative The - sum of the previous billing period values. Note: - “Cumulative” is commonly used in conjunction with - “demand.” Each demand reset causes the maximum demand value - for the present billing period (since the last demand reset) to - accumulate as an accumulative total of all maximum demands. So - instead of “zeroing” the demand register, a demand reset has - the affect of adding the present maximum demand to this - accumulating total. 4 = DeltaData The difference between the - value at the end of the prescribed interval and the beginning of - the interval. This is used for incremental interval data. Note: - One common application would be for load profile data, another - use might be to report the number of events within an interval - (such as the number of equipment energizations within the - specified period of time.) 6 = Indicating As if a needle is - swung out on the meter face to a value to indicate the current - value. (Note: An “indicating” value is typically measured - over hundreds of milliseconds or greater, or may imply a - “pusher” mechanism to capture a value. Compare this to - “instantaneous” which is measured over a shorter period of - time.) 9 = Summation A form of accumulation which is selective - with respect to time. Note : “Summation” could be considered - a specialization of “Bulk Quantity” according to the rules - of inheritance where “Summation” selectively accumulates - pulses over a timing pattern, and “BulkQuantity” accumulates - pulses all of the time. 12 = Instantaneous Typically measured - over the fastest period of time allowed by the definition of the - metric (usually milliseconds or tens of milliseconds.) (Note: - “Instantaneous” was moved to attribute #3 in 61968-9Ed2 from - attribute #1 in 61968-9Ed1.) All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if AccumulationBehaviourType.subclass: - return AccumulationBehaviourType.subclass(*args_, **kwargs_) - else: - return AccumulationBehaviourType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AccumulationBehaviourType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AccumulationBehaviourType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='AccumulationBehaviourType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AccumulationBehaviourType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='AccumulationBehaviourType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='AccumulationBehaviourType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class AccumulationBehaviourType - - -class ApplianceLoadReductionType(GeneratedsSuper): - """0 - Delay Appliance Load Parameter requesting the appliance to - respond by providing a moderate load reduction for the duration - of a delay period. Typically referring to a “non-emergency” - event in which appliances can continue operating if already in a - load consuming period. 1 - Temporary Appliance Load Reduction - Parameter requesting the appliance to respond by providing an - aggressive load reduction for a short time period. Typically - referring to an “emergency/spinning reserve” event in which - an appliance should start shedding load if currently in a load - consuming period. * Full definition of how appliances react when - receiving each parameter is document in the EPA document - - ENERGY STAR® Program Requirements, Product Specification for - Residential Refrigerators and Freezers, Eligibility Criteria 5, - Draft 2 Version 5.0. All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if ApplianceLoadReductionType.subclass: - return ApplianceLoadReductionType.subclass(*args_, **kwargs_) - else: - return ApplianceLoadReductionType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ApplianceLoadReductionType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ApplianceLoadReductionType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='ApplianceLoadReductionType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ApplianceLoadReductionType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ApplianceLoadReductionType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='ApplianceLoadReductionType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class ApplianceLoadReductionType - - -class CommodityType(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 1 = Electricity - secondary metered value (a premises meter is typically a - secondary meter) 2 = Electricity primary metered value 4 = Air 7 - = NaturalGas 8 = Propane 9 = PotableWater 10 = Steam 11 = - WasteWater 12 = HeatingFluid 13 = CoolingFluid All other values - reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if CommodityType.subclass: - return CommodityType.subclass(*args_, **kwargs_) - else: - return CommodityType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CommodityType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CommodityType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='CommodityType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CommodityType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CommodityType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='CommodityType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class CommodityType - - -class ConsumptionBlockType(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 1 = Block 1 2 = Block - 2 3 = Block 3 4 = Block 4 5 = Block 5 6 = Block 6 7 = Block 7 8 - = Block 8 9 = Block 9 10 = Block 10 11 = Block 11 12 = Block 12 - 13 = Block 13 14 = Block 14 15 = Block 15 16 = Block 16 All - other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if ConsumptionBlockType.subclass: - return ConsumptionBlockType.subclass(*args_, **kwargs_) - else: - return ConsumptionBlockType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ConsumptionBlockType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ConsumptionBlockType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='ConsumptionBlockType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ConsumptionBlockType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ConsumptionBlockType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='ConsumptionBlockType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class ConsumptionBlockType - - -class CurrencyCode(GeneratedsSuper): - """Follows codes defined in [ISO 4217]. 0 - Not Applicable (default, if - not specified) 36 - Australian Dollar 124 - Canadian Dollar 840 - - US Dollar 978 - Euro This is not a complete list.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if CurrencyCode.subclass: - return CurrencyCode.subclass(*args_, **kwargs_) - else: - return CurrencyCode(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CurrencyCode', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CurrencyCode') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='CurrencyCode', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CurrencyCode'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='CurrencyCode', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='CurrencyCode'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class CurrencyCode - - -class DataQualifierType(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 2 = Average 8 = - Maximum 9 = Minimum 12 = Normal All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if DataQualifierType.subclass: - return DataQualifierType.subclass(*args_, **kwargs_) - else: - return DataQualifierType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DataQualifierType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DataQualifierType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='DataQualifierType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DataQualifierType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DataQualifierType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='DataQualifierType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class DataQualifierType - - -class DateTimeInterval(GeneratedsSuper): - """Interval of date and time.""" - subclass = None - superclass = None - def __init__(self, duration=None, start=None): - self.original_tagname_ = None - self.duration = duration - self.start = start - def factory(*args_, **kwargs_): - if DateTimeInterval.subclass: - return DateTimeInterval.subclass(*args_, **kwargs_) - else: - return DateTimeInterval(*args_, **kwargs_) - factory = staticmethod(factory) - def get_duration(self): return self.duration - def set_duration(self, duration): self.duration = duration - def get_start(self): return self.start - def set_start(self, start): self.start = start - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def hasContent_(self): - if ( - self.duration is not None or - self.start is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DateTimeInterval', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DateTimeInterval') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DateTimeInterval', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DateTimeInterval'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DateTimeInterval', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.duration is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sduration>%s%s' % (namespace_, self.gds_format_integer(self.duration, input_name='duration'), namespace_, eol_)) - if self.start is not None: - self.start.export(outfile, level, namespace_, name_='start', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DateTimeInterval'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.duration is not None: - showIndent(outfile, level) - outfile.write('duration=%d,\n' % self.duration) - if self.start is not None: - showIndent(outfile, level) - outfile.write('start=model_.TimeType(\n') - self.start.exportLiteral(outfile, level, name_='start') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'duration': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'duration') - self.duration = ival_ - self.validate_UInt32(self.duration) # validate type UInt32 - elif nodeName_ == 'start': - obj_ = TimeType.factory() - obj_.build(child_) - self.start = obj_ - obj_.original_tagname_ = 'start' -# end class DateTimeInterval - - -class DeviceCategoryType(GeneratedsSuper): - """The Device category types defined. Bit positions SHALL be defined as - follows: 0 - Programmable Communicating Thermostat 1 - Strip - Heaters 2 - Baseboard Heaters 3 - Water Heater 4 - Pool Pump 5 - - Sauna 6 - Hot tub 7 - Smart Appliance 8 - Irrigation Pump 9 - - Managed Commercial and Industrial (C&I) Loads 10 - Simple - misc. (Residential On/Off) loads 11 - Exterior Lighting 12 - - Interior Lighting 13 - Electric Vehicle 14 - Generation Systems - 15 - Load Control Switch 16 - Smart Inverter 17 - EVSE 18 - RESU - 19 - Energy Management System 20 - Smart Energy Module All other - values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if DeviceCategoryType.subclass: - return DeviceCategoryType.subclass(*args_, **kwargs_) - else: - return DeviceCategoryType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DeviceCategoryType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceCategoryType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='DeviceCategoryType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DeviceCategoryType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DeviceCategoryType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='DeviceCategoryType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class DeviceCategoryType - - -class DstRuleType(GeneratedsSuper): - """Bit map encoded rule from which is calculated the start or end time, - within the current year, to which daylight savings time offset - must be applied. The rule encoding: Bits 0 - 11: seconds 0 - - 3599 Bits 12 - 16: hours 0 - 23 Bits 17 - 19: day of the week 0 - = not applicable, 1 - 7 (Monday = 1) Bits:20 - 24: day of the - month 0 = not applicable, 1 - 31 Bits: 25 - 27: operator - (detailed below) Bits: 28 - 31: month 1 - 12 Rule value of - 0xFFFFFFFF means rule processing/DST correction is disabled. The - operators: 0: DST starts/ends on the Day of the Month 1: DST - starts/ends on the Day of the Week that is on or after the Day - of the Month 2: DST starts/ends on the first occurrence of the - Day of the Week in a month 3: DST starts/ends on the second - occurrence of the Day of the Week in a month 4: DST starts/ends - on the third occurrence of the Day of the Week in a month 5: DST - starts/ends on the forth occurrence of the Day of the Week in a - month 6: DST starts/ends on the fifth occurrence of the Day of - the Week in a month 7: DST starts/ends on the last occurrence of - the Day of the Week in a month An example: DST starts on third - Friday in March at 1:45 AM. The rule... Seconds: 2700 Hours: 1 - Day of Week: 5 Day of Month: 0 Operator: 4 Month: 3""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if DstRuleType.subclass: - return DstRuleType.subclass(*args_, **kwargs_) - else: - return DstRuleType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DstRuleType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DstRuleType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='DstRuleType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DstRuleType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='DstRuleType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='DstRuleType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class DstRuleType - - -class FlowDirectionType(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 1 = Forward - (delivered to customer) 19 = Reverse (received from customer) - All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if FlowDirectionType.subclass: - return FlowDirectionType.subclass(*args_, **kwargs_) - else: - return FlowDirectionType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FlowDirectionType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FlowDirectionType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='FlowDirectionType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FlowDirectionType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='FlowDirectionType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='FlowDirectionType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class FlowDirectionType - - -class KindType(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 3 = Currency 8 = - Demand 12 = Energy 37 = Power All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if KindType.subclass: - return KindType.subclass(*args_, **kwargs_) - else: - return KindType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='KindType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='KindType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='KindType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='KindType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='KindType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='KindType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class KindType - - -class LocaleType(GeneratedsSuper): - """[RFC 4646] identifier of a language-region""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if LocaleType.subclass: - return LocaleType.subclass(*args_, **kwargs_) - else: - return LocaleType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LocaleType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LocaleType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='LocaleType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LocaleType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='LocaleType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='LocaleType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class LocaleType - - -class mRIDType(GeneratedsSuper): - """A master resource identifier. The IANA PEN [PEN] provider ID SHALL - be specified in bits 0-31, the least-significant bits, and - objects created by that provider SHALL be assigned unique IDs - with the remaining 96 bits. - 0xFFFFFFFFFFFFFFFFFFFFFFFF[XXXXXXXX], where [XXXXXXXX] is the - PEN, is reserved for a object that is being created (e.g., a - ReadingSet for the current time that is still accumulating). - Except for this special reserved identifier, each modification - of an object (resource) representation MUST have a different - "version".""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if mRIDType.subclass: - return mRIDType.subclass(*args_, **kwargs_) - else: - return mRIDType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='mRIDType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='mRIDType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='mRIDType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='mRIDType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='mRIDType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='mRIDType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class mRIDType - - -class OneHourRangeType(GeneratedsSuper): - """A signed time offset, typically applied to a Time value, expressed - in seconds, with range -3600 to 3600.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if OneHourRangeType.subclass: - return OneHourRangeType.subclass(*args_, **kwargs_) - else: - return OneHourRangeType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='OneHourRangeType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='OneHourRangeType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='OneHourRangeType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='OneHourRangeType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='OneHourRangeType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='OneHourRangeType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class OneHourRangeType - - -class PENType(GeneratedsSuper): - """IANA Private Enterprise Number [PEN].""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PENType.subclass: - return PENType.subclass(*args_, **kwargs_) - else: - return PENType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PENType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PENType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PENType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PENType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PENType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PENType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PENType - - -class PerCent(GeneratedsSuper): - """Used for percentages, specified in hundredths of a percent, 0 - - 10000. (10000 = 100%)""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PerCent.subclass: - return PerCent.subclass(*args_, **kwargs_) - else: - return PerCent(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PerCent', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PerCent') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PerCent', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PerCent'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PerCent', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PerCent'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PerCent - - -class PhaseCode(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 32 = Phase C (and S2) - 33 = Phase CN (and S2N) 40 = Phase CA 64 = Phase B 65 = Phase BN - 66 = Phase BC 128 = Phase A (and S1) 129 = Phase AN (and S1N) - 132 = Phase AB 224 = Phase ABC All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PhaseCode.subclass: - return PhaseCode.subclass(*args_, **kwargs_) - else: - return PhaseCode(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PhaseCode', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PhaseCode') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PhaseCode', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PhaseCode'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PhaseCode', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PhaseCode'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PhaseCode - - -class PINType(GeneratedsSuper): - """6 digit unsigned decimal integer (0 - 999999). (Note that this only - requires 20 bits, if it can be allocated.)""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PINType.subclass: - return PINType.subclass(*args_, **kwargs_) - else: - return PINType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PINType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PINType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PINType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PINType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PINType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PINType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PINType - - -class PowerOfTenMultiplierType(GeneratedsSuper): - """-9 = nano=x10^-9 -6 = micro=x10^-6 -3 = milli=x10^-3 0 = none=x1 - (default, if not specified) 1 = deca=x10 2 = hecto=x100 3 = - kilo=x1000 6 = Mega=x10^6 9 = Giga=x10^9 This is not a complete - list. Any integer between -9 and 9 SHALL be supported, - indicating the power of ten multiplier for the units.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PowerOfTenMultiplierType.subclass: - return PowerOfTenMultiplierType.subclass(*args_, **kwargs_) - else: - return PowerOfTenMultiplierType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PowerOfTenMultiplierType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PowerOfTenMultiplierType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PowerOfTenMultiplierType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PowerOfTenMultiplierType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PowerOfTenMultiplierType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PowerOfTenMultiplierType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PowerOfTenMultiplierType - - -class PrimacyType(GeneratedsSuper): - """Values possible for indication of "Primary" provider: 0: In home - energy management system 1: Contracted premises service provider - 2: Non-contractual service provider All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if PrimacyType.subclass: - return PrimacyType.subclass(*args_, **kwargs_) - else: - return PrimacyType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PrimacyType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PrimacyType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='PrimacyType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PrimacyType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='PrimacyType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='PrimacyType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class PrimacyType - - -class RealEnergy(GeneratedsSuper): - """Real electrical energy""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if RealEnergy.subclass: - return RealEnergy.subclass(*args_, **kwargs_) - else: - return RealEnergy(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_UInt48(self, value): - # Validate type UInt48, a restriction on xs:unsignedLong. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RealEnergy', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RealEnergy') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RealEnergy', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RealEnergy'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='RealEnergy', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='RealEnergy'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_UInt48(self.value) # validate type UInt48 -# end class RealEnergy - - -class RoleFlagsType(GeneratedsSuper): - """Specifies the roles that apply to a usage point. Bit 0 - isMirror - - SHALL be set if the server is not the measurement device Bit 1 - - isPremisesAggregationPoint - SHALL be set if the UsagePoint is - the point of delivery for a premises Bit 2 - isPEV - SHALL be - set if the usage applies to an electric vehicle Bit 3 - isDER - - SHALL be set if the usage applies to a distributed energy - resource, capable of delivering power to the grid. Bit 4 - - isRevenueQuality - SHALL be set if usage was measured by a - device certified as revenue quality Bit 5 - isDC - SHALL be set - if the usage point measures direct current Bit 6 - isSubmeter - - SHALL be set if the usage point is not a premises aggregation - point Bit 7-15 - Reserved""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if RoleFlagsType.subclass: - return RoleFlagsType.subclass(*args_, **kwargs_) - else: - return RoleFlagsType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RoleFlagsType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RoleFlagsType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='RoleFlagsType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RoleFlagsType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='RoleFlagsType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='RoleFlagsType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class RoleFlagsType - - -class ServiceKind(GeneratedsSuper): - """Service kind 0 - electricity 1 - gas 2 - water 3 - time 4 - pressure - 5 - heat 6 - cooling All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if ServiceKind.subclass: - return ServiceKind.subclass(*args_, **kwargs_) - else: - return ServiceKind(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ServiceKind', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceKind') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='ServiceKind', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ServiceKind'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='ServiceKind', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='ServiceKind'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class ServiceKind - - -class SFDIType(GeneratedsSuper): - """Unsigned integer, max inclusive 687194767359, which is 2^36-1 - (68719476735), with added check digit. See Section 8.3.2 for - check digit calculation.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if SFDIType.subclass: - return SFDIType.subclass(*args_, **kwargs_) - else: - return SFDIType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SFDIType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SFDIType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='SFDIType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SFDIType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='SFDIType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='SFDIType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class SFDIType - - -class SignedPerCent(GeneratedsSuper): - """Used for signed percentages, specified in hundredths of a percent, - -10000 - 10000. (10000 = 100%)""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if SignedPerCent.subclass: - return SignedPerCent.subclass(*args_, **kwargs_) - else: - return SignedPerCent(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - # Added by Kisensum so that 0 value will generate element - self.valueOf_ is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SignedPerCent', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SignedPerCent') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='SignedPerCent', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SignedPerCent'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='SignedPerCent', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='SignedPerCent'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class SignedPerCent - - -class SignedRealEnergy(GeneratedsSuper): - """Real electrical energy, signed.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.value = value - def factory(*args_, **kwargs_): - if SignedRealEnergy.subclass: - return SignedRealEnergy.subclass(*args_, **kwargs_) - else: - return SignedRealEnergy(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_Int48(self, value): - # Validate type Int48, a restriction on xs:long. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SignedRealEnergy', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SignedRealEnergy') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SignedRealEnergy', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SignedRealEnergy'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='SignedRealEnergy', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='SignedRealEnergy'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int48(self.value) # validate type Int48 -# end class SignedRealEnergy - - -class TimeOffsetType(GeneratedsSuper): - """A signed time offset, typically applied to a Time value, expressed - in seconds.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if TimeOffsetType.subclass: - return TimeOffsetType.subclass(*args_, **kwargs_) - else: - return TimeOffsetType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TimeOffsetType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TimeOffsetType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='TimeOffsetType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TimeOffsetType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='TimeOffsetType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='TimeOffsetType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class TimeOffsetType - - -class TimeType(GeneratedsSuper): - """Time is a signed 64 bit value representing the number of seconds - since 0 hours, 0 minutes, 0 seconds, on the 1st of January, - 1970, in UTC, not counting leap seconds.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if TimeType.subclass: - return TimeType.subclass(*args_, **kwargs_) - else: - return TimeType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TimeType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TimeType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='TimeType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TimeType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='TimeType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='TimeType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class TimeType - - -class TOUType(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 1 = TOU A 2 = TOU B 3 - = TOU C 4 = TOU D 5 = TOU E 6 = TOU F 7 = TOU G 8 = TOU H 9 = - TOU I 10 = TOU J 11 = TOU K 12 = TOU L 13 = TOU M 14 = TOU N 15 - = TOU O All other values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if TOUType.subclass: - return TOUType.subclass(*args_, **kwargs_) - else: - return TOUType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TOUType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TOUType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='TOUType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TOUType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='TOUType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='TOUType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class TOUType - - -class UnitType(GeneratedsSuper): - """The unit types defined for end device control target reductions. 0 - - kWh 1 - kW 2 - Watts 3 - Cubic Meters 4 - Cubic Feet 5 - US - Gallons 6 - Imperial Gallons 7 - BTUs 8 - Liters 9 - kPA (gauge) - 10 - kPA (absolute) 11 - Mega Joule 12 - Unitless All other - values reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if UnitType.subclass: - return UnitType.subclass(*args_, **kwargs_) - else: - return UnitType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UnitType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UnitType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='UnitType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UnitType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='UnitType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='UnitType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class UnitType - - -class UnitValueType(GeneratedsSuper): - """Type for specification of a specific value, with units and power of - ten multiplier.""" - subclass = None - superclass = None - def __init__(self, multiplier=None, unit=None, value=None): - self.original_tagname_ = None - self.multiplier = multiplier - self.unit = unit - self.value = value - def factory(*args_, **kwargs_): - if UnitValueType.subclass: - return UnitValueType.subclass(*args_, **kwargs_) - else: - return UnitValueType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_multiplier(self): return self.multiplier - def set_multiplier(self, multiplier): self.multiplier = multiplier - def get_unit(self): return self.unit - def set_unit(self, unit): self.unit = unit - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_Int32(self, value): - # Validate type Int32, a restriction on xs:int. - pass - def hasContent_(self): - if ( - self.multiplier is not None or - self.unit is not None or - self.value is not None - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UnitValueType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UnitValueType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='UnitValueType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UnitValueType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='UnitValueType', fromsubclass_=False, pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.multiplier is not None: - self.multiplier.export(outfile, level, namespace_, name_='multiplier', pretty_print=pretty_print) - if self.unit is not None: - self.unit.export(outfile, level, namespace_, name_='unit', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='UnitValueType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - if self.multiplier is not None: - showIndent(outfile, level) - outfile.write('multiplier=model_.PowerOfTenMultiplierType(\n') - self.multiplier.exportLiteral(outfile, level, name_='multiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.unit is not None: - showIndent(outfile, level) - outfile.write('unit=model_.UomType(\n') - self.unit.exportLiteral(outfile, level, name_='unit') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'multiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.multiplier = obj_ - obj_.original_tagname_ = 'multiplier' - elif nodeName_ == 'unit': - obj_ = UomType.factory() - obj_.build(child_) - self.unit = obj_ - obj_.original_tagname_ = 'unit' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int32(self.value) # validate type Int32 -# end class UnitValueType - - -class UomType(GeneratedsSuper): - """0 = Not Applicable (default, if not specified) 5 = A (Current in - Amperes (RMS)) 6 = Kelvin (Temperature) 23 = Degrees Celsius - (Relative temperature) 29 = Voltage 31 = J (Energy joule) 33 = - Hz (Frequency) 38 =W (Real power in Watts) 42 = m3 (Cubic Meter) - 61 = VA (Apparent power) 63 = var (Reactive power) 65 = CosTheta - (Displacement Power Factor) 67 = V² (Volts squared) 69 = A² - (Amp squared) 71 = VAh (Apparent energy) 72 = Wh (Real energy in - Watt-hours) 73 = varh (Reactive energy) 106 = Ah (Ampere-hours / - Available Charge) 119 = ft3 (Cubic Feet) 122 = ft3/h (Cubic Feet - per Hour) 125 = m3/h (Cubic Meter per Hour) 128 = US gl (US - Gallons) 129 = US gl/h (US Gallons per Hour) 130 = IMP gl - (Imperial Gallons) 131 = IMP gl/h (Imperial Gallons per Hour) - 132 = BTU 133 = BTU/h 134 = Liter 137 = L/h (Liters per Hour) - 140 = PA(gauge) 155 = PA(absolute) 169 = Therm All other values - reserved.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if UomType.subclass: - return UomType.subclass(*args_, **kwargs_) - else: - return UomType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UomType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UomType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='UomType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UomType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='UomType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='UomType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class UomType - - -class VersionType(GeneratedsSuper): - """Version SHALL indicate a distinct identifier for each revision of an - IdentifiedObject. If not specified, a default version of "0" - (initial version) SHALL be assumed. Upon modification of any - IdentifiedObject, the mRID SHALL remain the same, but the - version SHALL be incremented. Servers MAY NOT modify objects - that they did not create, unless they were notified of the - change from the entity controlling the object's PEN.""" - subclass = None - superclass = None - def __init__(self, valueOf_=None): - self.original_tagname_ = None - self.valueOf_ = valueOf_ - def factory(*args_, **kwargs_): - if VersionType.subclass: - return VersionType.subclass(*args_, **kwargs_) - else: - return VersionType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_valueOf_(self): return self.valueOf_ - def set_valueOf_(self, valueOf_): self.valueOf_ = valueOf_ - def hasContent_(self): - if ( - self.valueOf_ - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='VersionType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='VersionType') - if self.hasContent_(): - outfile.write('>') - outfile.write(str(self.valueOf_).encode(ExternalEncoding)) - self.exportChildren(outfile, level + 1, namespace_='', name_='VersionType', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='VersionType'): - pass - def exportChildren(self, outfile, level, namespace_='', name_='VersionType', fromsubclass_=False, pretty_print=True): - pass - def exportLiteral(self, outfile, level, name_='VersionType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('valueOf_ = """%s""",\n' % (self.valueOf_,)) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - pass - def exportLiteralChildren(self, outfile, level, name_): - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - self.valueOf_ = get_all_text_(node) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - pass - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - pass -# end class VersionType - - -class ReadingBase(Resource): - """Specific value measured by a meter or other asset. ReadingBase is - abstract, used to define the elements common to Reading and - IntervalReading.""" - subclass = None - superclass = Resource - def __init__(self, consumptionBlock=None, qualityFlags=None, timePeriod=None, touTier=None, value=None): - self.original_tagname_ = None - super(ReadingBase, self).__init__() - self.consumptionBlock = consumptionBlock - self.qualityFlags = qualityFlags - self.timePeriod = timePeriod - self.touTier = touTier - self.value = value - def factory(*args_, **kwargs_): - if ReadingBase.subclass: - return ReadingBase.subclass(*args_, **kwargs_) - else: - return ReadingBase(*args_, **kwargs_) - factory = staticmethod(factory) - def get_consumptionBlock(self): return self.consumptionBlock - def set_consumptionBlock(self, consumptionBlock): self.consumptionBlock = consumptionBlock - def get_qualityFlags(self): return self.qualityFlags - def set_qualityFlags(self, qualityFlags): self.qualityFlags = qualityFlags - def get_timePeriod(self): return self.timePeriod - def set_timePeriod(self, timePeriod): self.timePeriod = timePeriod - def get_touTier(self): return self.touTier - def set_touTier(self, touTier): self.touTier = touTier - def get_value(self): return self.value - def set_value(self, value): self.value = value - def validate_HexBinary16(self, value): - # Validate type HexBinary16, a restriction on xs:hexBinary. - pass - def validate_Int48(self, value): - # Validate type Int48, a restriction on xs:long. - pass - def hasContent_(self): - if ( - self.consumptionBlock is not None or - self.qualityFlags is not None or - self.timePeriod is not None or - self.touTier is not None or - self.value is not None or - super(ReadingBase, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingBase', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingBase') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingBase', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingBase'): - super(ReadingBase, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingBase') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingBase', fromsubclass_=False, pretty_print=True): - super(ReadingBase, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.consumptionBlock is not None: - self.consumptionBlock.export(outfile, level, namespace_, name_='consumptionBlock', pretty_print=pretty_print) - if self.qualityFlags is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%squalityFlags>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.qualityFlags).encode(ExternalEncoding), input_name='qualityFlags'), namespace_, eol_)) - if self.timePeriod is not None: - self.timePeriod.export(outfile, level, namespace_, name_='timePeriod', pretty_print=pretty_print) - if self.touTier is not None: - self.touTier.export(outfile, level, namespace_, name_='touTier', pretty_print=pretty_print) - if self.value is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%svalue>%s%s' % (namespace_, self.gds_format_integer(self.value, input_name='value'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='ReadingBase'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingBase, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingBase, self).exportLiteralChildren(outfile, level, name_) - if self.consumptionBlock is not None: - showIndent(outfile, level) - outfile.write('consumptionBlock=model_.ConsumptionBlockType(\n') - self.consumptionBlock.exportLiteral(outfile, level, name_='consumptionBlock') - showIndent(outfile, level) - outfile.write('),\n') - if self.qualityFlags is not None: - showIndent(outfile, level) - outfile.write('qualityFlags=%s,\n' % quote_python(self.qualityFlags).encode(ExternalEncoding)) - if self.timePeriod is not None: - showIndent(outfile, level) - outfile.write('timePeriod=model_.DateTimeInterval(\n') - self.timePeriod.exportLiteral(outfile, level, name_='timePeriod') - showIndent(outfile, level) - outfile.write('),\n') - if self.touTier is not None: - showIndent(outfile, level) - outfile.write('touTier=model_.TOUType(\n') - self.touTier.exportLiteral(outfile, level, name_='touTier') - showIndent(outfile, level) - outfile.write('),\n') - if self.value is not None: - showIndent(outfile, level) - outfile.write('value=%d,\n' % self.value) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingBase, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'consumptionBlock': - obj_ = ConsumptionBlockType.factory() - obj_.build(child_) - self.consumptionBlock = obj_ - obj_.original_tagname_ = 'consumptionBlock' - elif nodeName_ == 'qualityFlags': - qualityFlags_ = child_.text - qualityFlags_ = self.gds_validate_string(qualityFlags_, node, 'qualityFlags') - self.qualityFlags = qualityFlags_ - self.validate_HexBinary16(self.qualityFlags) # validate type HexBinary16 - elif nodeName_ == 'timePeriod': - obj_ = DateTimeInterval.factory() - obj_.build(child_) - self.timePeriod = obj_ - obj_.original_tagname_ = 'timePeriod' - elif nodeName_ == 'touTier': - obj_ = TOUType.factory() - obj_.build(child_) - self.touTier = obj_ - obj_.original_tagname_ = 'touTier' - elif nodeName_ == 'value': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'value') - self.value = ival_ - self.validate_Int48(self.value) # validate type Int48 - super(ReadingBase, self).buildChildren(child_, node, nodeName_, True) -# end class ReadingBase - - -class SubscribableList(SubscribableResource): - """A List to which a Subscription can be requested.The number - specifying "all" of the items in the list. Required on GET, - ignored otherwise.Indicates the number of items in this page of - results.""" - subclass = None - superclass = SubscribableResource - def __init__(self, all=None, results=None): - self.original_tagname_ = None - super(SubscribableList, self).__init__() - self.all = _cast(None, all) - self.results = _cast(None, results) - def factory(*args_, **kwargs_): - if SubscribableList.subclass: - return SubscribableList.subclass(*args_, **kwargs_) - else: - return SubscribableList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_all(self): return self.all - def set_all(self, all): self.all = all - def get_results(self): return self.results - def set_results(self, results): self.results = results - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - super(SubscribableList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SubscribableList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SubscribableList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SubscribableList', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SubscribableList'): - super(SubscribableList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SubscribableList') - if self.all is not None and 'all' not in already_processed: - already_processed.add('all') - outfile.write(' all=%s' % (quote_attrib(self.all), )) - if self.results is not None and 'results' not in already_processed: - already_processed.add('results') - outfile.write(' results=%s' % (quote_attrib(self.results), )) - def exportChildren(self, outfile, level, namespace_='', name_='SubscribableList', fromsubclass_=False, pretty_print=True): - super(SubscribableList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='SubscribableList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.all is not None and 'all' not in already_processed: - already_processed.add('all') - showIndent(outfile, level) - outfile.write('all=%d,\n' % (self.all,)) - if self.results is not None and 'results' not in already_processed: - already_processed.add('results') - showIndent(outfile, level) - outfile.write('results=%d,\n' % (self.results,)) - super(SubscribableList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SubscribableList, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('all', node) - if value is not None and 'all' not in already_processed: - already_processed.add('all') - try: - self.all = int(value) - except ValueError as exp: - raise_parse_error(node, 'Bad integer attribute: %s' % exp) - self.validate_UInt16(self.all) # validate type UInt16 - value = find_attr_value_('results', node) - if value is not None and 'results' not in already_processed: - already_processed.add('results') - try: - self.results = int(value) - except ValueError as exp: - raise_parse_error(node, 'Bad integer attribute: %s' % exp) - self.validate_UInt8(self.results) # validate type UInt8 - super(SubscribableList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(SubscribableList, self).buildChildren(child_, node, nodeName_, True) - pass -# end class SubscribableList - - -class SubscribableIdentifiedObject(SubscribableResource): - """An IdentifiedObject to which a Subscription can be requested.""" - subclass = None - superclass = SubscribableResource - def __init__(self, mRID=None, description=None, version=None): - self.original_tagname_ = None - super(SubscribableIdentifiedObject, self).__init__() - self.mRID = mRID - self.description = description - self.version = version - def factory(*args_, **kwargs_): - if SubscribableIdentifiedObject.subclass: - return SubscribableIdentifiedObject.subclass(*args_, **kwargs_) - else: - return SubscribableIdentifiedObject(*args_, **kwargs_) - factory = staticmethod(factory) - def get_mRID(self): return self.mRID - def set_mRID(self, mRID): self.mRID = mRID - def get_description(self): return self.description - def set_description(self, description): self.description = description - def get_version(self): return self.version - def set_version(self, version): self.version = version - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.mRID is not None or - self.description is not None or - self.version is not None or - super(SubscribableIdentifiedObject, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SubscribableIdentifiedObject', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SubscribableIdentifiedObject') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SubscribableIdentifiedObject', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SubscribableIdentifiedObject'): - super(SubscribableIdentifiedObject, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SubscribableIdentifiedObject') - def exportChildren(self, outfile, level, namespace_='', name_='SubscribableIdentifiedObject', fromsubclass_=False, pretty_print=True): - super(SubscribableIdentifiedObject, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.mRID is not None: - self.mRID.export(outfile, level, namespace_, name_='mRID', pretty_print=pretty_print) - if self.description is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdescription>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.description).encode(ExternalEncoding), input_name='description'), namespace_, eol_)) - if self.version is not None: - self.version.export(outfile, level, namespace_, name_='version', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='SubscribableIdentifiedObject'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SubscribableIdentifiedObject, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SubscribableIdentifiedObject, self).exportLiteralChildren(outfile, level, name_) - if self.mRID is not None: - showIndent(outfile, level) - outfile.write('mRID=model_.mRIDType(\n') - self.mRID.exportLiteral(outfile, level, name_='mRID') - showIndent(outfile, level) - outfile.write('),\n') - if self.description is not None: - showIndent(outfile, level) - outfile.write('description=%s,\n' % quote_python(self.description).encode(ExternalEncoding)) - if self.version is not None: - showIndent(outfile, level) - outfile.write('version=model_.VersionType(\n') - self.version.exportLiteral(outfile, level, name_='version') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SubscribableIdentifiedObject, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'mRID': - obj_ = mRIDType.factory() - obj_.build(child_) - self.mRID = obj_ - obj_.original_tagname_ = 'mRID' - elif nodeName_ == 'description': - description_ = child_.text - description_ = self.gds_validate_string(description_, node, 'description') - self.description = description_ - self.validate_String32(self.description) # validate type String32 - elif nodeName_ == 'version': - obj_ = VersionType.factory() - obj_.build(child_) - self.version = obj_ - obj_.original_tagname_ = 'version' - super(SubscribableIdentifiedObject, self).buildChildren(child_, node, nodeName_, True) -# end class SubscribableIdentifiedObject - - -class RespondableIdentifiedObject(RespondableResource): - """An IdentifiedObject to which a Response can be requested.""" - subclass = None - superclass = RespondableResource - def __init__(self, mRID=None, description=None, version=None): - self.original_tagname_ = None - super(RespondableIdentifiedObject, self).__init__() - self.mRID = mRID - self.description = description - self.version = version - def factory(*args_, **kwargs_): - if RespondableIdentifiedObject.subclass: - return RespondableIdentifiedObject.subclass(*args_, **kwargs_) - else: - return RespondableIdentifiedObject(*args_, **kwargs_) - factory = staticmethod(factory) - def get_mRID(self): return self.mRID - def set_mRID(self, mRID): self.mRID = mRID - def get_description(self): return self.description - def set_description(self, description): self.description = description - def get_version(self): return self.version - def set_version(self, version): self.version = version - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.mRID is not None or - self.description is not None or - self.version is not None or - super(RespondableIdentifiedObject, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RespondableIdentifiedObject', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RespondableIdentifiedObject') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RespondableIdentifiedObject', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RespondableIdentifiedObject'): - super(RespondableIdentifiedObject, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RespondableIdentifiedObject') - def exportChildren(self, outfile, level, namespace_='', name_='RespondableIdentifiedObject', fromsubclass_=False, pretty_print=True): - super(RespondableIdentifiedObject, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.mRID is not None: - self.mRID.export(outfile, level, namespace_, name_='mRID', pretty_print=pretty_print) - if self.description is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdescription>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.description).encode(ExternalEncoding), input_name='description'), namespace_, eol_)) - if self.version is not None: - self.version.export(outfile, level, namespace_, name_='version', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='RespondableIdentifiedObject'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RespondableIdentifiedObject, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RespondableIdentifiedObject, self).exportLiteralChildren(outfile, level, name_) - if self.mRID is not None: - showIndent(outfile, level) - outfile.write('mRID=model_.mRIDType(\n') - self.mRID.exportLiteral(outfile, level, name_='mRID') - showIndent(outfile, level) - outfile.write('),\n') - if self.description is not None: - showIndent(outfile, level) - outfile.write('description=%s,\n' % quote_python(self.description).encode(ExternalEncoding)) - if self.version is not None: - showIndent(outfile, level) - outfile.write('version=model_.VersionType(\n') - self.version.exportLiteral(outfile, level, name_='version') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RespondableIdentifiedObject, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'mRID': - obj_ = mRIDType.factory() - obj_.build(child_) - self.mRID = obj_ - obj_.original_tagname_ = 'mRID' - elif nodeName_ == 'description': - description_ = child_.text - description_ = self.gds_validate_string(description_, node, 'description') - self.description = description_ - self.validate_String32(self.description) # validate type String32 - elif nodeName_ == 'version': - obj_ = VersionType.factory() - obj_.build(child_) - self.version = obj_ - obj_.original_tagname_ = 'version' - super(RespondableIdentifiedObject, self).buildChildren(child_, node, nodeName_, True) -# end class RespondableIdentifiedObject - - -class List(Resource): - """Container to hold a collection of object instances or references. - See [ZB 11-0167] Design Patterns section for additional - details.The number specifying "all" of the items in the list. - Required on a response to a GET, ignored otherwise.Indicates the - number of items in this page of results.""" - subclass = None - superclass = Resource - def __init__(self, all=None, results=None): - self.original_tagname_ = None - super(List, self).__init__() - self.all = _cast(None, all) - self.results = _cast(None, results) - def factory(*args_, **kwargs_): - if List.subclass: - return List.subclass(*args_, **kwargs_) - else: - return List(*args_, **kwargs_) - factory = staticmethod(factory) - def get_all(self): return self.all - def set_all(self, all): self.all = all - def get_results(self): return self.results - def set_results(self, results): self.results = results - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - super(List, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='List', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='List') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='List', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='List'): - super(List, self).exportAttributes(outfile, level, already_processed, namespace_, name_='List') - if self.all is not None and 'all' not in already_processed: - already_processed.add('all') - outfile.write(' all=%s' % (quote_attrib(self.all), )) - if self.results is not None and 'results' not in already_processed: - already_processed.add('results') - outfile.write(' results=%s' % (quote_attrib(self.results), )) - def exportChildren(self, outfile, level, namespace_='', name_='List', fromsubclass_=False, pretty_print=True): - super(List, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='List'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.all is not None and 'all' not in already_processed: - already_processed.add('all') - showIndent(outfile, level) - outfile.write('all=%d,\n' % (self.all,)) - if self.results is not None and 'results' not in already_processed: - already_processed.add('results') - showIndent(outfile, level) - outfile.write('results=%d,\n' % (self.results,)) - super(List, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(List, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('all', node) - if value is not None and 'all' not in already_processed: - already_processed.add('all') - try: - self.all = int(value) - except ValueError as exp: - raise_parse_error(node, 'Bad integer attribute: %s' % exp) - self.validate_UInt16(self.all) # validate type UInt16 - value = find_attr_value_('results', node) - if value is not None and 'results' not in already_processed: - already_processed.add('results') - try: - self.results = int(value) - except ValueError as exp: - raise_parse_error(node, 'Bad integer attribute: %s' % exp) - self.validate_UInt8(self.results) # validate type UInt8 - super(List, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(List, self).buildChildren(child_, node, nodeName_, True) - pass -# end class List - - -class IdentifiedObject(Resource): - """This is a root class to provide common naming attributes for all - classes needing naming attributes""" - subclass = None - superclass = Resource - def __init__(self, mRID=None, description=None, version=None): - self.original_tagname_ = None - super(IdentifiedObject, self).__init__() - self.mRID = mRID - self.description = description - self.version = version - def factory(*args_, **kwargs_): - if IdentifiedObject.subclass: - return IdentifiedObject.subclass(*args_, **kwargs_) - else: - return IdentifiedObject(*args_, **kwargs_) - factory = staticmethod(factory) - def get_mRID(self): return self.mRID - def set_mRID(self, mRID): self.mRID = mRID - def get_description(self): return self.description - def set_description(self, description): self.description = description - def get_version(self): return self.version - def set_version(self, version): self.version = version - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.mRID is not None or - self.description is not None or - self.version is not None or - super(IdentifiedObject, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='IdentifiedObject', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='IdentifiedObject') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='IdentifiedObject', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='IdentifiedObject'): - super(IdentifiedObject, self).exportAttributes(outfile, level, already_processed, namespace_, name_='IdentifiedObject') - def exportChildren(self, outfile, level, namespace_='', name_='IdentifiedObject', fromsubclass_=False, pretty_print=True): - super(IdentifiedObject, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.mRID is not None: - self.mRID.export(outfile, level, namespace_, name_='mRID', pretty_print=pretty_print) - if self.description is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdescription>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.description).encode(ExternalEncoding), input_name='description'), namespace_, eol_)) - if self.version is not None: - self.version.export(outfile, level, namespace_, name_='version', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='IdentifiedObject'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(IdentifiedObject, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(IdentifiedObject, self).exportLiteralChildren(outfile, level, name_) - if self.mRID is not None: - showIndent(outfile, level) - outfile.write('mRID=model_.mRIDType(\n') - self.mRID.exportLiteral(outfile, level, name_='mRID') - showIndent(outfile, level) - outfile.write('),\n') - if self.description is not None: - showIndent(outfile, level) - outfile.write('description=%s,\n' % quote_python(self.description).encode(ExternalEncoding)) - if self.version is not None: - showIndent(outfile, level) - outfile.write('version=model_.VersionType(\n') - self.version.exportLiteral(outfile, level, name_='version') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(IdentifiedObject, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'mRID': - obj_ = mRIDType.factory() - obj_.build(child_) - self.mRID = obj_ - obj_.original_tagname_ = 'mRID' - elif nodeName_ == 'description': - description_ = child_.text - description_ = self.gds_validate_string(description_, node, 'description') - self.description = description_ - self.validate_String32(self.description) # validate type String32 - elif nodeName_ == 'version': - obj_ = VersionType.factory() - obj_.build(child_) - self.version = obj_ - obj_.original_tagname_ = 'version' - super(IdentifiedObject, self).buildChildren(child_, node, nodeName_, True) -# end class IdentifiedObject - - -class UsagePointListLink(ListLink): - """SHALL contain a Link to a List of UsagePoint instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(UsagePointListLink, self).__init__() - def factory(*args_, **kwargs_): - if UsagePointListLink.subclass: - return UsagePointListLink.subclass(*args_, **kwargs_) - else: - return UsagePointListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(UsagePointListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UsagePointListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePointListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='UsagePointListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UsagePointListLink'): - super(UsagePointListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePointListLink') - def exportChildren(self, outfile, level, namespace_='', name_='UsagePointListLink', fromsubclass_=False, pretty_print=True): - super(UsagePointListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='UsagePointListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(UsagePointListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(UsagePointListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(UsagePointListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(UsagePointListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class UsagePointListLink - - -class UsagePointLink(Link): - """SHALL contain a Link to an instance of UsagePoint.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(UsagePointLink, self).__init__() - def factory(*args_, **kwargs_): - if UsagePointLink.subclass: - return UsagePointLink.subclass(*args_, **kwargs_) - else: - return UsagePointLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(UsagePointLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UsagePointLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePointLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='UsagePointLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UsagePointLink'): - super(UsagePointLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePointLink') - def exportChildren(self, outfile, level, namespace_='', name_='UsagePointLink', fromsubclass_=False, pretty_print=True): - super(UsagePointLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='UsagePointLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(UsagePointLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(UsagePointLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(UsagePointLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(UsagePointLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class UsagePointLink - - -class TimeTariffIntervalListLink(ListLink): - """SHALL contain a Link to a List of TimeTariffInterval instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(TimeTariffIntervalListLink, self).__init__() - def factory(*args_, **kwargs_): - if TimeTariffIntervalListLink.subclass: - return TimeTariffIntervalListLink.subclass(*args_, **kwargs_) - else: - return TimeTariffIntervalListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(TimeTariffIntervalListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TimeTariffIntervalListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TimeTariffIntervalListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TimeTariffIntervalListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TimeTariffIntervalListLink'): - super(TimeTariffIntervalListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TimeTariffIntervalListLink') - def exportChildren(self, outfile, level, namespace_='', name_='TimeTariffIntervalListLink', fromsubclass_=False, pretty_print=True): - super(TimeTariffIntervalListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='TimeTariffIntervalListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TimeTariffIntervalListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TimeTariffIntervalListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TimeTariffIntervalListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(TimeTariffIntervalListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class TimeTariffIntervalListLink - - -class TimeLink(Link): - """SHALL contain a Link to an instance of Time.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(TimeLink, self).__init__() - def factory(*args_, **kwargs_): - if TimeLink.subclass: - return TimeLink.subclass(*args_, **kwargs_) - else: - return TimeLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(TimeLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TimeLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TimeLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TimeLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TimeLink'): - super(TimeLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TimeLink') - def exportChildren(self, outfile, level, namespace_='', name_='TimeLink', fromsubclass_=False, pretty_print=True): - super(TimeLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='TimeLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TimeLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TimeLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TimeLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(TimeLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class TimeLink - - -class TextMessageListLink(ListLink): - """SHALL contain a Link to a List of TextMessage instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(TextMessageListLink, self).__init__() - def factory(*args_, **kwargs_): - if TextMessageListLink.subclass: - return TextMessageListLink.subclass(*args_, **kwargs_) - else: - return TextMessageListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(TextMessageListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TextMessageListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TextMessageListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TextMessageListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TextMessageListLink'): - super(TextMessageListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TextMessageListLink') - def exportChildren(self, outfile, level, namespace_='', name_='TextMessageListLink', fromsubclass_=False, pretty_print=True): - super(TextMessageListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='TextMessageListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TextMessageListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TextMessageListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TextMessageListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(TextMessageListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class TextMessageListLink - - -class TariffProfileListLink(ListLink): - """SHALL contain a Link to a List of TariffProfile instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(TariffProfileListLink, self).__init__() - def factory(*args_, **kwargs_): - if TariffProfileListLink.subclass: - return TariffProfileListLink.subclass(*args_, **kwargs_) - else: - return TariffProfileListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(TariffProfileListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TariffProfileListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TariffProfileListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TariffProfileListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TariffProfileListLink'): - super(TariffProfileListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TariffProfileListLink') - def exportChildren(self, outfile, level, namespace_='', name_='TariffProfileListLink', fromsubclass_=False, pretty_print=True): - super(TariffProfileListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='TariffProfileListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TariffProfileListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TariffProfileListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TariffProfileListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(TariffProfileListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class TariffProfileListLink - - -class TariffProfileLink(Link): - """SHALL contain a Link to an instance of TariffProfile.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(TariffProfileLink, self).__init__() - def factory(*args_, **kwargs_): - if TariffProfileLink.subclass: - return TariffProfileLink.subclass(*args_, **kwargs_) - else: - return TariffProfileLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(TariffProfileLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TariffProfileLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TariffProfileLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TariffProfileLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TariffProfileLink'): - super(TariffProfileLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TariffProfileLink') - def exportChildren(self, outfile, level, namespace_='', name_='TariffProfileLink', fromsubclass_=False, pretty_print=True): - super(TariffProfileLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='TariffProfileLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TariffProfileLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TariffProfileLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TariffProfileLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(TariffProfileLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class TariffProfileLink - - -class TargetReadingListLink(ListLink): - """SHALL contain a Link to a List of TargetReading instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(TargetReadingListLink, self).__init__() - def factory(*args_, **kwargs_): - if TargetReadingListLink.subclass: - return TargetReadingListLink.subclass(*args_, **kwargs_) - else: - return TargetReadingListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(TargetReadingListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TargetReadingListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TargetReadingListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TargetReadingListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TargetReadingListLink'): - super(TargetReadingListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TargetReadingListLink') - def exportChildren(self, outfile, level, namespace_='', name_='TargetReadingListLink', fromsubclass_=False, pretty_print=True): - super(TargetReadingListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='TargetReadingListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TargetReadingListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TargetReadingListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TargetReadingListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(TargetReadingListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class TargetReadingListLink - - -class SupportedLocaleListLink(ListLink): - """SHALL contain a Link to a List of SupportedLocale instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(SupportedLocaleListLink, self).__init__() - def factory(*args_, **kwargs_): - if SupportedLocaleListLink.subclass: - return SupportedLocaleListLink.subclass(*args_, **kwargs_) - else: - return SupportedLocaleListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(SupportedLocaleListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SupportedLocaleListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SupportedLocaleListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SupportedLocaleListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SupportedLocaleListLink'): - super(SupportedLocaleListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SupportedLocaleListLink') - def exportChildren(self, outfile, level, namespace_='', name_='SupportedLocaleListLink', fromsubclass_=False, pretty_print=True): - super(SupportedLocaleListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='SupportedLocaleListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SupportedLocaleListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SupportedLocaleListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SupportedLocaleListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(SupportedLocaleListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class SupportedLocaleListLink - - -class SupplyInterruptionOverrideListLink(ListLink): - """SHALL contain a Link to a List of SupplyInterruptionOverride - instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(SupplyInterruptionOverrideListLink, self).__init__() - def factory(*args_, **kwargs_): - if SupplyInterruptionOverrideListLink.subclass: - return SupplyInterruptionOverrideListLink.subclass(*args_, **kwargs_) - else: - return SupplyInterruptionOverrideListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(SupplyInterruptionOverrideListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SupplyInterruptionOverrideListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SupplyInterruptionOverrideListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SupplyInterruptionOverrideListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SupplyInterruptionOverrideListLink'): - super(SupplyInterruptionOverrideListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SupplyInterruptionOverrideListLink') - def exportChildren(self, outfile, level, namespace_='', name_='SupplyInterruptionOverrideListLink', fromsubclass_=False, pretty_print=True): - super(SupplyInterruptionOverrideListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='SupplyInterruptionOverrideListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SupplyInterruptionOverrideListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SupplyInterruptionOverrideListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SupplyInterruptionOverrideListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(SupplyInterruptionOverrideListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class SupplyInterruptionOverrideListLink - - -class SubscriptionListLink(ListLink): - """SHALL contain a Link to a List of Subscription instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(SubscriptionListLink, self).__init__() - def factory(*args_, **kwargs_): - if SubscriptionListLink.subclass: - return SubscriptionListLink.subclass(*args_, **kwargs_) - else: - return SubscriptionListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(SubscriptionListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SubscriptionListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SubscriptionListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SubscriptionListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SubscriptionListLink'): - super(SubscriptionListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SubscriptionListLink') - def exportChildren(self, outfile, level, namespace_='', name_='SubscriptionListLink', fromsubclass_=False, pretty_print=True): - super(SubscriptionListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='SubscriptionListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SubscriptionListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SubscriptionListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SubscriptionListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(SubscriptionListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class SubscriptionListLink - - -class ServiceSupplierLink(Link): - """SHALL contain a Link to an instance of ServiceSupplier.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(ServiceSupplierLink, self).__init__() - def factory(*args_, **kwargs_): - if ServiceSupplierLink.subclass: - return ServiceSupplierLink.subclass(*args_, **kwargs_) - else: - return ServiceSupplierLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ServiceSupplierLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ServiceSupplierLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceSupplierLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ServiceSupplierLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ServiceSupplierLink'): - super(ServiceSupplierLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceSupplierLink') - def exportChildren(self, outfile, level, namespace_='', name_='ServiceSupplierLink', fromsubclass_=False, pretty_print=True): - super(ServiceSupplierLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ServiceSupplierLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ServiceSupplierLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ServiceSupplierLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ServiceSupplierLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ServiceSupplierLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ServiceSupplierLink - - -class SelfDeviceLink(Link): - """SHALL contain a Link to an instance of SelfDevice.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(SelfDeviceLink, self).__init__() - def factory(*args_, **kwargs_): - if SelfDeviceLink.subclass: - return SelfDeviceLink.subclass(*args_, **kwargs_) - else: - return SelfDeviceLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(SelfDeviceLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SelfDeviceLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SelfDeviceLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SelfDeviceLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SelfDeviceLink'): - super(SelfDeviceLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SelfDeviceLink') - def exportChildren(self, outfile, level, namespace_='', name_='SelfDeviceLink', fromsubclass_=False, pretty_print=True): - super(SelfDeviceLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='SelfDeviceLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SelfDeviceLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SelfDeviceLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SelfDeviceLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(SelfDeviceLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class SelfDeviceLink - - -class RPLSourceRoutesListLink(ListLink): - """SHALL contain a Link to a List of RPLSourceRoutes instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(RPLSourceRoutesListLink, self).__init__() - def factory(*args_, **kwargs_): - if RPLSourceRoutesListLink.subclass: - return RPLSourceRoutesListLink.subclass(*args_, **kwargs_) - else: - return RPLSourceRoutesListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(RPLSourceRoutesListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RPLSourceRoutesListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RPLSourceRoutesListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RPLSourceRoutesListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RPLSourceRoutesListLink'): - super(RPLSourceRoutesListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RPLSourceRoutesListLink') - def exportChildren(self, outfile, level, namespace_='', name_='RPLSourceRoutesListLink', fromsubclass_=False, pretty_print=True): - super(RPLSourceRoutesListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='RPLSourceRoutesListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RPLSourceRoutesListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RPLSourceRoutesListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RPLSourceRoutesListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(RPLSourceRoutesListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class RPLSourceRoutesListLink - - -class RPLInstanceListLink(ListLink): - """SHALL contain a Link to a List of RPLInterface instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(RPLInstanceListLink, self).__init__() - def factory(*args_, **kwargs_): - if RPLInstanceListLink.subclass: - return RPLInstanceListLink.subclass(*args_, **kwargs_) - else: - return RPLInstanceListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(RPLInstanceListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RPLInstanceListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RPLInstanceListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RPLInstanceListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RPLInstanceListLink'): - super(RPLInstanceListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RPLInstanceListLink') - def exportChildren(self, outfile, level, namespace_='', name_='RPLInstanceListLink', fromsubclass_=False, pretty_print=True): - super(RPLInstanceListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='RPLInstanceListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RPLInstanceListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RPLInstanceListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RPLInstanceListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(RPLInstanceListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class RPLInstanceListLink - - -class ResponseSetListLink(ListLink): - """SHALL contain a Link to a List of ResponseSet instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ResponseSetListLink, self).__init__() - def factory(*args_, **kwargs_): - if ResponseSetListLink.subclass: - return ResponseSetListLink.subclass(*args_, **kwargs_) - else: - return ResponseSetListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ResponseSetListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ResponseSetListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseSetListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ResponseSetListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ResponseSetListLink'): - super(ResponseSetListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseSetListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ResponseSetListLink', fromsubclass_=False, pretty_print=True): - super(ResponseSetListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ResponseSetListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ResponseSetListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ResponseSetListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ResponseSetListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ResponseSetListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ResponseSetListLink - - -class ResponseListLink(ListLink): - """SHALL contain a Link to a List of Response instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ResponseListLink, self).__init__() - def factory(*args_, **kwargs_): - if ResponseListLink.subclass: - return ResponseListLink.subclass(*args_, **kwargs_) - else: - return ResponseListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ResponseListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ResponseListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ResponseListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ResponseListLink'): - super(ResponseListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ResponseListLink', fromsubclass_=False, pretty_print=True): - super(ResponseListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ResponseListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ResponseListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ResponseListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ResponseListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ResponseListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ResponseListLink - - -class RegistrationLink(Link): - """SHALL contain a Link to an instance of Registration.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(RegistrationLink, self).__init__() - def factory(*args_, **kwargs_): - if RegistrationLink.subclass: - return RegistrationLink.subclass(*args_, **kwargs_) - else: - return RegistrationLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(RegistrationLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RegistrationLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RegistrationLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RegistrationLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RegistrationLink'): - super(RegistrationLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RegistrationLink') - def exportChildren(self, outfile, level, namespace_='', name_='RegistrationLink', fromsubclass_=False, pretty_print=True): - super(RegistrationLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='RegistrationLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RegistrationLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RegistrationLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RegistrationLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(RegistrationLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class RegistrationLink - - -class ReadingTypeLink(Link): - """SHALL contain a Link to an instance of ReadingType.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(ReadingTypeLink, self).__init__() - def factory(*args_, **kwargs_): - if ReadingTypeLink.subclass: - return ReadingTypeLink.subclass(*args_, **kwargs_) - else: - return ReadingTypeLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ReadingTypeLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingTypeLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingTypeLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingTypeLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingTypeLink'): - super(ReadingTypeLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingTypeLink') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingTypeLink', fromsubclass_=False, pretty_print=True): - super(ReadingTypeLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ReadingTypeLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingTypeLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingTypeLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingTypeLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ReadingTypeLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ReadingTypeLink - - -class ReadingSetListLink(ListLink): - """SHALL contain a Link to a List of ReadingSet instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ReadingSetListLink, self).__init__() - def factory(*args_, **kwargs_): - if ReadingSetListLink.subclass: - return ReadingSetListLink.subclass(*args_, **kwargs_) - else: - return ReadingSetListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ReadingSetListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingSetListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingSetListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingSetListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingSetListLink'): - super(ReadingSetListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingSetListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingSetListLink', fromsubclass_=False, pretty_print=True): - super(ReadingSetListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ReadingSetListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingSetListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingSetListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingSetListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ReadingSetListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ReadingSetListLink - - -class ReadingListLink(ListLink): - """SHALL contain a Link to a List of Reading instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ReadingListLink, self).__init__() - def factory(*args_, **kwargs_): - if ReadingListLink.subclass: - return ReadingListLink.subclass(*args_, **kwargs_) - else: - return ReadingListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ReadingListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingListLink'): - super(ReadingListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingListLink', fromsubclass_=False, pretty_print=True): - super(ReadingListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ReadingListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ReadingListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ReadingListLink - - -class ReadingLink(Link): - """A Link to a Reading.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(ReadingLink, self).__init__() - def factory(*args_, **kwargs_): - if ReadingLink.subclass: - return ReadingLink.subclass(*args_, **kwargs_) - else: - return ReadingLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ReadingLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingLink'): - super(ReadingLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingLink') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingLink', fromsubclass_=False, pretty_print=True): - super(ReadingLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ReadingLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ReadingLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ReadingLink - - -class RateComponentListLink(ListLink): - """SHALL contain a Link to a List of RateComponent instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(RateComponentListLink, self).__init__() - def factory(*args_, **kwargs_): - if RateComponentListLink.subclass: - return RateComponentListLink.subclass(*args_, **kwargs_) - else: - return RateComponentListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(RateComponentListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RateComponentListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RateComponentListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RateComponentListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RateComponentListLink'): - super(RateComponentListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RateComponentListLink') - def exportChildren(self, outfile, level, namespace_='', name_='RateComponentListLink', fromsubclass_=False, pretty_print=True): - super(RateComponentListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='RateComponentListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RateComponentListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RateComponentListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RateComponentListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(RateComponentListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class RateComponentListLink - - -class RateComponentLink(Link): - """SHALL contain a Link to an instance of RateComponent.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(RateComponentLink, self).__init__() - def factory(*args_, **kwargs_): - if RateComponentLink.subclass: - return RateComponentLink.subclass(*args_, **kwargs_) - else: - return RateComponentLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(RateComponentLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RateComponentLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RateComponentLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RateComponentLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RateComponentLink'): - super(RateComponentLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RateComponentLink') - def exportChildren(self, outfile, level, namespace_='', name_='RateComponentLink', fromsubclass_=False, pretty_print=True): - super(RateComponentLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='RateComponentLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RateComponentLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RateComponentLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RateComponentLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(RateComponentLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class RateComponentLink - - -class ProjectionReadingListLink(ListLink): - """SHALL contain a Link to a List of ProjectionReading instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ProjectionReadingListLink, self).__init__() - def factory(*args_, **kwargs_): - if ProjectionReadingListLink.subclass: - return ProjectionReadingListLink.subclass(*args_, **kwargs_) - else: - return ProjectionReadingListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ProjectionReadingListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ProjectionReadingListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ProjectionReadingListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ProjectionReadingListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ProjectionReadingListLink'): - super(ProjectionReadingListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ProjectionReadingListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ProjectionReadingListLink', fromsubclass_=False, pretty_print=True): - super(ProjectionReadingListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ProjectionReadingListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ProjectionReadingListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ProjectionReadingListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ProjectionReadingListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ProjectionReadingListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ProjectionReadingListLink - - -class PriceResponseCfgListLink(ListLink): - """SHALL contain a Link to a List of PriceResponseCfg instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(PriceResponseCfgListLink, self).__init__() - def factory(*args_, **kwargs_): - if PriceResponseCfgListLink.subclass: - return PriceResponseCfgListLink.subclass(*args_, **kwargs_) - else: - return PriceResponseCfgListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(PriceResponseCfgListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PriceResponseCfgListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PriceResponseCfgListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PriceResponseCfgListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PriceResponseCfgListLink'): - super(PriceResponseCfgListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PriceResponseCfgListLink') - def exportChildren(self, outfile, level, namespace_='', name_='PriceResponseCfgListLink', fromsubclass_=False, pretty_print=True): - super(PriceResponseCfgListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='PriceResponseCfgListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PriceResponseCfgListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PriceResponseCfgListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PriceResponseCfgListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(PriceResponseCfgListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class PriceResponseCfgListLink - - -class PrepayOperationStatusLink(Link): - """SHALL contain a Link to an instance of PrepayOperationStatus.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(PrepayOperationStatusLink, self).__init__() - def factory(*args_, **kwargs_): - if PrepayOperationStatusLink.subclass: - return PrepayOperationStatusLink.subclass(*args_, **kwargs_) - else: - return PrepayOperationStatusLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(PrepayOperationStatusLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PrepayOperationStatusLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PrepayOperationStatusLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PrepayOperationStatusLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PrepayOperationStatusLink'): - super(PrepayOperationStatusLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PrepayOperationStatusLink') - def exportChildren(self, outfile, level, namespace_='', name_='PrepayOperationStatusLink', fromsubclass_=False, pretty_print=True): - super(PrepayOperationStatusLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='PrepayOperationStatusLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PrepayOperationStatusLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PrepayOperationStatusLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PrepayOperationStatusLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(PrepayOperationStatusLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class PrepayOperationStatusLink - - -class PrepaymentListLink(ListLink): - """SHALL contain a Link to a List of Prepayment instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(PrepaymentListLink, self).__init__() - def factory(*args_, **kwargs_): - if PrepaymentListLink.subclass: - return PrepaymentListLink.subclass(*args_, **kwargs_) - else: - return PrepaymentListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(PrepaymentListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PrepaymentListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PrepaymentListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PrepaymentListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PrepaymentListLink'): - super(PrepaymentListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PrepaymentListLink') - def exportChildren(self, outfile, level, namespace_='', name_='PrepaymentListLink', fromsubclass_=False, pretty_print=True): - super(PrepaymentListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='PrepaymentListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PrepaymentListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PrepaymentListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PrepaymentListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(PrepaymentListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class PrepaymentListLink - - -class PrepaymentLink(Link): - """SHALL contain a Link to an instance of Prepayment.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(PrepaymentLink, self).__init__() - def factory(*args_, **kwargs_): - if PrepaymentLink.subclass: - return PrepaymentLink.subclass(*args_, **kwargs_) - else: - return PrepaymentLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(PrepaymentLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PrepaymentLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PrepaymentLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PrepaymentLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PrepaymentLink'): - super(PrepaymentLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PrepaymentLink') - def exportChildren(self, outfile, level, namespace_='', name_='PrepaymentLink', fromsubclass_=False, pretty_print=True): - super(PrepaymentLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='PrepaymentLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PrepaymentLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PrepaymentLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PrepaymentLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(PrepaymentLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class PrepaymentLink - - -class PowerStatusLink(Link): - """SHALL contain a Link to an instance of PowerStatus.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(PowerStatusLink, self).__init__() - def factory(*args_, **kwargs_): - if PowerStatusLink.subclass: - return PowerStatusLink.subclass(*args_, **kwargs_) - else: - return PowerStatusLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(PowerStatusLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PowerStatusLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PowerStatusLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PowerStatusLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PowerStatusLink'): - super(PowerStatusLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PowerStatusLink') - def exportChildren(self, outfile, level, namespace_='', name_='PowerStatusLink', fromsubclass_=False, pretty_print=True): - super(PowerStatusLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='PowerStatusLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PowerStatusLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PowerStatusLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PowerStatusLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(PowerStatusLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class PowerStatusLink - - -class NotificationListLink(ListLink): - """SHALL contain a Link to a List of Notification instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(NotificationListLink, self).__init__() - def factory(*args_, **kwargs_): - if NotificationListLink.subclass: - return NotificationListLink.subclass(*args_, **kwargs_) - else: - return NotificationListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(NotificationListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='NotificationListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='NotificationListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='NotificationListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='NotificationListLink'): - super(NotificationListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='NotificationListLink') - def exportChildren(self, outfile, level, namespace_='', name_='NotificationListLink', fromsubclass_=False, pretty_print=True): - super(NotificationListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='NotificationListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(NotificationListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(NotificationListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(NotificationListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(NotificationListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class NotificationListLink - - -class NeighborListLink(ListLink): - """SHALL contain a Link to a List of Neighbor instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(NeighborListLink, self).__init__() - def factory(*args_, **kwargs_): - if NeighborListLink.subclass: - return NeighborListLink.subclass(*args_, **kwargs_) - else: - return NeighborListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(NeighborListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='NeighborListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='NeighborListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='NeighborListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='NeighborListLink'): - super(NeighborListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='NeighborListLink') - def exportChildren(self, outfile, level, namespace_='', name_='NeighborListLink', fromsubclass_=False, pretty_print=True): - super(NeighborListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='NeighborListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(NeighborListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(NeighborListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(NeighborListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(NeighborListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class NeighborListLink - - -class MirrorUsagePointListLink(ListLink): - """SHALL contain a Link to a List of MirrorUsagePoint instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(MirrorUsagePointListLink, self).__init__() - def factory(*args_, **kwargs_): - if MirrorUsagePointListLink.subclass: - return MirrorUsagePointListLink.subclass(*args_, **kwargs_) - else: - return MirrorUsagePointListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(MirrorUsagePointListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MirrorUsagePointListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorUsagePointListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MirrorUsagePointListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MirrorUsagePointListLink'): - super(MirrorUsagePointListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorUsagePointListLink') - def exportChildren(self, outfile, level, namespace_='', name_='MirrorUsagePointListLink', fromsubclass_=False, pretty_print=True): - super(MirrorUsagePointListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='MirrorUsagePointListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MirrorUsagePointListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MirrorUsagePointListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MirrorUsagePointListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(MirrorUsagePointListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class MirrorUsagePointListLink - - -class MeterReadingListLink(ListLink): - """SHALL contain a Link to a List of MeterReading instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(MeterReadingListLink, self).__init__() - def factory(*args_, **kwargs_): - if MeterReadingListLink.subclass: - return MeterReadingListLink.subclass(*args_, **kwargs_) - else: - return MeterReadingListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(MeterReadingListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MeterReadingListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReadingListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MeterReadingListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MeterReadingListLink'): - super(MeterReadingListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReadingListLink') - def exportChildren(self, outfile, level, namespace_='', name_='MeterReadingListLink', fromsubclass_=False, pretty_print=True): - super(MeterReadingListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='MeterReadingListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MeterReadingListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MeterReadingListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MeterReadingListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(MeterReadingListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class MeterReadingListLink - - -class MeterReadingLink(Link): - """SHALL contain a Link to an instance of MeterReading.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(MeterReadingLink, self).__init__() - def factory(*args_, **kwargs_): - if MeterReadingLink.subclass: - return MeterReadingLink.subclass(*args_, **kwargs_) - else: - return MeterReadingLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(MeterReadingLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MeterReadingLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReadingLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MeterReadingLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MeterReadingLink'): - super(MeterReadingLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReadingLink') - def exportChildren(self, outfile, level, namespace_='', name_='MeterReadingLink', fromsubclass_=False, pretty_print=True): - super(MeterReadingLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='MeterReadingLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MeterReadingLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MeterReadingLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MeterReadingLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(MeterReadingLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class MeterReadingLink - - -class MessagingProgramListLink(ListLink): - """SHALL contain a Link to a List of MessagingProgram instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(MessagingProgramListLink, self).__init__() - def factory(*args_, **kwargs_): - if MessagingProgramListLink.subclass: - return MessagingProgramListLink.subclass(*args_, **kwargs_) - else: - return MessagingProgramListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(MessagingProgramListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MessagingProgramListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MessagingProgramListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MessagingProgramListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MessagingProgramListLink'): - super(MessagingProgramListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MessagingProgramListLink') - def exportChildren(self, outfile, level, namespace_='', name_='MessagingProgramListLink', fromsubclass_=False, pretty_print=True): - super(MessagingProgramListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='MessagingProgramListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MessagingProgramListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MessagingProgramListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MessagingProgramListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(MessagingProgramListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class MessagingProgramListLink - - -class LogEventListLink(ListLink): - """SHALL contain a Link to a List of LogEvent instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(LogEventListLink, self).__init__() - def factory(*args_, **kwargs_): - if LogEventListLink.subclass: - return LogEventListLink.subclass(*args_, **kwargs_) - else: - return LogEventListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(LogEventListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LogEventListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LogEventListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LogEventListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LogEventListLink'): - super(LogEventListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='LogEventListLink') - def exportChildren(self, outfile, level, namespace_='', name_='LogEventListLink', fromsubclass_=False, pretty_print=True): - super(LogEventListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='LogEventListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(LogEventListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(LogEventListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(LogEventListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(LogEventListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class LogEventListLink - - -class LoadShedAvailabilityLink(Link): - """SHALL contain a Link to an instance of LoadShedAvailability.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(LoadShedAvailabilityLink, self).__init__() - def factory(*args_, **kwargs_): - if LoadShedAvailabilityLink.subclass: - return LoadShedAvailabilityLink.subclass(*args_, **kwargs_) - else: - return LoadShedAvailabilityLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(LoadShedAvailabilityLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LoadShedAvailabilityLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LoadShedAvailabilityLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LoadShedAvailabilityLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LoadShedAvailabilityLink'): - super(LoadShedAvailabilityLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='LoadShedAvailabilityLink') - def exportChildren(self, outfile, level, namespace_='', name_='LoadShedAvailabilityLink', fromsubclass_=False, pretty_print=True): - super(LoadShedAvailabilityLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='LoadShedAvailabilityLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(LoadShedAvailabilityLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(LoadShedAvailabilityLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(LoadShedAvailabilityLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(LoadShedAvailabilityLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class LoadShedAvailabilityLink - - -class LLInterfaceListLink(ListLink): - """SHALL contain a Link to a List of LLInterface instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(LLInterfaceListLink, self).__init__() - def factory(*args_, **kwargs_): - if LLInterfaceListLink.subclass: - return LLInterfaceListLink.subclass(*args_, **kwargs_) - else: - return LLInterfaceListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(LLInterfaceListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LLInterfaceListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LLInterfaceListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LLInterfaceListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LLInterfaceListLink'): - super(LLInterfaceListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='LLInterfaceListLink') - def exportChildren(self, outfile, level, namespace_='', name_='LLInterfaceListLink', fromsubclass_=False, pretty_print=True): - super(LLInterfaceListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='LLInterfaceListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(LLInterfaceListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(LLInterfaceListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(LLInterfaceListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(LLInterfaceListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class LLInterfaceListLink - - -class IPInterfaceListLink(ListLink): - """SHALL contain a Link to a List of IPInterface instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(IPInterfaceListLink, self).__init__() - def factory(*args_, **kwargs_): - if IPInterfaceListLink.subclass: - return IPInterfaceListLink.subclass(*args_, **kwargs_) - else: - return IPInterfaceListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(IPInterfaceListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='IPInterfaceListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='IPInterfaceListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='IPInterfaceListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='IPInterfaceListLink'): - super(IPInterfaceListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='IPInterfaceListLink') - def exportChildren(self, outfile, level, namespace_='', name_='IPInterfaceListLink', fromsubclass_=False, pretty_print=True): - super(IPInterfaceListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='IPInterfaceListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(IPInterfaceListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(IPInterfaceListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(IPInterfaceListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(IPInterfaceListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class IPInterfaceListLink - - -class IPAddrListLink(ListLink): - """SHALL contain a Link to a List of IPAddr instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(IPAddrListLink, self).__init__() - def factory(*args_, **kwargs_): - if IPAddrListLink.subclass: - return IPAddrListLink.subclass(*args_, **kwargs_) - else: - return IPAddrListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(IPAddrListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='IPAddrListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='IPAddrListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='IPAddrListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='IPAddrListLink'): - super(IPAddrListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='IPAddrListLink') - def exportChildren(self, outfile, level, namespace_='', name_='IPAddrListLink', fromsubclass_=False, pretty_print=True): - super(IPAddrListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='IPAddrListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(IPAddrListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(IPAddrListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(IPAddrListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(IPAddrListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class IPAddrListLink - - -class HistoricalReadingListLink(ListLink): - """SHALL contain a Link to a List of HistoricalReading instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(HistoricalReadingListLink, self).__init__() - def factory(*args_, **kwargs_): - if HistoricalReadingListLink.subclass: - return HistoricalReadingListLink.subclass(*args_, **kwargs_) - else: - return HistoricalReadingListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(HistoricalReadingListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='HistoricalReadingListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='HistoricalReadingListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='HistoricalReadingListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='HistoricalReadingListLink'): - super(HistoricalReadingListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='HistoricalReadingListLink') - def exportChildren(self, outfile, level, namespace_='', name_='HistoricalReadingListLink', fromsubclass_=False, pretty_print=True): - super(HistoricalReadingListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='HistoricalReadingListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(HistoricalReadingListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(HistoricalReadingListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(HistoricalReadingListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(HistoricalReadingListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class HistoricalReadingListLink - - -class FunctionSetAssignmentsListLink(ListLink): - """SHALL contain a Link to a List of FunctionSetAssignments instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(FunctionSetAssignmentsListLink, self).__init__() - def factory(*args_, **kwargs_): - if FunctionSetAssignmentsListLink.subclass: - return FunctionSetAssignmentsListLink.subclass(*args_, **kwargs_) - else: - return FunctionSetAssignmentsListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(FunctionSetAssignmentsListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FunctionSetAssignmentsListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FunctionSetAssignmentsListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FunctionSetAssignmentsListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FunctionSetAssignmentsListLink'): - super(FunctionSetAssignmentsListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FunctionSetAssignmentsListLink') - def exportChildren(self, outfile, level, namespace_='', name_='FunctionSetAssignmentsListLink', fromsubclass_=False, pretty_print=True): - super(FunctionSetAssignmentsListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='FunctionSetAssignmentsListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FunctionSetAssignmentsListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FunctionSetAssignmentsListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FunctionSetAssignmentsListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(FunctionSetAssignmentsListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class FunctionSetAssignmentsListLink - - -class FlowReservationResponseListLink(ListLink): - """SHALL contain a Link to a List of FlowReservationResponse instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(FlowReservationResponseListLink, self).__init__() - def factory(*args_, **kwargs_): - if FlowReservationResponseListLink.subclass: - return FlowReservationResponseListLink.subclass(*args_, **kwargs_) - else: - return FlowReservationResponseListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(FlowReservationResponseListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FlowReservationResponseListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationResponseListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FlowReservationResponseListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FlowReservationResponseListLink'): - super(FlowReservationResponseListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationResponseListLink') - def exportChildren(self, outfile, level, namespace_='', name_='FlowReservationResponseListLink', fromsubclass_=False, pretty_print=True): - super(FlowReservationResponseListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='FlowReservationResponseListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FlowReservationResponseListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FlowReservationResponseListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FlowReservationResponseListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(FlowReservationResponseListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class FlowReservationResponseListLink - - -class FlowReservationRequestListLink(ListLink): - """SHALL contain a Link to a List of FlowReservationRequest instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(FlowReservationRequestListLink, self).__init__() - def factory(*args_, **kwargs_): - if FlowReservationRequestListLink.subclass: - return FlowReservationRequestListLink.subclass(*args_, **kwargs_) - else: - return FlowReservationRequestListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(FlowReservationRequestListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FlowReservationRequestListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationRequestListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FlowReservationRequestListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FlowReservationRequestListLink'): - super(FlowReservationRequestListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationRequestListLink') - def exportChildren(self, outfile, level, namespace_='', name_='FlowReservationRequestListLink', fromsubclass_=False, pretty_print=True): - super(FlowReservationRequestListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='FlowReservationRequestListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FlowReservationRequestListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FlowReservationRequestListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FlowReservationRequestListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(FlowReservationRequestListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class FlowReservationRequestListLink - - -class FileStatusLink(Link): - """SHALL contain a Link to an instance of FileStatus.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(FileStatusLink, self).__init__() - def factory(*args_, **kwargs_): - if FileStatusLink.subclass: - return FileStatusLink.subclass(*args_, **kwargs_) - else: - return FileStatusLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(FileStatusLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FileStatusLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FileStatusLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FileStatusLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FileStatusLink'): - super(FileStatusLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FileStatusLink') - def exportChildren(self, outfile, level, namespace_='', name_='FileStatusLink', fromsubclass_=False, pretty_print=True): - super(FileStatusLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='FileStatusLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FileStatusLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FileStatusLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FileStatusLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(FileStatusLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class FileStatusLink - - -class FileListLink(ListLink): - """SHALL contain a Link to a List of File instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(FileListLink, self).__init__() - def factory(*args_, **kwargs_): - if FileListLink.subclass: - return FileListLink.subclass(*args_, **kwargs_) - else: - return FileListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(FileListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FileListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FileListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FileListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FileListLink'): - super(FileListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FileListLink') - def exportChildren(self, outfile, level, namespace_='', name_='FileListLink', fromsubclass_=False, pretty_print=True): - super(FileListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='FileListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FileListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FileListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FileListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(FileListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class FileListLink - - -class FileLink(Link): - """This element MUST be set to the URI of the most recent File being - loaded/activated by the LD. In the case of file status 0, this - element MUST be omitted.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(FileLink, self).__init__() - def factory(*args_, **kwargs_): - if FileLink.subclass: - return FileLink.subclass(*args_, **kwargs_) - else: - return FileLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(FileLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FileLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FileLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FileLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FileLink'): - super(FileLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FileLink') - def exportChildren(self, outfile, level, namespace_='', name_='FileLink', fromsubclass_=False, pretty_print=True): - super(FileLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='FileLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FileLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FileLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FileLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(FileLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class FileLink - - -class EndDeviceListLink(ListLink): - """SHALL contain a Link to a List of EndDevice instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(EndDeviceListLink, self).__init__() - def factory(*args_, **kwargs_): - if EndDeviceListLink.subclass: - return EndDeviceListLink.subclass(*args_, **kwargs_) - else: - return EndDeviceListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(EndDeviceListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EndDeviceListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EndDeviceListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EndDeviceListLink'): - super(EndDeviceListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceListLink') - def exportChildren(self, outfile, level, namespace_='', name_='EndDeviceListLink', fromsubclass_=False, pretty_print=True): - super(EndDeviceListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='EndDeviceListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(EndDeviceListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(EndDeviceListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(EndDeviceListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(EndDeviceListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class EndDeviceListLink - - -class EndDeviceLink(Link): - """SHALL contain a Link to an instance of EndDevice.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(EndDeviceLink, self).__init__() - def factory(*args_, **kwargs_): - if EndDeviceLink.subclass: - return EndDeviceLink.subclass(*args_, **kwargs_) - else: - return EndDeviceLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(EndDeviceLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EndDeviceLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EndDeviceLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EndDeviceLink'): - super(EndDeviceLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceLink') - def exportChildren(self, outfile, level, namespace_='', name_='EndDeviceLink', fromsubclass_=False, pretty_print=True): - super(EndDeviceLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='EndDeviceLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(EndDeviceLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(EndDeviceLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(EndDeviceLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(EndDeviceLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class EndDeviceLink - - -class EndDeviceControlListLink(ListLink): - """SHALL contain a Link to a List of EndDeviceControl instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(EndDeviceControlListLink, self).__init__() - def factory(*args_, **kwargs_): - if EndDeviceControlListLink.subclass: - return EndDeviceControlListLink.subclass(*args_, **kwargs_) - else: - return EndDeviceControlListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(EndDeviceControlListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EndDeviceControlListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceControlListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EndDeviceControlListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EndDeviceControlListLink'): - super(EndDeviceControlListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceControlListLink') - def exportChildren(self, outfile, level, namespace_='', name_='EndDeviceControlListLink', fromsubclass_=False, pretty_print=True): - super(EndDeviceControlListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='EndDeviceControlListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(EndDeviceControlListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(EndDeviceControlListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(EndDeviceControlListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(EndDeviceControlListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class EndDeviceControlListLink - - -class DeviceStatusLink(Link): - """SHALL contain a Link to an instance of DeviceStatus.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DeviceStatusLink, self).__init__() - def factory(*args_, **kwargs_): - if DeviceStatusLink.subclass: - return DeviceStatusLink.subclass(*args_, **kwargs_) - else: - return DeviceStatusLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DeviceStatusLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DeviceStatusLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceStatusLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DeviceStatusLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DeviceStatusLink'): - super(DeviceStatusLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceStatusLink') - def exportChildren(self, outfile, level, namespace_='', name_='DeviceStatusLink', fromsubclass_=False, pretty_print=True): - super(DeviceStatusLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DeviceStatusLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DeviceStatusLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DeviceStatusLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DeviceStatusLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DeviceStatusLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DeviceStatusLink - - -class DeviceInformationLink(Link): - """SHALL contain a Link to an instance of DeviceInformation.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DeviceInformationLink, self).__init__() - def factory(*args_, **kwargs_): - if DeviceInformationLink.subclass: - return DeviceInformationLink.subclass(*args_, **kwargs_) - else: - return DeviceInformationLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DeviceInformationLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DeviceInformationLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceInformationLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DeviceInformationLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DeviceInformationLink'): - super(DeviceInformationLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceInformationLink') - def exportChildren(self, outfile, level, namespace_='', name_='DeviceInformationLink', fromsubclass_=False, pretty_print=True): - super(DeviceInformationLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DeviceInformationLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DeviceInformationLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DeviceInformationLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DeviceInformationLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DeviceInformationLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DeviceInformationLink - - -class DeviceCapabilityLink(Link): - """SHALL contain a Link to an instance of DeviceCapability.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DeviceCapabilityLink, self).__init__() - def factory(*args_, **kwargs_): - if DeviceCapabilityLink.subclass: - return DeviceCapabilityLink.subclass(*args_, **kwargs_) - else: - return DeviceCapabilityLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DeviceCapabilityLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DeviceCapabilityLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceCapabilityLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DeviceCapabilityLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DeviceCapabilityLink'): - super(DeviceCapabilityLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceCapabilityLink') - def exportChildren(self, outfile, level, namespace_='', name_='DeviceCapabilityLink', fromsubclass_=False, pretty_print=True): - super(DeviceCapabilityLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DeviceCapabilityLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DeviceCapabilityLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DeviceCapabilityLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DeviceCapabilityLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DeviceCapabilityLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DeviceCapabilityLink - - -class DERStatusLink(Link): - """SHALL contain a Link to an instance of DERStatus.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DERStatusLink, self).__init__() - def factory(*args_, **kwargs_): - if DERStatusLink.subclass: - return DERStatusLink.subclass(*args_, **kwargs_) - else: - return DERStatusLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERStatusLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERStatusLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERStatusLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERStatusLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERStatusLink'): - super(DERStatusLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERStatusLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERStatusLink', fromsubclass_=False, pretty_print=True): - super(DERStatusLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERStatusLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERStatusLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERStatusLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERStatusLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERStatusLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERStatusLink - - -class DERSettingsLink(Link): - """SHALL contain a Link to an instance of DERSettings.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DERSettingsLink, self).__init__() - def factory(*args_, **kwargs_): - if DERSettingsLink.subclass: - return DERSettingsLink.subclass(*args_, **kwargs_) - else: - return DERSettingsLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERSettingsLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERSettingsLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERSettingsLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERSettingsLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERSettingsLink'): - super(DERSettingsLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERSettingsLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERSettingsLink', fromsubclass_=False, pretty_print=True): - super(DERSettingsLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERSettingsLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERSettingsLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERSettingsLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERSettingsLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERSettingsLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERSettingsLink - - -class DERProgramListLink(ListLink): - """SHALL contain a Link to a List of DERProgram instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(DERProgramListLink, self).__init__() - def factory(*args_, **kwargs_): - if DERProgramListLink.subclass: - return DERProgramListLink.subclass(*args_, **kwargs_) - else: - return DERProgramListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERProgramListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERProgramListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERProgramListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERProgramListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERProgramListLink'): - super(DERProgramListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERProgramListLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERProgramListLink', fromsubclass_=False, pretty_print=True): - super(DERProgramListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERProgramListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERProgramListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERProgramListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERProgramListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERProgramListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERProgramListLink - - -class DERProgramLink(Link): - """SHALL contain a Link to an instance of DERProgram.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DERProgramLink, self).__init__() - def factory(*args_, **kwargs_): - if DERProgramLink.subclass: - return DERProgramLink.subclass(*args_, **kwargs_) - else: - return DERProgramLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERProgramLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERProgramLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERProgramLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERProgramLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERProgramLink'): - super(DERProgramLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERProgramLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERProgramLink', fromsubclass_=False, pretty_print=True): - super(DERProgramLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERProgramLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERProgramLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERProgramLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERProgramLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERProgramLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERProgramLink - - -class DERListLink(ListLink): - """SHALL contain a Link to a List of DER instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(DERListLink, self).__init__() - def factory(*args_, **kwargs_): - if DERListLink.subclass: - return DERListLink.subclass(*args_, **kwargs_) - else: - return DERListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERListLink'): - super(DERListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERListLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERListLink', fromsubclass_=False, pretty_print=True): - super(DERListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERListLink - - -class DERLink(Link): - """SHALL contain a Link to an instance of DER.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DERLink, self).__init__() - def factory(*args_, **kwargs_): - if DERLink.subclass: - return DERLink.subclass(*args_, **kwargs_) - else: - return DERLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERLink'): - super(DERLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERLink', fromsubclass_=False, pretty_print=True): - super(DERLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERLink - - -class DERCurveListLink(ListLink): - """SHALL contain a Link to a List of DERCurve instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(DERCurveListLink, self).__init__() - def factory(*args_, **kwargs_): - if DERCurveListLink.subclass: - return DERCurveListLink.subclass(*args_, **kwargs_) - else: - return DERCurveListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERCurveListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERCurveListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurveListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERCurveListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERCurveListLink'): - super(DERCurveListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurveListLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERCurveListLink', fromsubclass_=False, pretty_print=True): - super(DERCurveListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERCurveListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERCurveListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERCurveListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERCurveListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERCurveListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERCurveListLink - - -class DERCurveLink(Link): - """SHALL contain a Link to an instance of DERCurve.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DERCurveLink, self).__init__() - def factory(*args_, **kwargs_): - if DERCurveLink.subclass: - return DERCurveLink.subclass(*args_, **kwargs_) - else: - return DERCurveLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERCurveLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERCurveLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurveLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERCurveLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERCurveLink'): - super(DERCurveLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurveLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERCurveLink', fromsubclass_=False, pretty_print=True): - super(DERCurveLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERCurveLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERCurveLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERCurveLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERCurveLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERCurveLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERCurveLink - - -class DERControlListLink(ListLink): - """SHALL contain a Link to a List of DERControl instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(DERControlListLink, self).__init__() - def factory(*args_, **kwargs_): - if DERControlListLink.subclass: - return DERControlListLink.subclass(*args_, **kwargs_) - else: - return DERControlListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERControlListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERControlListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERControlListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERControlListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERControlListLink'): - super(DERControlListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERControlListLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERControlListLink', fromsubclass_=False, pretty_print=True): - super(DERControlListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERControlListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERControlListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERControlListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERControlListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERControlListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERControlListLink - - -class DERCapabilityLink(Link): - """SHALL contain a Link to an instance of DERCapability.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DERCapabilityLink, self).__init__() - def factory(*args_, **kwargs_): - if DERCapabilityLink.subclass: - return DERCapabilityLink.subclass(*args_, **kwargs_) - else: - return DERCapabilityLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERCapabilityLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERCapabilityLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERCapabilityLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERCapabilityLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERCapabilityLink'): - super(DERCapabilityLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERCapabilityLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERCapabilityLink', fromsubclass_=False, pretty_print=True): - super(DERCapabilityLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERCapabilityLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERCapabilityLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERCapabilityLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERCapabilityLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERCapabilityLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERCapabilityLink - - -class DefaultDERControlLink(Link): - """SHALL contain a Link to an instance of DefaultDERControl. This is - the default mode of the DER which MAY be overridden by - DERControl events.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DefaultDERControlLink, self).__init__() - def factory(*args_, **kwargs_): - if DefaultDERControlLink.subclass: - return DefaultDERControlLink.subclass(*args_, **kwargs_) - else: - return DefaultDERControlLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DefaultDERControlLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DefaultDERControlLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DefaultDERControlLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DefaultDERControlLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DefaultDERControlLink'): - super(DefaultDERControlLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DefaultDERControlLink') - def exportChildren(self, outfile, level, namespace_='', name_='DefaultDERControlLink', fromsubclass_=False, pretty_print=True): - super(DefaultDERControlLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DefaultDERControlLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DefaultDERControlLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DefaultDERControlLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DefaultDERControlLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DefaultDERControlLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DefaultDERControlLink - - -class DERAvailabilityLink(Link): - """SHALL contain a Link to an instance of DERAvailability.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DERAvailabilityLink, self).__init__() - def factory(*args_, **kwargs_): - if DERAvailabilityLink.subclass: - return DERAvailabilityLink.subclass(*args_, **kwargs_) - else: - return DERAvailabilityLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DERAvailabilityLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERAvailabilityLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERAvailabilityLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERAvailabilityLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERAvailabilityLink'): - super(DERAvailabilityLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERAvailabilityLink') - def exportChildren(self, outfile, level, namespace_='', name_='DERAvailabilityLink', fromsubclass_=False, pretty_print=True): - super(DERAvailabilityLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DERAvailabilityLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERAvailabilityLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERAvailabilityLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERAvailabilityLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DERAvailabilityLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DERAvailabilityLink - - -class DemandResponseProgramListLink(ListLink): - """SHALL contain a Link to a List of DemandResponseProgram instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(DemandResponseProgramListLink, self).__init__() - def factory(*args_, **kwargs_): - if DemandResponseProgramListLink.subclass: - return DemandResponseProgramListLink.subclass(*args_, **kwargs_) - else: - return DemandResponseProgramListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DemandResponseProgramListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DemandResponseProgramListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DemandResponseProgramListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DemandResponseProgramListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DemandResponseProgramListLink'): - super(DemandResponseProgramListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DemandResponseProgramListLink') - def exportChildren(self, outfile, level, namespace_='', name_='DemandResponseProgramListLink', fromsubclass_=False, pretty_print=True): - super(DemandResponseProgramListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DemandResponseProgramListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DemandResponseProgramListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DemandResponseProgramListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DemandResponseProgramListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DemandResponseProgramListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DemandResponseProgramListLink - - -class DemandResponseProgramLink(Link): - """SHALL contain a Link to an instance of DemandResponseProgram.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(DemandResponseProgramLink, self).__init__() - def factory(*args_, **kwargs_): - if DemandResponseProgramLink.subclass: - return DemandResponseProgramLink.subclass(*args_, **kwargs_) - else: - return DemandResponseProgramLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(DemandResponseProgramLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DemandResponseProgramLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DemandResponseProgramLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DemandResponseProgramLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DemandResponseProgramLink'): - super(DemandResponseProgramLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DemandResponseProgramLink') - def exportChildren(self, outfile, level, namespace_='', name_='DemandResponseProgramLink', fromsubclass_=False, pretty_print=True): - super(DemandResponseProgramLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='DemandResponseProgramLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DemandResponseProgramLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DemandResponseProgramLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DemandResponseProgramLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(DemandResponseProgramLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class DemandResponseProgramLink - - -class CustomerAgreementListLink(ListLink): - """SHALL contain a Link to a List of CustomerAgreement instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(CustomerAgreementListLink, self).__init__() - def factory(*args_, **kwargs_): - if CustomerAgreementListLink.subclass: - return CustomerAgreementListLink.subclass(*args_, **kwargs_) - else: - return CustomerAgreementListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(CustomerAgreementListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CustomerAgreementListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAgreementListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CustomerAgreementListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CustomerAgreementListLink'): - super(CustomerAgreementListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAgreementListLink') - def exportChildren(self, outfile, level, namespace_='', name_='CustomerAgreementListLink', fromsubclass_=False, pretty_print=True): - super(CustomerAgreementListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='CustomerAgreementListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CustomerAgreementListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CustomerAgreementListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CustomerAgreementListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(CustomerAgreementListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class CustomerAgreementListLink - - -class CustomerAccountListLink(ListLink): - """SHALL contain a Link to a List of CustomerAccount instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(CustomerAccountListLink, self).__init__() - def factory(*args_, **kwargs_): - if CustomerAccountListLink.subclass: - return CustomerAccountListLink.subclass(*args_, **kwargs_) - else: - return CustomerAccountListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(CustomerAccountListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CustomerAccountListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAccountListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CustomerAccountListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CustomerAccountListLink'): - super(CustomerAccountListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAccountListLink') - def exportChildren(self, outfile, level, namespace_='', name_='CustomerAccountListLink', fromsubclass_=False, pretty_print=True): - super(CustomerAccountListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='CustomerAccountListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CustomerAccountListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CustomerAccountListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CustomerAccountListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(CustomerAccountListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class CustomerAccountListLink - - -class CustomerAccountLink(Link): - """SHALL contain a Link to an instance of CustomerAccount.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(CustomerAccountLink, self).__init__() - def factory(*args_, **kwargs_): - if CustomerAccountLink.subclass: - return CustomerAccountLink.subclass(*args_, **kwargs_) - else: - return CustomerAccountLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(CustomerAccountLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CustomerAccountLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAccountLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CustomerAccountLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CustomerAccountLink'): - super(CustomerAccountLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAccountLink') - def exportChildren(self, outfile, level, namespace_='', name_='CustomerAccountLink', fromsubclass_=False, pretty_print=True): - super(CustomerAccountLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='CustomerAccountLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CustomerAccountLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CustomerAccountLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CustomerAccountLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(CustomerAccountLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class CustomerAccountLink - - -class CreditRegisterListLink(ListLink): - """SHALL contain a Link to a List of CreditRegister instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(CreditRegisterListLink, self).__init__() - def factory(*args_, **kwargs_): - if CreditRegisterListLink.subclass: - return CreditRegisterListLink.subclass(*args_, **kwargs_) - else: - return CreditRegisterListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(CreditRegisterListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CreditRegisterListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CreditRegisterListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CreditRegisterListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CreditRegisterListLink'): - super(CreditRegisterListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CreditRegisterListLink') - def exportChildren(self, outfile, level, namespace_='', name_='CreditRegisterListLink', fromsubclass_=False, pretty_print=True): - super(CreditRegisterListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='CreditRegisterListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CreditRegisterListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CreditRegisterListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CreditRegisterListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(CreditRegisterListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class CreditRegisterListLink - - -class ConsumptionTariffIntervalListLink(ListLink): - """SHALL contain a Link to a List of ConsumptionTariffInterval - instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ConsumptionTariffIntervalListLink, self).__init__() - def factory(*args_, **kwargs_): - if ConsumptionTariffIntervalListLink.subclass: - return ConsumptionTariffIntervalListLink.subclass(*args_, **kwargs_) - else: - return ConsumptionTariffIntervalListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ConsumptionTariffIntervalListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ConsumptionTariffIntervalListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ConsumptionTariffIntervalListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ConsumptionTariffIntervalListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ConsumptionTariffIntervalListLink'): - super(ConsumptionTariffIntervalListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ConsumptionTariffIntervalListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ConsumptionTariffIntervalListLink', fromsubclass_=False, pretty_print=True): - super(ConsumptionTariffIntervalListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ConsumptionTariffIntervalListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ConsumptionTariffIntervalListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ConsumptionTariffIntervalListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ConsumptionTariffIntervalListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ConsumptionTariffIntervalListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ConsumptionTariffIntervalListLink - - -class ConfigurationLink(Link): - """SHALL contain a Link to an instance of Configuration.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(ConfigurationLink, self).__init__() - def factory(*args_, **kwargs_): - if ConfigurationLink.subclass: - return ConfigurationLink.subclass(*args_, **kwargs_) - else: - return ConfigurationLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ConfigurationLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ConfigurationLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ConfigurationLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ConfigurationLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ConfigurationLink'): - super(ConfigurationLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ConfigurationLink') - def exportChildren(self, outfile, level, namespace_='', name_='ConfigurationLink', fromsubclass_=False, pretty_print=True): - super(ConfigurationLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ConfigurationLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ConfigurationLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ConfigurationLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ConfigurationLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ConfigurationLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ConfigurationLink - - -class BillingReadingSetListLink(ListLink): - """SHALL contain a Link to a List of BillingReadingSet instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(BillingReadingSetListLink, self).__init__() - def factory(*args_, **kwargs_): - if BillingReadingSetListLink.subclass: - return BillingReadingSetListLink.subclass(*args_, **kwargs_) - else: - return BillingReadingSetListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(BillingReadingSetListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingReadingSetListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingSetListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingReadingSetListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingReadingSetListLink'): - super(BillingReadingSetListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingSetListLink') - def exportChildren(self, outfile, level, namespace_='', name_='BillingReadingSetListLink', fromsubclass_=False, pretty_print=True): - super(BillingReadingSetListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='BillingReadingSetListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingReadingSetListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingReadingSetListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingReadingSetListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(BillingReadingSetListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class BillingReadingSetListLink - - -class BillingReadingListLink(ListLink): - """SHALL contain a Link to a List of BillingReading instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(BillingReadingListLink, self).__init__() - def factory(*args_, **kwargs_): - if BillingReadingListLink.subclass: - return BillingReadingListLink.subclass(*args_, **kwargs_) - else: - return BillingReadingListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(BillingReadingListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingReadingListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingReadingListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingReadingListLink'): - super(BillingReadingListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingListLink') - def exportChildren(self, outfile, level, namespace_='', name_='BillingReadingListLink', fromsubclass_=False, pretty_print=True): - super(BillingReadingListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='BillingReadingListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingReadingListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingReadingListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingReadingListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(BillingReadingListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class BillingReadingListLink - - -class BillingPeriodListLink(ListLink): - """SHALL contain a Link to a List of BillingPeriod instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(BillingPeriodListLink, self).__init__() - def factory(*args_, **kwargs_): - if BillingPeriodListLink.subclass: - return BillingPeriodListLink.subclass(*args_, **kwargs_) - else: - return BillingPeriodListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(BillingPeriodListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingPeriodListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingPeriodListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingPeriodListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingPeriodListLink'): - super(BillingPeriodListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingPeriodListLink') - def exportChildren(self, outfile, level, namespace_='', name_='BillingPeriodListLink', fromsubclass_=False, pretty_print=True): - super(BillingPeriodListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='BillingPeriodListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingPeriodListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingPeriodListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingPeriodListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(BillingPeriodListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class BillingPeriodListLink - - -class AssociatedUsagePointLink(Link): - """SHALL contain a Link to an instance of UsagePoint. If present, this - is the submeter that monitors the DER output.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(AssociatedUsagePointLink, self).__init__() - def factory(*args_, **kwargs_): - if AssociatedUsagePointLink.subclass: - return AssociatedUsagePointLink.subclass(*args_, **kwargs_) - else: - return AssociatedUsagePointLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(AssociatedUsagePointLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AssociatedUsagePointLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AssociatedUsagePointLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AssociatedUsagePointLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AssociatedUsagePointLink'): - super(AssociatedUsagePointLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='AssociatedUsagePointLink') - def exportChildren(self, outfile, level, namespace_='', name_='AssociatedUsagePointLink', fromsubclass_=False, pretty_print=True): - super(AssociatedUsagePointLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='AssociatedUsagePointLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(AssociatedUsagePointLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(AssociatedUsagePointLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(AssociatedUsagePointLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(AssociatedUsagePointLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class AssociatedUsagePointLink - - -class AssociatedDERProgramListLink(ListLink): - """SHALL contain a Link to a List of DERPrograms having the - DERControl(s) for this DER.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(AssociatedDERProgramListLink, self).__init__() - def factory(*args_, **kwargs_): - if AssociatedDERProgramListLink.subclass: - return AssociatedDERProgramListLink.subclass(*args_, **kwargs_) - else: - return AssociatedDERProgramListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(AssociatedDERProgramListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AssociatedDERProgramListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AssociatedDERProgramListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AssociatedDERProgramListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AssociatedDERProgramListLink'): - super(AssociatedDERProgramListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='AssociatedDERProgramListLink') - def exportChildren(self, outfile, level, namespace_='', name_='AssociatedDERProgramListLink', fromsubclass_=False, pretty_print=True): - super(AssociatedDERProgramListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='AssociatedDERProgramListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(AssociatedDERProgramListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(AssociatedDERProgramListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(AssociatedDERProgramListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(AssociatedDERProgramListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class AssociatedDERProgramListLink - - -class ActiveTimeTariffIntervalListLink(ListLink): - """SHALL contain a Link to a List of active TimeTariffInterval - instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveTimeTariffIntervalListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveTimeTariffIntervalListLink.subclass: - return ActiveTimeTariffIntervalListLink.subclass(*args_, **kwargs_) - else: - return ActiveTimeTariffIntervalListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveTimeTariffIntervalListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveTimeTariffIntervalListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveTimeTariffIntervalListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveTimeTariffIntervalListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveTimeTariffIntervalListLink'): - super(ActiveTimeTariffIntervalListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveTimeTariffIntervalListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveTimeTariffIntervalListLink', fromsubclass_=False, pretty_print=True): - super(ActiveTimeTariffIntervalListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveTimeTariffIntervalListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveTimeTariffIntervalListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveTimeTariffIntervalListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveTimeTariffIntervalListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveTimeTariffIntervalListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveTimeTariffIntervalListLink - - -class ActiveTextMessageListLink(ListLink): - """SHALL contain a Link to a List of active TextMessage instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveTextMessageListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveTextMessageListLink.subclass: - return ActiveTextMessageListLink.subclass(*args_, **kwargs_) - else: - return ActiveTextMessageListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveTextMessageListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveTextMessageListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveTextMessageListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveTextMessageListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveTextMessageListLink'): - super(ActiveTextMessageListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveTextMessageListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveTextMessageListLink', fromsubclass_=False, pretty_print=True): - super(ActiveTextMessageListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveTextMessageListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveTextMessageListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveTextMessageListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveTextMessageListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveTextMessageListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveTextMessageListLink - - -class ActiveTargetReadingListLink(ListLink): - """SHALL contain a Link to a List of active TargetReading instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveTargetReadingListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveTargetReadingListLink.subclass: - return ActiveTargetReadingListLink.subclass(*args_, **kwargs_) - else: - return ActiveTargetReadingListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveTargetReadingListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveTargetReadingListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveTargetReadingListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveTargetReadingListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveTargetReadingListLink'): - super(ActiveTargetReadingListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveTargetReadingListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveTargetReadingListLink', fromsubclass_=False, pretty_print=True): - super(ActiveTargetReadingListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveTargetReadingListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveTargetReadingListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveTargetReadingListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveTargetReadingListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveTargetReadingListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveTargetReadingListLink - - -class ActiveSupplyInterruptionOverrideListLink(ListLink): - """SHALL contain a Link to a List of active SupplyInterruptionOverride - instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveSupplyInterruptionOverrideListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveSupplyInterruptionOverrideListLink.subclass: - return ActiveSupplyInterruptionOverrideListLink.subclass(*args_, **kwargs_) - else: - return ActiveSupplyInterruptionOverrideListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveSupplyInterruptionOverrideListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveSupplyInterruptionOverrideListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveSupplyInterruptionOverrideListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveSupplyInterruptionOverrideListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveSupplyInterruptionOverrideListLink'): - super(ActiveSupplyInterruptionOverrideListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveSupplyInterruptionOverrideListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveSupplyInterruptionOverrideListLink', fromsubclass_=False, pretty_print=True): - super(ActiveSupplyInterruptionOverrideListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveSupplyInterruptionOverrideListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveSupplyInterruptionOverrideListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveSupplyInterruptionOverrideListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveSupplyInterruptionOverrideListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveSupplyInterruptionOverrideListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveSupplyInterruptionOverrideListLink - - -class ActiveProjectionReadingListLink(ListLink): - """SHALL contain a Link to a List of active ProjectionReading - instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveProjectionReadingListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveProjectionReadingListLink.subclass: - return ActiveProjectionReadingListLink.subclass(*args_, **kwargs_) - else: - return ActiveProjectionReadingListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveProjectionReadingListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveProjectionReadingListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveProjectionReadingListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveProjectionReadingListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveProjectionReadingListLink'): - super(ActiveProjectionReadingListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveProjectionReadingListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveProjectionReadingListLink', fromsubclass_=False, pretty_print=True): - super(ActiveProjectionReadingListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveProjectionReadingListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveProjectionReadingListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveProjectionReadingListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveProjectionReadingListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveProjectionReadingListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveProjectionReadingListLink - - -class ActiveFlowReservationListLink(ListLink): - """SHALL contain a Link to a List of active FlowReservation instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveFlowReservationListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveFlowReservationListLink.subclass: - return ActiveFlowReservationListLink.subclass(*args_, **kwargs_) - else: - return ActiveFlowReservationListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveFlowReservationListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveFlowReservationListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveFlowReservationListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveFlowReservationListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveFlowReservationListLink'): - super(ActiveFlowReservationListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveFlowReservationListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveFlowReservationListLink', fromsubclass_=False, pretty_print=True): - super(ActiveFlowReservationListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveFlowReservationListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveFlowReservationListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveFlowReservationListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveFlowReservationListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveFlowReservationListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveFlowReservationListLink - - -class ActiveEndDeviceControlListLink(ListLink): - """SHALL contain a Link to a List of active EndDeviceControl instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveEndDeviceControlListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveEndDeviceControlListLink.subclass: - return ActiveEndDeviceControlListLink.subclass(*args_, **kwargs_) - else: - return ActiveEndDeviceControlListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveEndDeviceControlListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveEndDeviceControlListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveEndDeviceControlListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveEndDeviceControlListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveEndDeviceControlListLink'): - super(ActiveEndDeviceControlListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveEndDeviceControlListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveEndDeviceControlListLink', fromsubclass_=False, pretty_print=True): - super(ActiveEndDeviceControlListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveEndDeviceControlListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveEndDeviceControlListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveEndDeviceControlListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveEndDeviceControlListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveEndDeviceControlListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveEndDeviceControlListLink - - -class ActiveDERControlListLink(ListLink): - """SHALL contain a Link to a List of active DERControl instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveDERControlListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveDERControlListLink.subclass: - return ActiveDERControlListLink.subclass(*args_, **kwargs_) - else: - return ActiveDERControlListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveDERControlListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveDERControlListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveDERControlListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveDERControlListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveDERControlListLink'): - super(ActiveDERControlListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveDERControlListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveDERControlListLink', fromsubclass_=False, pretty_print=True): - super(ActiveDERControlListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveDERControlListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveDERControlListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveDERControlListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveDERControlListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveDERControlListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveDERControlListLink - - -class ActiveCreditRegisterListLink(ListLink): - """SHALL contain a Link to a List of active CreditRegister instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveCreditRegisterListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveCreditRegisterListLink.subclass: - return ActiveCreditRegisterListLink.subclass(*args_, **kwargs_) - else: - return ActiveCreditRegisterListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveCreditRegisterListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveCreditRegisterListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveCreditRegisterListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveCreditRegisterListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveCreditRegisterListLink'): - super(ActiveCreditRegisterListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveCreditRegisterListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveCreditRegisterListLink', fromsubclass_=False, pretty_print=True): - super(ActiveCreditRegisterListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveCreditRegisterListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveCreditRegisterListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveCreditRegisterListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveCreditRegisterListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveCreditRegisterListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveCreditRegisterListLink - - -class ActiveBillingPeriodListLink(ListLink): - """SHALL contain a Link to a List of active BillingPeriod instances.""" - subclass = None - superclass = ListLink - def __init__(self): - self.original_tagname_ = None - super(ActiveBillingPeriodListLink, self).__init__() - def factory(*args_, **kwargs_): - if ActiveBillingPeriodListLink.subclass: - return ActiveBillingPeriodListLink.subclass(*args_, **kwargs_) - else: - return ActiveBillingPeriodListLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ActiveBillingPeriodListLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ActiveBillingPeriodListLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveBillingPeriodListLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ActiveBillingPeriodListLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActiveBillingPeriodListLink'): - super(ActiveBillingPeriodListLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ActiveBillingPeriodListLink') - def exportChildren(self, outfile, level, namespace_='', name_='ActiveBillingPeriodListLink', fromsubclass_=False, pretty_print=True): - super(ActiveBillingPeriodListLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ActiveBillingPeriodListLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ActiveBillingPeriodListLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ActiveBillingPeriodListLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ActiveBillingPeriodListLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ActiveBillingPeriodListLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ActiveBillingPeriodListLink - - -class AccountBalanceLink(Link): - """SHALL contain a Link to an instance of AccountBalance.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(AccountBalanceLink, self).__init__() - def factory(*args_, **kwargs_): - if AccountBalanceLink.subclass: - return AccountBalanceLink.subclass(*args_, **kwargs_) - else: - return AccountBalanceLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(AccountBalanceLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AccountBalanceLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AccountBalanceLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AccountBalanceLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AccountBalanceLink'): - super(AccountBalanceLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='AccountBalanceLink') - def exportChildren(self, outfile, level, namespace_='', name_='AccountBalanceLink', fromsubclass_=False, pretty_print=True): - super(AccountBalanceLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='AccountBalanceLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(AccountBalanceLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(AccountBalanceLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(AccountBalanceLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(AccountBalanceLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class AccountBalanceLink - - -class DERStatus(SubscribableResource): - """DER status information.""" - subclass = None - superclass = SubscribableResource - def __init__(self, genConnectStatus=None, inverterStatus=None, localControlModeStatus=None, manufacturerStatus=None, operationalModeStatus=None, readingTime=None, stateOfChargeStatus=None, storageModeStatus=None, storConnectStatus=None): - self.original_tagname_ = None - super(DERStatus, self).__init__() - self.genConnectStatus = genConnectStatus - self.inverterStatus = inverterStatus - self.localControlModeStatus = localControlModeStatus - self.manufacturerStatus = manufacturerStatus - self.operationalModeStatus = operationalModeStatus - self.readingTime = readingTime - self.stateOfChargeStatus = stateOfChargeStatus - self.storageModeStatus = storageModeStatus - self.storConnectStatus = storConnectStatus - def factory(*args_, **kwargs_): - if DERStatus.subclass: - return DERStatus.subclass(*args_, **kwargs_) - else: - return DERStatus(*args_, **kwargs_) - factory = staticmethod(factory) - def get_genConnectStatus(self): return self.genConnectStatus - def set_genConnectStatus(self, genConnectStatus): self.genConnectStatus = genConnectStatus - def get_inverterStatus(self): return self.inverterStatus - def set_inverterStatus(self, inverterStatus): self.inverterStatus = inverterStatus - def get_localControlModeStatus(self): return self.localControlModeStatus - def set_localControlModeStatus(self, localControlModeStatus): self.localControlModeStatus = localControlModeStatus - def get_manufacturerStatus(self): return self.manufacturerStatus - def set_manufacturerStatus(self, manufacturerStatus): self.manufacturerStatus = manufacturerStatus - def get_operationalModeStatus(self): return self.operationalModeStatus - def set_operationalModeStatus(self, operationalModeStatus): self.operationalModeStatus = operationalModeStatus - def get_readingTime(self): return self.readingTime - def set_readingTime(self, readingTime): self.readingTime = readingTime - def get_stateOfChargeStatus(self): return self.stateOfChargeStatus - def set_stateOfChargeStatus(self, stateOfChargeStatus): self.stateOfChargeStatus = stateOfChargeStatus - def get_storageModeStatus(self): return self.storageModeStatus - def set_storageModeStatus(self, storageModeStatus): self.storageModeStatus = storageModeStatus - def get_storConnectStatus(self): return self.storConnectStatus - def set_storConnectStatus(self, storConnectStatus): self.storConnectStatus = storConnectStatus - def hasContent_(self): - if ( - self.genConnectStatus is not None or - self.inverterStatus is not None or - self.localControlModeStatus is not None or - self.manufacturerStatus is not None or - self.operationalModeStatus is not None or - self.readingTime is not None or - self.stateOfChargeStatus is not None or - self.storageModeStatus is not None or - self.storConnectStatus is not None or - super(DERStatus, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERStatus', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERStatus') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERStatus', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERStatus'): - super(DERStatus, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERStatus') - def exportChildren(self, outfile, level, namespace_='', name_='DERStatus', fromsubclass_=False, pretty_print=True): - super(DERStatus, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.genConnectStatus is not None: - self.genConnectStatus.export(outfile, level, namespace_, name_='genConnectStatus', pretty_print=pretty_print) - if self.inverterStatus is not None: - self.inverterStatus.export(outfile, level, namespace_, name_='inverterStatus', pretty_print=pretty_print) - if self.localControlModeStatus is not None: - self.localControlModeStatus.export(outfile, level, namespace_, name_='localControlModeStatus', pretty_print=pretty_print) - if self.manufacturerStatus is not None: - self.manufacturerStatus.export(outfile, level, namespace_, name_='manufacturerStatus', pretty_print=pretty_print) - if self.operationalModeStatus is not None: - self.operationalModeStatus.export(outfile, level, namespace_, name_='operationalModeStatus', pretty_print=pretty_print) - if self.readingTime is not None: - self.readingTime.export(outfile, level, namespace_, name_='readingTime', pretty_print=pretty_print) - if self.stateOfChargeStatus is not None: - self.stateOfChargeStatus.export(outfile, level, namespace_, name_='stateOfChargeStatus', pretty_print=pretty_print) - if self.storageModeStatus is not None: - self.storageModeStatus.export(outfile, level, namespace_, name_='storageModeStatus', pretty_print=pretty_print) - if self.storConnectStatus is not None: - self.storConnectStatus.export(outfile, level, namespace_, name_='storConnectStatus', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERStatus'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERStatus, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERStatus, self).exportLiteralChildren(outfile, level, name_) - if self.genConnectStatus is not None: - showIndent(outfile, level) - outfile.write('genConnectStatus=model_.ConnectStatusType(\n') - self.genConnectStatus.exportLiteral(outfile, level, name_='genConnectStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.inverterStatus is not None: - showIndent(outfile, level) - outfile.write('inverterStatus=model_.InverterStatusType(\n') - self.inverterStatus.exportLiteral(outfile, level, name_='inverterStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.localControlModeStatus is not None: - showIndent(outfile, level) - outfile.write('localControlModeStatus=model_.LocalControlModeStatusType(\n') - self.localControlModeStatus.exportLiteral(outfile, level, name_='localControlModeStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.manufacturerStatus is not None: - showIndent(outfile, level) - outfile.write('manufacturerStatus=model_.ManufacturerStatusType(\n') - self.manufacturerStatus.exportLiteral(outfile, level, name_='manufacturerStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.operationalModeStatus is not None: - showIndent(outfile, level) - outfile.write('operationalModeStatus=model_.OperationalModeStatusType(\n') - self.operationalModeStatus.exportLiteral(outfile, level, name_='operationalModeStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.readingTime is not None: - showIndent(outfile, level) - outfile.write('readingTime=model_.TimeType(\n') - self.readingTime.exportLiteral(outfile, level, name_='readingTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.stateOfChargeStatus is not None: - showIndent(outfile, level) - outfile.write('stateOfChargeStatus=model_.StateOfChargeStatusType(\n') - self.stateOfChargeStatus.exportLiteral(outfile, level, name_='stateOfChargeStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.storageModeStatus is not None: - showIndent(outfile, level) - outfile.write('storageModeStatus=model_.StorageModeStatusType(\n') - self.storageModeStatus.exportLiteral(outfile, level, name_='storageModeStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.storConnectStatus is not None: - showIndent(outfile, level) - outfile.write('storConnectStatus=model_.ConnectStatusType(\n') - self.storConnectStatus.exportLiteral(outfile, level, name_='storConnectStatus') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERStatus, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'genConnectStatus': - obj_ = ConnectStatusType.factory() - obj_.build(child_) - self.genConnectStatus = obj_ - obj_.original_tagname_ = 'genConnectStatus' - elif nodeName_ == 'inverterStatus': - obj_ = InverterStatusType.factory() - obj_.build(child_) - self.inverterStatus = obj_ - obj_.original_tagname_ = 'inverterStatus' - elif nodeName_ == 'localControlModeStatus': - obj_ = LocalControlModeStatusType.factory() - obj_.build(child_) - self.localControlModeStatus = obj_ - obj_.original_tagname_ = 'localControlModeStatus' - elif nodeName_ == 'manufacturerStatus': - obj_ = ManufacturerStatusType.factory() - obj_.build(child_) - self.manufacturerStatus = obj_ - obj_.original_tagname_ = 'manufacturerStatus' - elif nodeName_ == 'operationalModeStatus': - obj_ = OperationalModeStatusType.factory() - obj_.build(child_) - self.operationalModeStatus = obj_ - obj_.original_tagname_ = 'operationalModeStatus' - elif nodeName_ == 'readingTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.readingTime = obj_ - obj_.original_tagname_ = 'readingTime' - elif nodeName_ == 'stateOfChargeStatus': - obj_ = StateOfChargeStatusType.factory() - obj_.build(child_) - self.stateOfChargeStatus = obj_ - obj_.original_tagname_ = 'stateOfChargeStatus' - elif nodeName_ == 'storageModeStatus': - obj_ = StorageModeStatusType.factory() - obj_.build(child_) - self.storageModeStatus = obj_ - obj_.original_tagname_ = 'storageModeStatus' - elif nodeName_ == 'storConnectStatus': - obj_ = ConnectStatusType.factory() - obj_.build(child_) - self.storConnectStatus = obj_ - obj_.original_tagname_ = 'storConnectStatus' - super(DERStatus, self).buildChildren(child_, node, nodeName_, True) -# end class DERStatus - - -class DERProgramList(List): - """A List element to hold DERProgram objects.""" - subclass = None - superclass = List - def __init__(self, DERProgram=None): - self.original_tagname_ = None - super(DERProgramList, self).__init__() - if DERProgram is None: - self.DERProgram = [] - else: - self.DERProgram = DERProgram - def factory(*args_, **kwargs_): - if DERProgramList.subclass: - return DERProgramList.subclass(*args_, **kwargs_) - else: - return DERProgramList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DERProgram(self): return self.DERProgram - def set_DERProgram(self, DERProgram): self.DERProgram = DERProgram - def add_DERProgram(self, value): self.DERProgram.append(value) - def insert_DERProgram_at(self, index, value): self.DERProgram.insert(index, value) - def replace_DERProgram_at(self, index, value): self.DERProgram[index] = value - def hasContent_(self): - if ( - self.DERProgram or - super(DERProgramList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERProgramList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERProgramList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERProgramList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERProgramList'): - super(DERProgramList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERProgramList') - def exportChildren(self, outfile, level, namespace_='', name_='DERProgramList', fromsubclass_=False, pretty_print=True): - super(DERProgramList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for DERProgram_ in self.DERProgram: - DERProgram_.export(outfile, level, namespace_, name_='DERProgram', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERProgramList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERProgramList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERProgramList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('DERProgram=[\n') - level += 1 - for DERProgram_ in self.DERProgram: - showIndent(outfile, level) - outfile.write('model_.DERProgram(\n') - DERProgram_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERProgramList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DERProgram': - obj_ = DERProgram.factory() - obj_.build(child_) - self.DERProgram.append(obj_) - obj_.original_tagname_ = 'DERProgram' - super(DERProgramList, self).buildChildren(child_, node, nodeName_, True) -# end class DERProgramList - - -class DERProgram(IdentifiedObject): - """Distributed Energy Resource program.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, ActiveDERControlListLink=None, DefaultDERControlLink=None, DERControlListLink=None, DERCurveListLink=None, primacy=None): - self.original_tagname_ = None - super(DERProgram, self).__init__() - self.ActiveDERControlListLink = ActiveDERControlListLink - self.DefaultDERControlLink = DefaultDERControlLink - self.DERControlListLink = DERControlListLink - self.DERCurveListLink = DERCurveListLink - self.primacy = primacy - def factory(*args_, **kwargs_): - if DERProgram.subclass: - return DERProgram.subclass(*args_, **kwargs_) - else: - return DERProgram(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ActiveDERControlListLink(self): return self.ActiveDERControlListLink - def set_ActiveDERControlListLink(self, ActiveDERControlListLink): self.ActiveDERControlListLink = ActiveDERControlListLink - def get_DefaultDERControlLink(self): return self.DefaultDERControlLink - def set_DefaultDERControlLink(self, DefaultDERControlLink): self.DefaultDERControlLink = DefaultDERControlLink - def get_DERControlListLink(self): return self.DERControlListLink - def set_DERControlListLink(self, DERControlListLink): self.DERControlListLink = DERControlListLink - def get_DERCurveListLink(self): return self.DERCurveListLink - def set_DERCurveListLink(self, DERCurveListLink): self.DERCurveListLink = DERCurveListLink - def get_primacy(self): return self.primacy - def set_primacy(self, primacy): self.primacy = primacy - def hasContent_(self): - if ( - self.ActiveDERControlListLink is not None or - self.DefaultDERControlLink is not None or - self.DERControlListLink is not None or - self.DERCurveListLink is not None or - self.primacy is not None or - super(DERProgram, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERProgram', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERProgram') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERProgram', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERProgram'): - super(DERProgram, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERProgram') - def exportChildren(self, outfile, level, namespace_='', name_='DERProgram', fromsubclass_=False, pretty_print=True): - super(DERProgram, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ActiveDERControlListLink is not None: - self.ActiveDERControlListLink.export(outfile, level, namespace_, name_='ActiveDERControlListLink', pretty_print=pretty_print) - if self.DefaultDERControlLink is not None: - self.DefaultDERControlLink.export(outfile, level, namespace_, name_='DefaultDERControlLink', pretty_print=pretty_print) - if self.DERControlListLink is not None: - self.DERControlListLink.export(outfile, level, namespace_, name_='DERControlListLink', pretty_print=pretty_print) - if self.DERCurveListLink is not None: - self.DERCurveListLink.export(outfile, level, namespace_, name_='DERCurveListLink', pretty_print=pretty_print) - if self.primacy is not None: - self.primacy.export(outfile, level, namespace_, name_='primacy', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERProgram'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERProgram, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERProgram, self).exportLiteralChildren(outfile, level, name_) - if self.ActiveDERControlListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveDERControlListLink=model_.ActiveDERControlListLink(\n') - self.ActiveDERControlListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DefaultDERControlLink is not None: - showIndent(outfile, level) - outfile.write('DefaultDERControlLink=model_.DefaultDERControlLink(\n') - self.DefaultDERControlLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DERControlListLink is not None: - showIndent(outfile, level) - outfile.write('DERControlListLink=model_.DERControlListLink(\n') - self.DERControlListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DERCurveListLink is not None: - showIndent(outfile, level) - outfile.write('DERCurveListLink=model_.DERCurveListLink(\n') - self.DERCurveListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.primacy is not None: - showIndent(outfile, level) - outfile.write('primacy=model_.PrimacyType(\n') - self.primacy.exportLiteral(outfile, level, name_='primacy') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERProgram, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ActiveDERControlListLink': - obj_ = ActiveDERControlListLink.factory() - obj_.build(child_) - self.ActiveDERControlListLink = obj_ - obj_.original_tagname_ = 'ActiveDERControlListLink' - elif nodeName_ == 'DefaultDERControlLink': - obj_ = DefaultDERControlLink.factory() - obj_.build(child_) - self.DefaultDERControlLink = obj_ - obj_.original_tagname_ = 'DefaultDERControlLink' - elif nodeName_ == 'DERControlListLink': - obj_ = DERControlListLink.factory() - obj_.build(child_) - self.DERControlListLink = obj_ - obj_.original_tagname_ = 'DERControlListLink' - elif nodeName_ == 'DERCurveListLink': - obj_ = DERCurveListLink.factory() - obj_.build(child_) - self.DERCurveListLink = obj_ - obj_.original_tagname_ = 'DERCurveListLink' - elif nodeName_ == 'primacy': - obj_ = PrimacyType.factory() - obj_.build(child_) - self.primacy = obj_ - obj_.original_tagname_ = 'primacy' - super(DERProgram, self).buildChildren(child_, node, nodeName_, True) -# end class DERProgram - - -class DERCurveList(List): - """A List element to hold DERCurve objects.""" - subclass = None - superclass = List - def __init__(self, DERCurve=None): - self.original_tagname_ = None - super(DERCurveList, self).__init__() - if DERCurve is None: - self.DERCurve = [] - else: - self.DERCurve = DERCurve - def factory(*args_, **kwargs_): - if DERCurveList.subclass: - return DERCurveList.subclass(*args_, **kwargs_) - else: - return DERCurveList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DERCurve(self): return self.DERCurve - def set_DERCurve(self, DERCurve): self.DERCurve = DERCurve - def add_DERCurve(self, value): self.DERCurve.append(value) - def insert_DERCurve_at(self, index, value): self.DERCurve.insert(index, value) - def replace_DERCurve_at(self, index, value): self.DERCurve[index] = value - def hasContent_(self): - if ( - self.DERCurve or - super(DERCurveList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERCurveList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurveList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERCurveList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERCurveList'): - super(DERCurveList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurveList') - def exportChildren(self, outfile, level, namespace_='', name_='DERCurveList', fromsubclass_=False, pretty_print=True): - super(DERCurveList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for DERCurve_ in self.DERCurve: - DERCurve_.export(outfile, level, namespace_, name_='DERCurve', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERCurveList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERCurveList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERCurveList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('DERCurve=[\n') - level += 1 - for DERCurve_ in self.DERCurve: - showIndent(outfile, level) - outfile.write('model_.DERCurve(\n') - DERCurve_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERCurveList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DERCurve': - obj_ = DERCurve.factory() - obj_.build(child_) - self.DERCurve.append(obj_) - obj_.original_tagname_ = 'DERCurve' - super(DERCurveList, self).buildChildren(child_, node, nodeName_, True) -# end class DERCurveList - - -class CurrentDERProgramLink(Link): - """SHALL contain a Link to an instance of DERProgram. If present, this - is the DERProgram containing the currently active DERControl.""" - subclass = None - superclass = Link - def __init__(self): - self.original_tagname_ = None - super(CurrentDERProgramLink, self).__init__() - def factory(*args_, **kwargs_): - if CurrentDERProgramLink.subclass: - return CurrentDERProgramLink.subclass(*args_, **kwargs_) - else: - return CurrentDERProgramLink(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(CurrentDERProgramLink, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CurrentDERProgramLink', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CurrentDERProgramLink') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CurrentDERProgramLink', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CurrentDERProgramLink'): - super(CurrentDERProgramLink, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CurrentDERProgramLink') - def exportChildren(self, outfile, level, namespace_='', name_='CurrentDERProgramLink', fromsubclass_=False, pretty_print=True): - super(CurrentDERProgramLink, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='CurrentDERProgramLink'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CurrentDERProgramLink, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CurrentDERProgramLink, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CurrentDERProgramLink, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(CurrentDERProgramLink, self).buildChildren(child_, node, nodeName_, True) - pass -# end class CurrentDERProgramLink - - -class DERCurve(IdentifiedObject): - """DER related curves such as Volt-VAr mode curves. Relationship - between an independent variable (X-axis) and one or two - dependent variables (Y-axis and excitation).""" - subclass = None - superclass = IdentifiedObject - def __init__(self, creationTime=None, CurveData=None, curveType=None, rampDecTms=None, rampIncTms=None, rampPT1Tms=None, xMultiplier=None, yMultiplier=None, yRefType=None): - self.original_tagname_ = None - super(DERCurve, self).__init__() - self.creationTime = creationTime - if CurveData is None: - self.CurveData = [] - else: - self.CurveData = CurveData - self.curveType = curveType - self.rampDecTms = rampDecTms - self.rampIncTms = rampIncTms - self.rampPT1Tms = rampPT1Tms - self.xMultiplier = xMultiplier - self.yMultiplier = yMultiplier - self.yRefType = yRefType - def factory(*args_, **kwargs_): - if DERCurve.subclass: - return DERCurve.subclass(*args_, **kwargs_) - else: - return DERCurve(*args_, **kwargs_) - factory = staticmethod(factory) - def get_creationTime(self): return self.creationTime - def set_creationTime(self, creationTime): self.creationTime = creationTime - def get_CurveData(self): return self.CurveData - def set_CurveData(self, CurveData): self.CurveData = CurveData - def add_CurveData(self, value): self.CurveData.append(value) - def insert_CurveData_at(self, index, value): self.CurveData.insert(index, value) - def replace_CurveData_at(self, index, value): self.CurveData[index] = value - def get_curveType(self): return self.curveType - def set_curveType(self, curveType): self.curveType = curveType - def get_rampDecTms(self): return self.rampDecTms - def set_rampDecTms(self, rampDecTms): self.rampDecTms = rampDecTms - def get_rampIncTms(self): return self.rampIncTms - def set_rampIncTms(self, rampIncTms): self.rampIncTms = rampIncTms - def get_rampPT1Tms(self): return self.rampPT1Tms - def set_rampPT1Tms(self, rampPT1Tms): self.rampPT1Tms = rampPT1Tms - def get_xMultiplier(self): return self.xMultiplier - def set_xMultiplier(self, xMultiplier): self.xMultiplier = xMultiplier - def get_yMultiplier(self): return self.yMultiplier - def set_yMultiplier(self, yMultiplier): self.yMultiplier = yMultiplier - def get_yRefType(self): return self.yRefType - def set_yRefType(self, yRefType): self.yRefType = yRefType - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.creationTime is not None or - self.CurveData or - self.curveType is not None or - self.rampDecTms is not None or - self.rampIncTms is not None or - self.rampPT1Tms is not None or - self.xMultiplier is not None or - self.yMultiplier is not None or - self.yRefType is not None or - super(DERCurve, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERCurve', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurve') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERCurve', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERCurve'): - super(DERCurve, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERCurve') - def exportChildren(self, outfile, level, namespace_='', name_='DERCurve', fromsubclass_=False, pretty_print=True): - super(DERCurve, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.creationTime is not None: - self.creationTime.export(outfile, level, namespace_, name_='creationTime', pretty_print=pretty_print) - for CurveData_ in self.CurveData: - CurveData_.export(outfile, level, namespace_, name_='CurveData', pretty_print=pretty_print) - if self.curveType is not None: - self.curveType.export(outfile, level, namespace_, name_='curveType', pretty_print=pretty_print) - if self.rampDecTms is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srampDecTms>%s%s' % (namespace_, self.gds_format_integer(self.rampDecTms, input_name='rampDecTms'), namespace_, eol_)) - if self.rampIncTms is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srampIncTms>%s%s' % (namespace_, self.gds_format_integer(self.rampIncTms, input_name='rampIncTms'), namespace_, eol_)) - if self.rampPT1Tms is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srampPT1Tms>%s%s' % (namespace_, self.gds_format_integer(self.rampPT1Tms, input_name='rampPT1Tms'), namespace_, eol_)) - if self.xMultiplier is not None: - self.xMultiplier.export(outfile, level, namespace_, name_='xMultiplier', pretty_print=pretty_print) - if self.yMultiplier is not None: - self.yMultiplier.export(outfile, level, namespace_, name_='yMultiplier', pretty_print=pretty_print) - if self.yRefType is not None: - self.yRefType.export(outfile, level, namespace_, name_='yRefType', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERCurve'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERCurve, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERCurve, self).exportLiteralChildren(outfile, level, name_) - if self.creationTime is not None: - showIndent(outfile, level) - outfile.write('creationTime=model_.TimeType(\n') - self.creationTime.exportLiteral(outfile, level, name_='creationTime') - showIndent(outfile, level) - outfile.write('),\n') - showIndent(outfile, level) - outfile.write('CurveData=[\n') - level += 1 - for CurveData_ in self.CurveData: - showIndent(outfile, level) - outfile.write('model_.CurveData(\n') - CurveData_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - if self.curveType is not None: - showIndent(outfile, level) - outfile.write('curveType=model_.DERCurveType(\n') - self.curveType.exportLiteral(outfile, level, name_='curveType') - showIndent(outfile, level) - outfile.write('),\n') - if self.rampDecTms is not None: - showIndent(outfile, level) - outfile.write('rampDecTms=%d,\n' % self.rampDecTms) - if self.rampIncTms is not None: - showIndent(outfile, level) - outfile.write('rampIncTms=%d,\n' % self.rampIncTms) - if self.rampPT1Tms is not None: - showIndent(outfile, level) - outfile.write('rampPT1Tms=%d,\n' % self.rampPT1Tms) - if self.xMultiplier is not None: - showIndent(outfile, level) - outfile.write('xMultiplier=model_.PowerOfTenMultiplierType(\n') - self.xMultiplier.exportLiteral(outfile, level, name_='xMultiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.yMultiplier is not None: - showIndent(outfile, level) - outfile.write('yMultiplier=model_.PowerOfTenMultiplierType(\n') - self.yMultiplier.exportLiteral(outfile, level, name_='yMultiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.yRefType is not None: - showIndent(outfile, level) - outfile.write('yRefType=model_.DERUnitRefType(\n') - self.yRefType.exportLiteral(outfile, level, name_='yRefType') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERCurve, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'creationTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.creationTime = obj_ - obj_.original_tagname_ = 'creationTime' - elif nodeName_ == 'CurveData': - obj_ = CurveData.factory() - obj_.build(child_) - self.CurveData.append(obj_) - obj_.original_tagname_ = 'CurveData' - elif nodeName_ == 'curveType': - obj_ = DERCurveType.factory() - obj_.build(child_) - self.curveType = obj_ - obj_.original_tagname_ = 'curveType' - elif nodeName_ == 'rampDecTms': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'rampDecTms') - self.rampDecTms = ival_ - self.validate_UInt16(self.rampDecTms) # validate type UInt16 - elif nodeName_ == 'rampIncTms': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'rampIncTms') - self.rampIncTms = ival_ - self.validate_UInt16(self.rampIncTms) # validate type UInt16 - elif nodeName_ == 'rampPT1Tms': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'rampPT1Tms') - self.rampPT1Tms = ival_ - self.validate_UInt16(self.rampPT1Tms) # validate type UInt16 - elif nodeName_ == 'xMultiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.xMultiplier = obj_ - obj_.original_tagname_ = 'xMultiplier' - elif nodeName_ == 'yMultiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.yMultiplier = obj_ - obj_.original_tagname_ = 'yMultiplier' - elif nodeName_ == 'yRefType': - obj_ = DERUnitRefType.factory() - obj_.build(child_) - self.yRefType = obj_ - obj_.original_tagname_ = 'yRefType' - super(DERCurve, self).buildChildren(child_, node, nodeName_, True) -# end class DERCurve - - -class DERControlList(SubscribableList): - """A List element to hold DERControl objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, DERControl=None): - self.original_tagname_ = None - super(DERControlList, self).__init__() - if DERControl is None: - self.DERControl = [] - else: - self.DERControl = DERControl - def factory(*args_, **kwargs_): - if DERControlList.subclass: - return DERControlList.subclass(*args_, **kwargs_) - else: - return DERControlList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DERControl(self): return self.DERControl - def set_DERControl(self, DERControl): self.DERControl = DERControl - def add_DERControl(self, value): self.DERControl.append(value) - def insert_DERControl_at(self, index, value): self.DERControl.insert(index, value) - def replace_DERControl_at(self, index, value): self.DERControl[index] = value - def hasContent_(self): - if ( - self.DERControl or - super(DERControlList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERControlList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERControlList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERControlList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERControlList'): - super(DERControlList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERControlList') - def exportChildren(self, outfile, level, namespace_='', name_='DERControlList', fromsubclass_=False, pretty_print=True): - super(DERControlList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for DERControl_ in self.DERControl: - DERControl_.export(outfile, level, namespace_, name_='DERControl', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERControlList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERControlList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERControlList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('DERControl=[\n') - level += 1 - for DERControl_ in self.DERControl: - showIndent(outfile, level) - outfile.write('model_.DERControl(\n') - DERControl_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERControlList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DERControl': - obj_ = DERControl.factory() - obj_.build(child_) - self.DERControl.append(obj_) - obj_.original_tagname_ = 'DERControl' - super(DERControlList, self).buildChildren(child_, node, nodeName_, True) -# end class DERControlList - - -class DERControl(RandomizableEvent): - """Distributed Energy Resource (DER) time/event-based control.""" - subclass = None - superclass = RandomizableEvent - def __init__(self, DERControlBase=None): - self.original_tagname_ = None - super(DERControl, self).__init__() - self.DERControlBase = DERControlBase - def factory(*args_, **kwargs_): - if DERControl.subclass: - return DERControl.subclass(*args_, **kwargs_) - else: - return DERControl(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DERControlBase(self): return self.DERControlBase - def set_DERControlBase(self, DERControlBase): self.DERControlBase = DERControlBase - def hasContent_(self): - if ( - self.DERControlBase is not None or - super(DERControl, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERControl', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERControl') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERControl', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERControl'): - super(DERControl, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERControl') - def exportChildren(self, outfile, level, namespace_='', name_='DERControl', fromsubclass_=False, pretty_print=True): - super(DERControl, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.DERControlBase is not None: - self.DERControlBase.export(outfile, level, namespace_, name_='DERControlBase', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERControl'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERControl, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERControl, self).exportLiteralChildren(outfile, level, name_) - if self.DERControlBase is not None: - showIndent(outfile, level) - outfile.write('DERControlBase=model_.DERControlBase(\n') - self.DERControlBase.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERControl, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DERControlBase': - obj_ = DERControlBase.factory() - obj_.build(child_) - self.DERControlBase = obj_ - obj_.original_tagname_ = 'DERControlBase' - super(DERControl, self).buildChildren(child_, node, nodeName_, True) -# end class DERControl - - -class DERCapability(Resource): - """Distributed energy resource type and nameplate ratings.""" - subclass = None - superclass = Resource - def __init__(self, modesSupported=None, rtgA=None, rtgAh=None, rtgMaxChargeRate=None, rtgMaxDischargeRate=None, rtgMinPF=None, rtgMinPFNeg=None, rtgVA=None, rtgVAr=None, rtgVArNeg=None, rtgW=None, rtgWh=None, type_=None): - self.original_tagname_ = None - super(DERCapability, self).__init__() - self.modesSupported = modesSupported - self.rtgA = rtgA - self.rtgAh = rtgAh - self.rtgMaxChargeRate = rtgMaxChargeRate - self.rtgMaxDischargeRate = rtgMaxDischargeRate - self.rtgMinPF = rtgMinPF - self.rtgMinPFNeg = rtgMinPFNeg - self.rtgVA = rtgVA - self.rtgVAr = rtgVAr - self.rtgVArNeg = rtgVArNeg - self.rtgW = rtgW - self.rtgWh = rtgWh - self.type_ = type_ - def factory(*args_, **kwargs_): - if DERCapability.subclass: - return DERCapability.subclass(*args_, **kwargs_) - else: - return DERCapability(*args_, **kwargs_) - factory = staticmethod(factory) - def get_modesSupported(self): return self.modesSupported - def set_modesSupported(self, modesSupported): self.modesSupported = modesSupported - def get_rtgA(self): return self.rtgA - def set_rtgA(self, rtgA): self.rtgA = rtgA - def get_rtgAh(self): return self.rtgAh - def set_rtgAh(self, rtgAh): self.rtgAh = rtgAh - def get_rtgMaxChargeRate(self): return self.rtgMaxChargeRate - def set_rtgMaxChargeRate(self, rtgMaxChargeRate): self.rtgMaxChargeRate = rtgMaxChargeRate - def get_rtgMaxDischargeRate(self): return self.rtgMaxDischargeRate - def set_rtgMaxDischargeRate(self, rtgMaxDischargeRate): self.rtgMaxDischargeRate = rtgMaxDischargeRate - def get_rtgMinPF(self): return self.rtgMinPF - def set_rtgMinPF(self, rtgMinPF): self.rtgMinPF = rtgMinPF - def get_rtgMinPFNeg(self): return self.rtgMinPFNeg - def set_rtgMinPFNeg(self, rtgMinPFNeg): self.rtgMinPFNeg = rtgMinPFNeg - def get_rtgVA(self): return self.rtgVA - def set_rtgVA(self, rtgVA): self.rtgVA = rtgVA - def get_rtgVAr(self): return self.rtgVAr - def set_rtgVAr(self, rtgVAr): self.rtgVAr = rtgVAr - def get_rtgVArNeg(self): return self.rtgVArNeg - def set_rtgVArNeg(self, rtgVArNeg): self.rtgVArNeg = rtgVArNeg - def get_rtgW(self): return self.rtgW - def set_rtgW(self, rtgW): self.rtgW = rtgW - def get_rtgWh(self): return self.rtgWh - def set_rtgWh(self, rtgWh): self.rtgWh = rtgWh - def get_type(self): return self.type_ - def set_type(self, type_): self.type_ = type_ - def hasContent_(self): - if ( - self.modesSupported is not None or - self.rtgA is not None or - self.rtgAh is not None or - self.rtgMaxChargeRate is not None or - self.rtgMaxDischargeRate is not None or - self.rtgMinPF is not None or - self.rtgMinPFNeg is not None or - self.rtgVA is not None or - self.rtgVAr is not None or - self.rtgVArNeg is not None or - self.rtgW is not None or - self.rtgWh is not None or - self.type_ is not None or - super(DERCapability, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERCapability', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERCapability') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERCapability', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERCapability'): - super(DERCapability, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERCapability') - def exportChildren(self, outfile, level, namespace_='', name_='DERCapability', fromsubclass_=False, pretty_print=True): - super(DERCapability, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.modesSupported is not None: - self.modesSupported.export(outfile, level, namespace_, name_='modesSupported', pretty_print=pretty_print) - if self.rtgA is not None: - self.rtgA.export(outfile, level, namespace_, name_='rtgA', pretty_print=pretty_print) - if self.rtgAh is not None: - self.rtgAh.export(outfile, level, namespace_, name_='rtgAh', pretty_print=pretty_print) - if self.rtgMaxChargeRate is not None: - self.rtgMaxChargeRate.export(outfile, level, namespace_, name_='rtgMaxChargeRate', pretty_print=pretty_print) - if self.rtgMaxDischargeRate is not None: - self.rtgMaxDischargeRate.export(outfile, level, namespace_, name_='rtgMaxDischargeRate', pretty_print=pretty_print) - if self.rtgMinPF is not None: - self.rtgMinPF.export(outfile, level, namespace_, name_='rtgMinPF', pretty_print=pretty_print) - if self.rtgMinPFNeg is not None: - self.rtgMinPFNeg.export(outfile, level, namespace_, name_='rtgMinPFNeg', pretty_print=pretty_print) - if self.rtgVA is not None: - self.rtgVA.export(outfile, level, namespace_, name_='rtgVA', pretty_print=pretty_print) - if self.rtgVAr is not None: - self.rtgVAr.export(outfile, level, namespace_, name_='rtgVAr', pretty_print=pretty_print) - if self.rtgVArNeg is not None: - self.rtgVArNeg.export(outfile, level, namespace_, name_='rtgVArNeg', pretty_print=pretty_print) - if self.rtgW is not None: - self.rtgW.export(outfile, level, namespace_, name_='rtgW', pretty_print=pretty_print) - if self.rtgWh is not None: - self.rtgWh.export(outfile, level, namespace_, name_='rtgWh', pretty_print=pretty_print) - if self.type_ is not None: - self.type_.export(outfile, level, namespace_, name_='type', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERCapability'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERCapability, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERCapability, self).exportLiteralChildren(outfile, level, name_) - if self.modesSupported is not None: - showIndent(outfile, level) - outfile.write('modesSupported=model_.DERControlType(\n') - self.modesSupported.exportLiteral(outfile, level, name_='modesSupported') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgA is not None: - showIndent(outfile, level) - outfile.write('rtgA=model_.CurrentRMS(\n') - self.rtgA.exportLiteral(outfile, level, name_='rtgA') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgAh is not None: - showIndent(outfile, level) - outfile.write('rtgAh=model_.AmpereHour(\n') - self.rtgAh.exportLiteral(outfile, level, name_='rtgAh') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgMaxChargeRate is not None: - showIndent(outfile, level) - outfile.write('rtgMaxChargeRate=model_.ActivePower(\n') - self.rtgMaxChargeRate.exportLiteral(outfile, level, name_='rtgMaxChargeRate') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgMaxDischargeRate is not None: - showIndent(outfile, level) - outfile.write('rtgMaxDischargeRate=model_.ActivePower(\n') - self.rtgMaxDischargeRate.exportLiteral(outfile, level, name_='rtgMaxDischargeRate') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgMinPF is not None: - showIndent(outfile, level) - outfile.write('rtgMinPF=model_.UnsignedFixedPointType(\n') - self.rtgMinPF.exportLiteral(outfile, level, name_='rtgMinPF') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgMinPFNeg is not None: - showIndent(outfile, level) - outfile.write('rtgMinPFNeg=model_.FixedPointType(\n') - self.rtgMinPFNeg.exportLiteral(outfile, level, name_='rtgMinPFNeg') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgVA is not None: - showIndent(outfile, level) - outfile.write('rtgVA=model_.ApparentPower(\n') - self.rtgVA.exportLiteral(outfile, level, name_='rtgVA') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgVAr is not None: - showIndent(outfile, level) - outfile.write('rtgVAr=model_.ReactivePower(\n') - self.rtgVAr.exportLiteral(outfile, level, name_='rtgVAr') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgVArNeg is not None: - showIndent(outfile, level) - outfile.write('rtgVArNeg=model_.ReactivePower(\n') - self.rtgVArNeg.exportLiteral(outfile, level, name_='rtgVArNeg') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgW is not None: - showIndent(outfile, level) - outfile.write('rtgW=model_.ActivePower(\n') - self.rtgW.exportLiteral(outfile, level, name_='rtgW') - showIndent(outfile, level) - outfile.write('),\n') - if self.rtgWh is not None: - showIndent(outfile, level) - outfile.write('rtgWh=model_.WattHour(\n') - self.rtgWh.exportLiteral(outfile, level, name_='rtgWh') - showIndent(outfile, level) - outfile.write('),\n') - if self.type_ is not None: - showIndent(outfile, level) - outfile.write('type_=model_.DERType(\n') - self.type_.exportLiteral(outfile, level, name_='type') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERCapability, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'modesSupported': - obj_ = DERControlType.factory() - obj_.build(child_) - self.modesSupported = obj_ - obj_.original_tagname_ = 'modesSupported' - elif nodeName_ == 'rtgA': - obj_ = CurrentRMS.factory() - obj_.build(child_) - self.rtgA = obj_ - obj_.original_tagname_ = 'rtgA' - elif nodeName_ == 'rtgAh': - obj_ = AmpereHour.factory() - obj_.build(child_) - self.rtgAh = obj_ - obj_.original_tagname_ = 'rtgAh' - elif nodeName_ == 'rtgMaxChargeRate': - obj_ = ActivePower.factory() - obj_.build(child_) - self.rtgMaxChargeRate = obj_ - obj_.original_tagname_ = 'rtgMaxChargeRate' - elif nodeName_ == 'rtgMaxDischargeRate': - obj_ = ActivePower.factory() - obj_.build(child_) - self.rtgMaxDischargeRate = obj_ - obj_.original_tagname_ = 'rtgMaxDischargeRate' - elif nodeName_ == 'rtgMinPF': - obj_ = UnsignedFixedPointType.factory() - obj_.build(child_) - self.rtgMinPF = obj_ - obj_.original_tagname_ = 'rtgMinPF' - elif nodeName_ == 'rtgMinPFNeg': - obj_ = FixedPointType.factory() - obj_.build(child_) - self.rtgMinPFNeg = obj_ - obj_.original_tagname_ = 'rtgMinPFNeg' - elif nodeName_ == 'rtgVA': - obj_ = ApparentPower.factory() - obj_.build(child_) - self.rtgVA = obj_ - obj_.original_tagname_ = 'rtgVA' - elif nodeName_ == 'rtgVAr': - obj_ = ReactivePower.factory() - obj_.build(child_) - self.rtgVAr = obj_ - obj_.original_tagname_ = 'rtgVAr' - elif nodeName_ == 'rtgVArNeg': - obj_ = ReactivePower.factory() - obj_.build(child_) - self.rtgVArNeg = obj_ - obj_.original_tagname_ = 'rtgVArNeg' - elif nodeName_ == 'rtgW': - obj_ = ActivePower.factory() - obj_.build(child_) - self.rtgW = obj_ - obj_.original_tagname_ = 'rtgW' - elif nodeName_ == 'rtgWh': - obj_ = WattHour.factory() - obj_.build(child_) - self.rtgWh = obj_ - obj_.original_tagname_ = 'rtgWh' - elif nodeName_ == 'type': - obj_ = DERType.factory() - obj_.build(child_) - self.type_ = obj_ - obj_.original_tagname_ = 'type' - super(DERCapability, self).buildChildren(child_, node, nodeName_, True) -# end class DERCapability - - -class DERAvailability(SubscribableResource): - """Indicates current reserve generation status""" - subclass = None - superclass = SubscribableResource - def __init__(self, availabilityDuration=None, maxChargeDuration=None, readingTime=None, reserveChargePercent=None, reservePercent=None, statVArAvail=None, statWAvail=None): - self.original_tagname_ = None - super(DERAvailability, self).__init__() - self.availabilityDuration = availabilityDuration - self.maxChargeDuration = maxChargeDuration - self.readingTime = readingTime - self.reserveChargePercent = reserveChargePercent - self.reservePercent = reservePercent - self.statVArAvail = statVArAvail - self.statWAvail = statWAvail - def factory(*args_, **kwargs_): - if DERAvailability.subclass: - return DERAvailability.subclass(*args_, **kwargs_) - else: - return DERAvailability(*args_, **kwargs_) - factory = staticmethod(factory) - def get_availabilityDuration(self): return self.availabilityDuration - def set_availabilityDuration(self, availabilityDuration): self.availabilityDuration = availabilityDuration - def get_maxChargeDuration(self): return self.maxChargeDuration - def set_maxChargeDuration(self, maxChargeDuration): self.maxChargeDuration = maxChargeDuration - def get_readingTime(self): return self.readingTime - def set_readingTime(self, readingTime): self.readingTime = readingTime - def get_reserveChargePercent(self): return self.reserveChargePercent - def set_reserveChargePercent(self, reserveChargePercent): self.reserveChargePercent = reserveChargePercent - def get_reservePercent(self): return self.reservePercent - def set_reservePercent(self, reservePercent): self.reservePercent = reservePercent - def get_statVArAvail(self): return self.statVArAvail - def set_statVArAvail(self, statVArAvail): self.statVArAvail = statVArAvail - def get_statWAvail(self): return self.statWAvail - def set_statWAvail(self, statWAvail): self.statWAvail = statWAvail - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def hasContent_(self): - if ( - self.availabilityDuration is not None or - self.maxChargeDuration is not None or - self.readingTime is not None or - self.reserveChargePercent is not None or - self.reservePercent is not None or - self.statVArAvail is not None or - self.statWAvail is not None or - super(DERAvailability, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERAvailability', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERAvailability') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERAvailability', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERAvailability'): - super(DERAvailability, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERAvailability') - def exportChildren(self, outfile, level, namespace_='', name_='DERAvailability', fromsubclass_=False, pretty_print=True): - super(DERAvailability, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.availabilityDuration is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%savailabilityDuration>%s%s' % (namespace_, self.gds_format_integer(self.availabilityDuration, input_name='availabilityDuration'), namespace_, eol_)) - if self.maxChargeDuration is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smaxChargeDuration>%s%s' % (namespace_, self.gds_format_integer(self.maxChargeDuration, input_name='maxChargeDuration'), namespace_, eol_)) - if self.readingTime is not None: - self.readingTime.export(outfile, level, namespace_, name_='readingTime', pretty_print=pretty_print) - if self.reserveChargePercent is not None: - self.reserveChargePercent.export(outfile, level, namespace_, name_='reserveChargePercent', pretty_print=pretty_print) - if self.reservePercent is not None: - self.reservePercent.export(outfile, level, namespace_, name_='reservePercent', pretty_print=pretty_print) - if self.statVArAvail is not None: - self.statVArAvail.export(outfile, level, namespace_, name_='statVArAvail', pretty_print=pretty_print) - if self.statWAvail is not None: - self.statWAvail.export(outfile, level, namespace_, name_='statWAvail', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERAvailability'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERAvailability, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERAvailability, self).exportLiteralChildren(outfile, level, name_) - if self.availabilityDuration is not None: - showIndent(outfile, level) - outfile.write('availabilityDuration=%d,\n' % self.availabilityDuration) - if self.maxChargeDuration is not None: - showIndent(outfile, level) - outfile.write('maxChargeDuration=%d,\n' % self.maxChargeDuration) - if self.readingTime is not None: - showIndent(outfile, level) - outfile.write('readingTime=model_.TimeType(\n') - self.readingTime.exportLiteral(outfile, level, name_='readingTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.reserveChargePercent is not None: - showIndent(outfile, level) - outfile.write('reserveChargePercent=model_.PerCent(\n') - self.reserveChargePercent.exportLiteral(outfile, level, name_='reserveChargePercent') - showIndent(outfile, level) - outfile.write('),\n') - if self.reservePercent is not None: - showIndent(outfile, level) - outfile.write('reservePercent=model_.PerCent(\n') - self.reservePercent.exportLiteral(outfile, level, name_='reservePercent') - showIndent(outfile, level) - outfile.write('),\n') - if self.statVArAvail is not None: - showIndent(outfile, level) - outfile.write('statVArAvail=model_.ReactivePower(\n') - self.statVArAvail.exportLiteral(outfile, level, name_='statVArAvail') - showIndent(outfile, level) - outfile.write('),\n') - if self.statWAvail is not None: - showIndent(outfile, level) - outfile.write('statWAvail=model_.ActivePower(\n') - self.statWAvail.exportLiteral(outfile, level, name_='statWAvail') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERAvailability, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'availabilityDuration': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'availabilityDuration') - self.availabilityDuration = ival_ - self.validate_UInt32(self.availabilityDuration) # validate type UInt32 - elif nodeName_ == 'maxChargeDuration': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'maxChargeDuration') - self.maxChargeDuration = ival_ - self.validate_UInt32(self.maxChargeDuration) # validate type UInt32 - elif nodeName_ == 'readingTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.readingTime = obj_ - obj_.original_tagname_ = 'readingTime' - elif nodeName_ == 'reserveChargePercent': - obj_ = PerCent.factory() - obj_.build(child_) - self.reserveChargePercent = obj_ - obj_.original_tagname_ = 'reserveChargePercent' - elif nodeName_ == 'reservePercent': - obj_ = PerCent.factory() - obj_.build(child_) - self.reservePercent = obj_ - obj_.original_tagname_ = 'reservePercent' - elif nodeName_ == 'statVArAvail': - obj_ = ReactivePower.factory() - obj_.build(child_) - self.statVArAvail = obj_ - obj_.original_tagname_ = 'statVArAvail' - elif nodeName_ == 'statWAvail': - obj_ = ActivePower.factory() - obj_.build(child_) - self.statWAvail = obj_ - obj_.original_tagname_ = 'statWAvail' - super(DERAvailability, self).buildChildren(child_, node, nodeName_, True) -# end class DERAvailability - - -class DERSettings(SubscribableResource): - """Distributed energy resource settings""" - subclass = None - superclass = SubscribableResource - def __init__(self, setGenConnect=None, setGradW=None, setMaxChargeRate=None, setMaxDischargeRate=None, setMaxVA=None, setMaxVAr=None, setMaxVArNeg=None, setMaxW=None, setMinPF=None, setMinPFNeg=None, setStorConnect=None, setVRef=None, setVRefOfs=None, updatedTime=None): - self.original_tagname_ = None - super(DERSettings, self).__init__() - self.setGenConnect = setGenConnect - self.setGradW = setGradW - self.setMaxChargeRate = setMaxChargeRate - self.setMaxDischargeRate = setMaxDischargeRate - self.setMaxVA = setMaxVA - self.setMaxVAr = setMaxVAr - self.setMaxVArNeg = setMaxVArNeg - self.setMaxW = setMaxW - self.setMinPF = setMinPF - self.setMinPFNeg = setMinPFNeg - self.setStorConnect = setStorConnect - self.setVRef = setVRef - self.setVRefOfs = setVRefOfs - self.updatedTime = updatedTime - def factory(*args_, **kwargs_): - if DERSettings.subclass: - return DERSettings.subclass(*args_, **kwargs_) - else: - return DERSettings(*args_, **kwargs_) - factory = staticmethod(factory) - def get_setGenConnect(self): return self.setGenConnect - def set_setGenConnect(self, setGenConnect): self.setGenConnect = setGenConnect - def get_setGradW(self): return self.setGradW - def set_setGradW(self, setGradW): self.setGradW = setGradW - def get_setMaxChargeRate(self): return self.setMaxChargeRate - def set_setMaxChargeRate(self, setMaxChargeRate): self.setMaxChargeRate = setMaxChargeRate - def get_setMaxDischargeRate(self): return self.setMaxDischargeRate - def set_setMaxDischargeRate(self, setMaxDischargeRate): self.setMaxDischargeRate = setMaxDischargeRate - def get_setMaxVA(self): return self.setMaxVA - def set_setMaxVA(self, setMaxVA): self.setMaxVA = setMaxVA - def get_setMaxVAr(self): return self.setMaxVAr - def set_setMaxVAr(self, setMaxVAr): self.setMaxVAr = setMaxVAr - def get_setMaxVArNeg(self): return self.setMaxVArNeg - def set_setMaxVArNeg(self, setMaxVArNeg): self.setMaxVArNeg = setMaxVArNeg - def get_setMaxW(self): return self.setMaxW - def set_setMaxW(self, setMaxW): self.setMaxW = setMaxW - def get_setMinPF(self): return self.setMinPF - def set_setMinPF(self, setMinPF): self.setMinPF = setMinPF - def get_setMinPFNeg(self): return self.setMinPFNeg - def set_setMinPFNeg(self, setMinPFNeg): self.setMinPFNeg = setMinPFNeg - def get_setStorConnect(self): return self.setStorConnect - def set_setStorConnect(self, setStorConnect): self.setStorConnect = setStorConnect - def get_setVRef(self): return self.setVRef - def set_setVRef(self, setVRef): self.setVRef = setVRef - def get_setVRefOfs(self): return self.setVRefOfs - def set_setVRefOfs(self, setVRefOfs): self.setVRefOfs = setVRefOfs - def get_updatedTime(self): return self.updatedTime - def set_updatedTime(self, updatedTime): self.updatedTime = updatedTime - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.setGenConnect is not None or - self.setGradW is not None or - self.setMaxChargeRate is not None or - self.setMaxDischargeRate is not None or - self.setMaxVA is not None or - self.setMaxVAr is not None or - self.setMaxVArNeg is not None or - self.setMaxW is not None or - self.setMinPF is not None or - self.setMinPFNeg is not None or - self.setStorConnect is not None or - self.setVRef is not None or - self.setVRefOfs is not None or - self.updatedTime is not None or - super(DERSettings, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERSettings', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERSettings') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERSettings', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERSettings'): - super(DERSettings, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERSettings') - def exportChildren(self, outfile, level, namespace_='', name_='DERSettings', fromsubclass_=False, pretty_print=True): - super(DERSettings, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.setGenConnect is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssetGenConnect>%s%s' % (namespace_, self.gds_format_boolean(self.setGenConnect, input_name='setGenConnect'), namespace_, eol_)) - if self.setGradW is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssetGradW>%s%s' % (namespace_, self.gds_format_integer(self.setGradW, input_name='setGradW'), namespace_, eol_)) - if self.setMaxChargeRate is not None: - self.setMaxChargeRate.export(outfile, level, namespace_, name_='setMaxChargeRate', pretty_print=pretty_print) - if self.setMaxDischargeRate is not None: - self.setMaxDischargeRate.export(outfile, level, namespace_, name_='setMaxDischargeRate', pretty_print=pretty_print) - if self.setMaxVA is not None: - self.setMaxVA.export(outfile, level, namespace_, name_='setMaxVA', pretty_print=pretty_print) - if self.setMaxVAr is not None: - self.setMaxVAr.export(outfile, level, namespace_, name_='setMaxVAr', pretty_print=pretty_print) - if self.setMaxVArNeg is not None: - self.setMaxVArNeg.export(outfile, level, namespace_, name_='setMaxVArNeg', pretty_print=pretty_print) - if self.setMaxW is not None: - self.setMaxW.export(outfile, level, namespace_, name_='setMaxW', pretty_print=pretty_print) - if self.setMinPF is not None: - self.setMinPF.export(outfile, level, namespace_, name_='setMinPF', pretty_print=pretty_print) - if self.setMinPFNeg is not None: - self.setMinPFNeg.export(outfile, level, namespace_, name_='setMinPFNeg', pretty_print=pretty_print) - if self.setStorConnect is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssetStorConnect>%s%s' % (namespace_, self.gds_format_boolean(self.setStorConnect, input_name='setStorConnect'), namespace_, eol_)) - if self.setVRef is not None: - self.setVRef.export(outfile, level, namespace_, name_='setVRef', pretty_print=pretty_print) - if self.setVRefOfs is not None: - self.setVRefOfs.export(outfile, level, namespace_, name_='setVRefOfs', pretty_print=pretty_print) - if self.updatedTime is not None: - self.updatedTime.export(outfile, level, namespace_, name_='updatedTime', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERSettings'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERSettings, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERSettings, self).exportLiteralChildren(outfile, level, name_) - if self.setGenConnect is not None: - showIndent(outfile, level) - outfile.write('setGenConnect=%s,\n' % self.setGenConnect) - if self.setGradW is not None: - showIndent(outfile, level) - outfile.write('setGradW=%d,\n' % self.setGradW) - if self.setMaxChargeRate is not None: - showIndent(outfile, level) - outfile.write('setMaxChargeRate=model_.ActivePower(\n') - self.setMaxChargeRate.exportLiteral(outfile, level, name_='setMaxChargeRate') - showIndent(outfile, level) - outfile.write('),\n') - if self.setMaxDischargeRate is not None: - showIndent(outfile, level) - outfile.write('setMaxDischargeRate=model_.ActivePower(\n') - self.setMaxDischargeRate.exportLiteral(outfile, level, name_='setMaxDischargeRate') - showIndent(outfile, level) - outfile.write('),\n') - if self.setMaxVA is not None: - showIndent(outfile, level) - outfile.write('setMaxVA=model_.ApparentPower(\n') - self.setMaxVA.exportLiteral(outfile, level, name_='setMaxVA') - showIndent(outfile, level) - outfile.write('),\n') - if self.setMaxVAr is not None: - showIndent(outfile, level) - outfile.write('setMaxVAr=model_.ReactivePower(\n') - self.setMaxVAr.exportLiteral(outfile, level, name_='setMaxVAr') - showIndent(outfile, level) - outfile.write('),\n') - if self.setMaxVArNeg is not None: - showIndent(outfile, level) - outfile.write('setMaxVArNeg=model_.ReactivePower(\n') - self.setMaxVArNeg.exportLiteral(outfile, level, name_='setMaxVArNeg') - showIndent(outfile, level) - outfile.write('),\n') - if self.setMaxW is not None: - showIndent(outfile, level) - outfile.write('setMaxW=model_.ActivePower(\n') - self.setMaxW.exportLiteral(outfile, level, name_='setMaxW') - showIndent(outfile, level) - outfile.write('),\n') - if self.setMinPF is not None: - showIndent(outfile, level) - outfile.write('setMinPF=model_.UnsignedFixedPointType(\n') - self.setMinPF.exportLiteral(outfile, level, name_='setMinPF') - showIndent(outfile, level) - outfile.write('),\n') - if self.setMinPFNeg is not None: - showIndent(outfile, level) - outfile.write('setMinPFNeg=model_.FixedPointType(\n') - self.setMinPFNeg.exportLiteral(outfile, level, name_='setMinPFNeg') - showIndent(outfile, level) - outfile.write('),\n') - if self.setStorConnect is not None: - showIndent(outfile, level) - outfile.write('setStorConnect=%s,\n' % self.setStorConnect) - if self.setVRef is not None: - showIndent(outfile, level) - outfile.write('setVRef=model_.VoltageRMS(\n') - self.setVRef.exportLiteral(outfile, level, name_='setVRef') - showIndent(outfile, level) - outfile.write('),\n') - if self.setVRefOfs is not None: - showIndent(outfile, level) - outfile.write('setVRefOfs=model_.VoltageRMS(\n') - self.setVRefOfs.exportLiteral(outfile, level, name_='setVRefOfs') - showIndent(outfile, level) - outfile.write('),\n') - if self.updatedTime is not None: - showIndent(outfile, level) - outfile.write('updatedTime=model_.TimeType(\n') - self.updatedTime.exportLiteral(outfile, level, name_='updatedTime') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERSettings, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'setGenConnect': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'setGenConnect') - self.setGenConnect = ival_ - elif nodeName_ == 'setGradW': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'setGradW') - self.setGradW = ival_ - self.validate_UInt16(self.setGradW) # validate type UInt16 - elif nodeName_ == 'setMaxChargeRate': - obj_ = ActivePower.factory() - obj_.build(child_) - self.setMaxChargeRate = obj_ - obj_.original_tagname_ = 'setMaxChargeRate' - elif nodeName_ == 'setMaxDischargeRate': - obj_ = ActivePower.factory() - obj_.build(child_) - self.setMaxDischargeRate = obj_ - obj_.original_tagname_ = 'setMaxDischargeRate' - elif nodeName_ == 'setMaxVA': - obj_ = ApparentPower.factory() - obj_.build(child_) - self.setMaxVA = obj_ - obj_.original_tagname_ = 'setMaxVA' - elif nodeName_ == 'setMaxVAr': - obj_ = ReactivePower.factory() - obj_.build(child_) - self.setMaxVAr = obj_ - obj_.original_tagname_ = 'setMaxVAr' - elif nodeName_ == 'setMaxVArNeg': - obj_ = ReactivePower.factory() - obj_.build(child_) - self.setMaxVArNeg = obj_ - obj_.original_tagname_ = 'setMaxVArNeg' - elif nodeName_ == 'setMaxW': - obj_ = ActivePower.factory() - obj_.build(child_) - self.setMaxW = obj_ - obj_.original_tagname_ = 'setMaxW' - elif nodeName_ == 'setMinPF': - obj_ = UnsignedFixedPointType.factory() - obj_.build(child_) - self.setMinPF = obj_ - obj_.original_tagname_ = 'setMinPF' - elif nodeName_ == 'setMinPFNeg': - obj_ = FixedPointType.factory() - obj_.build(child_) - self.setMinPFNeg = obj_ - obj_.original_tagname_ = 'setMinPFNeg' - elif nodeName_ == 'setStorConnect': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'setStorConnect') - self.setStorConnect = ival_ - elif nodeName_ == 'setVRef': - obj_ = VoltageRMS.factory() - obj_.build(child_) - self.setVRef = obj_ - obj_.original_tagname_ = 'setVRef' - elif nodeName_ == 'setVRefOfs': - obj_ = VoltageRMS.factory() - obj_.build(child_) - self.setVRefOfs = obj_ - obj_.original_tagname_ = 'setVRefOfs' - elif nodeName_ == 'updatedTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.updatedTime = obj_ - obj_.original_tagname_ = 'updatedTime' - super(DERSettings, self).buildChildren(child_, node, nodeName_, True) -# end class DERSettings - - -class DERList(List): - """A List element to hold DER objects.""" - subclass = None - superclass = List - def __init__(self, DER=None): - self.original_tagname_ = None - super(DERList, self).__init__() - if DER is None: - self.DER = [] - else: - self.DER = DER - def factory(*args_, **kwargs_): - if DERList.subclass: - return DERList.subclass(*args_, **kwargs_) - else: - return DERList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DER(self): return self.DER - def set_DER(self, DER): self.DER = DER - def add_DER(self, value): self.DER.append(value) - def insert_DER_at(self, index, value): self.DER.insert(index, value) - def replace_DER_at(self, index, value): self.DER[index] = value - def hasContent_(self): - if ( - self.DER or - super(DERList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DERList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DERList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DERList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DERList'): - super(DERList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DERList') - def exportChildren(self, outfile, level, namespace_='', name_='DERList', fromsubclass_=False, pretty_print=True): - super(DERList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for DER_ in self.DER: - DER_.export(outfile, level, namespace_, name_='DER', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DERList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DERList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DERList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('DER=[\n') - level += 1 - for DER_ in self.DER: - showIndent(outfile, level) - outfile.write('model_.DER(\n') - DER_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DERList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DER': - obj_ = DER.factory() - obj_.build(child_) - self.DER.append(obj_) - obj_.original_tagname_ = 'DER' - super(DERList, self).buildChildren(child_, node, nodeName_, True) -# end class DERList - - -class DER(SubscribableResource): - """Contains links to DER resources.""" - subclass = None - superclass = SubscribableResource - def __init__(self, AssociatedDERProgramListLink=None, AssociatedUsagePointLink=None, CurrentDERProgramLink=None, DERAvailabilityLink=None, DERCapabilityLink=None, DERSettingsLink=None, DERStatusLink=None): - self.original_tagname_ = None - super(DER, self).__init__() - self.AssociatedDERProgramListLink = AssociatedDERProgramListLink - self.AssociatedUsagePointLink = AssociatedUsagePointLink - self.CurrentDERProgramLink = CurrentDERProgramLink - self.DERAvailabilityLink = DERAvailabilityLink - self.DERCapabilityLink = DERCapabilityLink - self.DERSettingsLink = DERSettingsLink - self.DERStatusLink = DERStatusLink - def factory(*args_, **kwargs_): - if DER.subclass: - return DER.subclass(*args_, **kwargs_) - else: - return DER(*args_, **kwargs_) - factory = staticmethod(factory) - def get_AssociatedDERProgramListLink(self): return self.AssociatedDERProgramListLink - def set_AssociatedDERProgramListLink(self, AssociatedDERProgramListLink): self.AssociatedDERProgramListLink = AssociatedDERProgramListLink - def get_AssociatedUsagePointLink(self): return self.AssociatedUsagePointLink - def set_AssociatedUsagePointLink(self, AssociatedUsagePointLink): self.AssociatedUsagePointLink = AssociatedUsagePointLink - def get_CurrentDERProgramLink(self): return self.CurrentDERProgramLink - def set_CurrentDERProgramLink(self, CurrentDERProgramLink): self.CurrentDERProgramLink = CurrentDERProgramLink - def get_DERAvailabilityLink(self): return self.DERAvailabilityLink - def set_DERAvailabilityLink(self, DERAvailabilityLink): self.DERAvailabilityLink = DERAvailabilityLink - def get_DERCapabilityLink(self): return self.DERCapabilityLink - def set_DERCapabilityLink(self, DERCapabilityLink): self.DERCapabilityLink = DERCapabilityLink - def get_DERSettingsLink(self): return self.DERSettingsLink - def set_DERSettingsLink(self, DERSettingsLink): self.DERSettingsLink = DERSettingsLink - def get_DERStatusLink(self): return self.DERStatusLink - def set_DERStatusLink(self, DERStatusLink): self.DERStatusLink = DERStatusLink - def hasContent_(self): - if ( - self.AssociatedDERProgramListLink is not None or - self.AssociatedUsagePointLink is not None or - self.CurrentDERProgramLink is not None or - self.DERAvailabilityLink is not None or - self.DERCapabilityLink is not None or - self.DERSettingsLink is not None or - self.DERStatusLink is not None or - super(DER, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DER', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DER') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DER', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DER'): - super(DER, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DER') - def exportChildren(self, outfile, level, namespace_='', name_='DER', fromsubclass_=False, pretty_print=True): - super(DER, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.AssociatedDERProgramListLink is not None: - self.AssociatedDERProgramListLink.export(outfile, level, namespace_, name_='AssociatedDERProgramListLink', pretty_print=pretty_print) - if self.AssociatedUsagePointLink is not None: - self.AssociatedUsagePointLink.export(outfile, level, namespace_, name_='AssociatedUsagePointLink', pretty_print=pretty_print) - if self.CurrentDERProgramLink is not None: - self.CurrentDERProgramLink.export(outfile, level, namespace_, name_='CurrentDERProgramLink', pretty_print=pretty_print) - if self.DERAvailabilityLink is not None: - self.DERAvailabilityLink.export(outfile, level, namespace_, name_='DERAvailabilityLink', pretty_print=pretty_print) - if self.DERCapabilityLink is not None: - self.DERCapabilityLink.export(outfile, level, namespace_, name_='DERCapabilityLink', pretty_print=pretty_print) - if self.DERSettingsLink is not None: - self.DERSettingsLink.export(outfile, level, namespace_, name_='DERSettingsLink', pretty_print=pretty_print) - if self.DERStatusLink is not None: - self.DERStatusLink.export(outfile, level, namespace_, name_='DERStatusLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DER'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DER, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DER, self).exportLiteralChildren(outfile, level, name_) - if self.AssociatedDERProgramListLink is not None: - showIndent(outfile, level) - outfile.write('AssociatedDERProgramListLink=model_.AssociatedDERProgramListLink(\n') - self.AssociatedDERProgramListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.AssociatedUsagePointLink is not None: - showIndent(outfile, level) - outfile.write('AssociatedUsagePointLink=model_.AssociatedUsagePointLink(\n') - self.AssociatedUsagePointLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.CurrentDERProgramLink is not None: - showIndent(outfile, level) - outfile.write('CurrentDERProgramLink=model_.CurrentDERProgramLink(\n') - self.CurrentDERProgramLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DERAvailabilityLink is not None: - showIndent(outfile, level) - outfile.write('DERAvailabilityLink=model_.DERAvailabilityLink(\n') - self.DERAvailabilityLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DERCapabilityLink is not None: - showIndent(outfile, level) - outfile.write('DERCapabilityLink=model_.DERCapabilityLink(\n') - self.DERCapabilityLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DERSettingsLink is not None: - showIndent(outfile, level) - outfile.write('DERSettingsLink=model_.DERSettingsLink(\n') - self.DERSettingsLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DERStatusLink is not None: - showIndent(outfile, level) - outfile.write('DERStatusLink=model_.DERStatusLink(\n') - self.DERStatusLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DER, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'AssociatedDERProgramListLink': - obj_ = AssociatedDERProgramListLink.factory() - obj_.build(child_) - self.AssociatedDERProgramListLink = obj_ - obj_.original_tagname_ = 'AssociatedDERProgramListLink' - elif nodeName_ == 'AssociatedUsagePointLink': - obj_ = AssociatedUsagePointLink.factory() - obj_.build(child_) - self.AssociatedUsagePointLink = obj_ - obj_.original_tagname_ = 'AssociatedUsagePointLink' - elif nodeName_ == 'CurrentDERProgramLink': - obj_ = CurrentDERProgramLink.factory() - obj_.build(child_) - self.CurrentDERProgramLink = obj_ - obj_.original_tagname_ = 'CurrentDERProgramLink' - elif nodeName_ == 'DERAvailabilityLink': - obj_ = DERAvailabilityLink.factory() - obj_.build(child_) - self.DERAvailabilityLink = obj_ - obj_.original_tagname_ = 'DERAvailabilityLink' - elif nodeName_ == 'DERCapabilityLink': - obj_ = DERCapabilityLink.factory() - obj_.build(child_) - self.DERCapabilityLink = obj_ - obj_.original_tagname_ = 'DERCapabilityLink' - elif nodeName_ == 'DERSettingsLink': - obj_ = DERSettingsLink.factory() - obj_.build(child_) - self.DERSettingsLink = obj_ - obj_.original_tagname_ = 'DERSettingsLink' - elif nodeName_ == 'DERStatusLink': - obj_ = DERStatusLink.factory() - obj_.build(child_) - self.DERStatusLink = obj_ - obj_.original_tagname_ = 'DERStatusLink' - super(DER, self).buildChildren(child_, node, nodeName_, True) -# end class DER - - -class DefaultDERControl(SubscribableIdentifiedObject): - """Contains control mode information to be used if no active DERControl - is found.""" - subclass = None - superclass = SubscribableIdentifiedObject - def __init__(self, DERControlBase=None): - self.original_tagname_ = None - super(DefaultDERControl, self).__init__() - self.DERControlBase = DERControlBase - def factory(*args_, **kwargs_): - if DefaultDERControl.subclass: - return DefaultDERControl.subclass(*args_, **kwargs_) - else: - return DefaultDERControl(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DERControlBase(self): return self.DERControlBase - def set_DERControlBase(self, DERControlBase): self.DERControlBase = DERControlBase - def hasContent_(self): - if ( - self.DERControlBase is not None or - super(DefaultDERControl, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DefaultDERControl', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DefaultDERControl') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DefaultDERControl', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DefaultDERControl'): - super(DefaultDERControl, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DefaultDERControl') - def exportChildren(self, outfile, level, namespace_='', name_='DefaultDERControl', fromsubclass_=False, pretty_print=True): - super(DefaultDERControl, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.DERControlBase is not None: - self.DERControlBase.export(outfile, level, namespace_, name_='DERControlBase', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DefaultDERControl'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DefaultDERControl, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DefaultDERControl, self).exportLiteralChildren(outfile, level, name_) - if self.DERControlBase is not None: - showIndent(outfile, level) - outfile.write('DERControlBase=model_.DERControlBase(\n') - self.DERControlBase.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DefaultDERControl, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DERControlBase': - obj_ = DERControlBase.factory() - obj_.build(child_) - self.DERControlBase = obj_ - obj_.original_tagname_ = 'DERControlBase' - super(DefaultDERControl, self).buildChildren(child_, node, nodeName_, True) -# end class DefaultDERControl - - -class FlowReservationResponseList(SubscribableList): - """A List element to hold FlowReservationResponse objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, FlowReservationResponse=None): - self.original_tagname_ = None - super(FlowReservationResponseList, self).__init__() - if FlowReservationResponse is None: - self.FlowReservationResponse = [] - else: - self.FlowReservationResponse = FlowReservationResponse - def factory(*args_, **kwargs_): - if FlowReservationResponseList.subclass: - return FlowReservationResponseList.subclass(*args_, **kwargs_) - else: - return FlowReservationResponseList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_FlowReservationResponse(self): return self.FlowReservationResponse - def set_FlowReservationResponse(self, FlowReservationResponse): self.FlowReservationResponse = FlowReservationResponse - def add_FlowReservationResponse(self, value): self.FlowReservationResponse.append(value) - def insert_FlowReservationResponse_at(self, index, value): self.FlowReservationResponse.insert(index, value) - def replace_FlowReservationResponse_at(self, index, value): self.FlowReservationResponse[index] = value - def hasContent_(self): - if ( - self.FlowReservationResponse or - super(FlowReservationResponseList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FlowReservationResponseList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationResponseList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FlowReservationResponseList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FlowReservationResponseList'): - super(FlowReservationResponseList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationResponseList') - def exportChildren(self, outfile, level, namespace_='', name_='FlowReservationResponseList', fromsubclass_=False, pretty_print=True): - super(FlowReservationResponseList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for FlowReservationResponse_ in self.FlowReservationResponse: - FlowReservationResponse_.export(outfile, level, namespace_, name_='FlowReservationResponse', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FlowReservationResponseList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FlowReservationResponseList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FlowReservationResponseList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('FlowReservationResponse=[\n') - level += 1 - for FlowReservationResponse_ in self.FlowReservationResponse: - showIndent(outfile, level) - outfile.write('model_.FlowReservationResponse(\n') - FlowReservationResponse_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FlowReservationResponseList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'FlowReservationResponse': - obj_ = FlowReservationResponse.factory() - obj_.build(child_) - self.FlowReservationResponse.append(obj_) - obj_.original_tagname_ = 'FlowReservationResponse' - super(FlowReservationResponseList, self).buildChildren(child_, node, nodeName_, True) -# end class FlowReservationResponseList - - -class FlowReservationResponse(Event): - """The server may modify the charging or discharging parameters and - interval to provide a lower aggregated demand at the premises, - or within a larger part of the distribution system.""" - subclass = None - superclass = Event - def __init__(self, energyAvailable=None, powerAvailable=None, subject=None): - self.original_tagname_ = None - super(FlowReservationResponse, self).__init__() - self.energyAvailable = energyAvailable - self.powerAvailable = powerAvailable - self.subject = subject - def factory(*args_, **kwargs_): - if FlowReservationResponse.subclass: - return FlowReservationResponse.subclass(*args_, **kwargs_) - else: - return FlowReservationResponse(*args_, **kwargs_) - factory = staticmethod(factory) - def get_energyAvailable(self): return self.energyAvailable - def set_energyAvailable(self, energyAvailable): self.energyAvailable = energyAvailable - def get_powerAvailable(self): return self.powerAvailable - def set_powerAvailable(self, powerAvailable): self.powerAvailable = powerAvailable - def get_subject(self): return self.subject - def set_subject(self, subject): self.subject = subject - def hasContent_(self): - if ( - self.energyAvailable is not None or - self.powerAvailable is not None or - self.subject is not None or - super(FlowReservationResponse, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FlowReservationResponse', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationResponse') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FlowReservationResponse', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FlowReservationResponse'): - super(FlowReservationResponse, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationResponse') - def exportChildren(self, outfile, level, namespace_='', name_='FlowReservationResponse', fromsubclass_=False, pretty_print=True): - super(FlowReservationResponse, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.energyAvailable is not None: - self.energyAvailable.export(outfile, level, namespace_, name_='energyAvailable', pretty_print=pretty_print) - if self.powerAvailable is not None: - self.powerAvailable.export(outfile, level, namespace_, name_='powerAvailable', pretty_print=pretty_print) - if self.subject is not None: - self.subject.export(outfile, level, namespace_, name_='subject', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FlowReservationResponse'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FlowReservationResponse, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FlowReservationResponse, self).exportLiteralChildren(outfile, level, name_) - if self.energyAvailable is not None: - showIndent(outfile, level) - outfile.write('energyAvailable=model_.RealEnergy(\n') - self.energyAvailable.exportLiteral(outfile, level, name_='energyAvailable') - showIndent(outfile, level) - outfile.write('),\n') - if self.powerAvailable is not None: - showIndent(outfile, level) - outfile.write('powerAvailable=model_.ActivePower(\n') - self.powerAvailable.exportLiteral(outfile, level, name_='powerAvailable') - showIndent(outfile, level) - outfile.write('),\n') - if self.subject is not None: - showIndent(outfile, level) - outfile.write('subject=model_.mRIDType(\n') - self.subject.exportLiteral(outfile, level, name_='subject') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FlowReservationResponse, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'energyAvailable': - obj_ = RealEnergy.factory() - obj_.build(child_) - self.energyAvailable = obj_ - obj_.original_tagname_ = 'energyAvailable' - elif nodeName_ == 'powerAvailable': - obj_ = ActivePower.factory() - obj_.build(child_) - self.powerAvailable = obj_ - obj_.original_tagname_ = 'powerAvailable' - elif nodeName_ == 'subject': - obj_ = mRIDType.factory() - obj_.build(child_) - self.subject = obj_ - obj_.original_tagname_ = 'subject' - super(FlowReservationResponse, self).buildChildren(child_, node, nodeName_, True) -# end class FlowReservationResponse - - -class FlowReservationRequestList(List): - """A List element to hold FlowReservationRequest objects.""" - subclass = None - superclass = List - def __init__(self, FlowReservationRequest=None): - self.original_tagname_ = None - super(FlowReservationRequestList, self).__init__() - if FlowReservationRequest is None: - self.FlowReservationRequest = [] - else: - self.FlowReservationRequest = FlowReservationRequest - def factory(*args_, **kwargs_): - if FlowReservationRequestList.subclass: - return FlowReservationRequestList.subclass(*args_, **kwargs_) - else: - return FlowReservationRequestList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_FlowReservationRequest(self): return self.FlowReservationRequest - def set_FlowReservationRequest(self, FlowReservationRequest): self.FlowReservationRequest = FlowReservationRequest - def add_FlowReservationRequest(self, value): self.FlowReservationRequest.append(value) - def insert_FlowReservationRequest_at(self, index, value): self.FlowReservationRequest.insert(index, value) - def replace_FlowReservationRequest_at(self, index, value): self.FlowReservationRequest[index] = value - def hasContent_(self): - if ( - self.FlowReservationRequest or - super(FlowReservationRequestList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FlowReservationRequestList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationRequestList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FlowReservationRequestList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FlowReservationRequestList'): - super(FlowReservationRequestList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationRequestList') - def exportChildren(self, outfile, level, namespace_='', name_='FlowReservationRequestList', fromsubclass_=False, pretty_print=True): - super(FlowReservationRequestList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for FlowReservationRequest_ in self.FlowReservationRequest: - FlowReservationRequest_.export(outfile, level, namespace_, name_='FlowReservationRequest', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FlowReservationRequestList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FlowReservationRequestList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FlowReservationRequestList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('FlowReservationRequest=[\n') - level += 1 - for FlowReservationRequest_ in self.FlowReservationRequest: - showIndent(outfile, level) - outfile.write('model_.FlowReservationRequest(\n') - FlowReservationRequest_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FlowReservationRequestList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'FlowReservationRequest': - obj_ = FlowReservationRequest.factory() - obj_.build(child_) - self.FlowReservationRequest.append(obj_) - obj_.original_tagname_ = 'FlowReservationRequest' - super(FlowReservationRequestList, self).buildChildren(child_, node, nodeName_, True) -# end class FlowReservationRequestList - - -class FlowReservationRequest(IdentifiedObject): - """Used to request flow transactions. Client EndDevices submit a - request for charging or discharging from the server. The server - creates an associated FlowReservationResponse containing the - charging parameters and interval to provide a lower aggregated - demand at the premises, or within a larger part of the - distribution system.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, creationTime=None, durationRequested=None, energyRequested=None, intervalRequested=None, powerRequested=None, RequestStatus=None): - self.original_tagname_ = None - super(FlowReservationRequest, self).__init__() - self.creationTime = creationTime - self.durationRequested = durationRequested - self.energyRequested = energyRequested - self.intervalRequested = intervalRequested - self.powerRequested = powerRequested - self.RequestStatus = RequestStatus - def factory(*args_, **kwargs_): - if FlowReservationRequest.subclass: - return FlowReservationRequest.subclass(*args_, **kwargs_) - else: - return FlowReservationRequest(*args_, **kwargs_) - factory = staticmethod(factory) - def get_creationTime(self): return self.creationTime - def set_creationTime(self, creationTime): self.creationTime = creationTime - def get_durationRequested(self): return self.durationRequested - def set_durationRequested(self, durationRequested): self.durationRequested = durationRequested - def get_energyRequested(self): return self.energyRequested - def set_energyRequested(self, energyRequested): self.energyRequested = energyRequested - def get_intervalRequested(self): return self.intervalRequested - def set_intervalRequested(self, intervalRequested): self.intervalRequested = intervalRequested - def get_powerRequested(self): return self.powerRequested - def set_powerRequested(self, powerRequested): self.powerRequested = powerRequested - def get_RequestStatus(self): return self.RequestStatus - def set_RequestStatus(self, RequestStatus): self.RequestStatus = RequestStatus - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.creationTime is not None or - self.durationRequested is not None or - self.energyRequested is not None or - self.intervalRequested is not None or - self.powerRequested is not None or - self.RequestStatus is not None or - super(FlowReservationRequest, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FlowReservationRequest', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationRequest') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FlowReservationRequest', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FlowReservationRequest'): - super(FlowReservationRequest, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FlowReservationRequest') - def exportChildren(self, outfile, level, namespace_='', name_='FlowReservationRequest', fromsubclass_=False, pretty_print=True): - super(FlowReservationRequest, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.creationTime is not None: - self.creationTime.export(outfile, level, namespace_, name_='creationTime', pretty_print=pretty_print) - if self.durationRequested is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdurationRequested>%s%s' % (namespace_, self.gds_format_integer(self.durationRequested, input_name='durationRequested'), namespace_, eol_)) - if self.energyRequested is not None: - self.energyRequested.export(outfile, level, namespace_, name_='energyRequested', pretty_print=pretty_print) - if self.intervalRequested is not None: - self.intervalRequested.export(outfile, level, namespace_, name_='intervalRequested', pretty_print=pretty_print) - if self.powerRequested is not None: - self.powerRequested.export(outfile, level, namespace_, name_='powerRequested', pretty_print=pretty_print) - if self.RequestStatus is not None: - self.RequestStatus.export(outfile, level, namespace_, name_='RequestStatus', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FlowReservationRequest'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FlowReservationRequest, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FlowReservationRequest, self).exportLiteralChildren(outfile, level, name_) - if self.creationTime is not None: - showIndent(outfile, level) - outfile.write('creationTime=model_.TimeType(\n') - self.creationTime.exportLiteral(outfile, level, name_='creationTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.durationRequested is not None: - showIndent(outfile, level) - outfile.write('durationRequested=%d,\n' % self.durationRequested) - if self.energyRequested is not None: - showIndent(outfile, level) - outfile.write('energyRequested=model_.SignedRealEnergy(\n') - self.energyRequested.exportLiteral(outfile, level, name_='energyRequested') - showIndent(outfile, level) - outfile.write('),\n') - if self.intervalRequested is not None: - showIndent(outfile, level) - outfile.write('intervalRequested=model_.DateTimeInterval(\n') - self.intervalRequested.exportLiteral(outfile, level, name_='intervalRequested') - showIndent(outfile, level) - outfile.write('),\n') - if self.powerRequested is not None: - showIndent(outfile, level) - outfile.write('powerRequested=model_.ActivePower(\n') - self.powerRequested.exportLiteral(outfile, level, name_='powerRequested') - showIndent(outfile, level) - outfile.write('),\n') - if self.RequestStatus is not None: - showIndent(outfile, level) - outfile.write('RequestStatus=model_.RequestStatus(\n') - self.RequestStatus.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FlowReservationRequest, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'creationTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.creationTime = obj_ - obj_.original_tagname_ = 'creationTime' - elif nodeName_ == 'durationRequested': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'durationRequested') - self.durationRequested = ival_ - self.validate_UInt16(self.durationRequested) # validate type UInt16 - elif nodeName_ == 'energyRequested': - obj_ = SignedRealEnergy.factory() - obj_.build(child_) - self.energyRequested = obj_ - obj_.original_tagname_ = 'energyRequested' - elif nodeName_ == 'intervalRequested': - obj_ = DateTimeInterval.factory() - obj_.build(child_) - self.intervalRequested = obj_ - obj_.original_tagname_ = 'intervalRequested' - elif nodeName_ == 'powerRequested': - obj_ = ActivePower.factory() - obj_.build(child_) - self.powerRequested = obj_ - obj_.original_tagname_ = 'powerRequested' - elif nodeName_ == 'RequestStatus': - obj_ = RequestStatus.factory() - obj_.build(child_) - self.RequestStatus = obj_ - obj_.original_tagname_ = 'RequestStatus' - super(FlowReservationRequest, self).buildChildren(child_, node, nodeName_, True) -# end class FlowReservationRequest - - -class AbstractFlowReservation(Event): - """Provides definition of FlowReservation elements in common between - Requests and Responses.""" - subclass = None - superclass = Event - def __init__(self): - self.original_tagname_ = None - super(AbstractFlowReservation, self).__init__() - def factory(*args_, **kwargs_): - if AbstractFlowReservation.subclass: - return AbstractFlowReservation.subclass(*args_, **kwargs_) - else: - return AbstractFlowReservation(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(AbstractFlowReservation, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AbstractFlowReservation', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AbstractFlowReservation') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AbstractFlowReservation', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AbstractFlowReservation'): - super(AbstractFlowReservation, self).exportAttributes(outfile, level, already_processed, namespace_, name_='AbstractFlowReservation') - def exportChildren(self, outfile, level, namespace_='', name_='AbstractFlowReservation', fromsubclass_=False, pretty_print=True): - super(AbstractFlowReservation, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='AbstractFlowReservation'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(AbstractFlowReservation, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(AbstractFlowReservation, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(AbstractFlowReservation, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(AbstractFlowReservation, self).buildChildren(child_, node, nodeName_, True) - pass -# end class AbstractFlowReservation - - -class SupplyInterruptionOverrideList(List): - """A List element to hold SupplyInterruptionOverride objects.""" - subclass = None - superclass = List - def __init__(self, SupplyInterruptionOverride=None): - self.original_tagname_ = None - super(SupplyInterruptionOverrideList, self).__init__() - if SupplyInterruptionOverride is None: - self.SupplyInterruptionOverride = [] - else: - self.SupplyInterruptionOverride = SupplyInterruptionOverride - def factory(*args_, **kwargs_): - if SupplyInterruptionOverrideList.subclass: - return SupplyInterruptionOverrideList.subclass(*args_, **kwargs_) - else: - return SupplyInterruptionOverrideList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_SupplyInterruptionOverride(self): return self.SupplyInterruptionOverride - def set_SupplyInterruptionOverride(self, SupplyInterruptionOverride): self.SupplyInterruptionOverride = SupplyInterruptionOverride - def add_SupplyInterruptionOverride(self, value): self.SupplyInterruptionOverride.append(value) - def insert_SupplyInterruptionOverride_at(self, index, value): self.SupplyInterruptionOverride.insert(index, value) - def replace_SupplyInterruptionOverride_at(self, index, value): self.SupplyInterruptionOverride[index] = value - def hasContent_(self): - if ( - self.SupplyInterruptionOverride or - super(SupplyInterruptionOverrideList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SupplyInterruptionOverrideList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SupplyInterruptionOverrideList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SupplyInterruptionOverrideList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SupplyInterruptionOverrideList'): - super(SupplyInterruptionOverrideList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SupplyInterruptionOverrideList') - def exportChildren(self, outfile, level, namespace_='', name_='SupplyInterruptionOverrideList', fromsubclass_=False, pretty_print=True): - super(SupplyInterruptionOverrideList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for SupplyInterruptionOverride_ in self.SupplyInterruptionOverride: - SupplyInterruptionOverride_.export(outfile, level, namespace_, name_='SupplyInterruptionOverride', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='SupplyInterruptionOverrideList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SupplyInterruptionOverrideList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SupplyInterruptionOverrideList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('SupplyInterruptionOverride=[\n') - level += 1 - for SupplyInterruptionOverride_ in self.SupplyInterruptionOverride: - showIndent(outfile, level) - outfile.write('model_.SupplyInterruptionOverride(\n') - SupplyInterruptionOverride_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SupplyInterruptionOverrideList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'SupplyInterruptionOverride': - obj_ = SupplyInterruptionOverride.factory() - obj_.build(child_) - self.SupplyInterruptionOverride.append(obj_) - obj_.original_tagname_ = 'SupplyInterruptionOverride' - super(SupplyInterruptionOverrideList, self).buildChildren(child_, node, nodeName_, True) -# end class SupplyInterruptionOverrideList - - -class SupplyInterruptionOverride(Resource): - """SupplyInterruptionOverride: There may be periods of time when - social, regulatory or other concerns mean that service should - not be interrupted, even when available credit has been - exhausted. Each Prepayment instance links to a List of - SupplyInterruptionOverride instances. Each - SupplyInterruptionOverride defines a contiguous period of time - during which supply SHALL NOT be interrupted.""" - subclass = None - superclass = Resource - def __init__(self, description=None, interval=None): - self.original_tagname_ = None - super(SupplyInterruptionOverride, self).__init__() - self.description = description - self.interval = interval - def factory(*args_, **kwargs_): - if SupplyInterruptionOverride.subclass: - return SupplyInterruptionOverride.subclass(*args_, **kwargs_) - else: - return SupplyInterruptionOverride(*args_, **kwargs_) - factory = staticmethod(factory) - def get_description(self): return self.description - def set_description(self, description): self.description = description - def get_interval(self): return self.interval - def set_interval(self, interval): self.interval = interval - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.description is not None or - self.interval is not None or - super(SupplyInterruptionOverride, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SupplyInterruptionOverride', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SupplyInterruptionOverride') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SupplyInterruptionOverride', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SupplyInterruptionOverride'): - super(SupplyInterruptionOverride, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SupplyInterruptionOverride') - def exportChildren(self, outfile, level, namespace_='', name_='SupplyInterruptionOverride', fromsubclass_=False, pretty_print=True): - super(SupplyInterruptionOverride, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.description is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdescription>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.description).encode(ExternalEncoding), input_name='description'), namespace_, eol_)) - if self.interval is not None: - self.interval.export(outfile, level, namespace_, name_='interval', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='SupplyInterruptionOverride'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SupplyInterruptionOverride, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SupplyInterruptionOverride, self).exportLiteralChildren(outfile, level, name_) - if self.description is not None: - showIndent(outfile, level) - outfile.write('description=%s,\n' % quote_python(self.description).encode(ExternalEncoding)) - if self.interval is not None: - showIndent(outfile, level) - outfile.write('interval=model_.DateTimeInterval(\n') - self.interval.exportLiteral(outfile, level, name_='interval') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SupplyInterruptionOverride, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'description': - description_ = child_.text - description_ = self.gds_validate_string(description_, node, 'description') - self.description = description_ - self.validate_String32(self.description) # validate type String32 - elif nodeName_ == 'interval': - obj_ = DateTimeInterval.factory() - obj_.build(child_) - self.interval = obj_ - obj_.original_tagname_ = 'interval' - super(SupplyInterruptionOverride, self).buildChildren(child_, node, nodeName_, True) -# end class SupplyInterruptionOverride - - -class PrepayOperationStatus(Resource): - """PrepayOperationStatus describes the status of the service or - commodity being conditionally controlled by the Prepayment - function set.""" - subclass = None - superclass = Resource - def __init__(self, creditTypeChange=None, creditTypeInUse=None, serviceChange=None, serviceStatus=None): - self.original_tagname_ = None - super(PrepayOperationStatus, self).__init__() - self.creditTypeChange = creditTypeChange - self.creditTypeInUse = creditTypeInUse - self.serviceChange = serviceChange - self.serviceStatus = serviceStatus - def factory(*args_, **kwargs_): - if PrepayOperationStatus.subclass: - return PrepayOperationStatus.subclass(*args_, **kwargs_) - else: - return PrepayOperationStatus(*args_, **kwargs_) - factory = staticmethod(factory) - def get_creditTypeChange(self): return self.creditTypeChange - def set_creditTypeChange(self, creditTypeChange): self.creditTypeChange = creditTypeChange - def get_creditTypeInUse(self): return self.creditTypeInUse - def set_creditTypeInUse(self, creditTypeInUse): self.creditTypeInUse = creditTypeInUse - def get_serviceChange(self): return self.serviceChange - def set_serviceChange(self, serviceChange): self.serviceChange = serviceChange - def get_serviceStatus(self): return self.serviceStatus - def set_serviceStatus(self, serviceStatus): self.serviceStatus = serviceStatus - def hasContent_(self): - if ( - self.creditTypeChange is not None or - self.creditTypeInUse is not None or - self.serviceChange is not None or - self.serviceStatus is not None or - super(PrepayOperationStatus, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PrepayOperationStatus', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PrepayOperationStatus') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PrepayOperationStatus', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PrepayOperationStatus'): - super(PrepayOperationStatus, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PrepayOperationStatus') - def exportChildren(self, outfile, level, namespace_='', name_='PrepayOperationStatus', fromsubclass_=False, pretty_print=True): - super(PrepayOperationStatus, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.creditTypeChange is not None: - self.creditTypeChange.export(outfile, level, namespace_, name_='creditTypeChange', pretty_print=pretty_print) - if self.creditTypeInUse is not None: - self.creditTypeInUse.export(outfile, level, namespace_, name_='creditTypeInUse', pretty_print=pretty_print) - if self.serviceChange is not None: - self.serviceChange.export(outfile, level, namespace_, name_='serviceChange', pretty_print=pretty_print) - if self.serviceStatus is not None: - self.serviceStatus.export(outfile, level, namespace_, name_='serviceStatus', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='PrepayOperationStatus'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PrepayOperationStatus, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PrepayOperationStatus, self).exportLiteralChildren(outfile, level, name_) - if self.creditTypeChange is not None: - showIndent(outfile, level) - outfile.write('creditTypeChange=model_.CreditTypeChange(\n') - self.creditTypeChange.exportLiteral(outfile, level, name_='creditTypeChange') - showIndent(outfile, level) - outfile.write('),\n') - if self.creditTypeInUse is not None: - showIndent(outfile, level) - outfile.write('creditTypeInUse=model_.CreditTypeType(\n') - self.creditTypeInUse.exportLiteral(outfile, level, name_='creditTypeInUse') - showIndent(outfile, level) - outfile.write('),\n') - if self.serviceChange is not None: - showIndent(outfile, level) - outfile.write('serviceChange=model_.ServiceChange(\n') - self.serviceChange.exportLiteral(outfile, level, name_='serviceChange') - showIndent(outfile, level) - outfile.write('),\n') - if self.serviceStatus is not None: - showIndent(outfile, level) - outfile.write('serviceStatus=model_.ServiceStatusType(\n') - self.serviceStatus.exportLiteral(outfile, level, name_='serviceStatus') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PrepayOperationStatus, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'creditTypeChange': - obj_ = CreditTypeChange.factory() - obj_.build(child_) - self.creditTypeChange = obj_ - obj_.original_tagname_ = 'creditTypeChange' - elif nodeName_ == 'creditTypeInUse': - obj_ = CreditTypeType.factory() - obj_.build(child_) - self.creditTypeInUse = obj_ - obj_.original_tagname_ = 'creditTypeInUse' - elif nodeName_ == 'serviceChange': - obj_ = ServiceChange.factory() - obj_.build(child_) - self.serviceChange = obj_ - obj_.original_tagname_ = 'serviceChange' - elif nodeName_ == 'serviceStatus': - obj_ = ServiceStatusType.factory() - obj_.build(child_) - self.serviceStatus = obj_ - obj_.original_tagname_ = 'serviceStatus' - super(PrepayOperationStatus, self).buildChildren(child_, node, nodeName_, True) -# end class PrepayOperationStatus - - -class PrepaymentList(SubscribableList): - """A List element to hold Prepayment objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, Prepayment=None): - self.original_tagname_ = None - super(PrepaymentList, self).__init__() - if Prepayment is None: - self.Prepayment = [] - else: - self.Prepayment = Prepayment - def factory(*args_, **kwargs_): - if PrepaymentList.subclass: - return PrepaymentList.subclass(*args_, **kwargs_) - else: - return PrepaymentList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Prepayment(self): return self.Prepayment - def set_Prepayment(self, Prepayment): self.Prepayment = Prepayment - def add_Prepayment(self, value): self.Prepayment.append(value) - def insert_Prepayment_at(self, index, value): self.Prepayment.insert(index, value) - def replace_Prepayment_at(self, index, value): self.Prepayment[index] = value - def hasContent_(self): - if ( - self.Prepayment or - super(PrepaymentList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PrepaymentList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PrepaymentList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PrepaymentList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PrepaymentList'): - super(PrepaymentList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PrepaymentList') - def exportChildren(self, outfile, level, namespace_='', name_='PrepaymentList', fromsubclass_=False, pretty_print=True): - super(PrepaymentList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Prepayment_ in self.Prepayment: - Prepayment_.export(outfile, level, namespace_, name_='Prepayment', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='PrepaymentList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PrepaymentList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PrepaymentList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('Prepayment=[\n') - level += 1 - for Prepayment_ in self.Prepayment: - showIndent(outfile, level) - outfile.write('model_.Prepayment(\n') - Prepayment_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PrepaymentList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Prepayment': - obj_ = Prepayment.factory() - obj_.build(child_) - self.Prepayment.append(obj_) - obj_.original_tagname_ = 'Prepayment' - super(PrepaymentList, self).buildChildren(child_, node, nodeName_, True) -# end class PrepaymentList - - -class Prepayment(IdentifiedObject): - """Prepayment (inherited from CIM SDPAccountingFunction)""" - subclass = None - superclass = IdentifiedObject - def __init__(self, AccountBalanceLink=None, ActiveCreditRegisterListLink=None, ActiveSupplyInterruptionOverrideListLink=None, creditExpiryLevel=None, CreditRegisterListLink=None, lowCreditWarningLevel=None, lowEmergencyCreditWarningLevel=None, prepayMode=None, PrepayOperationStatusLink=None, SupplyInterruptionOverrideListLink=None, UsagePoint=None, UsagePointLink=None): - self.original_tagname_ = None - super(Prepayment, self).__init__() - self.AccountBalanceLink = AccountBalanceLink - self.ActiveCreditRegisterListLink = ActiveCreditRegisterListLink - self.ActiveSupplyInterruptionOverrideListLink = ActiveSupplyInterruptionOverrideListLink - self.creditExpiryLevel = creditExpiryLevel - self.CreditRegisterListLink = CreditRegisterListLink - self.lowCreditWarningLevel = lowCreditWarningLevel - self.lowEmergencyCreditWarningLevel = lowEmergencyCreditWarningLevel - self.prepayMode = prepayMode - self.PrepayOperationStatusLink = PrepayOperationStatusLink - self.SupplyInterruptionOverrideListLink = SupplyInterruptionOverrideListLink - if UsagePoint is None: - self.UsagePoint = [] - else: - self.UsagePoint = UsagePoint - self.UsagePointLink = UsagePointLink - def factory(*args_, **kwargs_): - if Prepayment.subclass: - return Prepayment.subclass(*args_, **kwargs_) - else: - return Prepayment(*args_, **kwargs_) - factory = staticmethod(factory) - def get_AccountBalanceLink(self): return self.AccountBalanceLink - def set_AccountBalanceLink(self, AccountBalanceLink): self.AccountBalanceLink = AccountBalanceLink - def get_ActiveCreditRegisterListLink(self): return self.ActiveCreditRegisterListLink - def set_ActiveCreditRegisterListLink(self, ActiveCreditRegisterListLink): self.ActiveCreditRegisterListLink = ActiveCreditRegisterListLink - def get_ActiveSupplyInterruptionOverrideListLink(self): return self.ActiveSupplyInterruptionOverrideListLink - def set_ActiveSupplyInterruptionOverrideListLink(self, ActiveSupplyInterruptionOverrideListLink): self.ActiveSupplyInterruptionOverrideListLink = ActiveSupplyInterruptionOverrideListLink - def get_creditExpiryLevel(self): return self.creditExpiryLevel - def set_creditExpiryLevel(self, creditExpiryLevel): self.creditExpiryLevel = creditExpiryLevel - def get_CreditRegisterListLink(self): return self.CreditRegisterListLink - def set_CreditRegisterListLink(self, CreditRegisterListLink): self.CreditRegisterListLink = CreditRegisterListLink - def get_lowCreditWarningLevel(self): return self.lowCreditWarningLevel - def set_lowCreditWarningLevel(self, lowCreditWarningLevel): self.lowCreditWarningLevel = lowCreditWarningLevel - def get_lowEmergencyCreditWarningLevel(self): return self.lowEmergencyCreditWarningLevel - def set_lowEmergencyCreditWarningLevel(self, lowEmergencyCreditWarningLevel): self.lowEmergencyCreditWarningLevel = lowEmergencyCreditWarningLevel - def get_prepayMode(self): return self.prepayMode - def set_prepayMode(self, prepayMode): self.prepayMode = prepayMode - def get_PrepayOperationStatusLink(self): return self.PrepayOperationStatusLink - def set_PrepayOperationStatusLink(self, PrepayOperationStatusLink): self.PrepayOperationStatusLink = PrepayOperationStatusLink - def get_SupplyInterruptionOverrideListLink(self): return self.SupplyInterruptionOverrideListLink - def set_SupplyInterruptionOverrideListLink(self, SupplyInterruptionOverrideListLink): self.SupplyInterruptionOverrideListLink = SupplyInterruptionOverrideListLink - def get_UsagePoint(self): return self.UsagePoint - def set_UsagePoint(self, UsagePoint): self.UsagePoint = UsagePoint - def add_UsagePoint(self, value): self.UsagePoint.append(value) - def insert_UsagePoint_at(self, index, value): self.UsagePoint.insert(index, value) - def replace_UsagePoint_at(self, index, value): self.UsagePoint[index] = value - def get_UsagePointLink(self): return self.UsagePointLink - def set_UsagePointLink(self, UsagePointLink): self.UsagePointLink = UsagePointLink - def hasContent_(self): - if ( - self.AccountBalanceLink is not None or - self.ActiveCreditRegisterListLink is not None or - self.ActiveSupplyInterruptionOverrideListLink is not None or - self.creditExpiryLevel is not None or - self.CreditRegisterListLink is not None or - self.lowCreditWarningLevel is not None or - self.lowEmergencyCreditWarningLevel is not None or - self.prepayMode is not None or - self.PrepayOperationStatusLink is not None or - self.SupplyInterruptionOverrideListLink is not None or - self.UsagePoint or - self.UsagePointLink is not None or - super(Prepayment, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Prepayment', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Prepayment') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Prepayment', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Prepayment'): - super(Prepayment, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Prepayment') - def exportChildren(self, outfile, level, namespace_='', name_='Prepayment', fromsubclass_=False, pretty_print=True): - super(Prepayment, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.AccountBalanceLink is not None: - self.AccountBalanceLink.export(outfile, level, namespace_, name_='AccountBalanceLink', pretty_print=pretty_print) - if self.ActiveCreditRegisterListLink is not None: - self.ActiveCreditRegisterListLink.export(outfile, level, namespace_, name_='ActiveCreditRegisterListLink', pretty_print=pretty_print) - if self.ActiveSupplyInterruptionOverrideListLink is not None: - self.ActiveSupplyInterruptionOverrideListLink.export(outfile, level, namespace_, name_='ActiveSupplyInterruptionOverrideListLink', pretty_print=pretty_print) - if self.creditExpiryLevel is not None: - self.creditExpiryLevel.export(outfile, level, namespace_, name_='creditExpiryLevel', pretty_print=pretty_print) - if self.CreditRegisterListLink is not None: - self.CreditRegisterListLink.export(outfile, level, namespace_, name_='CreditRegisterListLink', pretty_print=pretty_print) - if self.lowCreditWarningLevel is not None: - self.lowCreditWarningLevel.export(outfile, level, namespace_, name_='lowCreditWarningLevel', pretty_print=pretty_print) - if self.lowEmergencyCreditWarningLevel is not None: - self.lowEmergencyCreditWarningLevel.export(outfile, level, namespace_, name_='lowEmergencyCreditWarningLevel', pretty_print=pretty_print) - if self.prepayMode is not None: - self.prepayMode.export(outfile, level, namespace_, name_='prepayMode', pretty_print=pretty_print) - if self.PrepayOperationStatusLink is not None: - self.PrepayOperationStatusLink.export(outfile, level, namespace_, name_='PrepayOperationStatusLink', pretty_print=pretty_print) - if self.SupplyInterruptionOverrideListLink is not None: - self.SupplyInterruptionOverrideListLink.export(outfile, level, namespace_, name_='SupplyInterruptionOverrideListLink', pretty_print=pretty_print) - for UsagePoint_ in self.UsagePoint: - UsagePoint_.export(outfile, level, namespace_, name_='UsagePoint', pretty_print=pretty_print) - if self.UsagePointLink is not None: - self.UsagePointLink.export(outfile, level, namespace_, name_='UsagePointLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='Prepayment'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Prepayment, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Prepayment, self).exportLiteralChildren(outfile, level, name_) - if self.AccountBalanceLink is not None: - showIndent(outfile, level) - outfile.write('AccountBalanceLink=model_.AccountBalanceLink(\n') - self.AccountBalanceLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ActiveCreditRegisterListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveCreditRegisterListLink=model_.ActiveCreditRegisterListLink(\n') - self.ActiveCreditRegisterListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ActiveSupplyInterruptionOverrideListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveSupplyInterruptionOverrideListLink=model_.ActiveSupplyInterruptionOverrideListLink(\n') - self.ActiveSupplyInterruptionOverrideListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.creditExpiryLevel is not None: - showIndent(outfile, level) - outfile.write('creditExpiryLevel=model_.AccountingUnit(\n') - self.creditExpiryLevel.exportLiteral(outfile, level, name_='creditExpiryLevel') - showIndent(outfile, level) - outfile.write('),\n') - if self.CreditRegisterListLink is not None: - showIndent(outfile, level) - outfile.write('CreditRegisterListLink=model_.CreditRegisterListLink(\n') - self.CreditRegisterListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.lowCreditWarningLevel is not None: - showIndent(outfile, level) - outfile.write('lowCreditWarningLevel=model_.AccountingUnit(\n') - self.lowCreditWarningLevel.exportLiteral(outfile, level, name_='lowCreditWarningLevel') - showIndent(outfile, level) - outfile.write('),\n') - if self.lowEmergencyCreditWarningLevel is not None: - showIndent(outfile, level) - outfile.write('lowEmergencyCreditWarningLevel=model_.AccountingUnit(\n') - self.lowEmergencyCreditWarningLevel.exportLiteral(outfile, level, name_='lowEmergencyCreditWarningLevel') - showIndent(outfile, level) - outfile.write('),\n') - if self.prepayMode is not None: - showIndent(outfile, level) - outfile.write('prepayMode=model_.PrepayModeType(\n') - self.prepayMode.exportLiteral(outfile, level, name_='prepayMode') - showIndent(outfile, level) - outfile.write('),\n') - if self.PrepayOperationStatusLink is not None: - showIndent(outfile, level) - outfile.write('PrepayOperationStatusLink=model_.PrepayOperationStatusLink(\n') - self.PrepayOperationStatusLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.SupplyInterruptionOverrideListLink is not None: - showIndent(outfile, level) - outfile.write('SupplyInterruptionOverrideListLink=model_.SupplyInterruptionOverrideListLink(\n') - self.SupplyInterruptionOverrideListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - showIndent(outfile, level) - outfile.write('UsagePoint=[\n') - level += 1 - for UsagePoint_ in self.UsagePoint: - showIndent(outfile, level) - outfile.write('model_.UsagePoint(\n') - UsagePoint_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - if self.UsagePointLink is not None: - showIndent(outfile, level) - outfile.write('UsagePointLink=model_.UsagePointLink(\n') - self.UsagePointLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Prepayment, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'AccountBalanceLink': - obj_ = AccountBalanceLink.factory() - obj_.build(child_) - self.AccountBalanceLink = obj_ - obj_.original_tagname_ = 'AccountBalanceLink' - elif nodeName_ == 'ActiveCreditRegisterListLink': - obj_ = ActiveCreditRegisterListLink.factory() - obj_.build(child_) - self.ActiveCreditRegisterListLink = obj_ - obj_.original_tagname_ = 'ActiveCreditRegisterListLink' - elif nodeName_ == 'ActiveSupplyInterruptionOverrideListLink': - obj_ = ActiveSupplyInterruptionOverrideListLink.factory() - obj_.build(child_) - self.ActiveSupplyInterruptionOverrideListLink = obj_ - obj_.original_tagname_ = 'ActiveSupplyInterruptionOverrideListLink' - elif nodeName_ == 'creditExpiryLevel': - obj_ = AccountingUnit.factory() - obj_.build(child_) - self.creditExpiryLevel = obj_ - obj_.original_tagname_ = 'creditExpiryLevel' - elif nodeName_ == 'CreditRegisterListLink': - obj_ = CreditRegisterListLink.factory() - obj_.build(child_) - self.CreditRegisterListLink = obj_ - obj_.original_tagname_ = 'CreditRegisterListLink' - elif nodeName_ == 'lowCreditWarningLevel': - obj_ = AccountingUnit.factory() - obj_.build(child_) - self.lowCreditWarningLevel = obj_ - obj_.original_tagname_ = 'lowCreditWarningLevel' - elif nodeName_ == 'lowEmergencyCreditWarningLevel': - obj_ = AccountingUnit.factory() - obj_.build(child_) - self.lowEmergencyCreditWarningLevel = obj_ - obj_.original_tagname_ = 'lowEmergencyCreditWarningLevel' - elif nodeName_ == 'prepayMode': - obj_ = PrepayModeType.factory() - obj_.build(child_) - self.prepayMode = obj_ - obj_.original_tagname_ = 'prepayMode' - elif nodeName_ == 'PrepayOperationStatusLink': - obj_ = PrepayOperationStatusLink.factory() - obj_.build(child_) - self.PrepayOperationStatusLink = obj_ - obj_.original_tagname_ = 'PrepayOperationStatusLink' - elif nodeName_ == 'SupplyInterruptionOverrideListLink': - obj_ = SupplyInterruptionOverrideListLink.factory() - obj_.build(child_) - self.SupplyInterruptionOverrideListLink = obj_ - obj_.original_tagname_ = 'SupplyInterruptionOverrideListLink' - elif nodeName_ == 'UsagePoint': - obj_ = UsagePoint.factory() - obj_.build(child_) - self.UsagePoint.append(obj_) - obj_.original_tagname_ = 'UsagePoint' - elif nodeName_ == 'UsagePointLink': - obj_ = UsagePointLink.factory() - obj_.build(child_) - self.UsagePointLink = obj_ - obj_.original_tagname_ = 'UsagePointLink' - super(Prepayment, self).buildChildren(child_, node, nodeName_, True) -# end class Prepayment - - -class CreditRegisterList(List): - """A List element to hold CreditRegister objects.""" - subclass = None - superclass = List - def __init__(self, CreditRegister=None): - self.original_tagname_ = None - super(CreditRegisterList, self).__init__() - if CreditRegister is None: - self.CreditRegister = [] - else: - self.CreditRegister = CreditRegister - def factory(*args_, **kwargs_): - if CreditRegisterList.subclass: - return CreditRegisterList.subclass(*args_, **kwargs_) - else: - return CreditRegisterList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_CreditRegister(self): return self.CreditRegister - def set_CreditRegister(self, CreditRegister): self.CreditRegister = CreditRegister - def add_CreditRegister(self, value): self.CreditRegister.append(value) - def insert_CreditRegister_at(self, index, value): self.CreditRegister.insert(index, value) - def replace_CreditRegister_at(self, index, value): self.CreditRegister[index] = value - def hasContent_(self): - if ( - self.CreditRegister or - super(CreditRegisterList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CreditRegisterList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CreditRegisterList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CreditRegisterList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CreditRegisterList'): - super(CreditRegisterList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CreditRegisterList') - def exportChildren(self, outfile, level, namespace_='', name_='CreditRegisterList', fromsubclass_=False, pretty_print=True): - super(CreditRegisterList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for CreditRegister_ in self.CreditRegister: - CreditRegister_.export(outfile, level, namespace_, name_='CreditRegister', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='CreditRegisterList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CreditRegisterList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CreditRegisterList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('CreditRegister=[\n') - level += 1 - for CreditRegister_ in self.CreditRegister: - showIndent(outfile, level) - outfile.write('model_.CreditRegister(\n') - CreditRegister_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CreditRegisterList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'CreditRegister': - obj_ = CreditRegister.factory() - obj_.build(child_) - self.CreditRegister.append(obj_) - obj_.original_tagname_ = 'CreditRegister' - super(CreditRegisterList, self).buildChildren(child_, node, nodeName_, True) -# end class CreditRegisterList - - -class CreditRegister(IdentifiedObject): - """CreditRegister instances define a credit-modifying transaction. - Typically this would be a credit-adding transaction, but may be - a subtracting transaction (perhaps in response to an out-of-band - debt signal).""" - subclass = None - superclass = IdentifiedObject - def __init__(self, creditAmount=None, creditType=None, effectiveTime=None, token=None): - self.original_tagname_ = None - super(CreditRegister, self).__init__() - self.creditAmount = creditAmount - self.creditType = creditType - self.effectiveTime = effectiveTime - self.token = token - def factory(*args_, **kwargs_): - if CreditRegister.subclass: - return CreditRegister.subclass(*args_, **kwargs_) - else: - return CreditRegister(*args_, **kwargs_) - factory = staticmethod(factory) - def get_creditAmount(self): return self.creditAmount - def set_creditAmount(self, creditAmount): self.creditAmount = creditAmount - def get_creditType(self): return self.creditType - def set_creditType(self, creditType): self.creditType = creditType - def get_effectiveTime(self): return self.effectiveTime - def set_effectiveTime(self, effectiveTime): self.effectiveTime = effectiveTime - def get_token(self): return self.token - def set_token(self, token): self.token = token - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.creditAmount is not None or - self.creditType is not None or - self.effectiveTime is not None or - self.token is not None or - super(CreditRegister, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CreditRegister', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CreditRegister') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CreditRegister', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CreditRegister'): - super(CreditRegister, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CreditRegister') - def exportChildren(self, outfile, level, namespace_='', name_='CreditRegister', fromsubclass_=False, pretty_print=True): - super(CreditRegister, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.creditAmount is not None: - self.creditAmount.export(outfile, level, namespace_, name_='creditAmount', pretty_print=pretty_print) - if self.creditType is not None: - self.creditType.export(outfile, level, namespace_, name_='creditType', pretty_print=pretty_print) - if self.effectiveTime is not None: - self.effectiveTime.export(outfile, level, namespace_, name_='effectiveTime', pretty_print=pretty_print) - if self.token is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%stoken>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.token).encode(ExternalEncoding), input_name='token'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='CreditRegister'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CreditRegister, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CreditRegister, self).exportLiteralChildren(outfile, level, name_) - if self.creditAmount is not None: - showIndent(outfile, level) - outfile.write('creditAmount=model_.AccountingUnit(\n') - self.creditAmount.exportLiteral(outfile, level, name_='creditAmount') - showIndent(outfile, level) - outfile.write('),\n') - if self.creditType is not None: - showIndent(outfile, level) - outfile.write('creditType=model_.CreditTypeType(\n') - self.creditType.exportLiteral(outfile, level, name_='creditType') - showIndent(outfile, level) - outfile.write('),\n') - if self.effectiveTime is not None: - showIndent(outfile, level) - outfile.write('effectiveTime=model_.TimeType(\n') - self.effectiveTime.exportLiteral(outfile, level, name_='effectiveTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.token is not None: - showIndent(outfile, level) - outfile.write('token=%s,\n' % quote_python(self.token).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CreditRegister, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'creditAmount': - obj_ = AccountingUnit.factory() - obj_.build(child_) - self.creditAmount = obj_ - obj_.original_tagname_ = 'creditAmount' - elif nodeName_ == 'creditType': - obj_ = CreditTypeType.factory() - obj_.build(child_) - self.creditType = obj_ - obj_.original_tagname_ = 'creditType' - elif nodeName_ == 'effectiveTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.effectiveTime = obj_ - obj_.original_tagname_ = 'effectiveTime' - elif nodeName_ == 'token': - token_ = child_.text - token_ = self.gds_validate_string(token_, node, 'token') - self.token = token_ - self.validate_String32(self.token) # validate type String32 - super(CreditRegister, self).buildChildren(child_, node, nodeName_, True) -# end class CreditRegister - - -class AccountBalance(Resource): - """AccountBalance contains the regular credit and emergency credit - balance for this given service or commodity prepay instance. It - may also contain status information concerning the balance data.""" - subclass = None - superclass = Resource - def __init__(self, availableCredit=None, creditStatus=None, emergencyCredit=None, emergencyCreditStatus=None): - self.original_tagname_ = None - super(AccountBalance, self).__init__() - self.availableCredit = availableCredit - self.creditStatus = creditStatus - self.emergencyCredit = emergencyCredit - self.emergencyCreditStatus = emergencyCreditStatus - def factory(*args_, **kwargs_): - if AccountBalance.subclass: - return AccountBalance.subclass(*args_, **kwargs_) - else: - return AccountBalance(*args_, **kwargs_) - factory = staticmethod(factory) - def get_availableCredit(self): return self.availableCredit - def set_availableCredit(self, availableCredit): self.availableCredit = availableCredit - def get_creditStatus(self): return self.creditStatus - def set_creditStatus(self, creditStatus): self.creditStatus = creditStatus - def get_emergencyCredit(self): return self.emergencyCredit - def set_emergencyCredit(self, emergencyCredit): self.emergencyCredit = emergencyCredit - def get_emergencyCreditStatus(self): return self.emergencyCreditStatus - def set_emergencyCreditStatus(self, emergencyCreditStatus): self.emergencyCreditStatus = emergencyCreditStatus - def hasContent_(self): - if ( - self.availableCredit is not None or - self.creditStatus is not None or - self.emergencyCredit is not None or - self.emergencyCreditStatus is not None or - super(AccountBalance, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AccountBalance', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AccountBalance') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AccountBalance', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AccountBalance'): - super(AccountBalance, self).exportAttributes(outfile, level, already_processed, namespace_, name_='AccountBalance') - def exportChildren(self, outfile, level, namespace_='', name_='AccountBalance', fromsubclass_=False, pretty_print=True): - super(AccountBalance, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.availableCredit is not None: - self.availableCredit.export(outfile, level, namespace_, name_='availableCredit', pretty_print=pretty_print) - if self.creditStatus is not None: - self.creditStatus.export(outfile, level, namespace_, name_='creditStatus', pretty_print=pretty_print) - if self.emergencyCredit is not None: - self.emergencyCredit.export(outfile, level, namespace_, name_='emergencyCredit', pretty_print=pretty_print) - if self.emergencyCreditStatus is not None: - self.emergencyCreditStatus.export(outfile, level, namespace_, name_='emergencyCreditStatus', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='AccountBalance'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(AccountBalance, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(AccountBalance, self).exportLiteralChildren(outfile, level, name_) - if self.availableCredit is not None: - showIndent(outfile, level) - outfile.write('availableCredit=model_.AccountingUnit(\n') - self.availableCredit.exportLiteral(outfile, level, name_='availableCredit') - showIndent(outfile, level) - outfile.write('),\n') - if self.creditStatus is not None: - showIndent(outfile, level) - outfile.write('creditStatus=model_.CreditStatusType(\n') - self.creditStatus.exportLiteral(outfile, level, name_='creditStatus') - showIndent(outfile, level) - outfile.write('),\n') - if self.emergencyCredit is not None: - showIndent(outfile, level) - outfile.write('emergencyCredit=model_.AccountingUnit(\n') - self.emergencyCredit.exportLiteral(outfile, level, name_='emergencyCredit') - showIndent(outfile, level) - outfile.write('),\n') - if self.emergencyCreditStatus is not None: - showIndent(outfile, level) - outfile.write('emergencyCreditStatus=model_.CreditStatusType(\n') - self.emergencyCreditStatus.exportLiteral(outfile, level, name_='emergencyCreditStatus') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(AccountBalance, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'availableCredit': - obj_ = AccountingUnit.factory() - obj_.build(child_) - self.availableCredit = obj_ - obj_.original_tagname_ = 'availableCredit' - elif nodeName_ == 'creditStatus': - obj_ = CreditStatusType.factory() - obj_.build(child_) - self.creditStatus = obj_ - obj_.original_tagname_ = 'creditStatus' - elif nodeName_ == 'emergencyCredit': - obj_ = AccountingUnit.factory() - obj_.build(child_) - self.emergencyCredit = obj_ - obj_.original_tagname_ = 'emergencyCredit' - elif nodeName_ == 'emergencyCreditStatus': - obj_ = CreditStatusType.factory() - obj_.build(child_) - self.emergencyCreditStatus = obj_ - obj_.original_tagname_ = 'emergencyCreditStatus' - super(AccountBalance, self).buildChildren(child_, node, nodeName_, True) -# end class AccountBalance - - -class ServiceSupplierList(List): - """A List element to hold ServiceSupplier objects.""" - subclass = None - superclass = List - def __init__(self, ServiceSupplier=None): - self.original_tagname_ = None - super(ServiceSupplierList, self).__init__() - if ServiceSupplier is None: - self.ServiceSupplier = [] - else: - self.ServiceSupplier = ServiceSupplier - def factory(*args_, **kwargs_): - if ServiceSupplierList.subclass: - return ServiceSupplierList.subclass(*args_, **kwargs_) - else: - return ServiceSupplierList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ServiceSupplier(self): return self.ServiceSupplier - def set_ServiceSupplier(self, ServiceSupplier): self.ServiceSupplier = ServiceSupplier - def add_ServiceSupplier(self, value): self.ServiceSupplier.append(value) - def insert_ServiceSupplier_at(self, index, value): self.ServiceSupplier.insert(index, value) - def replace_ServiceSupplier_at(self, index, value): self.ServiceSupplier[index] = value - def hasContent_(self): - if ( - self.ServiceSupplier or - super(ServiceSupplierList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ServiceSupplierList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceSupplierList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ServiceSupplierList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ServiceSupplierList'): - super(ServiceSupplierList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceSupplierList') - def exportChildren(self, outfile, level, namespace_='', name_='ServiceSupplierList', fromsubclass_=False, pretty_print=True): - super(ServiceSupplierList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for ServiceSupplier_ in self.ServiceSupplier: - ServiceSupplier_.export(outfile, level, namespace_, name_='ServiceSupplier', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ServiceSupplierList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ServiceSupplierList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ServiceSupplierList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('ServiceSupplier=[\n') - level += 1 - for ServiceSupplier_ in self.ServiceSupplier: - showIndent(outfile, level) - outfile.write('model_.ServiceSupplier(\n') - ServiceSupplier_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ServiceSupplierList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ServiceSupplier': - obj_ = ServiceSupplier.factory() - obj_.build(child_) - self.ServiceSupplier.append(obj_) - obj_.original_tagname_ = 'ServiceSupplier' - super(ServiceSupplierList, self).buildChildren(child_, node, nodeName_, True) -# end class ServiceSupplierList - - -class ServiceSupplier(IdentifiedObject): - """Organisation that provides services to Customers.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, email=None, phone=None, providerID=None, web=None): - self.original_tagname_ = None - super(ServiceSupplier, self).__init__() - self.email = email - self.phone = phone - self.providerID = providerID - self.web = web - def factory(*args_, **kwargs_): - if ServiceSupplier.subclass: - return ServiceSupplier.subclass(*args_, **kwargs_) - else: - return ServiceSupplier(*args_, **kwargs_) - factory = staticmethod(factory) - def get_email(self): return self.email - def set_email(self, email): self.email = email - def get_phone(self): return self.phone - def set_phone(self, phone): self.phone = phone - def get_providerID(self): return self.providerID - def set_providerID(self, providerID): self.providerID = providerID - def get_web(self): return self.web - def set_web(self, web): self.web = web - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def validate_String20(self, value): - # Validate type String20, a restriction on xs:string. - pass - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def validate_String42(self, value): - # Validate type String42, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.email is not None or - self.phone is not None or - self.providerID is not None or - self.web is not None or - super(ServiceSupplier, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ServiceSupplier', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceSupplier') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ServiceSupplier', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ServiceSupplier'): - super(ServiceSupplier, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceSupplier') - def exportChildren(self, outfile, level, namespace_='', name_='ServiceSupplier', fromsubclass_=False, pretty_print=True): - super(ServiceSupplier, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.email is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%semail>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.email).encode(ExternalEncoding), input_name='email'), namespace_, eol_)) - if self.phone is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sphone>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.phone).encode(ExternalEncoding), input_name='phone'), namespace_, eol_)) - if self.providerID is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sproviderID>%s%s' % (namespace_, self.gds_format_integer(self.providerID, input_name='providerID'), namespace_, eol_)) - if self.web is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sweb>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.web).encode(ExternalEncoding), input_name='web'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='ServiceSupplier'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ServiceSupplier, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ServiceSupplier, self).exportLiteralChildren(outfile, level, name_) - if self.email is not None: - showIndent(outfile, level) - outfile.write('email=%s,\n' % quote_python(self.email).encode(ExternalEncoding)) - if self.phone is not None: - showIndent(outfile, level) - outfile.write('phone=%s,\n' % quote_python(self.phone).encode(ExternalEncoding)) - if self.providerID is not None: - showIndent(outfile, level) - outfile.write('providerID=%d,\n' % self.providerID) - if self.web is not None: - showIndent(outfile, level) - outfile.write('web=%s,\n' % quote_python(self.web).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ServiceSupplier, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'email': - email_ = child_.text - email_ = self.gds_validate_string(email_, node, 'email') - self.email = email_ - self.validate_String32(self.email) # validate type String32 - elif nodeName_ == 'phone': - phone_ = child_.text - phone_ = self.gds_validate_string(phone_, node, 'phone') - self.phone = phone_ - self.validate_String20(self.phone) # validate type String20 - elif nodeName_ == 'providerID': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'providerID') - self.providerID = ival_ - self.validate_UInt32(self.providerID) # validate type UInt32 - elif nodeName_ == 'web': - web_ = child_.text - web_ = self.gds_validate_string(web_, node, 'web') - self.web = web_ - self.validate_String42(self.web) # validate type String42 - super(ServiceSupplier, self).buildChildren(child_, node, nodeName_, True) -# end class ServiceSupplier - - -class TargetReadingList(List): - """A List element to hold TargetReading objects.""" - subclass = None - superclass = List - def __init__(self, TargetReading=None): - self.original_tagname_ = None - super(TargetReadingList, self).__init__() - if TargetReading is None: - self.TargetReading = [] - else: - self.TargetReading = TargetReading - def factory(*args_, **kwargs_): - if TargetReadingList.subclass: - return TargetReadingList.subclass(*args_, **kwargs_) - else: - return TargetReadingList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_TargetReading(self): return self.TargetReading - def set_TargetReading(self, TargetReading): self.TargetReading = TargetReading - def add_TargetReading(self, value): self.TargetReading.append(value) - def insert_TargetReading_at(self, index, value): self.TargetReading.insert(index, value) - def replace_TargetReading_at(self, index, value): self.TargetReading[index] = value - def hasContent_(self): - if ( - self.TargetReading or - super(TargetReadingList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TargetReadingList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TargetReadingList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TargetReadingList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TargetReadingList'): - super(TargetReadingList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TargetReadingList') - def exportChildren(self, outfile, level, namespace_='', name_='TargetReadingList', fromsubclass_=False, pretty_print=True): - super(TargetReadingList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for TargetReading_ in self.TargetReading: - TargetReading_.export(outfile, level, namespace_, name_='TargetReading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='TargetReadingList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TargetReadingList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TargetReadingList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('TargetReading=[\n') - level += 1 - for TargetReading_ in self.TargetReading: - showIndent(outfile, level) - outfile.write('model_.TargetReading(\n') - TargetReading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TargetReadingList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'TargetReading': - obj_ = TargetReading.factory() - obj_.build(child_) - self.TargetReading.append(obj_) - obj_.original_tagname_ = 'TargetReading' - super(TargetReadingList, self).buildChildren(child_, node, nodeName_, True) -# end class TargetReadingList - - -class ProjectionReadingList(List): - """A List element to hold ProjectionReading objects.""" - subclass = None - superclass = List - def __init__(self, ProjectionReading=None): - self.original_tagname_ = None - super(ProjectionReadingList, self).__init__() - if ProjectionReading is None: - self.ProjectionReading = [] - else: - self.ProjectionReading = ProjectionReading - def factory(*args_, **kwargs_): - if ProjectionReadingList.subclass: - return ProjectionReadingList.subclass(*args_, **kwargs_) - else: - return ProjectionReadingList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ProjectionReading(self): return self.ProjectionReading - def set_ProjectionReading(self, ProjectionReading): self.ProjectionReading = ProjectionReading - def add_ProjectionReading(self, value): self.ProjectionReading.append(value) - def insert_ProjectionReading_at(self, index, value): self.ProjectionReading.insert(index, value) - def replace_ProjectionReading_at(self, index, value): self.ProjectionReading[index] = value - def hasContent_(self): - if ( - self.ProjectionReading or - super(ProjectionReadingList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ProjectionReadingList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ProjectionReadingList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ProjectionReadingList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ProjectionReadingList'): - super(ProjectionReadingList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ProjectionReadingList') - def exportChildren(self, outfile, level, namespace_='', name_='ProjectionReadingList', fromsubclass_=False, pretty_print=True): - super(ProjectionReadingList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for ProjectionReading_ in self.ProjectionReading: - ProjectionReading_.export(outfile, level, namespace_, name_='ProjectionReading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ProjectionReadingList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ProjectionReadingList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ProjectionReadingList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('ProjectionReading=[\n') - level += 1 - for ProjectionReading_ in self.ProjectionReading: - showIndent(outfile, level) - outfile.write('model_.ProjectionReading(\n') - ProjectionReading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ProjectionReadingList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ProjectionReading': - obj_ = ProjectionReading.factory() - obj_.build(child_) - self.ProjectionReading.append(obj_) - obj_.original_tagname_ = 'ProjectionReading' - super(ProjectionReadingList, self).buildChildren(child_, node, nodeName_, True) -# end class ProjectionReadingList - - -class HistoricalReadingList(List): - """A List element to hold HistoricalReading objects.""" - subclass = None - superclass = List - def __init__(self, HistoricalReading=None): - self.original_tagname_ = None - super(HistoricalReadingList, self).__init__() - if HistoricalReading is None: - self.HistoricalReading = [] - else: - self.HistoricalReading = HistoricalReading - def factory(*args_, **kwargs_): - if HistoricalReadingList.subclass: - return HistoricalReadingList.subclass(*args_, **kwargs_) - else: - return HistoricalReadingList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_HistoricalReading(self): return self.HistoricalReading - def set_HistoricalReading(self, HistoricalReading): self.HistoricalReading = HistoricalReading - def add_HistoricalReading(self, value): self.HistoricalReading.append(value) - def insert_HistoricalReading_at(self, index, value): self.HistoricalReading.insert(index, value) - def replace_HistoricalReading_at(self, index, value): self.HistoricalReading[index] = value - def hasContent_(self): - if ( - self.HistoricalReading or - super(HistoricalReadingList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='HistoricalReadingList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='HistoricalReadingList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='HistoricalReadingList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='HistoricalReadingList'): - super(HistoricalReadingList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='HistoricalReadingList') - def exportChildren(self, outfile, level, namespace_='', name_='HistoricalReadingList', fromsubclass_=False, pretty_print=True): - super(HistoricalReadingList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for HistoricalReading_ in self.HistoricalReading: - HistoricalReading_.export(outfile, level, namespace_, name_='HistoricalReading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='HistoricalReadingList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(HistoricalReadingList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(HistoricalReadingList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('HistoricalReading=[\n') - level += 1 - for HistoricalReading_ in self.HistoricalReading: - showIndent(outfile, level) - outfile.write('model_.HistoricalReading(\n') - HistoricalReading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(HistoricalReadingList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'HistoricalReading': - obj_ = HistoricalReading.factory() - obj_.build(child_) - self.HistoricalReading.append(obj_) - obj_.original_tagname_ = 'HistoricalReading' - super(HistoricalReadingList, self).buildChildren(child_, node, nodeName_, True) -# end class HistoricalReadingList - - -class CustomerAgreementList(SubscribableList): - """A List element to hold CustomerAgreement objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, CustomerAgreement=None): - self.original_tagname_ = None - super(CustomerAgreementList, self).__init__() - if CustomerAgreement is None: - self.CustomerAgreement = [] - else: - self.CustomerAgreement = CustomerAgreement - def factory(*args_, **kwargs_): - if CustomerAgreementList.subclass: - return CustomerAgreementList.subclass(*args_, **kwargs_) - else: - return CustomerAgreementList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_CustomerAgreement(self): return self.CustomerAgreement - def set_CustomerAgreement(self, CustomerAgreement): self.CustomerAgreement = CustomerAgreement - def add_CustomerAgreement(self, value): self.CustomerAgreement.append(value) - def insert_CustomerAgreement_at(self, index, value): self.CustomerAgreement.insert(index, value) - def replace_CustomerAgreement_at(self, index, value): self.CustomerAgreement[index] = value - def hasContent_(self): - if ( - self.CustomerAgreement or - super(CustomerAgreementList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CustomerAgreementList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAgreementList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CustomerAgreementList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CustomerAgreementList'): - super(CustomerAgreementList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAgreementList') - def exportChildren(self, outfile, level, namespace_='', name_='CustomerAgreementList', fromsubclass_=False, pretty_print=True): - super(CustomerAgreementList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for CustomerAgreement_ in self.CustomerAgreement: - CustomerAgreement_.export(outfile, level, namespace_, name_='CustomerAgreement', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='CustomerAgreementList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CustomerAgreementList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CustomerAgreementList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('CustomerAgreement=[\n') - level += 1 - for CustomerAgreement_ in self.CustomerAgreement: - showIndent(outfile, level) - outfile.write('model_.CustomerAgreement(\n') - CustomerAgreement_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CustomerAgreementList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'CustomerAgreement': - obj_ = CustomerAgreement.factory() - obj_.build(child_) - self.CustomerAgreement.append(obj_) - obj_.original_tagname_ = 'CustomerAgreement' - super(CustomerAgreementList, self).buildChildren(child_, node, nodeName_, True) -# end class CustomerAgreementList - - -class CustomerAgreement(IdentifiedObject): - """Agreement between the customer and the service supplier to pay for - service at a specific service location. It records certain - billing information about the type of service provided at the - service location and is used during charge creation to determine - the type of service.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, ActiveBillingPeriodListLink=None, ActiveProjectionReadingListLink=None, ActiveTargetReadingListLink=None, BillingPeriodListLink=None, HistoricalReadingListLink=None, PrepaymentLink=None, ProjectionReadingListLink=None, serviceAccount=None, serviceLocation=None, TargetReadingListLink=None, TariffProfileLink=None, UsagePointLink=None): - self.original_tagname_ = None - super(CustomerAgreement, self).__init__() - self.ActiveBillingPeriodListLink = ActiveBillingPeriodListLink - self.ActiveProjectionReadingListLink = ActiveProjectionReadingListLink - self.ActiveTargetReadingListLink = ActiveTargetReadingListLink - self.BillingPeriodListLink = BillingPeriodListLink - self.HistoricalReadingListLink = HistoricalReadingListLink - self.PrepaymentLink = PrepaymentLink - self.ProjectionReadingListLink = ProjectionReadingListLink - self.serviceAccount = serviceAccount - self.serviceLocation = serviceLocation - self.TargetReadingListLink = TargetReadingListLink - self.TariffProfileLink = TariffProfileLink - self.UsagePointLink = UsagePointLink - def factory(*args_, **kwargs_): - if CustomerAgreement.subclass: - return CustomerAgreement.subclass(*args_, **kwargs_) - else: - return CustomerAgreement(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ActiveBillingPeriodListLink(self): return self.ActiveBillingPeriodListLink - def set_ActiveBillingPeriodListLink(self, ActiveBillingPeriodListLink): self.ActiveBillingPeriodListLink = ActiveBillingPeriodListLink - def get_ActiveProjectionReadingListLink(self): return self.ActiveProjectionReadingListLink - def set_ActiveProjectionReadingListLink(self, ActiveProjectionReadingListLink): self.ActiveProjectionReadingListLink = ActiveProjectionReadingListLink - def get_ActiveTargetReadingListLink(self): return self.ActiveTargetReadingListLink - def set_ActiveTargetReadingListLink(self, ActiveTargetReadingListLink): self.ActiveTargetReadingListLink = ActiveTargetReadingListLink - def get_BillingPeriodListLink(self): return self.BillingPeriodListLink - def set_BillingPeriodListLink(self, BillingPeriodListLink): self.BillingPeriodListLink = BillingPeriodListLink - def get_HistoricalReadingListLink(self): return self.HistoricalReadingListLink - def set_HistoricalReadingListLink(self, HistoricalReadingListLink): self.HistoricalReadingListLink = HistoricalReadingListLink - def get_PrepaymentLink(self): return self.PrepaymentLink - def set_PrepaymentLink(self, PrepaymentLink): self.PrepaymentLink = PrepaymentLink - def get_ProjectionReadingListLink(self): return self.ProjectionReadingListLink - def set_ProjectionReadingListLink(self, ProjectionReadingListLink): self.ProjectionReadingListLink = ProjectionReadingListLink - def get_serviceAccount(self): return self.serviceAccount - def set_serviceAccount(self, serviceAccount): self.serviceAccount = serviceAccount - def get_serviceLocation(self): return self.serviceLocation - def set_serviceLocation(self, serviceLocation): self.serviceLocation = serviceLocation - def get_TargetReadingListLink(self): return self.TargetReadingListLink - def set_TargetReadingListLink(self, TargetReadingListLink): self.TargetReadingListLink = TargetReadingListLink - def get_TariffProfileLink(self): return self.TariffProfileLink - def set_TariffProfileLink(self, TariffProfileLink): self.TariffProfileLink = TariffProfileLink - def get_UsagePointLink(self): return self.UsagePointLink - def set_UsagePointLink(self, UsagePointLink): self.UsagePointLink = UsagePointLink - def validate_String42(self, value): - # Validate type String42, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.ActiveBillingPeriodListLink is not None or - self.ActiveProjectionReadingListLink is not None or - self.ActiveTargetReadingListLink is not None or - self.BillingPeriodListLink is not None or - self.HistoricalReadingListLink is not None or - self.PrepaymentLink is not None or - self.ProjectionReadingListLink is not None or - self.serviceAccount is not None or - self.serviceLocation is not None or - self.TargetReadingListLink is not None or - self.TariffProfileLink is not None or - self.UsagePointLink is not None or - super(CustomerAgreement, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CustomerAgreement', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAgreement') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CustomerAgreement', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CustomerAgreement'): - super(CustomerAgreement, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAgreement') - def exportChildren(self, outfile, level, namespace_='', name_='CustomerAgreement', fromsubclass_=False, pretty_print=True): - super(CustomerAgreement, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ActiveBillingPeriodListLink is not None: - self.ActiveBillingPeriodListLink.export(outfile, level, namespace_, name_='ActiveBillingPeriodListLink', pretty_print=pretty_print) - if self.ActiveProjectionReadingListLink is not None: - self.ActiveProjectionReadingListLink.export(outfile, level, namespace_, name_='ActiveProjectionReadingListLink', pretty_print=pretty_print) - if self.ActiveTargetReadingListLink is not None: - self.ActiveTargetReadingListLink.export(outfile, level, namespace_, name_='ActiveTargetReadingListLink', pretty_print=pretty_print) - if self.BillingPeriodListLink is not None: - self.BillingPeriodListLink.export(outfile, level, namespace_, name_='BillingPeriodListLink', pretty_print=pretty_print) - if self.HistoricalReadingListLink is not None: - self.HistoricalReadingListLink.export(outfile, level, namespace_, name_='HistoricalReadingListLink', pretty_print=pretty_print) - if self.PrepaymentLink is not None: - self.PrepaymentLink.export(outfile, level, namespace_, name_='PrepaymentLink', pretty_print=pretty_print) - if self.ProjectionReadingListLink is not None: - self.ProjectionReadingListLink.export(outfile, level, namespace_, name_='ProjectionReadingListLink', pretty_print=pretty_print) - if self.serviceAccount is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sserviceAccount>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.serviceAccount).encode(ExternalEncoding), input_name='serviceAccount'), namespace_, eol_)) - if self.serviceLocation is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sserviceLocation>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.serviceLocation).encode(ExternalEncoding), input_name='serviceLocation'), namespace_, eol_)) - if self.TargetReadingListLink is not None: - self.TargetReadingListLink.export(outfile, level, namespace_, name_='TargetReadingListLink', pretty_print=pretty_print) - if self.TariffProfileLink is not None: - self.TariffProfileLink.export(outfile, level, namespace_, name_='TariffProfileLink', pretty_print=pretty_print) - if self.UsagePointLink is not None: - self.UsagePointLink.export(outfile, level, namespace_, name_='UsagePointLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='CustomerAgreement'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CustomerAgreement, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CustomerAgreement, self).exportLiteralChildren(outfile, level, name_) - if self.ActiveBillingPeriodListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveBillingPeriodListLink=model_.ActiveBillingPeriodListLink(\n') - self.ActiveBillingPeriodListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ActiveProjectionReadingListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveProjectionReadingListLink=model_.ActiveProjectionReadingListLink(\n') - self.ActiveProjectionReadingListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ActiveTargetReadingListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveTargetReadingListLink=model_.ActiveTargetReadingListLink(\n') - self.ActiveTargetReadingListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.BillingPeriodListLink is not None: - showIndent(outfile, level) - outfile.write('BillingPeriodListLink=model_.BillingPeriodListLink(\n') - self.BillingPeriodListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.HistoricalReadingListLink is not None: - showIndent(outfile, level) - outfile.write('HistoricalReadingListLink=model_.HistoricalReadingListLink(\n') - self.HistoricalReadingListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.PrepaymentLink is not None: - showIndent(outfile, level) - outfile.write('PrepaymentLink=model_.PrepaymentLink(\n') - self.PrepaymentLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ProjectionReadingListLink is not None: - showIndent(outfile, level) - outfile.write('ProjectionReadingListLink=model_.ProjectionReadingListLink(\n') - self.ProjectionReadingListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.serviceAccount is not None: - showIndent(outfile, level) - outfile.write('serviceAccount=%s,\n' % quote_python(self.serviceAccount).encode(ExternalEncoding)) - if self.serviceLocation is not None: - showIndent(outfile, level) - outfile.write('serviceLocation=%s,\n' % quote_python(self.serviceLocation).encode(ExternalEncoding)) - if self.TargetReadingListLink is not None: - showIndent(outfile, level) - outfile.write('TargetReadingListLink=model_.TargetReadingListLink(\n') - self.TargetReadingListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.TariffProfileLink is not None: - showIndent(outfile, level) - outfile.write('TariffProfileLink=model_.TariffProfileLink(\n') - self.TariffProfileLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.UsagePointLink is not None: - showIndent(outfile, level) - outfile.write('UsagePointLink=model_.UsagePointLink(\n') - self.UsagePointLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CustomerAgreement, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ActiveBillingPeriodListLink': - obj_ = ActiveBillingPeriodListLink.factory() - obj_.build(child_) - self.ActiveBillingPeriodListLink = obj_ - obj_.original_tagname_ = 'ActiveBillingPeriodListLink' - elif nodeName_ == 'ActiveProjectionReadingListLink': - obj_ = ActiveProjectionReadingListLink.factory() - obj_.build(child_) - self.ActiveProjectionReadingListLink = obj_ - obj_.original_tagname_ = 'ActiveProjectionReadingListLink' - elif nodeName_ == 'ActiveTargetReadingListLink': - obj_ = ActiveTargetReadingListLink.factory() - obj_.build(child_) - self.ActiveTargetReadingListLink = obj_ - obj_.original_tagname_ = 'ActiveTargetReadingListLink' - elif nodeName_ == 'BillingPeriodListLink': - obj_ = BillingPeriodListLink.factory() - obj_.build(child_) - self.BillingPeriodListLink = obj_ - obj_.original_tagname_ = 'BillingPeriodListLink' - elif nodeName_ == 'HistoricalReadingListLink': - obj_ = HistoricalReadingListLink.factory() - obj_.build(child_) - self.HistoricalReadingListLink = obj_ - obj_.original_tagname_ = 'HistoricalReadingListLink' - elif nodeName_ == 'PrepaymentLink': - obj_ = PrepaymentLink.factory() - obj_.build(child_) - self.PrepaymentLink = obj_ - obj_.original_tagname_ = 'PrepaymentLink' - elif nodeName_ == 'ProjectionReadingListLink': - obj_ = ProjectionReadingListLink.factory() - obj_.build(child_) - self.ProjectionReadingListLink = obj_ - obj_.original_tagname_ = 'ProjectionReadingListLink' - elif nodeName_ == 'serviceAccount': - serviceAccount_ = child_.text - serviceAccount_ = self.gds_validate_string(serviceAccount_, node, 'serviceAccount') - self.serviceAccount = serviceAccount_ - self.validate_String42(self.serviceAccount) # validate type String42 - elif nodeName_ == 'serviceLocation': - serviceLocation_ = child_.text - serviceLocation_ = self.gds_validate_string(serviceLocation_, node, 'serviceLocation') - self.serviceLocation = serviceLocation_ - self.validate_String42(self.serviceLocation) # validate type String42 - elif nodeName_ == 'TargetReadingListLink': - obj_ = TargetReadingListLink.factory() - obj_.build(child_) - self.TargetReadingListLink = obj_ - obj_.original_tagname_ = 'TargetReadingListLink' - elif nodeName_ == 'TariffProfileLink': - obj_ = TariffProfileLink.factory() - obj_.build(child_) - self.TariffProfileLink = obj_ - obj_.original_tagname_ = 'TariffProfileLink' - elif nodeName_ == 'UsagePointLink': - obj_ = UsagePointLink.factory() - obj_.build(child_) - self.UsagePointLink = obj_ - obj_.original_tagname_ = 'UsagePointLink' - super(CustomerAgreement, self).buildChildren(child_, node, nodeName_, True) -# end class CustomerAgreement - - -class CustomerAccountList(SubscribableList): - """A List element to hold CustomerAccount objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, CustomerAccount=None): - self.original_tagname_ = None - super(CustomerAccountList, self).__init__() - if CustomerAccount is None: - self.CustomerAccount = [] - else: - self.CustomerAccount = CustomerAccount - def factory(*args_, **kwargs_): - if CustomerAccountList.subclass: - return CustomerAccountList.subclass(*args_, **kwargs_) - else: - return CustomerAccountList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_CustomerAccount(self): return self.CustomerAccount - def set_CustomerAccount(self, CustomerAccount): self.CustomerAccount = CustomerAccount - def add_CustomerAccount(self, value): self.CustomerAccount.append(value) - def insert_CustomerAccount_at(self, index, value): self.CustomerAccount.insert(index, value) - def replace_CustomerAccount_at(self, index, value): self.CustomerAccount[index] = value - def hasContent_(self): - if ( - self.CustomerAccount or - super(CustomerAccountList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CustomerAccountList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAccountList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CustomerAccountList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CustomerAccountList'): - super(CustomerAccountList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAccountList') - def exportChildren(self, outfile, level, namespace_='', name_='CustomerAccountList', fromsubclass_=False, pretty_print=True): - super(CustomerAccountList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for CustomerAccount_ in self.CustomerAccount: - CustomerAccount_.export(outfile, level, namespace_, name_='CustomerAccount', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='CustomerAccountList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CustomerAccountList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CustomerAccountList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('CustomerAccount=[\n') - level += 1 - for CustomerAccount_ in self.CustomerAccount: - showIndent(outfile, level) - outfile.write('model_.CustomerAccount(\n') - CustomerAccount_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CustomerAccountList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'CustomerAccount': - obj_ = CustomerAccount.factory() - obj_.build(child_) - self.CustomerAccount.append(obj_) - obj_.original_tagname_ = 'CustomerAccount' - super(CustomerAccountList, self).buildChildren(child_, node, nodeName_, True) -# end class CustomerAccountList - - -class CustomerAccount(IdentifiedObject): - """Assignment of a group of products and services purchased by the - Customer through a CustomerAgreement, used as a mechanism for - customer billing and payment. It contains common information - from the various types of CustomerAgreements to create billings - (invoices) for a Customer and receive payment.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, currency=None, customerAccount=None, CustomerAgreementListLink=None, customerName=None, pricePowerOfTenMultiplier=None, ServiceSupplierLink=None): - self.original_tagname_ = None - super(CustomerAccount, self).__init__() - self.currency = currency - self.customerAccount = customerAccount - self.CustomerAgreementListLink = CustomerAgreementListLink - self.customerName = customerName - self.pricePowerOfTenMultiplier = pricePowerOfTenMultiplier - self.ServiceSupplierLink = ServiceSupplierLink - def factory(*args_, **kwargs_): - if CustomerAccount.subclass: - return CustomerAccount.subclass(*args_, **kwargs_) - else: - return CustomerAccount(*args_, **kwargs_) - factory = staticmethod(factory) - def get_currency(self): return self.currency - def set_currency(self, currency): self.currency = currency - def get_customerAccount(self): return self.customerAccount - def set_customerAccount(self, customerAccount): self.customerAccount = customerAccount - def get_CustomerAgreementListLink(self): return self.CustomerAgreementListLink - def set_CustomerAgreementListLink(self, CustomerAgreementListLink): self.CustomerAgreementListLink = CustomerAgreementListLink - def get_customerName(self): return self.customerName - def set_customerName(self, customerName): self.customerName = customerName - def get_pricePowerOfTenMultiplier(self): return self.pricePowerOfTenMultiplier - def set_pricePowerOfTenMultiplier(self, pricePowerOfTenMultiplier): self.pricePowerOfTenMultiplier = pricePowerOfTenMultiplier - def get_ServiceSupplierLink(self): return self.ServiceSupplierLink - def set_ServiceSupplierLink(self, ServiceSupplierLink): self.ServiceSupplierLink = ServiceSupplierLink - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def validate_String42(self, value): - # Validate type String42, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.currency is not None or - self.customerAccount is not None or - self.CustomerAgreementListLink is not None or - self.customerName is not None or - self.pricePowerOfTenMultiplier is not None or - self.ServiceSupplierLink is not None or - super(CustomerAccount, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='CustomerAccount', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAccount') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='CustomerAccount', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='CustomerAccount'): - super(CustomerAccount, self).exportAttributes(outfile, level, already_processed, namespace_, name_='CustomerAccount') - def exportChildren(self, outfile, level, namespace_='', name_='CustomerAccount', fromsubclass_=False, pretty_print=True): - super(CustomerAccount, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.currency is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%scurrency>%s%s' % (namespace_, self.gds_format_integer(self.currency, input_name='currency'), namespace_, eol_)) - if self.customerAccount is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%scustomerAccount>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.customerAccount).encode(ExternalEncoding), input_name='customerAccount'), namespace_, eol_)) - if self.CustomerAgreementListLink is not None: - self.CustomerAgreementListLink.export(outfile, level, namespace_, name_='CustomerAgreementListLink', pretty_print=pretty_print) - if self.customerName is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%scustomerName>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.customerName).encode(ExternalEncoding), input_name='customerName'), namespace_, eol_)) - if self.pricePowerOfTenMultiplier is not None: - self.pricePowerOfTenMultiplier.export(outfile, level, namespace_, name_='pricePowerOfTenMultiplier', pretty_print=pretty_print) - if self.ServiceSupplierLink is not None: - self.ServiceSupplierLink.export(outfile, level, namespace_, name_='ServiceSupplierLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='CustomerAccount'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(CustomerAccount, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(CustomerAccount, self).exportLiteralChildren(outfile, level, name_) - if self.currency is not None: - showIndent(outfile, level) - outfile.write('currency=%d,\n' % self.currency) - if self.customerAccount is not None: - showIndent(outfile, level) - outfile.write('customerAccount=%s,\n' % quote_python(self.customerAccount).encode(ExternalEncoding)) - if self.CustomerAgreementListLink is not None: - showIndent(outfile, level) - outfile.write('CustomerAgreementListLink=model_.CustomerAgreementListLink(\n') - self.CustomerAgreementListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.customerName is not None: - showIndent(outfile, level) - outfile.write('customerName=%s,\n' % quote_python(self.customerName).encode(ExternalEncoding)) - if self.pricePowerOfTenMultiplier is not None: - showIndent(outfile, level) - outfile.write('pricePowerOfTenMultiplier=model_.PowerOfTenMultiplierType(\n') - self.pricePowerOfTenMultiplier.exportLiteral(outfile, level, name_='pricePowerOfTenMultiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.ServiceSupplierLink is not None: - showIndent(outfile, level) - outfile.write('ServiceSupplierLink=model_.ServiceSupplierLink(\n') - self.ServiceSupplierLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(CustomerAccount, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'currency': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'currency') - self.currency = ival_ - self.validate_UInt16(self.currency) # validate type UInt16 - elif nodeName_ == 'customerAccount': - customerAccount_ = child_.text - customerAccount_ = self.gds_validate_string(customerAccount_, node, 'customerAccount') - self.customerAccount = customerAccount_ - self.validate_String42(self.customerAccount) # validate type String42 - elif nodeName_ == 'CustomerAgreementListLink': - obj_ = CustomerAgreementListLink.factory() - obj_.build(child_) - self.CustomerAgreementListLink = obj_ - obj_.original_tagname_ = 'CustomerAgreementListLink' - elif nodeName_ == 'customerName': - customerName_ = child_.text - customerName_ = self.gds_validate_string(customerName_, node, 'customerName') - self.customerName = customerName_ - self.validate_String42(self.customerName) # validate type String42 - elif nodeName_ == 'pricePowerOfTenMultiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.pricePowerOfTenMultiplier = obj_ - obj_.original_tagname_ = 'pricePowerOfTenMultiplier' - elif nodeName_ == 'ServiceSupplierLink': - obj_ = ServiceSupplierLink.factory() - obj_.build(child_) - self.ServiceSupplierLink = obj_ - obj_.original_tagname_ = 'ServiceSupplierLink' - super(CustomerAccount, self).buildChildren(child_, node, nodeName_, True) -# end class CustomerAccount - - -class BillingReadingSetList(SubscribableList): - """A List element to hold BillingReadingSet objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, BillingReadingSet=None): - self.original_tagname_ = None - super(BillingReadingSetList, self).__init__() - if BillingReadingSet is None: - self.BillingReadingSet = [] - else: - self.BillingReadingSet = BillingReadingSet - def factory(*args_, **kwargs_): - if BillingReadingSetList.subclass: - return BillingReadingSetList.subclass(*args_, **kwargs_) - else: - return BillingReadingSetList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_BillingReadingSet(self): return self.BillingReadingSet - def set_BillingReadingSet(self, BillingReadingSet): self.BillingReadingSet = BillingReadingSet - def add_BillingReadingSet(self, value): self.BillingReadingSet.append(value) - def insert_BillingReadingSet_at(self, index, value): self.BillingReadingSet.insert(index, value) - def replace_BillingReadingSet_at(self, index, value): self.BillingReadingSet[index] = value - def hasContent_(self): - if ( - self.BillingReadingSet or - super(BillingReadingSetList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingReadingSetList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingSetList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingReadingSetList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingReadingSetList'): - super(BillingReadingSetList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingSetList') - def exportChildren(self, outfile, level, namespace_='', name_='BillingReadingSetList', fromsubclass_=False, pretty_print=True): - super(BillingReadingSetList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for BillingReadingSet_ in self.BillingReadingSet: - BillingReadingSet_.export(outfile, level, namespace_, name_='BillingReadingSet', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='BillingReadingSetList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingReadingSetList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingReadingSetList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('BillingReadingSet=[\n') - level += 1 - for BillingReadingSet_ in self.BillingReadingSet: - showIndent(outfile, level) - outfile.write('model_.BillingReadingSet(\n') - BillingReadingSet_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingReadingSetList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'BillingReadingSet': - obj_ = BillingReadingSet.factory() - obj_.build(child_) - self.BillingReadingSet.append(obj_) - obj_.original_tagname_ = 'BillingReadingSet' - super(BillingReadingSetList, self).buildChildren(child_, node, nodeName_, True) -# end class BillingReadingSetList - - -class BillingReadingList(List): - """A List element to hold BillingReading objects.""" - subclass = None - superclass = List - def __init__(self, BillingReading=None): - self.original_tagname_ = None - super(BillingReadingList, self).__init__() - if BillingReading is None: - self.BillingReading = [] - else: - self.BillingReading = BillingReading - def factory(*args_, **kwargs_): - if BillingReadingList.subclass: - return BillingReadingList.subclass(*args_, **kwargs_) - else: - return BillingReadingList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_BillingReading(self): return self.BillingReading - def set_BillingReading(self, BillingReading): self.BillingReading = BillingReading - def add_BillingReading(self, value): self.BillingReading.append(value) - def insert_BillingReading_at(self, index, value): self.BillingReading.insert(index, value) - def replace_BillingReading_at(self, index, value): self.BillingReading[index] = value - def hasContent_(self): - if ( - self.BillingReading or - super(BillingReadingList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingReadingList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingReadingList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingReadingList'): - super(BillingReadingList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingList') - def exportChildren(self, outfile, level, namespace_='', name_='BillingReadingList', fromsubclass_=False, pretty_print=True): - super(BillingReadingList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for BillingReading_ in self.BillingReading: - BillingReading_.export(outfile, level, namespace_, name_='BillingReading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='BillingReadingList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingReadingList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingReadingList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('BillingReading=[\n') - level += 1 - for BillingReading_ in self.BillingReading: - showIndent(outfile, level) - outfile.write('model_.BillingReading(\n') - BillingReading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingReadingList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'BillingReading': - obj_ = BillingReading.factory() - obj_.build(child_) - self.BillingReading.append(obj_) - obj_.original_tagname_ = 'BillingReading' - super(BillingReadingList, self).buildChildren(child_, node, nodeName_, True) -# end class BillingReadingList - - -class BillingReading(ReadingBase): - """Data captured at regular intervals of time. Interval data could be - captured as incremental data, absolute data, or relative data. - The source for the data is usually a tariff quantity or an - engineering quantity. Data is typically captured in time-tagged, - uniform, fixed-length intervals of 5 min, 10 min, 15 min, 30 - min, or 60 min. However, consumption aggregations can also be - represented with this class.""" - subclass = None - superclass = ReadingBase - def __init__(self, Charge=None): - self.original_tagname_ = None - super(BillingReading, self).__init__() - if Charge is None: - self.Charge = [] - else: - self.Charge = Charge - def factory(*args_, **kwargs_): - if BillingReading.subclass: - return BillingReading.subclass(*args_, **kwargs_) - else: - return BillingReading(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Charge(self): return self.Charge - def set_Charge(self, Charge): self.Charge = Charge - def add_Charge(self, value): self.Charge.append(value) - def insert_Charge_at(self, index, value): self.Charge.insert(index, value) - def replace_Charge_at(self, index, value): self.Charge[index] = value - def hasContent_(self): - if ( - self.Charge or - super(BillingReading, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingReading', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReading') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingReading', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingReading'): - super(BillingReading, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReading') - def exportChildren(self, outfile, level, namespace_='', name_='BillingReading', fromsubclass_=False, pretty_print=True): - super(BillingReading, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Charge_ in self.Charge: - Charge_.export(outfile, level, namespace_, name_='Charge', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='BillingReading'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingReading, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingReading, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('Charge=[\n') - level += 1 - for Charge_ in self.Charge: - showIndent(outfile, level) - outfile.write('model_.Charge(\n') - Charge_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingReading, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Charge': - obj_ = Charge.factory() - obj_.build(child_) - self.Charge.append(obj_) - obj_.original_tagname_ = 'Charge' - super(BillingReading, self).buildChildren(child_, node, nodeName_, True) -# end class BillingReading - - -class BillingPeriodList(SubscribableList): - """A List element to hold BillingPeriod objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, BillingPeriod=None): - self.original_tagname_ = None - super(BillingPeriodList, self).__init__() - if BillingPeriod is None: - self.BillingPeriod = [] - else: - self.BillingPeriod = BillingPeriod - def factory(*args_, **kwargs_): - if BillingPeriodList.subclass: - return BillingPeriodList.subclass(*args_, **kwargs_) - else: - return BillingPeriodList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_BillingPeriod(self): return self.BillingPeriod - def set_BillingPeriod(self, BillingPeriod): self.BillingPeriod = BillingPeriod - def add_BillingPeriod(self, value): self.BillingPeriod.append(value) - def insert_BillingPeriod_at(self, index, value): self.BillingPeriod.insert(index, value) - def replace_BillingPeriod_at(self, index, value): self.BillingPeriod[index] = value - def hasContent_(self): - if ( - self.BillingPeriod or - super(BillingPeriodList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingPeriodList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingPeriodList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingPeriodList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingPeriodList'): - super(BillingPeriodList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingPeriodList') - def exportChildren(self, outfile, level, namespace_='', name_='BillingPeriodList', fromsubclass_=False, pretty_print=True): - super(BillingPeriodList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for BillingPeriod_ in self.BillingPeriod: - BillingPeriod_.export(outfile, level, namespace_, name_='BillingPeriod', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='BillingPeriodList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingPeriodList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingPeriodList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('BillingPeriod=[\n') - level += 1 - for BillingPeriod_ in self.BillingPeriod: - showIndent(outfile, level) - outfile.write('model_.BillingPeriod(\n') - BillingPeriod_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingPeriodList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'BillingPeriod': - obj_ = BillingPeriod.factory() - obj_.build(child_) - self.BillingPeriod.append(obj_) - obj_.original_tagname_ = 'BillingPeriod' - super(BillingPeriodList, self).buildChildren(child_, node, nodeName_, True) -# end class BillingPeriodList - - -class BillingPeriod(Resource): - """A Billing Period relates to the period of time on which a customer - is billed. As an example the billing period interval for a - particular customer might be 31 days starting on July 1, 2011. - The start date and interval can change on each billing period. - There may also be multiple billing periods related to a customer - agreement to support different tariff structures.""" - subclass = None - superclass = Resource - def __init__(self, billLastPeriod=None, billToDate=None, interval=None, statusTimeStamp=None): - self.original_tagname_ = None - super(BillingPeriod, self).__init__() - self.billLastPeriod = billLastPeriod - self.billToDate = billToDate - self.interval = interval - self.statusTimeStamp = statusTimeStamp - def factory(*args_, **kwargs_): - if BillingPeriod.subclass: - return BillingPeriod.subclass(*args_, **kwargs_) - else: - return BillingPeriod(*args_, **kwargs_) - factory = staticmethod(factory) - def get_billLastPeriod(self): return self.billLastPeriod - def set_billLastPeriod(self, billLastPeriod): self.billLastPeriod = billLastPeriod - def get_billToDate(self): return self.billToDate - def set_billToDate(self, billToDate): self.billToDate = billToDate - def get_interval(self): return self.interval - def set_interval(self, interval): self.interval = interval - def get_statusTimeStamp(self): return self.statusTimeStamp - def set_statusTimeStamp(self, statusTimeStamp): self.statusTimeStamp = statusTimeStamp - def validate_Int48(self, value): - # Validate type Int48, a restriction on xs:long. - pass - def hasContent_(self): - if ( - self.billLastPeriod is not None or - self.billToDate is not None or - self.interval is not None or - self.statusTimeStamp is not None or - super(BillingPeriod, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingPeriod', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingPeriod') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingPeriod', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingPeriod'): - super(BillingPeriod, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingPeriod') - def exportChildren(self, outfile, level, namespace_='', name_='BillingPeriod', fromsubclass_=False, pretty_print=True): - super(BillingPeriod, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.billLastPeriod is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sbillLastPeriod>%s%s' % (namespace_, self.gds_format_integer(self.billLastPeriod, input_name='billLastPeriod'), namespace_, eol_)) - if self.billToDate is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sbillToDate>%s%s' % (namespace_, self.gds_format_integer(self.billToDate, input_name='billToDate'), namespace_, eol_)) - if self.interval is not None: - self.interval.export(outfile, level, namespace_, name_='interval', pretty_print=pretty_print) - if self.statusTimeStamp is not None: - self.statusTimeStamp.export(outfile, level, namespace_, name_='statusTimeStamp', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='BillingPeriod'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingPeriod, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingPeriod, self).exportLiteralChildren(outfile, level, name_) - if self.billLastPeriod is not None: - showIndent(outfile, level) - outfile.write('billLastPeriod=%d,\n' % self.billLastPeriod) - if self.billToDate is not None: - showIndent(outfile, level) - outfile.write('billToDate=%d,\n' % self.billToDate) - if self.interval is not None: - showIndent(outfile, level) - outfile.write('interval=model_.DateTimeInterval(\n') - self.interval.exportLiteral(outfile, level, name_='interval') - showIndent(outfile, level) - outfile.write('),\n') - if self.statusTimeStamp is not None: - showIndent(outfile, level) - outfile.write('statusTimeStamp=model_.TimeType(\n') - self.statusTimeStamp.exportLiteral(outfile, level, name_='statusTimeStamp') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingPeriod, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'billLastPeriod': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'billLastPeriod') - self.billLastPeriod = ival_ - self.validate_Int48(self.billLastPeriod) # validate type Int48 - elif nodeName_ == 'billToDate': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'billToDate') - self.billToDate = ival_ - self.validate_Int48(self.billToDate) # validate type Int48 - elif nodeName_ == 'interval': - obj_ = DateTimeInterval.factory() - obj_.build(child_) - self.interval = obj_ - obj_.original_tagname_ = 'interval' - elif nodeName_ == 'statusTimeStamp': - obj_ = TimeType.factory() - obj_.build(child_) - self.statusTimeStamp = obj_ - obj_.original_tagname_ = 'statusTimeStamp' - super(BillingPeriod, self).buildChildren(child_, node, nodeName_, True) -# end class BillingPeriod - - -class TextMessageList(SubscribableList): - """A List element to hold TextMessage objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, TextMessage=None): - self.original_tagname_ = None - super(TextMessageList, self).__init__() - if TextMessage is None: - self.TextMessage = [] - else: - self.TextMessage = TextMessage - def factory(*args_, **kwargs_): - if TextMessageList.subclass: - return TextMessageList.subclass(*args_, **kwargs_) - else: - return TextMessageList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_TextMessage(self): return self.TextMessage - def set_TextMessage(self, TextMessage): self.TextMessage = TextMessage - def add_TextMessage(self, value): self.TextMessage.append(value) - def insert_TextMessage_at(self, index, value): self.TextMessage.insert(index, value) - def replace_TextMessage_at(self, index, value): self.TextMessage[index] = value - def hasContent_(self): - if ( - self.TextMessage or - super(TextMessageList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TextMessageList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TextMessageList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TextMessageList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TextMessageList'): - super(TextMessageList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TextMessageList') - def exportChildren(self, outfile, level, namespace_='', name_='TextMessageList', fromsubclass_=False, pretty_print=True): - super(TextMessageList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for TextMessage_ in self.TextMessage: - TextMessage_.export(outfile, level, namespace_, name_='TextMessage', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='TextMessageList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TextMessageList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TextMessageList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('TextMessage=[\n') - level += 1 - for TextMessage_ in self.TextMessage: - showIndent(outfile, level) - outfile.write('model_.TextMessage(\n') - TextMessage_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TextMessageList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'TextMessage': - obj_ = TextMessage.factory() - obj_.build(child_) - self.TextMessage.append(obj_) - obj_.original_tagname_ = 'TextMessage' - super(TextMessageList, self).buildChildren(child_, node, nodeName_, True) -# end class TextMessageList - - -class TextMessage(Event): - """Text message such as a notification.""" - subclass = None - superclass = Event - def __init__(self, originator=None, priority=None, textMessage=None): - self.original_tagname_ = None - super(TextMessage, self).__init__() - self.originator = originator - self.priority = priority - self.textMessage = textMessage - def factory(*args_, **kwargs_): - if TextMessage.subclass: - return TextMessage.subclass(*args_, **kwargs_) - else: - return TextMessage(*args_, **kwargs_) - factory = staticmethod(factory) - def get_originator(self): return self.originator - def set_originator(self, originator): self.originator = originator - def get_priority(self): return self.priority - def set_priority(self, priority): self.priority = priority - def get_textMessage(self): return self.textMessage - def set_textMessage(self, textMessage): self.textMessage = textMessage - def validate_String20(self, value): - # Validate type String20, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.originator is not None or - self.priority is not None or - self.textMessage is not None or - super(TextMessage, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TextMessage', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TextMessage') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TextMessage', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TextMessage'): - super(TextMessage, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TextMessage') - def exportChildren(self, outfile, level, namespace_='', name_='TextMessage', fromsubclass_=False, pretty_print=True): - super(TextMessage, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.originator is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%soriginator>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.originator).encode(ExternalEncoding), input_name='originator'), namespace_, eol_)) - if self.priority is not None: - self.priority.export(outfile, level, namespace_, name_='priority', pretty_print=pretty_print) - if self.textMessage is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%stextMessage>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.textMessage).encode(ExternalEncoding), input_name='textMessage'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='TextMessage'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TextMessage, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TextMessage, self).exportLiteralChildren(outfile, level, name_) - if self.originator is not None: - showIndent(outfile, level) - outfile.write('originator=%s,\n' % quote_python(self.originator).encode(ExternalEncoding)) - if self.priority is not None: - showIndent(outfile, level) - outfile.write('priority=model_.PriorityType(\n') - self.priority.exportLiteral(outfile, level, name_='priority') - showIndent(outfile, level) - outfile.write('),\n') - if self.textMessage is not None: - showIndent(outfile, level) - outfile.write('textMessage=%s,\n' % quote_python(self.textMessage).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TextMessage, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'originator': - originator_ = child_.text - originator_ = self.gds_validate_string(originator_, node, 'originator') - self.originator = originator_ - self.validate_String20(self.originator) # validate type String20 - elif nodeName_ == 'priority': - obj_ = PriorityType.factory() - obj_.build(child_) - self.priority = obj_ - obj_.original_tagname_ = 'priority' - elif nodeName_ == 'textMessage': - textMessage_ = child_.text - textMessage_ = self.gds_validate_string(textMessage_, node, 'textMessage') - self.textMessage = textMessage_ - super(TextMessage, self).buildChildren(child_, node, nodeName_, True) -# end class TextMessage - - -class MessagingProgramList(SubscribableList): - """A List element to hold MessagingProgram objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, MessagingProgram=None): - self.original_tagname_ = None - super(MessagingProgramList, self).__init__() - if MessagingProgram is None: - self.MessagingProgram = [] - else: - self.MessagingProgram = MessagingProgram - def factory(*args_, **kwargs_): - if MessagingProgramList.subclass: - return MessagingProgramList.subclass(*args_, **kwargs_) - else: - return MessagingProgramList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_MessagingProgram(self): return self.MessagingProgram - def set_MessagingProgram(self, MessagingProgram): self.MessagingProgram = MessagingProgram - def add_MessagingProgram(self, value): self.MessagingProgram.append(value) - def insert_MessagingProgram_at(self, index, value): self.MessagingProgram.insert(index, value) - def replace_MessagingProgram_at(self, index, value): self.MessagingProgram[index] = value - def hasContent_(self): - if ( - self.MessagingProgram or - super(MessagingProgramList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MessagingProgramList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MessagingProgramList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MessagingProgramList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MessagingProgramList'): - super(MessagingProgramList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MessagingProgramList') - def exportChildren(self, outfile, level, namespace_='', name_='MessagingProgramList', fromsubclass_=False, pretty_print=True): - super(MessagingProgramList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for MessagingProgram_ in self.MessagingProgram: - MessagingProgram_.export(outfile, level, namespace_, name_='MessagingProgram', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MessagingProgramList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MessagingProgramList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MessagingProgramList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('MessagingProgram=[\n') - level += 1 - for MessagingProgram_ in self.MessagingProgram: - showIndent(outfile, level) - outfile.write('model_.MessagingProgram(\n') - MessagingProgram_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MessagingProgramList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'MessagingProgram': - obj_ = MessagingProgram.factory() - obj_.build(child_) - self.MessagingProgram.append(obj_) - obj_.original_tagname_ = 'MessagingProgram' - super(MessagingProgramList, self).buildChildren(child_, node, nodeName_, True) -# end class MessagingProgramList - - -class MessagingProgram(SubscribableIdentifiedObject): - """Provides a container for collections of text messages.""" - subclass = None - superclass = SubscribableIdentifiedObject - def __init__(self, ActiveTextMessageListLink=None, locale=None, primacy=None, TextMessageListLink=None): - self.original_tagname_ = None - super(MessagingProgram, self).__init__() - self.ActiveTextMessageListLink = ActiveTextMessageListLink - self.locale = locale - self.primacy = primacy - self.TextMessageListLink = TextMessageListLink - def factory(*args_, **kwargs_): - if MessagingProgram.subclass: - return MessagingProgram.subclass(*args_, **kwargs_) - else: - return MessagingProgram(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ActiveTextMessageListLink(self): return self.ActiveTextMessageListLink - def set_ActiveTextMessageListLink(self, ActiveTextMessageListLink): self.ActiveTextMessageListLink = ActiveTextMessageListLink - def get_locale(self): return self.locale - def set_locale(self, locale): self.locale = locale - def get_primacy(self): return self.primacy - def set_primacy(self, primacy): self.primacy = primacy - def get_TextMessageListLink(self): return self.TextMessageListLink - def set_TextMessageListLink(self, TextMessageListLink): self.TextMessageListLink = TextMessageListLink - def hasContent_(self): - if ( - self.ActiveTextMessageListLink is not None or - self.locale is not None or - self.primacy is not None or - self.TextMessageListLink is not None or - super(MessagingProgram, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MessagingProgram', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MessagingProgram') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MessagingProgram', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MessagingProgram'): - super(MessagingProgram, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MessagingProgram') - def exportChildren(self, outfile, level, namespace_='', name_='MessagingProgram', fromsubclass_=False, pretty_print=True): - super(MessagingProgram, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ActiveTextMessageListLink is not None: - self.ActiveTextMessageListLink.export(outfile, level, namespace_, name_='ActiveTextMessageListLink', pretty_print=pretty_print) - if self.locale is not None: - self.locale.export(outfile, level, namespace_, name_='locale', pretty_print=pretty_print) - if self.primacy is not None: - self.primacy.export(outfile, level, namespace_, name_='primacy', pretty_print=pretty_print) - if self.TextMessageListLink is not None: - self.TextMessageListLink.export(outfile, level, namespace_, name_='TextMessageListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MessagingProgram'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MessagingProgram, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MessagingProgram, self).exportLiteralChildren(outfile, level, name_) - if self.ActiveTextMessageListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveTextMessageListLink=model_.ActiveTextMessageListLink(\n') - self.ActiveTextMessageListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.locale is not None: - showIndent(outfile, level) - outfile.write('locale=model_.LocaleType(\n') - self.locale.exportLiteral(outfile, level, name_='locale') - showIndent(outfile, level) - outfile.write('),\n') - if self.primacy is not None: - showIndent(outfile, level) - outfile.write('primacy=model_.PrimacyType(\n') - self.primacy.exportLiteral(outfile, level, name_='primacy') - showIndent(outfile, level) - outfile.write('),\n') - if self.TextMessageListLink is not None: - showIndent(outfile, level) - outfile.write('TextMessageListLink=model_.TextMessageListLink(\n') - self.TextMessageListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MessagingProgram, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ActiveTextMessageListLink': - obj_ = ActiveTextMessageListLink.factory() - obj_.build(child_) - self.ActiveTextMessageListLink = obj_ - obj_.original_tagname_ = 'ActiveTextMessageListLink' - elif nodeName_ == 'locale': - obj_ = LocaleType.factory() - obj_.build(child_) - self.locale = obj_ - obj_.original_tagname_ = 'locale' - elif nodeName_ == 'primacy': - obj_ = PrimacyType.factory() - obj_.build(child_) - self.primacy = obj_ - obj_.original_tagname_ = 'primacy' - elif nodeName_ == 'TextMessageListLink': - obj_ = TextMessageListLink.factory() - obj_.build(child_) - self.TextMessageListLink = obj_ - obj_.original_tagname_ = 'TextMessageListLink' - super(MessagingProgram, self).buildChildren(child_, node, nodeName_, True) -# end class MessagingProgram - - -class TimeTariffIntervalList(SubscribableList): - """A List element to hold TimeTariffInterval objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, TimeTariffInterval=None): - self.original_tagname_ = None - super(TimeTariffIntervalList, self).__init__() - if TimeTariffInterval is None: - self.TimeTariffInterval = [] - else: - self.TimeTariffInterval = TimeTariffInterval - def factory(*args_, **kwargs_): - if TimeTariffIntervalList.subclass: - return TimeTariffIntervalList.subclass(*args_, **kwargs_) - else: - return TimeTariffIntervalList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_TimeTariffInterval(self): return self.TimeTariffInterval - def set_TimeTariffInterval(self, TimeTariffInterval): self.TimeTariffInterval = TimeTariffInterval - def add_TimeTariffInterval(self, value): self.TimeTariffInterval.append(value) - def insert_TimeTariffInterval_at(self, index, value): self.TimeTariffInterval.insert(index, value) - def replace_TimeTariffInterval_at(self, index, value): self.TimeTariffInterval[index] = value - def hasContent_(self): - if ( - self.TimeTariffInterval or - super(TimeTariffIntervalList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TimeTariffIntervalList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TimeTariffIntervalList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TimeTariffIntervalList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TimeTariffIntervalList'): - super(TimeTariffIntervalList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TimeTariffIntervalList') - def exportChildren(self, outfile, level, namespace_='', name_='TimeTariffIntervalList', fromsubclass_=False, pretty_print=True): - super(TimeTariffIntervalList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for TimeTariffInterval_ in self.TimeTariffInterval: - TimeTariffInterval_.export(outfile, level, namespace_, name_='TimeTariffInterval', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='TimeTariffIntervalList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TimeTariffIntervalList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TimeTariffIntervalList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('TimeTariffInterval=[\n') - level += 1 - for TimeTariffInterval_ in self.TimeTariffInterval: - showIndent(outfile, level) - outfile.write('model_.TimeTariffInterval(\n') - TimeTariffInterval_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TimeTariffIntervalList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'TimeTariffInterval': - obj_ = TimeTariffInterval.factory() - obj_.build(child_) - self.TimeTariffInterval.append(obj_) - obj_.original_tagname_ = 'TimeTariffInterval' - super(TimeTariffIntervalList, self).buildChildren(child_, node, nodeName_, True) -# end class TimeTariffIntervalList - - -class TimeTariffInterval(RandomizableEvent): - """Describes the time-differentiated portion of the RateComponent, if - applicable, and provides the ability to specify multiple time - intervals, each with its own consumption-based components and - other attributes.""" - subclass = None - superclass = RandomizableEvent - def __init__(self, ConsumptionTariffIntervalListLink=None, touTier=None): - self.original_tagname_ = None - super(TimeTariffInterval, self).__init__() - self.ConsumptionTariffIntervalListLink = ConsumptionTariffIntervalListLink - self.touTier = touTier - def factory(*args_, **kwargs_): - if TimeTariffInterval.subclass: - return TimeTariffInterval.subclass(*args_, **kwargs_) - else: - return TimeTariffInterval(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ConsumptionTariffIntervalListLink(self): return self.ConsumptionTariffIntervalListLink - def set_ConsumptionTariffIntervalListLink(self, ConsumptionTariffIntervalListLink): self.ConsumptionTariffIntervalListLink = ConsumptionTariffIntervalListLink - def get_touTier(self): return self.touTier - def set_touTier(self, touTier): self.touTier = touTier - def hasContent_(self): - if ( - self.ConsumptionTariffIntervalListLink is not None or - self.touTier is not None or - super(TimeTariffInterval, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TimeTariffInterval', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TimeTariffInterval') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TimeTariffInterval', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TimeTariffInterval'): - super(TimeTariffInterval, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TimeTariffInterval') - def exportChildren(self, outfile, level, namespace_='', name_='TimeTariffInterval', fromsubclass_=False, pretty_print=True): - super(TimeTariffInterval, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ConsumptionTariffIntervalListLink is not None: - self.ConsumptionTariffIntervalListLink.export(outfile, level, namespace_, name_='ConsumptionTariffIntervalListLink', pretty_print=pretty_print) - if self.touTier is not None: - self.touTier.export(outfile, level, namespace_, name_='touTier', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='TimeTariffInterval'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TimeTariffInterval, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TimeTariffInterval, self).exportLiteralChildren(outfile, level, name_) - if self.ConsumptionTariffIntervalListLink is not None: - showIndent(outfile, level) - outfile.write('ConsumptionTariffIntervalListLink=model_.ConsumptionTariffIntervalListLink(\n') - self.ConsumptionTariffIntervalListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.touTier is not None: - showIndent(outfile, level) - outfile.write('touTier=model_.TOUType(\n') - self.touTier.exportLiteral(outfile, level, name_='touTier') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TimeTariffInterval, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ConsumptionTariffIntervalListLink': - obj_ = ConsumptionTariffIntervalListLink.factory() - obj_.build(child_) - self.ConsumptionTariffIntervalListLink = obj_ - obj_.original_tagname_ = 'ConsumptionTariffIntervalListLink' - elif nodeName_ == 'touTier': - obj_ = TOUType.factory() - obj_.build(child_) - self.touTier = obj_ - obj_.original_tagname_ = 'touTier' - super(TimeTariffInterval, self).buildChildren(child_, node, nodeName_, True) -# end class TimeTariffInterval - - -class TariffProfileList(SubscribableList): - """A List element to hold TariffProfile objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, TariffProfile=None): - self.original_tagname_ = None - super(TariffProfileList, self).__init__() - if TariffProfile is None: - self.TariffProfile = [] - else: - self.TariffProfile = TariffProfile - def factory(*args_, **kwargs_): - if TariffProfileList.subclass: - return TariffProfileList.subclass(*args_, **kwargs_) - else: - return TariffProfileList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_TariffProfile(self): return self.TariffProfile - def set_TariffProfile(self, TariffProfile): self.TariffProfile = TariffProfile - def add_TariffProfile(self, value): self.TariffProfile.append(value) - def insert_TariffProfile_at(self, index, value): self.TariffProfile.insert(index, value) - def replace_TariffProfile_at(self, index, value): self.TariffProfile[index] = value - def hasContent_(self): - if ( - self.TariffProfile or - super(TariffProfileList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TariffProfileList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TariffProfileList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TariffProfileList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TariffProfileList'): - super(TariffProfileList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TariffProfileList') - def exportChildren(self, outfile, level, namespace_='', name_='TariffProfileList', fromsubclass_=False, pretty_print=True): - super(TariffProfileList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for TariffProfile_ in self.TariffProfile: - TariffProfile_.export(outfile, level, namespace_, name_='TariffProfile', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='TariffProfileList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TariffProfileList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TariffProfileList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('TariffProfile=[\n') - level += 1 - for TariffProfile_ in self.TariffProfile: - showIndent(outfile, level) - outfile.write('model_.TariffProfile(\n') - TariffProfile_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TariffProfileList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'TariffProfile': - obj_ = TariffProfile.factory() - obj_.build(child_) - self.TariffProfile.append(obj_) - obj_.original_tagname_ = 'TariffProfile' - super(TariffProfileList, self).buildChildren(child_, node, nodeName_, True) -# end class TariffProfileList - - -class TariffProfile(IdentifiedObject): - """A schedule of charges; structure that allows the definition of - tariff structures such as step (block) and time of use (tier) - when used in conjunction with TimeTariffInterval and - ConsumptionTariffInterval.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, currency=None, pricePowerOfTenMultiplier=None, primacy=None, rateCode=None, RateComponentListLink=None, serviceCategoryKind=None): - self.original_tagname_ = None - super(TariffProfile, self).__init__() - self.currency = currency - self.pricePowerOfTenMultiplier = pricePowerOfTenMultiplier - self.primacy = primacy - self.rateCode = rateCode - self.RateComponentListLink = RateComponentListLink - self.serviceCategoryKind = serviceCategoryKind - def factory(*args_, **kwargs_): - if TariffProfile.subclass: - return TariffProfile.subclass(*args_, **kwargs_) - else: - return TariffProfile(*args_, **kwargs_) - factory = staticmethod(factory) - def get_currency(self): return self.currency - def set_currency(self, currency): self.currency = currency - def get_pricePowerOfTenMultiplier(self): return self.pricePowerOfTenMultiplier - def set_pricePowerOfTenMultiplier(self, pricePowerOfTenMultiplier): self.pricePowerOfTenMultiplier = pricePowerOfTenMultiplier - def get_primacy(self): return self.primacy - def set_primacy(self, primacy): self.primacy = primacy - def get_rateCode(self): return self.rateCode - def set_rateCode(self, rateCode): self.rateCode = rateCode - def get_RateComponentListLink(self): return self.RateComponentListLink - def set_RateComponentListLink(self, RateComponentListLink): self.RateComponentListLink = RateComponentListLink - def get_serviceCategoryKind(self): return self.serviceCategoryKind - def set_serviceCategoryKind(self, serviceCategoryKind): self.serviceCategoryKind = serviceCategoryKind - def validate_String20(self, value): - # Validate type String20, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.currency is not None or - self.pricePowerOfTenMultiplier is not None or - self.primacy is not None or - self.rateCode is not None or - self.RateComponentListLink is not None or - self.serviceCategoryKind is not None or - super(TariffProfile, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TariffProfile', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TariffProfile') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TariffProfile', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TariffProfile'): - super(TariffProfile, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TariffProfile') - def exportChildren(self, outfile, level, namespace_='', name_='TariffProfile', fromsubclass_=False, pretty_print=True): - super(TariffProfile, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.currency is not None: - self.currency.export(outfile, level, namespace_, name_='currency', pretty_print=pretty_print) - if self.pricePowerOfTenMultiplier is not None: - self.pricePowerOfTenMultiplier.export(outfile, level, namespace_, name_='pricePowerOfTenMultiplier', pretty_print=pretty_print) - if self.primacy is not None: - self.primacy.export(outfile, level, namespace_, name_='primacy', pretty_print=pretty_print) - if self.rateCode is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srateCode>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.rateCode).encode(ExternalEncoding), input_name='rateCode'), namespace_, eol_)) - if self.RateComponentListLink is not None: - self.RateComponentListLink.export(outfile, level, namespace_, name_='RateComponentListLink', pretty_print=pretty_print) - if self.serviceCategoryKind is not None: - self.serviceCategoryKind.export(outfile, level, namespace_, name_='serviceCategoryKind', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='TariffProfile'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TariffProfile, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TariffProfile, self).exportLiteralChildren(outfile, level, name_) - if self.currency is not None: - showIndent(outfile, level) - outfile.write('currency=model_.CurrencyCode(\n') - self.currency.exportLiteral(outfile, level, name_='currency') - showIndent(outfile, level) - outfile.write('),\n') - if self.pricePowerOfTenMultiplier is not None: - showIndent(outfile, level) - outfile.write('pricePowerOfTenMultiplier=model_.PowerOfTenMultiplierType(\n') - self.pricePowerOfTenMultiplier.exportLiteral(outfile, level, name_='pricePowerOfTenMultiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.primacy is not None: - showIndent(outfile, level) - outfile.write('primacy=model_.PrimacyType(\n') - self.primacy.exportLiteral(outfile, level, name_='primacy') - showIndent(outfile, level) - outfile.write('),\n') - if self.rateCode is not None: - showIndent(outfile, level) - outfile.write('rateCode=%s,\n' % quote_python(self.rateCode).encode(ExternalEncoding)) - if self.RateComponentListLink is not None: - showIndent(outfile, level) - outfile.write('RateComponentListLink=model_.RateComponentListLink(\n') - self.RateComponentListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.serviceCategoryKind is not None: - showIndent(outfile, level) - outfile.write('serviceCategoryKind=model_.ServiceKind(\n') - self.serviceCategoryKind.exportLiteral(outfile, level, name_='serviceCategoryKind') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TariffProfile, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'currency': - obj_ = CurrencyCode.factory() - obj_.build(child_) - self.currency = obj_ - obj_.original_tagname_ = 'currency' - elif nodeName_ == 'pricePowerOfTenMultiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.pricePowerOfTenMultiplier = obj_ - obj_.original_tagname_ = 'pricePowerOfTenMultiplier' - elif nodeName_ == 'primacy': - obj_ = PrimacyType.factory() - obj_.build(child_) - self.primacy = obj_ - obj_.original_tagname_ = 'primacy' - elif nodeName_ == 'rateCode': - rateCode_ = child_.text - rateCode_ = self.gds_validate_string(rateCode_, node, 'rateCode') - self.rateCode = rateCode_ - self.validate_String20(self.rateCode) # validate type String20 - elif nodeName_ == 'RateComponentListLink': - obj_ = RateComponentListLink.factory() - obj_.build(child_) - self.RateComponentListLink = obj_ - obj_.original_tagname_ = 'RateComponentListLink' - elif nodeName_ == 'serviceCategoryKind': - obj_ = ServiceKind.factory() - obj_.build(child_) - self.serviceCategoryKind = obj_ - obj_.original_tagname_ = 'serviceCategoryKind' - super(TariffProfile, self).buildChildren(child_, node, nodeName_, True) -# end class TariffProfile - - -class RateComponentList(List): - """A List element to hold RateComponent objects.""" - subclass = None - superclass = List - def __init__(self, RateComponent=None): - self.original_tagname_ = None - super(RateComponentList, self).__init__() - if RateComponent is None: - self.RateComponent = [] - else: - self.RateComponent = RateComponent - def factory(*args_, **kwargs_): - if RateComponentList.subclass: - return RateComponentList.subclass(*args_, **kwargs_) - else: - return RateComponentList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_RateComponent(self): return self.RateComponent - def set_RateComponent(self, RateComponent): self.RateComponent = RateComponent - def add_RateComponent(self, value): self.RateComponent.append(value) - def insert_RateComponent_at(self, index, value): self.RateComponent.insert(index, value) - def replace_RateComponent_at(self, index, value): self.RateComponent[index] = value - def hasContent_(self): - if ( - self.RateComponent or - super(RateComponentList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RateComponentList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RateComponentList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RateComponentList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RateComponentList'): - super(RateComponentList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RateComponentList') - def exportChildren(self, outfile, level, namespace_='', name_='RateComponentList', fromsubclass_=False, pretty_print=True): - super(RateComponentList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for RateComponent_ in self.RateComponent: - RateComponent_.export(outfile, level, namespace_, name_='RateComponent', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='RateComponentList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RateComponentList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RateComponentList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('RateComponent=[\n') - level += 1 - for RateComponent_ in self.RateComponent: - showIndent(outfile, level) - outfile.write('model_.RateComponent(\n') - RateComponent_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RateComponentList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'RateComponent': - obj_ = RateComponent.factory() - obj_.build(child_) - self.RateComponent.append(obj_) - obj_.original_tagname_ = 'RateComponent' - super(RateComponentList, self).buildChildren(child_, node, nodeName_, True) -# end class RateComponentList - - -class RateComponent(IdentifiedObject): - """Specifies the applicable charges for a single component of the rate, - which could be generation price or consumption price, for - example.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, ActiveTimeTariffIntervalListLink=None, flowRateEndLimit=None, flowRateStartLimit=None, ReadingTypeLink=None, roleFlags=None, TimeTariffIntervalListLink=None): - self.original_tagname_ = None - super(RateComponent, self).__init__() - self.ActiveTimeTariffIntervalListLink = ActiveTimeTariffIntervalListLink - self.flowRateEndLimit = flowRateEndLimit - self.flowRateStartLimit = flowRateStartLimit - self.ReadingTypeLink = ReadingTypeLink - self.roleFlags = roleFlags - self.TimeTariffIntervalListLink = TimeTariffIntervalListLink - def factory(*args_, **kwargs_): - if RateComponent.subclass: - return RateComponent.subclass(*args_, **kwargs_) - else: - return RateComponent(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ActiveTimeTariffIntervalListLink(self): return self.ActiveTimeTariffIntervalListLink - def set_ActiveTimeTariffIntervalListLink(self, ActiveTimeTariffIntervalListLink): self.ActiveTimeTariffIntervalListLink = ActiveTimeTariffIntervalListLink - def get_flowRateEndLimit(self): return self.flowRateEndLimit - def set_flowRateEndLimit(self, flowRateEndLimit): self.flowRateEndLimit = flowRateEndLimit - def get_flowRateStartLimit(self): return self.flowRateStartLimit - def set_flowRateStartLimit(self, flowRateStartLimit): self.flowRateStartLimit = flowRateStartLimit - def get_ReadingTypeLink(self): return self.ReadingTypeLink - def set_ReadingTypeLink(self, ReadingTypeLink): self.ReadingTypeLink = ReadingTypeLink - def get_roleFlags(self): return self.roleFlags - def set_roleFlags(self, roleFlags): self.roleFlags = roleFlags - def get_TimeTariffIntervalListLink(self): return self.TimeTariffIntervalListLink - def set_TimeTariffIntervalListLink(self, TimeTariffIntervalListLink): self.TimeTariffIntervalListLink = TimeTariffIntervalListLink - def hasContent_(self): - if ( - self.ActiveTimeTariffIntervalListLink is not None or - self.flowRateEndLimit is not None or - self.flowRateStartLimit is not None or - self.ReadingTypeLink is not None or - self.roleFlags is not None or - self.TimeTariffIntervalListLink is not None or - super(RateComponent, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RateComponent', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RateComponent') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RateComponent', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RateComponent'): - super(RateComponent, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RateComponent') - def exportChildren(self, outfile, level, namespace_='', name_='RateComponent', fromsubclass_=False, pretty_print=True): - super(RateComponent, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ActiveTimeTariffIntervalListLink is not None: - self.ActiveTimeTariffIntervalListLink.export(outfile, level, namespace_, name_='ActiveTimeTariffIntervalListLink', pretty_print=pretty_print) - if self.flowRateEndLimit is not None: - self.flowRateEndLimit.export(outfile, level, namespace_, name_='flowRateEndLimit', pretty_print=pretty_print) - if self.flowRateStartLimit is not None: - self.flowRateStartLimit.export(outfile, level, namespace_, name_='flowRateStartLimit', pretty_print=pretty_print) - if self.ReadingTypeLink is not None: - self.ReadingTypeLink.export(outfile, level, namespace_, name_='ReadingTypeLink', pretty_print=pretty_print) - if self.roleFlags is not None: - self.roleFlags.export(outfile, level, namespace_, name_='roleFlags', pretty_print=pretty_print) - if self.TimeTariffIntervalListLink is not None: - self.TimeTariffIntervalListLink.export(outfile, level, namespace_, name_='TimeTariffIntervalListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='RateComponent'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RateComponent, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RateComponent, self).exportLiteralChildren(outfile, level, name_) - if self.ActiveTimeTariffIntervalListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveTimeTariffIntervalListLink=model_.ActiveTimeTariffIntervalListLink(\n') - self.ActiveTimeTariffIntervalListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.flowRateEndLimit is not None: - showIndent(outfile, level) - outfile.write('flowRateEndLimit=model_.UnitValueType(\n') - self.flowRateEndLimit.exportLiteral(outfile, level, name_='flowRateEndLimit') - showIndent(outfile, level) - outfile.write('),\n') - if self.flowRateStartLimit is not None: - showIndent(outfile, level) - outfile.write('flowRateStartLimit=model_.UnitValueType(\n') - self.flowRateStartLimit.exportLiteral(outfile, level, name_='flowRateStartLimit') - showIndent(outfile, level) - outfile.write('),\n') - if self.ReadingTypeLink is not None: - showIndent(outfile, level) - outfile.write('ReadingTypeLink=model_.ReadingTypeLink(\n') - self.ReadingTypeLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.roleFlags is not None: - showIndent(outfile, level) - outfile.write('roleFlags=model_.RoleFlagsType(\n') - self.roleFlags.exportLiteral(outfile, level, name_='roleFlags') - showIndent(outfile, level) - outfile.write('),\n') - if self.TimeTariffIntervalListLink is not None: - showIndent(outfile, level) - outfile.write('TimeTariffIntervalListLink=model_.TimeTariffIntervalListLink(\n') - self.TimeTariffIntervalListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RateComponent, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ActiveTimeTariffIntervalListLink': - obj_ = ActiveTimeTariffIntervalListLink.factory() - obj_.build(child_) - self.ActiveTimeTariffIntervalListLink = obj_ - obj_.original_tagname_ = 'ActiveTimeTariffIntervalListLink' - elif nodeName_ == 'flowRateEndLimit': - obj_ = UnitValueType.factory() - obj_.build(child_) - self.flowRateEndLimit = obj_ - obj_.original_tagname_ = 'flowRateEndLimit' - elif nodeName_ == 'flowRateStartLimit': - obj_ = UnitValueType.factory() - obj_.build(child_) - self.flowRateStartLimit = obj_ - obj_.original_tagname_ = 'flowRateStartLimit' - elif nodeName_ == 'ReadingTypeLink': - obj_ = ReadingTypeLink.factory() - obj_.build(child_) - self.ReadingTypeLink = obj_ - obj_.original_tagname_ = 'ReadingTypeLink' - elif nodeName_ == 'roleFlags': - obj_ = RoleFlagsType.factory() - obj_.build(child_) - self.roleFlags = obj_ - obj_.original_tagname_ = 'roleFlags' - elif nodeName_ == 'TimeTariffIntervalListLink': - obj_ = TimeTariffIntervalListLink.factory() - obj_.build(child_) - self.TimeTariffIntervalListLink = obj_ - obj_.original_tagname_ = 'TimeTariffIntervalListLink' - super(RateComponent, self).buildChildren(child_, node, nodeName_, True) -# end class RateComponent - - -class ConsumptionTariffIntervalList(List): - """A List element to hold ConsumptionTariffInterval objects.""" - subclass = None - superclass = List - def __init__(self, ConsumptionTariffInterval=None): - self.original_tagname_ = None - super(ConsumptionTariffIntervalList, self).__init__() - if ConsumptionTariffInterval is None: - self.ConsumptionTariffInterval = [] - else: - self.ConsumptionTariffInterval = ConsumptionTariffInterval - def factory(*args_, **kwargs_): - if ConsumptionTariffIntervalList.subclass: - return ConsumptionTariffIntervalList.subclass(*args_, **kwargs_) - else: - return ConsumptionTariffIntervalList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ConsumptionTariffInterval(self): return self.ConsumptionTariffInterval - def set_ConsumptionTariffInterval(self, ConsumptionTariffInterval): self.ConsumptionTariffInterval = ConsumptionTariffInterval - def add_ConsumptionTariffInterval(self, value): self.ConsumptionTariffInterval.append(value) - def insert_ConsumptionTariffInterval_at(self, index, value): self.ConsumptionTariffInterval.insert(index, value) - def replace_ConsumptionTariffInterval_at(self, index, value): self.ConsumptionTariffInterval[index] = value - def hasContent_(self): - if ( - self.ConsumptionTariffInterval or - super(ConsumptionTariffIntervalList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ConsumptionTariffIntervalList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ConsumptionTariffIntervalList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ConsumptionTariffIntervalList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ConsumptionTariffIntervalList'): - super(ConsumptionTariffIntervalList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ConsumptionTariffIntervalList') - def exportChildren(self, outfile, level, namespace_='', name_='ConsumptionTariffIntervalList', fromsubclass_=False, pretty_print=True): - super(ConsumptionTariffIntervalList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for ConsumptionTariffInterval_ in self.ConsumptionTariffInterval: - ConsumptionTariffInterval_.export(outfile, level, namespace_, name_='ConsumptionTariffInterval', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ConsumptionTariffIntervalList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ConsumptionTariffIntervalList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ConsumptionTariffIntervalList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('ConsumptionTariffInterval=[\n') - level += 1 - for ConsumptionTariffInterval_ in self.ConsumptionTariffInterval: - showIndent(outfile, level) - outfile.write('model_.ConsumptionTariffInterval(\n') - ConsumptionTariffInterval_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ConsumptionTariffIntervalList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ConsumptionTariffInterval': - obj_ = ConsumptionTariffInterval.factory() - obj_.build(child_) - self.ConsumptionTariffInterval.append(obj_) - obj_.original_tagname_ = 'ConsumptionTariffInterval' - super(ConsumptionTariffIntervalList, self).buildChildren(child_, node, nodeName_, True) -# end class ConsumptionTariffIntervalList - - -class ConsumptionTariffInterval(Resource): - """One of a sequence of thresholds defined in terms of consumption - quantity of a service such as electricity, water, gas, etc. It - defines the steps or blocks in a step tariff structure, where - startValue simultaneously defines the entry value of this step - and the closing value of the previous step. Where consumption is - greater than startValue, it falls within this block and where - consumption is less than or equal to startValue, it falls within - one of the previous blocks.""" - subclass = None - superclass = Resource - def __init__(self, consumptionBlock=None, EnvironmentalCost=None, price=None, startValue=None): - self.original_tagname_ = None - super(ConsumptionTariffInterval, self).__init__() - self.consumptionBlock = consumptionBlock - if EnvironmentalCost is None: - self.EnvironmentalCost = [] - else: - self.EnvironmentalCost = EnvironmentalCost - self.price = price - self.startValue = startValue - def factory(*args_, **kwargs_): - if ConsumptionTariffInterval.subclass: - return ConsumptionTariffInterval.subclass(*args_, **kwargs_) - else: - return ConsumptionTariffInterval(*args_, **kwargs_) - factory = staticmethod(factory) - def get_consumptionBlock(self): return self.consumptionBlock - def set_consumptionBlock(self, consumptionBlock): self.consumptionBlock = consumptionBlock - def get_EnvironmentalCost(self): return self.EnvironmentalCost - def set_EnvironmentalCost(self, EnvironmentalCost): self.EnvironmentalCost = EnvironmentalCost - def add_EnvironmentalCost(self, value): self.EnvironmentalCost.append(value) - def insert_EnvironmentalCost_at(self, index, value): self.EnvironmentalCost.insert(index, value) - def replace_EnvironmentalCost_at(self, index, value): self.EnvironmentalCost[index] = value - def get_price(self): return self.price - def set_price(self, price): self.price = price - def get_startValue(self): return self.startValue - def set_startValue(self, startValue): self.startValue = startValue - def validate_Int32(self, value): - # Validate type Int32, a restriction on xs:int. - pass - def validate_UInt48(self, value): - # Validate type UInt48, a restriction on xs:unsignedLong. - pass - def hasContent_(self): - if ( - self.consumptionBlock is not None or - self.EnvironmentalCost or - self.price is not None or - self.startValue is not None or - super(ConsumptionTariffInterval, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ConsumptionTariffInterval', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ConsumptionTariffInterval') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ConsumptionTariffInterval', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ConsumptionTariffInterval'): - super(ConsumptionTariffInterval, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ConsumptionTariffInterval') - def exportChildren(self, outfile, level, namespace_='', name_='ConsumptionTariffInterval', fromsubclass_=False, pretty_print=True): - super(ConsumptionTariffInterval, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.consumptionBlock is not None: - self.consumptionBlock.export(outfile, level, namespace_, name_='consumptionBlock', pretty_print=pretty_print) - for EnvironmentalCost_ in self.EnvironmentalCost: - EnvironmentalCost_.export(outfile, level, namespace_, name_='EnvironmentalCost', pretty_print=pretty_print) - if self.price is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sprice>%s%s' % (namespace_, self.gds_format_integer(self.price, input_name='price'), namespace_, eol_)) - if self.startValue is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sstartValue>%s%s' % (namespace_, self.gds_format_integer(self.startValue, input_name='startValue'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='ConsumptionTariffInterval'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ConsumptionTariffInterval, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ConsumptionTariffInterval, self).exportLiteralChildren(outfile, level, name_) - if self.consumptionBlock is not None: - showIndent(outfile, level) - outfile.write('consumptionBlock=model_.ConsumptionBlockType(\n') - self.consumptionBlock.exportLiteral(outfile, level, name_='consumptionBlock') - showIndent(outfile, level) - outfile.write('),\n') - showIndent(outfile, level) - outfile.write('EnvironmentalCost=[\n') - level += 1 - for EnvironmentalCost_ in self.EnvironmentalCost: - showIndent(outfile, level) - outfile.write('model_.EnvironmentalCost(\n') - EnvironmentalCost_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - if self.price is not None: - showIndent(outfile, level) - outfile.write('price=%d,\n' % self.price) - if self.startValue is not None: - showIndent(outfile, level) - outfile.write('startValue=%d,\n' % self.startValue) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ConsumptionTariffInterval, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'consumptionBlock': - obj_ = ConsumptionBlockType.factory() - obj_.build(child_) - self.consumptionBlock = obj_ - obj_.original_tagname_ = 'consumptionBlock' - elif nodeName_ == 'EnvironmentalCost': - obj_ = EnvironmentalCost.factory() - obj_.build(child_) - self.EnvironmentalCost.append(obj_) - obj_.original_tagname_ = 'EnvironmentalCost' - elif nodeName_ == 'price': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'price') - self.price = ival_ - self.validate_Int32(self.price) # validate type Int32 - elif nodeName_ == 'startValue': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'startValue') - self.startValue = ival_ - self.validate_UInt48(self.startValue) # validate type UInt48 - super(ConsumptionTariffInterval, self).buildChildren(child_, node, nodeName_, True) -# end class ConsumptionTariffInterval - - -class UsagePointList(SubscribableList): - """A List element to hold UsagePoint objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, UsagePoint=None): - self.original_tagname_ = None - super(UsagePointList, self).__init__() - if UsagePoint is None: - self.UsagePoint = [] - else: - self.UsagePoint = UsagePoint - def factory(*args_, **kwargs_): - if UsagePointList.subclass: - return UsagePointList.subclass(*args_, **kwargs_) - else: - return UsagePointList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_UsagePoint(self): return self.UsagePoint - def set_UsagePoint(self, UsagePoint): self.UsagePoint = UsagePoint - def add_UsagePoint(self, value): self.UsagePoint.append(value) - def insert_UsagePoint_at(self, index, value): self.UsagePoint.insert(index, value) - def replace_UsagePoint_at(self, index, value): self.UsagePoint[index] = value - def hasContent_(self): - if ( - self.UsagePoint or - super(UsagePointList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UsagePointList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePointList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='UsagePointList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UsagePointList'): - super(UsagePointList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePointList') - def exportChildren(self, outfile, level, namespace_='', name_='UsagePointList', fromsubclass_=False, pretty_print=True): - super(UsagePointList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for UsagePoint_ in self.UsagePoint: - UsagePoint_.export(outfile, level, namespace_, name_='UsagePoint', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='UsagePointList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(UsagePointList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(UsagePointList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('UsagePoint=[\n') - level += 1 - for UsagePoint_ in self.UsagePoint: - showIndent(outfile, level) - outfile.write('model_.UsagePoint(\n') - UsagePoint_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(UsagePointList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'UsagePoint': - obj_ = UsagePoint.factory() - obj_.build(child_) - self.UsagePoint.append(obj_) - obj_.original_tagname_ = 'UsagePoint' - super(UsagePointList, self).buildChildren(child_, node, nodeName_, True) -# end class UsagePointList - - -class ReadingType(Resource): - """Type of data conveyed by a specific Reading. See IEC 61968 Part 9 - Annex C for full definitions of these values.""" - subclass = None - superclass = Resource - def __init__(self, accumulationBehaviour=None, calorificValue=None, commodity=None, conversionFactor=None, dataQualifier=None, flowDirection=None, intervalLength=None, kind=None, maxNumberOfIntervals=None, numberOfConsumptionBlocks=None, numberOfTouTiers=None, phase=None, powerOfTenMultiplier=None, subIntervalLength=None, supplyLimit=None, tieredConsumptionBlocks=None, uom=None): - self.original_tagname_ = None - super(ReadingType, self).__init__() - self.accumulationBehaviour = accumulationBehaviour - self.calorificValue = calorificValue - self.commodity = commodity - self.conversionFactor = conversionFactor - self.dataQualifier = dataQualifier - self.flowDirection = flowDirection - self.intervalLength = intervalLength - self.kind = kind - self.maxNumberOfIntervals = maxNumberOfIntervals - self.numberOfConsumptionBlocks = numberOfConsumptionBlocks - self.numberOfTouTiers = numberOfTouTiers - self.phase = phase - self.powerOfTenMultiplier = powerOfTenMultiplier - self.subIntervalLength = subIntervalLength - self.supplyLimit = supplyLimit - self.tieredConsumptionBlocks = tieredConsumptionBlocks - self.uom = uom - def factory(*args_, **kwargs_): - if ReadingType.subclass: - return ReadingType.subclass(*args_, **kwargs_) - else: - return ReadingType(*args_, **kwargs_) - factory = staticmethod(factory) - def get_accumulationBehaviour(self): return self.accumulationBehaviour - def set_accumulationBehaviour(self, accumulationBehaviour): self.accumulationBehaviour = accumulationBehaviour - def get_calorificValue(self): return self.calorificValue - def set_calorificValue(self, calorificValue): self.calorificValue = calorificValue - def get_commodity(self): return self.commodity - def set_commodity(self, commodity): self.commodity = commodity - def get_conversionFactor(self): return self.conversionFactor - def set_conversionFactor(self, conversionFactor): self.conversionFactor = conversionFactor - def get_dataQualifier(self): return self.dataQualifier - def set_dataQualifier(self, dataQualifier): self.dataQualifier = dataQualifier - def get_flowDirection(self): return self.flowDirection - def set_flowDirection(self, flowDirection): self.flowDirection = flowDirection - def get_intervalLength(self): return self.intervalLength - def set_intervalLength(self, intervalLength): self.intervalLength = intervalLength - def get_kind(self): return self.kind - def set_kind(self, kind): self.kind = kind - def get_maxNumberOfIntervals(self): return self.maxNumberOfIntervals - def set_maxNumberOfIntervals(self, maxNumberOfIntervals): self.maxNumberOfIntervals = maxNumberOfIntervals - def get_numberOfConsumptionBlocks(self): return self.numberOfConsumptionBlocks - def set_numberOfConsumptionBlocks(self, numberOfConsumptionBlocks): self.numberOfConsumptionBlocks = numberOfConsumptionBlocks - def get_numberOfTouTiers(self): return self.numberOfTouTiers - def set_numberOfTouTiers(self, numberOfTouTiers): self.numberOfTouTiers = numberOfTouTiers - def get_phase(self): return self.phase - def set_phase(self, phase): self.phase = phase - def get_powerOfTenMultiplier(self): return self.powerOfTenMultiplier - def set_powerOfTenMultiplier(self, powerOfTenMultiplier): self.powerOfTenMultiplier = powerOfTenMultiplier - def get_subIntervalLength(self): return self.subIntervalLength - def set_subIntervalLength(self, subIntervalLength): self.subIntervalLength = subIntervalLength - def get_supplyLimit(self): return self.supplyLimit - def set_supplyLimit(self, supplyLimit): self.supplyLimit = supplyLimit - def get_tieredConsumptionBlocks(self): return self.tieredConsumptionBlocks - def set_tieredConsumptionBlocks(self, tieredConsumptionBlocks): self.tieredConsumptionBlocks = tieredConsumptionBlocks - def get_uom(self): return self.uom - def set_uom(self, uom): self.uom = uom - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_UInt48(self, value): - # Validate type UInt48, a restriction on xs:unsignedLong. - pass - def hasContent_(self): - if ( - self.accumulationBehaviour is not None or - self.calorificValue is not None or - self.commodity is not None or - self.conversionFactor is not None or - self.dataQualifier is not None or - self.flowDirection is not None or - self.intervalLength is not None or - self.kind is not None or - self.maxNumberOfIntervals is not None or - self.numberOfConsumptionBlocks is not None or - self.numberOfTouTiers is not None or - self.phase is not None or - self.powerOfTenMultiplier is not None or - self.subIntervalLength is not None or - self.supplyLimit is not None or - self.tieredConsumptionBlocks is not None or - self.uom is not None or - super(ReadingType, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingType', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingType') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingType', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingType'): - super(ReadingType, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingType') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingType', fromsubclass_=False, pretty_print=True): - super(ReadingType, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.accumulationBehaviour is not None: - self.accumulationBehaviour.export(outfile, level, namespace_, name_='accumulationBehaviour', pretty_print=pretty_print) - if self.calorificValue is not None: - self.calorificValue.export(outfile, level, namespace_, name_='calorificValue', pretty_print=pretty_print) - if self.commodity is not None: - self.commodity.export(outfile, level, namespace_, name_='commodity', pretty_print=pretty_print) - if self.conversionFactor is not None: - self.conversionFactor.export(outfile, level, namespace_, name_='conversionFactor', pretty_print=pretty_print) - if self.dataQualifier is not None: - self.dataQualifier.export(outfile, level, namespace_, name_='dataQualifier', pretty_print=pretty_print) - if self.flowDirection is not None: - self.flowDirection.export(outfile, level, namespace_, name_='flowDirection', pretty_print=pretty_print) - if self.intervalLength is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sintervalLength>%s%s' % (namespace_, self.gds_format_integer(self.intervalLength, input_name='intervalLength'), namespace_, eol_)) - if self.kind is not None: - self.kind.export(outfile, level, namespace_, name_='kind', pretty_print=pretty_print) - if self.maxNumberOfIntervals is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smaxNumberOfIntervals>%s%s' % (namespace_, self.gds_format_integer(self.maxNumberOfIntervals, input_name='maxNumberOfIntervals'), namespace_, eol_)) - if self.numberOfConsumptionBlocks is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%snumberOfConsumptionBlocks>%s%s' % (namespace_, self.gds_format_integer(self.numberOfConsumptionBlocks, input_name='numberOfConsumptionBlocks'), namespace_, eol_)) - if self.numberOfTouTiers is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%snumberOfTouTiers>%s%s' % (namespace_, self.gds_format_integer(self.numberOfTouTiers, input_name='numberOfTouTiers'), namespace_, eol_)) - if self.phase is not None: - self.phase.export(outfile, level, namespace_, name_='phase', pretty_print=pretty_print) - if self.powerOfTenMultiplier is not None: - self.powerOfTenMultiplier.export(outfile, level, namespace_, name_='powerOfTenMultiplier', pretty_print=pretty_print) - if self.subIntervalLength is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssubIntervalLength>%s%s' % (namespace_, self.gds_format_integer(self.subIntervalLength, input_name='subIntervalLength'), namespace_, eol_)) - if self.supplyLimit is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssupplyLimit>%s%s' % (namespace_, self.gds_format_integer(self.supplyLimit, input_name='supplyLimit'), namespace_, eol_)) - if self.tieredConsumptionBlocks is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%stieredConsumptionBlocks>%s%s' % (namespace_, self.gds_format_boolean(self.tieredConsumptionBlocks, input_name='tieredConsumptionBlocks'), namespace_, eol_)) - if self.uom is not None: - self.uom.export(outfile, level, namespace_, name_='uom', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ReadingType'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingType, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingType, self).exportLiteralChildren(outfile, level, name_) - if self.accumulationBehaviour is not None: - showIndent(outfile, level) - outfile.write('accumulationBehaviour=model_.AccumulationBehaviourType(\n') - self.accumulationBehaviour.exportLiteral(outfile, level, name_='accumulationBehaviour') - showIndent(outfile, level) - outfile.write('),\n') - if self.calorificValue is not None: - showIndent(outfile, level) - outfile.write('calorificValue=model_.UnitValueType(\n') - self.calorificValue.exportLiteral(outfile, level, name_='calorificValue') - showIndent(outfile, level) - outfile.write('),\n') - if self.commodity is not None: - showIndent(outfile, level) - outfile.write('commodity=model_.CommodityType(\n') - self.commodity.exportLiteral(outfile, level, name_='commodity') - showIndent(outfile, level) - outfile.write('),\n') - if self.conversionFactor is not None: - showIndent(outfile, level) - outfile.write('conversionFactor=model_.UnitValueType(\n') - self.conversionFactor.exportLiteral(outfile, level, name_='conversionFactor') - showIndent(outfile, level) - outfile.write('),\n') - if self.dataQualifier is not None: - showIndent(outfile, level) - outfile.write('dataQualifier=model_.DataQualifierType(\n') - self.dataQualifier.exportLiteral(outfile, level, name_='dataQualifier') - showIndent(outfile, level) - outfile.write('),\n') - if self.flowDirection is not None: - showIndent(outfile, level) - outfile.write('flowDirection=model_.FlowDirectionType(\n') - self.flowDirection.exportLiteral(outfile, level, name_='flowDirection') - showIndent(outfile, level) - outfile.write('),\n') - if self.intervalLength is not None: - showIndent(outfile, level) - outfile.write('intervalLength=%d,\n' % self.intervalLength) - if self.kind is not None: - showIndent(outfile, level) - outfile.write('kind=model_.KindType(\n') - self.kind.exportLiteral(outfile, level, name_='kind') - showIndent(outfile, level) - outfile.write('),\n') - if self.maxNumberOfIntervals is not None: - showIndent(outfile, level) - outfile.write('maxNumberOfIntervals=%d,\n' % self.maxNumberOfIntervals) - if self.numberOfConsumptionBlocks is not None: - showIndent(outfile, level) - outfile.write('numberOfConsumptionBlocks=%d,\n' % self.numberOfConsumptionBlocks) - if self.numberOfTouTiers is not None: - showIndent(outfile, level) - outfile.write('numberOfTouTiers=%d,\n' % self.numberOfTouTiers) - if self.phase is not None: - showIndent(outfile, level) - outfile.write('phase=model_.PhaseCode(\n') - self.phase.exportLiteral(outfile, level, name_='phase') - showIndent(outfile, level) - outfile.write('),\n') - if self.powerOfTenMultiplier is not None: - showIndent(outfile, level) - outfile.write('powerOfTenMultiplier=model_.PowerOfTenMultiplierType(\n') - self.powerOfTenMultiplier.exportLiteral(outfile, level, name_='powerOfTenMultiplier') - showIndent(outfile, level) - outfile.write('),\n') - if self.subIntervalLength is not None: - showIndent(outfile, level) - outfile.write('subIntervalLength=%d,\n' % self.subIntervalLength) - if self.supplyLimit is not None: - showIndent(outfile, level) - outfile.write('supplyLimit=%d,\n' % self.supplyLimit) - if self.tieredConsumptionBlocks is not None: - showIndent(outfile, level) - outfile.write('tieredConsumptionBlocks=%s,\n' % self.tieredConsumptionBlocks) - if self.uom is not None: - showIndent(outfile, level) - outfile.write('uom=model_.UomType(\n') - self.uom.exportLiteral(outfile, level, name_='uom') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingType, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'accumulationBehaviour': - obj_ = AccumulationBehaviourType.factory() - obj_.build(child_) - self.accumulationBehaviour = obj_ - obj_.original_tagname_ = 'accumulationBehaviour' - elif nodeName_ == 'calorificValue': - obj_ = UnitValueType.factory() - obj_.build(child_) - self.calorificValue = obj_ - obj_.original_tagname_ = 'calorificValue' - elif nodeName_ == 'commodity': - obj_ = CommodityType.factory() - obj_.build(child_) - self.commodity = obj_ - obj_.original_tagname_ = 'commodity' - elif nodeName_ == 'conversionFactor': - obj_ = UnitValueType.factory() - obj_.build(child_) - self.conversionFactor = obj_ - obj_.original_tagname_ = 'conversionFactor' - elif nodeName_ == 'dataQualifier': - obj_ = DataQualifierType.factory() - obj_.build(child_) - self.dataQualifier = obj_ - obj_.original_tagname_ = 'dataQualifier' - elif nodeName_ == 'flowDirection': - obj_ = FlowDirectionType.factory() - obj_.build(child_) - self.flowDirection = obj_ - obj_.original_tagname_ = 'flowDirection' - elif nodeName_ == 'intervalLength': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'intervalLength') - self.intervalLength = ival_ - self.validate_UInt32(self.intervalLength) # validate type UInt32 - elif nodeName_ == 'kind': - obj_ = KindType.factory() - obj_.build(child_) - self.kind = obj_ - obj_.original_tagname_ = 'kind' - elif nodeName_ == 'maxNumberOfIntervals': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'maxNumberOfIntervals') - self.maxNumberOfIntervals = ival_ - self.validate_UInt8(self.maxNumberOfIntervals) # validate type UInt8 - elif nodeName_ == 'numberOfConsumptionBlocks': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'numberOfConsumptionBlocks') - self.numberOfConsumptionBlocks = ival_ - self.validate_UInt8(self.numberOfConsumptionBlocks) # validate type UInt8 - elif nodeName_ == 'numberOfTouTiers': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'numberOfTouTiers') - self.numberOfTouTiers = ival_ - self.validate_UInt8(self.numberOfTouTiers) # validate type UInt8 - elif nodeName_ == 'phase': - obj_ = PhaseCode.factory() - obj_.build(child_) - self.phase = obj_ - obj_.original_tagname_ = 'phase' - elif nodeName_ == 'powerOfTenMultiplier': - obj_ = PowerOfTenMultiplierType.factory() - obj_.build(child_) - self.powerOfTenMultiplier = obj_ - obj_.original_tagname_ = 'powerOfTenMultiplier' - elif nodeName_ == 'subIntervalLength': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'subIntervalLength') - self.subIntervalLength = ival_ - self.validate_UInt32(self.subIntervalLength) # validate type UInt32 - elif nodeName_ == 'supplyLimit': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'supplyLimit') - self.supplyLimit = ival_ - self.validate_UInt48(self.supplyLimit) # validate type UInt48 - elif nodeName_ == 'tieredConsumptionBlocks': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'tieredConsumptionBlocks') - self.tieredConsumptionBlocks = ival_ - elif nodeName_ == 'uom': - obj_ = UomType.factory() - obj_.build(child_) - self.uom = obj_ - obj_.original_tagname_ = 'uom' - super(ReadingType, self).buildChildren(child_, node, nodeName_, True) -# end class ReadingType - - -class ReadingSetList(SubscribableList): - """A List element to hold ReadingSet objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, ReadingSet=None): - self.original_tagname_ = None - super(ReadingSetList, self).__init__() - if ReadingSet is None: - self.ReadingSet = [] - else: - self.ReadingSet = ReadingSet - def factory(*args_, **kwargs_): - if ReadingSetList.subclass: - return ReadingSetList.subclass(*args_, **kwargs_) - else: - return ReadingSetList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ReadingSet(self): return self.ReadingSet - def set_ReadingSet(self, ReadingSet): self.ReadingSet = ReadingSet - def add_ReadingSet(self, value): self.ReadingSet.append(value) - def insert_ReadingSet_at(self, index, value): self.ReadingSet.insert(index, value) - def replace_ReadingSet_at(self, index, value): self.ReadingSet[index] = value - def hasContent_(self): - if ( - self.ReadingSet or - super(ReadingSetList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingSetList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingSetList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingSetList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingSetList'): - super(ReadingSetList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingSetList') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingSetList', fromsubclass_=False, pretty_print=True): - super(ReadingSetList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for ReadingSet_ in self.ReadingSet: - ReadingSet_.export(outfile, level, namespace_, name_='ReadingSet', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ReadingSetList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingSetList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingSetList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('ReadingSet=[\n') - level += 1 - for ReadingSet_ in self.ReadingSet: - showIndent(outfile, level) - outfile.write('model_.ReadingSet(\n') - ReadingSet_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingSetList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ReadingSet': - obj_ = ReadingSet.factory() - obj_.build(child_) - self.ReadingSet.append(obj_) - obj_.original_tagname_ = 'ReadingSet' - super(ReadingSetList, self).buildChildren(child_, node, nodeName_, True) -# end class ReadingSetList - - -class ReadingList(SubscribableList): - """A List element to hold Reading objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, Reading=None): - self.original_tagname_ = None - super(ReadingList, self).__init__() - if Reading is None: - self.Reading = [] - else: - self.Reading = Reading - def factory(*args_, **kwargs_): - if ReadingList.subclass: - return ReadingList.subclass(*args_, **kwargs_) - else: - return ReadingList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Reading(self): return self.Reading - def set_Reading(self, Reading): self.Reading = Reading - def add_Reading(self, value): self.Reading.append(value) - def insert_Reading_at(self, index, value): self.Reading.insert(index, value) - def replace_Reading_at(self, index, value): self.Reading[index] = value - def hasContent_(self): - if ( - self.Reading or - super(ReadingList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingList'): - super(ReadingList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingList') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingList', fromsubclass_=False, pretty_print=True): - super(ReadingList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Reading_ in self.Reading: - Reading_.export(outfile, level, namespace_, name_='Reading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ReadingList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('Reading=[\n') - level += 1 - for Reading_ in self.Reading: - showIndent(outfile, level) - outfile.write('model_.Reading(\n') - Reading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Reading': - obj_ = Reading.factory() - obj_.build(child_) - self.Reading.append(obj_) - obj_.original_tagname_ = 'Reading' - super(ReadingList, self).buildChildren(child_, node, nodeName_, True) -# end class ReadingList - - -class Reading(ReadingBase): - """Specific value measured by a meter or other asset.Indicates whether - or not subscriptions are supported for this resource, and - whether or not conditional (thresholds) are supported. If not - specified, is "not subscribable" (0).""" - subclass = None - superclass = ReadingBase - def __init__(self, subscribable='0', localID=None): - self.original_tagname_ = None - super(Reading, self).__init__() - self.subscribable = _cast(None, subscribable) - self.localID = localID - def factory(*args_, **kwargs_): - if Reading.subclass: - return Reading.subclass(*args_, **kwargs_) - else: - return Reading(*args_, **kwargs_) - factory = staticmethod(factory) - def get_localID(self): return self.localID - def set_localID(self, localID): self.localID = localID - def get_subscribable(self): return self.subscribable - def set_subscribable(self, subscribable): self.subscribable = subscribable - def validate_HexBinary16(self, value): - # Validate type HexBinary16, a restriction on xs:hexBinary. - pass - def validate_SubscribableType(self, value): - # Validate type SubscribableType, a restriction on UInt8. - pass - def hasContent_(self): - if ( - self.localID is not None or - super(Reading, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Reading', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Reading') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Reading', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Reading'): - super(Reading, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Reading') - if self.subscribable is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - outfile.write(' subscribable=%s' % (quote_attrib(self.subscribable), )) - def exportChildren(self, outfile, level, namespace_='', name_='Reading', fromsubclass_=False, pretty_print=True): - super(Reading, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.localID is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slocalID>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.localID).encode(ExternalEncoding), input_name='localID'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Reading'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.subscribable is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - showIndent(outfile, level) - outfile.write('subscribable=%d,\n' % (self.subscribable,)) - super(Reading, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Reading, self).exportLiteralChildren(outfile, level, name_) - if self.localID is not None: - showIndent(outfile, level) - outfile.write('localID=%s,\n' % quote_python(self.localID).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('subscribable', node) - if value is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - self.subscribable = value - self.validate_SubscribableType(self.subscribable) # validate type SubscribableType - super(Reading, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'localID': - localID_ = child_.text - localID_ = self.gds_validate_string(localID_, node, 'localID') - self.localID = localID_ - self.validate_HexBinary16(self.localID) # validate type HexBinary16 - super(Reading, self).buildChildren(child_, node, nodeName_, True) -# end class Reading - - -class MeterReadingList(SubscribableList): - """A List element to hold MeterReading objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, MeterReading=None): - self.original_tagname_ = None - super(MeterReadingList, self).__init__() - if MeterReading is None: - self.MeterReading = [] - else: - self.MeterReading = MeterReading - def factory(*args_, **kwargs_): - if MeterReadingList.subclass: - return MeterReadingList.subclass(*args_, **kwargs_) - else: - return MeterReadingList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_MeterReading(self): return self.MeterReading - def set_MeterReading(self, MeterReading): self.MeterReading = MeterReading - def add_MeterReading(self, value): self.MeterReading.append(value) - def insert_MeterReading_at(self, index, value): self.MeterReading.insert(index, value) - def replace_MeterReading_at(self, index, value): self.MeterReading[index] = value - def hasContent_(self): - if ( - self.MeterReading or - super(MeterReadingList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MeterReadingList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReadingList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MeterReadingList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MeterReadingList'): - super(MeterReadingList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReadingList') - def exportChildren(self, outfile, level, namespace_='', name_='MeterReadingList', fromsubclass_=False, pretty_print=True): - super(MeterReadingList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for MeterReading_ in self.MeterReading: - MeterReading_.export(outfile, level, namespace_, name_='MeterReading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MeterReadingList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MeterReadingList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MeterReadingList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('MeterReading=[\n') - level += 1 - for MeterReading_ in self.MeterReading: - showIndent(outfile, level) - outfile.write('model_.MeterReading(\n') - MeterReading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MeterReadingList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'MeterReading': - obj_ = MeterReading.factory() - obj_.build(child_) - self.MeterReading.append(obj_) - obj_.original_tagname_ = 'MeterReading' - super(MeterReadingList, self).buildChildren(child_, node, nodeName_, True) -# end class MeterReadingList - - -class LoadShedAvailability(Resource): - """Indicates current consumption status and ability to shed load.""" - subclass = None - superclass = Resource - def __init__(self, availabilityDuration=None, DemandResponseProgramLink=None, sheddablePercent=None, sheddablePower=None): - self.original_tagname_ = None - super(LoadShedAvailability, self).__init__() - self.availabilityDuration = availabilityDuration - self.DemandResponseProgramLink = DemandResponseProgramLink - self.sheddablePercent = sheddablePercent - self.sheddablePower = sheddablePower - def factory(*args_, **kwargs_): - if LoadShedAvailability.subclass: - return LoadShedAvailability.subclass(*args_, **kwargs_) - else: - return LoadShedAvailability(*args_, **kwargs_) - factory = staticmethod(factory) - def get_availabilityDuration(self): return self.availabilityDuration - def set_availabilityDuration(self, availabilityDuration): self.availabilityDuration = availabilityDuration - def get_DemandResponseProgramLink(self): return self.DemandResponseProgramLink - def set_DemandResponseProgramLink(self, DemandResponseProgramLink): self.DemandResponseProgramLink = DemandResponseProgramLink - def get_sheddablePercent(self): return self.sheddablePercent - def set_sheddablePercent(self, sheddablePercent): self.sheddablePercent = sheddablePercent - def get_sheddablePower(self): return self.sheddablePower - def set_sheddablePower(self, sheddablePower): self.sheddablePower = sheddablePower - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def hasContent_(self): - if ( - self.availabilityDuration is not None or - self.DemandResponseProgramLink is not None or - self.sheddablePercent is not None or - self.sheddablePower is not None or - super(LoadShedAvailability, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LoadShedAvailability', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LoadShedAvailability') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LoadShedAvailability', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LoadShedAvailability'): - super(LoadShedAvailability, self).exportAttributes(outfile, level, already_processed, namespace_, name_='LoadShedAvailability') - def exportChildren(self, outfile, level, namespace_='', name_='LoadShedAvailability', fromsubclass_=False, pretty_print=True): - super(LoadShedAvailability, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.availabilityDuration is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%savailabilityDuration>%s%s' % (namespace_, self.gds_format_integer(self.availabilityDuration, input_name='availabilityDuration'), namespace_, eol_)) - if self.DemandResponseProgramLink is not None: - self.DemandResponseProgramLink.export(outfile, level, namespace_, name_='DemandResponseProgramLink', pretty_print=pretty_print) - if self.sheddablePercent is not None: - self.sheddablePercent.export(outfile, level, namespace_, name_='sheddablePercent', pretty_print=pretty_print) - if self.sheddablePower is not None: - self.sheddablePower.export(outfile, level, namespace_, name_='sheddablePower', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='LoadShedAvailability'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(LoadShedAvailability, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(LoadShedAvailability, self).exportLiteralChildren(outfile, level, name_) - if self.availabilityDuration is not None: - showIndent(outfile, level) - outfile.write('availabilityDuration=%d,\n' % self.availabilityDuration) - if self.DemandResponseProgramLink is not None: - showIndent(outfile, level) - outfile.write('DemandResponseProgramLink=model_.DemandResponseProgramLink(\n') - self.DemandResponseProgramLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.sheddablePercent is not None: - showIndent(outfile, level) - outfile.write('sheddablePercent=model_.PerCent(\n') - self.sheddablePercent.exportLiteral(outfile, level, name_='sheddablePercent') - showIndent(outfile, level) - outfile.write('),\n') - if self.sheddablePower is not None: - showIndent(outfile, level) - outfile.write('sheddablePower=model_.ActivePower(\n') - self.sheddablePower.exportLiteral(outfile, level, name_='sheddablePower') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(LoadShedAvailability, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'availabilityDuration': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'availabilityDuration') - self.availabilityDuration = ival_ - self.validate_UInt32(self.availabilityDuration) # validate type UInt32 - elif nodeName_ == 'DemandResponseProgramLink': - obj_ = DemandResponseProgramLink.factory() - obj_.build(child_) - self.DemandResponseProgramLink = obj_ - obj_.original_tagname_ = 'DemandResponseProgramLink' - elif nodeName_ == 'sheddablePercent': - obj_ = PerCent.factory() - obj_.build(child_) - self.sheddablePercent = obj_ - obj_.original_tagname_ = 'sheddablePercent' - elif nodeName_ == 'sheddablePower': - obj_ = ActivePower.factory() - obj_.build(child_) - self.sheddablePower = obj_ - obj_.original_tagname_ = 'sheddablePower' - super(LoadShedAvailability, self).buildChildren(child_, node, nodeName_, True) -# end class LoadShedAvailability - - -class EndDeviceControlList(SubscribableList): - """A List element to hold EndDeviceControl objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, EndDeviceControl=None): - self.original_tagname_ = None - super(EndDeviceControlList, self).__init__() - if EndDeviceControl is None: - self.EndDeviceControl = [] - else: - self.EndDeviceControl = EndDeviceControl - def factory(*args_, **kwargs_): - if EndDeviceControlList.subclass: - return EndDeviceControlList.subclass(*args_, **kwargs_) - else: - return EndDeviceControlList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_EndDeviceControl(self): return self.EndDeviceControl - def set_EndDeviceControl(self, EndDeviceControl): self.EndDeviceControl = EndDeviceControl - def add_EndDeviceControl(self, value): self.EndDeviceControl.append(value) - def insert_EndDeviceControl_at(self, index, value): self.EndDeviceControl.insert(index, value) - def replace_EndDeviceControl_at(self, index, value): self.EndDeviceControl[index] = value - def hasContent_(self): - if ( - self.EndDeviceControl or - super(EndDeviceControlList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EndDeviceControlList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceControlList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EndDeviceControlList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EndDeviceControlList'): - super(EndDeviceControlList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceControlList') - def exportChildren(self, outfile, level, namespace_='', name_='EndDeviceControlList', fromsubclass_=False, pretty_print=True): - super(EndDeviceControlList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for EndDeviceControl_ in self.EndDeviceControl: - EndDeviceControl_.export(outfile, level, namespace_, name_='EndDeviceControl', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='EndDeviceControlList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(EndDeviceControlList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(EndDeviceControlList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('EndDeviceControl=[\n') - level += 1 - for EndDeviceControl_ in self.EndDeviceControl: - showIndent(outfile, level) - outfile.write('model_.EndDeviceControl(\n') - EndDeviceControl_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(EndDeviceControlList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'EndDeviceControl': - obj_ = EndDeviceControl.factory() - obj_.build(child_) - self.EndDeviceControl.append(obj_) - obj_.original_tagname_ = 'EndDeviceControl' - super(EndDeviceControlList, self).buildChildren(child_, node, nodeName_, True) -# end class EndDeviceControlList - - -class EndDeviceControl(RandomizableEvent): - """Instructs an EndDevice to perform a specified action.""" - subclass = None - superclass = RandomizableEvent - def __init__(self, ApplianceLoadReduction=None, deviceCategory=None, drProgramMandatory=None, DutyCycle=None, loadShiftForward=None, Offset=None, overrideDuration=None, SetPoint=None, TargetReduction=None): - self.original_tagname_ = None - super(EndDeviceControl, self).__init__() - self.ApplianceLoadReduction = ApplianceLoadReduction - self.deviceCategory = deviceCategory - self.drProgramMandatory = drProgramMandatory - self.DutyCycle = DutyCycle - self.loadShiftForward = loadShiftForward - self.Offset = Offset - self.overrideDuration = overrideDuration - self.SetPoint = SetPoint - self.TargetReduction = TargetReduction - def factory(*args_, **kwargs_): - if EndDeviceControl.subclass: - return EndDeviceControl.subclass(*args_, **kwargs_) - else: - return EndDeviceControl(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ApplianceLoadReduction(self): return self.ApplianceLoadReduction - def set_ApplianceLoadReduction(self, ApplianceLoadReduction): self.ApplianceLoadReduction = ApplianceLoadReduction - def get_deviceCategory(self): return self.deviceCategory - def set_deviceCategory(self, deviceCategory): self.deviceCategory = deviceCategory - def get_drProgramMandatory(self): return self.drProgramMandatory - def set_drProgramMandatory(self, drProgramMandatory): self.drProgramMandatory = drProgramMandatory - def get_DutyCycle(self): return self.DutyCycle - def set_DutyCycle(self, DutyCycle): self.DutyCycle = DutyCycle - def get_loadShiftForward(self): return self.loadShiftForward - def set_loadShiftForward(self, loadShiftForward): self.loadShiftForward = loadShiftForward - def get_Offset(self): return self.Offset - def set_Offset(self, Offset): self.Offset = Offset - def get_overrideDuration(self): return self.overrideDuration - def set_overrideDuration(self, overrideDuration): self.overrideDuration = overrideDuration - def get_SetPoint(self): return self.SetPoint - def set_SetPoint(self, SetPoint): self.SetPoint = SetPoint - def get_TargetReduction(self): return self.TargetReduction - def set_TargetReduction(self, TargetReduction): self.TargetReduction = TargetReduction - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.ApplianceLoadReduction is not None or - self.deviceCategory is not None or - self.drProgramMandatory is not None or - self.DutyCycle is not None or - self.loadShiftForward is not None or - self.Offset is not None or - self.overrideDuration is not None or - self.SetPoint is not None or - self.TargetReduction is not None or - super(EndDeviceControl, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EndDeviceControl', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceControl') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EndDeviceControl', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EndDeviceControl'): - super(EndDeviceControl, self).exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceControl') - def exportChildren(self, outfile, level, namespace_='', name_='EndDeviceControl', fromsubclass_=False, pretty_print=True): - super(EndDeviceControl, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ApplianceLoadReduction is not None: - self.ApplianceLoadReduction.export(outfile, level, namespace_, name_='ApplianceLoadReduction', pretty_print=pretty_print) - if self.deviceCategory is not None: - self.deviceCategory.export(outfile, level, namespace_, name_='deviceCategory', pretty_print=pretty_print) - if self.drProgramMandatory is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdrProgramMandatory>%s%s' % (namespace_, self.gds_format_boolean(self.drProgramMandatory, input_name='drProgramMandatory'), namespace_, eol_)) - if self.DutyCycle is not None: - self.DutyCycle.export(outfile, level, namespace_, name_='DutyCycle', pretty_print=pretty_print) - if self.loadShiftForward is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sloadShiftForward>%s%s' % (namespace_, self.gds_format_boolean(self.loadShiftForward, input_name='loadShiftForward'), namespace_, eol_)) - if self.Offset is not None: - self.Offset.export(outfile, level, namespace_, name_='Offset', pretty_print=pretty_print) - if self.overrideDuration is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%soverrideDuration>%s%s' % (namespace_, self.gds_format_integer(self.overrideDuration, input_name='overrideDuration'), namespace_, eol_)) - if self.SetPoint is not None: - self.SetPoint.export(outfile, level, namespace_, name_='SetPoint', pretty_print=pretty_print) - if self.TargetReduction is not None: - self.TargetReduction.export(outfile, level, namespace_, name_='TargetReduction', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='EndDeviceControl'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(EndDeviceControl, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(EndDeviceControl, self).exportLiteralChildren(outfile, level, name_) - if self.ApplianceLoadReduction is not None: - showIndent(outfile, level) - outfile.write('ApplianceLoadReduction=model_.ApplianceLoadReduction(\n') - self.ApplianceLoadReduction.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.deviceCategory is not None: - showIndent(outfile, level) - outfile.write('deviceCategory=model_.DeviceCategoryType(\n') - self.deviceCategory.exportLiteral(outfile, level, name_='deviceCategory') - showIndent(outfile, level) - outfile.write('),\n') - if self.drProgramMandatory is not None: - showIndent(outfile, level) - outfile.write('drProgramMandatory=%s,\n' % self.drProgramMandatory) - if self.DutyCycle is not None: - showIndent(outfile, level) - outfile.write('DutyCycle=model_.DutyCycle(\n') - self.DutyCycle.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.loadShiftForward is not None: - showIndent(outfile, level) - outfile.write('loadShiftForward=%s,\n' % self.loadShiftForward) - if self.Offset is not None: - showIndent(outfile, level) - outfile.write('Offset=model_.Offset(\n') - self.Offset.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.overrideDuration is not None: - showIndent(outfile, level) - outfile.write('overrideDuration=%d,\n' % self.overrideDuration) - if self.SetPoint is not None: - showIndent(outfile, level) - outfile.write('SetPoint=model_.SetPoint(\n') - self.SetPoint.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.TargetReduction is not None: - showIndent(outfile, level) - outfile.write('TargetReduction=model_.TargetReduction(\n') - self.TargetReduction.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(EndDeviceControl, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ApplianceLoadReduction': - obj_ = ApplianceLoadReduction.factory() - obj_.build(child_) - self.ApplianceLoadReduction = obj_ - obj_.original_tagname_ = 'ApplianceLoadReduction' - elif nodeName_ == 'deviceCategory': - obj_ = DeviceCategoryType.factory() - obj_.build(child_) - self.deviceCategory = obj_ - obj_.original_tagname_ = 'deviceCategory' - elif nodeName_ == 'drProgramMandatory': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'drProgramMandatory') - self.drProgramMandatory = ival_ - elif nodeName_ == 'DutyCycle': - obj_ = DutyCycle.factory() - obj_.build(child_) - self.DutyCycle = obj_ - obj_.original_tagname_ = 'DutyCycle' - elif nodeName_ == 'loadShiftForward': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'loadShiftForward') - self.loadShiftForward = ival_ - elif nodeName_ == 'Offset': - obj_ = Offset.factory() - obj_.build(child_) - self.Offset = obj_ - obj_.original_tagname_ = 'Offset' - elif nodeName_ == 'overrideDuration': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'overrideDuration') - self.overrideDuration = ival_ - self.validate_UInt16(self.overrideDuration) # validate type UInt16 - elif nodeName_ == 'SetPoint': - obj_ = SetPoint.factory() - obj_.build(child_) - self.SetPoint = obj_ - obj_.original_tagname_ = 'SetPoint' - elif nodeName_ == 'TargetReduction': - obj_ = TargetReduction.factory() - obj_.build(child_) - self.TargetReduction = obj_ - obj_.original_tagname_ = 'TargetReduction' - super(EndDeviceControl, self).buildChildren(child_, node, nodeName_, True) -# end class EndDeviceControl - - -class DemandResponseProgramList(SubscribableList): - """A List element to hold DemandResponseProgram objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, DemandResponseProgram=None): - self.original_tagname_ = None - super(DemandResponseProgramList, self).__init__() - if DemandResponseProgram is None: - self.DemandResponseProgram = [] - else: - self.DemandResponseProgram = DemandResponseProgram - def factory(*args_, **kwargs_): - if DemandResponseProgramList.subclass: - return DemandResponseProgramList.subclass(*args_, **kwargs_) - else: - return DemandResponseProgramList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DemandResponseProgram(self): return self.DemandResponseProgram - def set_DemandResponseProgram(self, DemandResponseProgram): self.DemandResponseProgram = DemandResponseProgram - def add_DemandResponseProgram(self, value): self.DemandResponseProgram.append(value) - def insert_DemandResponseProgram_at(self, index, value): self.DemandResponseProgram.insert(index, value) - def replace_DemandResponseProgram_at(self, index, value): self.DemandResponseProgram[index] = value - def hasContent_(self): - if ( - self.DemandResponseProgram or - super(DemandResponseProgramList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DemandResponseProgramList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DemandResponseProgramList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DemandResponseProgramList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DemandResponseProgramList'): - super(DemandResponseProgramList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DemandResponseProgramList') - def exportChildren(self, outfile, level, namespace_='', name_='DemandResponseProgramList', fromsubclass_=False, pretty_print=True): - super(DemandResponseProgramList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for DemandResponseProgram_ in self.DemandResponseProgram: - DemandResponseProgram_.export(outfile, level, namespace_, name_='DemandResponseProgram', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DemandResponseProgramList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DemandResponseProgramList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DemandResponseProgramList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('DemandResponseProgram=[\n') - level += 1 - for DemandResponseProgram_ in self.DemandResponseProgram: - showIndent(outfile, level) - outfile.write('model_.DemandResponseProgram(\n') - DemandResponseProgram_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DemandResponseProgramList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DemandResponseProgram': - obj_ = DemandResponseProgram.factory() - obj_.build(child_) - self.DemandResponseProgram.append(obj_) - obj_.original_tagname_ = 'DemandResponseProgram' - super(DemandResponseProgramList, self).buildChildren(child_, node, nodeName_, True) -# end class DemandResponseProgramList - - -class DemandResponseProgram(IdentifiedObject): - """Demand response program.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, ActiveEndDeviceControlListLink=None, availabilityUpdatePercentChangeThreshold=None, availabilityUpdatePowerChangeThreshold=None, EndDeviceControlListLink=None, primacy=None): - self.original_tagname_ = None - super(DemandResponseProgram, self).__init__() - self.ActiveEndDeviceControlListLink = ActiveEndDeviceControlListLink - self.availabilityUpdatePercentChangeThreshold = availabilityUpdatePercentChangeThreshold - self.availabilityUpdatePowerChangeThreshold = availabilityUpdatePowerChangeThreshold - self.EndDeviceControlListLink = EndDeviceControlListLink - self.primacy = primacy - def factory(*args_, **kwargs_): - if DemandResponseProgram.subclass: - return DemandResponseProgram.subclass(*args_, **kwargs_) - else: - return DemandResponseProgram(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ActiveEndDeviceControlListLink(self): return self.ActiveEndDeviceControlListLink - def set_ActiveEndDeviceControlListLink(self, ActiveEndDeviceControlListLink): self.ActiveEndDeviceControlListLink = ActiveEndDeviceControlListLink - def get_availabilityUpdatePercentChangeThreshold(self): return self.availabilityUpdatePercentChangeThreshold - def set_availabilityUpdatePercentChangeThreshold(self, availabilityUpdatePercentChangeThreshold): self.availabilityUpdatePercentChangeThreshold = availabilityUpdatePercentChangeThreshold - def get_availabilityUpdatePowerChangeThreshold(self): return self.availabilityUpdatePowerChangeThreshold - def set_availabilityUpdatePowerChangeThreshold(self, availabilityUpdatePowerChangeThreshold): self.availabilityUpdatePowerChangeThreshold = availabilityUpdatePowerChangeThreshold - def get_EndDeviceControlListLink(self): return self.EndDeviceControlListLink - def set_EndDeviceControlListLink(self, EndDeviceControlListLink): self.EndDeviceControlListLink = EndDeviceControlListLink - def get_primacy(self): return self.primacy - def set_primacy(self, primacy): self.primacy = primacy - def hasContent_(self): - if ( - self.ActiveEndDeviceControlListLink is not None or - self.availabilityUpdatePercentChangeThreshold is not None or - self.availabilityUpdatePowerChangeThreshold is not None or - self.EndDeviceControlListLink is not None or - self.primacy is not None or - super(DemandResponseProgram, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DemandResponseProgram', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DemandResponseProgram') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DemandResponseProgram', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DemandResponseProgram'): - super(DemandResponseProgram, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DemandResponseProgram') - def exportChildren(self, outfile, level, namespace_='', name_='DemandResponseProgram', fromsubclass_=False, pretty_print=True): - super(DemandResponseProgram, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ActiveEndDeviceControlListLink is not None: - self.ActiveEndDeviceControlListLink.export(outfile, level, namespace_, name_='ActiveEndDeviceControlListLink', pretty_print=pretty_print) - if self.availabilityUpdatePercentChangeThreshold is not None: - self.availabilityUpdatePercentChangeThreshold.export(outfile, level, namespace_, name_='availabilityUpdatePercentChangeThreshold', pretty_print=pretty_print) - if self.availabilityUpdatePowerChangeThreshold is not None: - self.availabilityUpdatePowerChangeThreshold.export(outfile, level, namespace_, name_='availabilityUpdatePowerChangeThreshold', pretty_print=pretty_print) - if self.EndDeviceControlListLink is not None: - self.EndDeviceControlListLink.export(outfile, level, namespace_, name_='EndDeviceControlListLink', pretty_print=pretty_print) - if self.primacy is not None: - self.primacy.export(outfile, level, namespace_, name_='primacy', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DemandResponseProgram'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DemandResponseProgram, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DemandResponseProgram, self).exportLiteralChildren(outfile, level, name_) - if self.ActiveEndDeviceControlListLink is not None: - showIndent(outfile, level) - outfile.write('ActiveEndDeviceControlListLink=model_.ActiveEndDeviceControlListLink(\n') - self.ActiveEndDeviceControlListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.availabilityUpdatePercentChangeThreshold is not None: - showIndent(outfile, level) - outfile.write('availabilityUpdatePercentChangeThreshold=model_.PerCent(\n') - self.availabilityUpdatePercentChangeThreshold.exportLiteral(outfile, level, name_='availabilityUpdatePercentChangeThreshold') - showIndent(outfile, level) - outfile.write('),\n') - if self.availabilityUpdatePowerChangeThreshold is not None: - showIndent(outfile, level) - outfile.write('availabilityUpdatePowerChangeThreshold=model_.ActivePower(\n') - self.availabilityUpdatePowerChangeThreshold.exportLiteral(outfile, level, name_='availabilityUpdatePowerChangeThreshold') - showIndent(outfile, level) - outfile.write('),\n') - if self.EndDeviceControlListLink is not None: - showIndent(outfile, level) - outfile.write('EndDeviceControlListLink=model_.EndDeviceControlListLink(\n') - self.EndDeviceControlListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.primacy is not None: - showIndent(outfile, level) - outfile.write('primacy=model_.PrimacyType(\n') - self.primacy.exportLiteral(outfile, level, name_='primacy') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DemandResponseProgram, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ActiveEndDeviceControlListLink': - obj_ = ActiveEndDeviceControlListLink.factory() - obj_.build(child_) - self.ActiveEndDeviceControlListLink = obj_ - obj_.original_tagname_ = 'ActiveEndDeviceControlListLink' - elif nodeName_ == 'availabilityUpdatePercentChangeThreshold': - obj_ = PerCent.factory() - obj_.build(child_) - self.availabilityUpdatePercentChangeThreshold = obj_ - obj_.original_tagname_ = 'availabilityUpdatePercentChangeThreshold' - elif nodeName_ == 'availabilityUpdatePowerChangeThreshold': - obj_ = ActivePower.factory() - obj_.build(child_) - self.availabilityUpdatePowerChangeThreshold = obj_ - obj_.original_tagname_ = 'availabilityUpdatePowerChangeThreshold' - elif nodeName_ == 'EndDeviceControlListLink': - obj_ = EndDeviceControlListLink.factory() - obj_.build(child_) - self.EndDeviceControlListLink = obj_ - obj_.original_tagname_ = 'EndDeviceControlListLink' - elif nodeName_ == 'primacy': - obj_ = PrimacyType.factory() - obj_.build(child_) - self.primacy = obj_ - obj_.original_tagname_ = 'primacy' - super(DemandResponseProgram, self).buildChildren(child_, node, nodeName_, True) -# end class DemandResponseProgram - - -class FileStatus(Resource): - """This object provides status of device file load and activation - operations.""" - subclass = None - superclass = Resource - def __init__(self, activateTime=None, FileLink=None, loadPercent=None, nextRequestAttempt=None, request503Count=None, requestFailCount=None, status=None, statusTime=None): - self.original_tagname_ = None - super(FileStatus, self).__init__() - self.activateTime = activateTime - self.FileLink = FileLink - self.loadPercent = loadPercent - self.nextRequestAttempt = nextRequestAttempt - self.request503Count = request503Count - self.requestFailCount = requestFailCount - self.status = status - self.statusTime = statusTime - def factory(*args_, **kwargs_): - if FileStatus.subclass: - return FileStatus.subclass(*args_, **kwargs_) - else: - return FileStatus(*args_, **kwargs_) - factory = staticmethod(factory) - def get_activateTime(self): return self.activateTime - def set_activateTime(self, activateTime): self.activateTime = activateTime - def get_FileLink(self): return self.FileLink - def set_FileLink(self, FileLink): self.FileLink = FileLink - def get_loadPercent(self): return self.loadPercent - def set_loadPercent(self, loadPercent): self.loadPercent = loadPercent - def get_nextRequestAttempt(self): return self.nextRequestAttempt - def set_nextRequestAttempt(self, nextRequestAttempt): self.nextRequestAttempt = nextRequestAttempt - def get_request503Count(self): return self.request503Count - def set_request503Count(self, request503Count): self.request503Count = request503Count - def get_requestFailCount(self): return self.requestFailCount - def set_requestFailCount(self, requestFailCount): self.requestFailCount = requestFailCount - def get_status(self): return self.status - def set_status(self, status): self.status = status - def get_statusTime(self): return self.statusTime - def set_statusTime(self, statusTime): self.statusTime = statusTime - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.activateTime is not None or - self.FileLink is not None or - self.loadPercent is not None or - self.nextRequestAttempt is not None or - self.request503Count is not None or - self.requestFailCount is not None or - self.status is not None or - self.statusTime is not None or - super(FileStatus, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FileStatus', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FileStatus') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FileStatus', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FileStatus'): - super(FileStatus, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FileStatus') - def exportChildren(self, outfile, level, namespace_='', name_='FileStatus', fromsubclass_=False, pretty_print=True): - super(FileStatus, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.activateTime is not None: - self.activateTime.export(outfile, level, namespace_, name_='activateTime', pretty_print=pretty_print) - if self.FileLink is not None: - self.FileLink.export(outfile, level, namespace_, name_='FileLink', pretty_print=pretty_print) - if self.loadPercent is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sloadPercent>%s%s' % (namespace_, self.gds_format_integer(self.loadPercent, input_name='loadPercent'), namespace_, eol_)) - if self.nextRequestAttempt is not None: - self.nextRequestAttempt.export(outfile, level, namespace_, name_='nextRequestAttempt', pretty_print=pretty_print) - if self.request503Count is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srequest503Count>%s%s' % (namespace_, self.gds_format_integer(self.request503Count, input_name='request503Count'), namespace_, eol_)) - if self.requestFailCount is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srequestFailCount>%s%s' % (namespace_, self.gds_format_integer(self.requestFailCount, input_name='requestFailCount'), namespace_, eol_)) - if self.status is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sstatus>%s%s' % (namespace_, self.gds_format_integer(self.status, input_name='status'), namespace_, eol_)) - if self.statusTime is not None: - self.statusTime.export(outfile, level, namespace_, name_='statusTime', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FileStatus'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FileStatus, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FileStatus, self).exportLiteralChildren(outfile, level, name_) - if self.activateTime is not None: - showIndent(outfile, level) - outfile.write('activateTime=model_.TimeType(\n') - self.activateTime.exportLiteral(outfile, level, name_='activateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.FileLink is not None: - showIndent(outfile, level) - outfile.write('FileLink=model_.FileLink(\n') - self.FileLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.loadPercent is not None: - showIndent(outfile, level) - outfile.write('loadPercent=%d,\n' % self.loadPercent) - if self.nextRequestAttempt is not None: - showIndent(outfile, level) - outfile.write('nextRequestAttempt=model_.TimeType(\n') - self.nextRequestAttempt.exportLiteral(outfile, level, name_='nextRequestAttempt') - showIndent(outfile, level) - outfile.write('),\n') - if self.request503Count is not None: - showIndent(outfile, level) - outfile.write('request503Count=%d,\n' % self.request503Count) - if self.requestFailCount is not None: - showIndent(outfile, level) - outfile.write('requestFailCount=%d,\n' % self.requestFailCount) - if self.status is not None: - showIndent(outfile, level) - outfile.write('status=%d,\n' % self.status) - if self.statusTime is not None: - showIndent(outfile, level) - outfile.write('statusTime=model_.TimeType(\n') - self.statusTime.exportLiteral(outfile, level, name_='statusTime') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FileStatus, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'activateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.activateTime = obj_ - obj_.original_tagname_ = 'activateTime' - elif nodeName_ == 'FileLink': - obj_ = FileLink.factory() - obj_.build(child_) - self.FileLink = obj_ - obj_.original_tagname_ = 'FileLink' - elif nodeName_ == 'loadPercent': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'loadPercent') - self.loadPercent = ival_ - self.validate_UInt8(self.loadPercent) # validate type UInt8 - elif nodeName_ == 'nextRequestAttempt': - obj_ = TimeType.factory() - obj_.build(child_) - self.nextRequestAttempt = obj_ - obj_.original_tagname_ = 'nextRequestAttempt' - elif nodeName_ == 'request503Count': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'request503Count') - self.request503Count = ival_ - self.validate_UInt16(self.request503Count) # validate type UInt16 - elif nodeName_ == 'requestFailCount': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'requestFailCount') - self.requestFailCount = ival_ - self.validate_UInt16(self.requestFailCount) # validate type UInt16 - elif nodeName_ == 'status': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'status') - self.status = ival_ - self.validate_UInt8(self.status) # validate type UInt8 - elif nodeName_ == 'statusTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.statusTime = obj_ - obj_.original_tagname_ = 'statusTime' - super(FileStatus, self).buildChildren(child_, node, nodeName_, True) -# end class FileStatus - - -class FileList(List): - """A List element to hold File objects.""" - subclass = None - superclass = List - def __init__(self, File=None): - self.original_tagname_ = None - super(FileList, self).__init__() - if File is None: - self.File = [] - else: - self.File = File - def factory(*args_, **kwargs_): - if FileList.subclass: - return FileList.subclass(*args_, **kwargs_) - else: - return FileList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_File(self): return self.File - def set_File(self, File): self.File = File - def add_File(self, value): self.File.append(value) - def insert_File_at(self, index, value): self.File.insert(index, value) - def replace_File_at(self, index, value): self.File[index] = value - def hasContent_(self): - if ( - self.File or - super(FileList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FileList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FileList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FileList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FileList'): - super(FileList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FileList') - def exportChildren(self, outfile, level, namespace_='', name_='FileList', fromsubclass_=False, pretty_print=True): - super(FileList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for File_ in self.File: - File_.export(outfile, level, namespace_, name_='File', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FileList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FileList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FileList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('File=[\n') - level += 1 - for File_ in self.File: - showIndent(outfile, level) - outfile.write('model_.File(\n') - File_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FileList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'File': - obj_ = File.factory() - obj_.build(child_) - self.File.append(obj_) - obj_.original_tagname_ = 'File' - super(FileList, self).buildChildren(child_, node, nodeName_, True) -# end class FileList - - -class File(Resource): - """This resource contains various meta-data describing a file's - characteristics. The meta-data provides general file information - and also is used to support filtered queries of file lists""" - subclass = None - superclass = Resource - def __init__(self, activateTime=None, fileURI=None, lFDI=None, mfHwVer=None, mfID=None, mfModel=None, mfSerNum=None, mfVer=None, size=None, type_=None): - self.original_tagname_ = None - super(File, self).__init__() - self.activateTime = activateTime - self.fileURI = fileURI - self.lFDI = lFDI - self.mfHwVer = mfHwVer - self.mfID = mfID - self.mfModel = mfModel - self.mfSerNum = mfSerNum - self.mfVer = mfVer - self.size = size - self.type_ = type_ - def factory(*args_, **kwargs_): - if File.subclass: - return File.subclass(*args_, **kwargs_) - else: - return File(*args_, **kwargs_) - factory = staticmethod(factory) - def get_activateTime(self): return self.activateTime - def set_activateTime(self, activateTime): self.activateTime = activateTime - def get_fileURI(self): return self.fileURI - def set_fileURI(self, fileURI): self.fileURI = fileURI - def get_lFDI(self): return self.lFDI - def set_lFDI(self, lFDI): self.lFDI = lFDI - def get_mfHwVer(self): return self.mfHwVer - def set_mfHwVer(self, mfHwVer): self.mfHwVer = mfHwVer - def get_mfID(self): return self.mfID - def set_mfID(self, mfID): self.mfID = mfID - def get_mfModel(self): return self.mfModel - def set_mfModel(self, mfModel): self.mfModel = mfModel - def get_mfSerNum(self): return self.mfSerNum - def set_mfSerNum(self, mfSerNum): self.mfSerNum = mfSerNum - def get_mfVer(self): return self.mfVer - def set_mfVer(self, mfVer): self.mfVer = mfVer - def get_size(self): return self.size - def set_size(self, size): self.size = size - def get_type(self): return self.type_ - def set_type(self, type_): self.type_ = type_ - def validate_HexBinary160(self, value): - # Validate type HexBinary160, a restriction on xs:hexBinary. - pass - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def validate_String16(self, value): - # Validate type String16, a restriction on xs:string. - pass - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def validate_HexBinary16(self, value): - # Validate type HexBinary16, a restriction on xs:hexBinary. - pass - def hasContent_(self): - if ( - self.activateTime is not None or - self.fileURI is not None or - self.lFDI is not None or - self.mfHwVer is not None or - self.mfID is not None or - self.mfModel is not None or - self.mfSerNum is not None or - self.mfVer is not None or - self.size is not None or - self.type_ is not None or - super(File, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='File', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='File') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='File', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='File'): - super(File, self).exportAttributes(outfile, level, already_processed, namespace_, name_='File') - def exportChildren(self, outfile, level, namespace_='', name_='File', fromsubclass_=False, pretty_print=True): - super(File, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.activateTime is not None: - self.activateTime.export(outfile, level, namespace_, name_='activateTime', pretty_print=pretty_print) - if self.fileURI is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sfileURI>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.fileURI).encode(ExternalEncoding), input_name='fileURI'), namespace_, eol_)) - if self.lFDI is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slFDI>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.lFDI).encode(ExternalEncoding), input_name='lFDI'), namespace_, eol_)) - if self.mfHwVer is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smfHwVer>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mfHwVer).encode(ExternalEncoding), input_name='mfHwVer'), namespace_, eol_)) - if self.mfID is not None: - self.mfID.export(outfile, level, namespace_, name_='mfID', pretty_print=pretty_print) - if self.mfModel is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smfModel>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mfModel).encode(ExternalEncoding), input_name='mfModel'), namespace_, eol_)) - if self.mfSerNum is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smfSerNum>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mfSerNum).encode(ExternalEncoding), input_name='mfSerNum'), namespace_, eol_)) - if self.mfVer is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smfVer>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mfVer).encode(ExternalEncoding), input_name='mfVer'), namespace_, eol_)) - if self.size is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssize>%s%s' % (namespace_, self.gds_format_integer(self.size, input_name='size'), namespace_, eol_)) - if self.type_ is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%stype>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.type_).encode(ExternalEncoding), input_name='type'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='File'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(File, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(File, self).exportLiteralChildren(outfile, level, name_) - if self.activateTime is not None: - showIndent(outfile, level) - outfile.write('activateTime=model_.TimeType(\n') - self.activateTime.exportLiteral(outfile, level, name_='activateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.fileURI is not None: - showIndent(outfile, level) - outfile.write('fileURI=%s,\n' % quote_python(self.fileURI).encode(ExternalEncoding)) - if self.lFDI is not None: - showIndent(outfile, level) - outfile.write('lFDI=%s,\n' % quote_python(self.lFDI).encode(ExternalEncoding)) - if self.mfHwVer is not None: - showIndent(outfile, level) - outfile.write('mfHwVer=%s,\n' % quote_python(self.mfHwVer).encode(ExternalEncoding)) - if self.mfID is not None: - showIndent(outfile, level) - outfile.write('mfID=model_.PENType(\n') - self.mfID.exportLiteral(outfile, level, name_='mfID') - showIndent(outfile, level) - outfile.write('),\n') - if self.mfModel is not None: - showIndent(outfile, level) - outfile.write('mfModel=%s,\n' % quote_python(self.mfModel).encode(ExternalEncoding)) - if self.mfSerNum is not None: - showIndent(outfile, level) - outfile.write('mfSerNum=%s,\n' % quote_python(self.mfSerNum).encode(ExternalEncoding)) - if self.mfVer is not None: - showIndent(outfile, level) - outfile.write('mfVer=%s,\n' % quote_python(self.mfVer).encode(ExternalEncoding)) - if self.size is not None: - showIndent(outfile, level) - outfile.write('size=%d,\n' % self.size) - if self.type_ is not None: - showIndent(outfile, level) - outfile.write('type_=%s,\n' % quote_python(self.type_).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(File, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'activateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.activateTime = obj_ - obj_.original_tagname_ = 'activateTime' - elif nodeName_ == 'fileURI': - fileURI_ = child_.text - fileURI_ = self.gds_validate_string(fileURI_, node, 'fileURI') - self.fileURI = fileURI_ - elif nodeName_ == 'lFDI': - lFDI_ = child_.text - lFDI_ = self.gds_validate_string(lFDI_, node, 'lFDI') - self.lFDI = lFDI_ - self.validate_HexBinary160(self.lFDI) # validate type HexBinary160 - elif nodeName_ == 'mfHwVer': - mfHwVer_ = child_.text - mfHwVer_ = self.gds_validate_string(mfHwVer_, node, 'mfHwVer') - self.mfHwVer = mfHwVer_ - self.validate_String32(self.mfHwVer) # validate type String32 - elif nodeName_ == 'mfID': - obj_ = PENType.factory() - obj_.build(child_) - self.mfID = obj_ - obj_.original_tagname_ = 'mfID' - elif nodeName_ == 'mfModel': - mfModel_ = child_.text - mfModel_ = self.gds_validate_string(mfModel_, node, 'mfModel') - self.mfModel = mfModel_ - self.validate_String32(self.mfModel) # validate type String32 - elif nodeName_ == 'mfSerNum': - mfSerNum_ = child_.text - mfSerNum_ = self.gds_validate_string(mfSerNum_, node, 'mfSerNum') - self.mfSerNum = mfSerNum_ - self.validate_String32(self.mfSerNum) # validate type String32 - elif nodeName_ == 'mfVer': - mfVer_ = child_.text - mfVer_ = self.gds_validate_string(mfVer_, node, 'mfVer') - self.mfVer = mfVer_ - self.validate_String16(self.mfVer) # validate type String16 - elif nodeName_ == 'size': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'size') - self.size = ival_ - self.validate_UInt32(self.size) # validate type UInt32 - elif nodeName_ == 'type': - type_ = child_.text - type_ = self.gds_validate_string(type_, node, 'type') - self.type_ = type_ - self.validate_HexBinary16(self.type_) # validate type HexBinary16 - super(File, self).buildChildren(child_, node, nodeName_, True) -# end class File - - -class PriceResponseCfgList(List): - """A List element to hold PriceResponseCfg objects.""" - subclass = None - superclass = List - def __init__(self, PriceResponseCfg=None): - self.original_tagname_ = None - super(PriceResponseCfgList, self).__init__() - if PriceResponseCfg is None: - self.PriceResponseCfg = [] - else: - self.PriceResponseCfg = PriceResponseCfg - def factory(*args_, **kwargs_): - if PriceResponseCfgList.subclass: - return PriceResponseCfgList.subclass(*args_, **kwargs_) - else: - return PriceResponseCfgList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_PriceResponseCfg(self): return self.PriceResponseCfg - def set_PriceResponseCfg(self, PriceResponseCfg): self.PriceResponseCfg = PriceResponseCfg - def add_PriceResponseCfg(self, value): self.PriceResponseCfg.append(value) - def insert_PriceResponseCfg_at(self, index, value): self.PriceResponseCfg.insert(index, value) - def replace_PriceResponseCfg_at(self, index, value): self.PriceResponseCfg[index] = value - def hasContent_(self): - if ( - self.PriceResponseCfg or - super(PriceResponseCfgList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PriceResponseCfgList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PriceResponseCfgList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PriceResponseCfgList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PriceResponseCfgList'): - super(PriceResponseCfgList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PriceResponseCfgList') - def exportChildren(self, outfile, level, namespace_='', name_='PriceResponseCfgList', fromsubclass_=False, pretty_print=True): - super(PriceResponseCfgList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for PriceResponseCfg_ in self.PriceResponseCfg: - PriceResponseCfg_.export(outfile, level, namespace_, name_='PriceResponseCfg', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='PriceResponseCfgList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PriceResponseCfgList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PriceResponseCfgList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('PriceResponseCfg=[\n') - level += 1 - for PriceResponseCfg_ in self.PriceResponseCfg: - showIndent(outfile, level) - outfile.write('model_.PriceResponseCfg(\n') - PriceResponseCfg_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PriceResponseCfgList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'PriceResponseCfg': - obj_ = PriceResponseCfg.factory() - obj_.build(child_) - self.PriceResponseCfg.append(obj_) - obj_.original_tagname_ = 'PriceResponseCfg' - super(PriceResponseCfgList, self).buildChildren(child_, node, nodeName_, True) -# end class PriceResponseCfgList - - -class PriceResponseCfg(Resource): - """Configuration data that specifies how price responsive devices - SHOULD respond to price changes while acting upon a given - RateComponent.""" - subclass = None - superclass = Resource - def __init__(self, consumeThreshold=None, maxReductionThreshold=None, RateComponentLink=None): - self.original_tagname_ = None - super(PriceResponseCfg, self).__init__() - self.consumeThreshold = consumeThreshold - self.maxReductionThreshold = maxReductionThreshold - self.RateComponentLink = RateComponentLink - def factory(*args_, **kwargs_): - if PriceResponseCfg.subclass: - return PriceResponseCfg.subclass(*args_, **kwargs_) - else: - return PriceResponseCfg(*args_, **kwargs_) - factory = staticmethod(factory) - def get_consumeThreshold(self): return self.consumeThreshold - def set_consumeThreshold(self, consumeThreshold): self.consumeThreshold = consumeThreshold - def get_maxReductionThreshold(self): return self.maxReductionThreshold - def set_maxReductionThreshold(self, maxReductionThreshold): self.maxReductionThreshold = maxReductionThreshold - def get_RateComponentLink(self): return self.RateComponentLink - def set_RateComponentLink(self, RateComponentLink): self.RateComponentLink = RateComponentLink - def validate_Int32(self, value): - # Validate type Int32, a restriction on xs:int. - pass - def hasContent_(self): - if ( - self.consumeThreshold is not None or - self.maxReductionThreshold is not None or - self.RateComponentLink is not None or - super(PriceResponseCfg, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PriceResponseCfg', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PriceResponseCfg') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PriceResponseCfg', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PriceResponseCfg'): - super(PriceResponseCfg, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PriceResponseCfg') - def exportChildren(self, outfile, level, namespace_='', name_='PriceResponseCfg', fromsubclass_=False, pretty_print=True): - super(PriceResponseCfg, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.consumeThreshold is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sconsumeThreshold>%s%s' % (namespace_, self.gds_format_integer(self.consumeThreshold, input_name='consumeThreshold'), namespace_, eol_)) - if self.maxReductionThreshold is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smaxReductionThreshold>%s%s' % (namespace_, self.gds_format_integer(self.maxReductionThreshold, input_name='maxReductionThreshold'), namespace_, eol_)) - if self.RateComponentLink is not None: - self.RateComponentLink.export(outfile, level, namespace_, name_='RateComponentLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='PriceResponseCfg'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PriceResponseCfg, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PriceResponseCfg, self).exportLiteralChildren(outfile, level, name_) - if self.consumeThreshold is not None: - showIndent(outfile, level) - outfile.write('consumeThreshold=%d,\n' % self.consumeThreshold) - if self.maxReductionThreshold is not None: - showIndent(outfile, level) - outfile.write('maxReductionThreshold=%d,\n' % self.maxReductionThreshold) - if self.RateComponentLink is not None: - showIndent(outfile, level) - outfile.write('RateComponentLink=model_.RateComponentLink(\n') - self.RateComponentLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PriceResponseCfg, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'consumeThreshold': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'consumeThreshold') - self.consumeThreshold = ival_ - self.validate_Int32(self.consumeThreshold) # validate type Int32 - elif nodeName_ == 'maxReductionThreshold': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'maxReductionThreshold') - self.maxReductionThreshold = ival_ - self.validate_Int32(self.maxReductionThreshold) # validate type Int32 - elif nodeName_ == 'RateComponentLink': - obj_ = RateComponentLink.factory() - obj_.build(child_) - self.RateComponentLink = obj_ - obj_.original_tagname_ = 'RateComponentLink' - super(PriceResponseCfg, self).buildChildren(child_, node, nodeName_, True) -# end class PriceResponseCfg - - -class Configuration(SubscribableResource): - """This resource contains various settings to control the operation of - the device""" - subclass = None - superclass = SubscribableResource - def __init__(self, currentLocale=None, PowerConfiguration=None, PriceResponseCfgListLink=None, TimeConfiguration=None, userDeviceName=None): - self.original_tagname_ = None - super(Configuration, self).__init__() - self.currentLocale = currentLocale - self.PowerConfiguration = PowerConfiguration - self.PriceResponseCfgListLink = PriceResponseCfgListLink - self.TimeConfiguration = TimeConfiguration - self.userDeviceName = userDeviceName - def factory(*args_, **kwargs_): - if Configuration.subclass: - return Configuration.subclass(*args_, **kwargs_) - else: - return Configuration(*args_, **kwargs_) - factory = staticmethod(factory) - def get_currentLocale(self): return self.currentLocale - def set_currentLocale(self, currentLocale): self.currentLocale = currentLocale - def get_PowerConfiguration(self): return self.PowerConfiguration - def set_PowerConfiguration(self, PowerConfiguration): self.PowerConfiguration = PowerConfiguration - def get_PriceResponseCfgListLink(self): return self.PriceResponseCfgListLink - def set_PriceResponseCfgListLink(self, PriceResponseCfgListLink): self.PriceResponseCfgListLink = PriceResponseCfgListLink - def get_TimeConfiguration(self): return self.TimeConfiguration - def set_TimeConfiguration(self, TimeConfiguration): self.TimeConfiguration = TimeConfiguration - def get_userDeviceName(self): return self.userDeviceName - def set_userDeviceName(self, userDeviceName): self.userDeviceName = userDeviceName - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.currentLocale is not None or - self.PowerConfiguration is not None or - self.PriceResponseCfgListLink is not None or - self.TimeConfiguration is not None or - self.userDeviceName is not None or - super(Configuration, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Configuration', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Configuration') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Configuration', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Configuration'): - super(Configuration, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Configuration') - def exportChildren(self, outfile, level, namespace_='', name_='Configuration', fromsubclass_=False, pretty_print=True): - super(Configuration, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.currentLocale is not None: - self.currentLocale.export(outfile, level, namespace_, name_='currentLocale', pretty_print=pretty_print) - if self.PowerConfiguration is not None: - self.PowerConfiguration.export(outfile, level, namespace_, name_='PowerConfiguration', pretty_print=pretty_print) - if self.PriceResponseCfgListLink is not None: - self.PriceResponseCfgListLink.export(outfile, level, namespace_, name_='PriceResponseCfgListLink', pretty_print=pretty_print) - if self.TimeConfiguration is not None: - self.TimeConfiguration.export(outfile, level, namespace_, name_='TimeConfiguration', pretty_print=pretty_print) - if self.userDeviceName is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%suserDeviceName>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.userDeviceName).encode(ExternalEncoding), input_name='userDeviceName'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Configuration'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Configuration, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Configuration, self).exportLiteralChildren(outfile, level, name_) - if self.currentLocale is not None: - showIndent(outfile, level) - outfile.write('currentLocale=model_.LocaleType(\n') - self.currentLocale.exportLiteral(outfile, level, name_='currentLocale') - showIndent(outfile, level) - outfile.write('),\n') - if self.PowerConfiguration is not None: - showIndent(outfile, level) - outfile.write('PowerConfiguration=model_.PowerConfiguration(\n') - self.PowerConfiguration.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.PriceResponseCfgListLink is not None: - showIndent(outfile, level) - outfile.write('PriceResponseCfgListLink=model_.PriceResponseCfgListLink(\n') - self.PriceResponseCfgListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.TimeConfiguration is not None: - showIndent(outfile, level) - outfile.write('TimeConfiguration=model_.TimeConfiguration(\n') - self.TimeConfiguration.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.userDeviceName is not None: - showIndent(outfile, level) - outfile.write('userDeviceName=%s,\n' % quote_python(self.userDeviceName).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Configuration, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'currentLocale': - obj_ = LocaleType.factory() - obj_.build(child_) - self.currentLocale = obj_ - obj_.original_tagname_ = 'currentLocale' - elif nodeName_ == 'PowerConfiguration': - obj_ = PowerConfiguration.factory() - obj_.build(child_) - self.PowerConfiguration = obj_ - obj_.original_tagname_ = 'PowerConfiguration' - elif nodeName_ == 'PriceResponseCfgListLink': - obj_ = PriceResponseCfgListLink.factory() - obj_.build(child_) - self.PriceResponseCfgListLink = obj_ - obj_.original_tagname_ = 'PriceResponseCfgListLink' - elif nodeName_ == 'TimeConfiguration': - obj_ = TimeConfiguration.factory() - obj_.build(child_) - self.TimeConfiguration = obj_ - obj_.original_tagname_ = 'TimeConfiguration' - elif nodeName_ == 'userDeviceName': - userDeviceName_ = child_.text - userDeviceName_ = self.gds_validate_string(userDeviceName_, node, 'userDeviceName') - self.userDeviceName = userDeviceName_ - self.validate_String32(self.userDeviceName) # validate type String32 - super(Configuration, self).buildChildren(child_, node, nodeName_, True) -# end class Configuration - - -class LogEventList(SubscribableList): - """A List element to hold LogEvent objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, LogEvent=None): - self.original_tagname_ = None - super(LogEventList, self).__init__() - if LogEvent is None: - self.LogEvent = [] - else: - self.LogEvent = LogEvent - def factory(*args_, **kwargs_): - if LogEventList.subclass: - return LogEventList.subclass(*args_, **kwargs_) - else: - return LogEventList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_LogEvent(self): return self.LogEvent - def set_LogEvent(self, LogEvent): self.LogEvent = LogEvent - def add_LogEvent(self, value): self.LogEvent.append(value) - def insert_LogEvent_at(self, index, value): self.LogEvent.insert(index, value) - def replace_LogEvent_at(self, index, value): self.LogEvent[index] = value - def hasContent_(self): - if ( - self.LogEvent or - super(LogEventList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LogEventList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LogEventList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LogEventList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LogEventList'): - super(LogEventList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='LogEventList') - def exportChildren(self, outfile, level, namespace_='', name_='LogEventList', fromsubclass_=False, pretty_print=True): - super(LogEventList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for LogEvent_ in self.LogEvent: - LogEvent_.export(outfile, level, namespace_, name_='LogEvent', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='LogEventList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(LogEventList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(LogEventList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('LogEvent=[\n') - level += 1 - for LogEvent_ in self.LogEvent: - showIndent(outfile, level) - outfile.write('model_.LogEvent(\n') - LogEvent_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(LogEventList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'LogEvent': - obj_ = LogEvent.factory() - obj_.build(child_) - self.LogEvent.append(obj_) - obj_.original_tagname_ = 'LogEvent' - super(LogEventList, self).buildChildren(child_, node, nodeName_, True) -# end class LogEventList - - -class LogEvent(Resource): - """A time stamped instance of a significant event detected by the - device.""" - subclass = None - superclass = Resource - def __init__(self, createdDateTime=None, extendedData=None, functionSet=None, logEventCode=None, logEventID=None, logEventPEN=None, profileID=None): - self.original_tagname_ = None - super(LogEvent, self).__init__() - self.createdDateTime = createdDateTime - self.extendedData = extendedData - self.functionSet = functionSet - self.logEventCode = logEventCode - self.logEventID = logEventID - self.logEventPEN = logEventPEN - self.profileID = profileID - def factory(*args_, **kwargs_): - if LogEvent.subclass: - return LogEvent.subclass(*args_, **kwargs_) - else: - return LogEvent(*args_, **kwargs_) - factory = staticmethod(factory) - def get_createdDateTime(self): return self.createdDateTime - def set_createdDateTime(self, createdDateTime): self.createdDateTime = createdDateTime - def get_extendedData(self): return self.extendedData - def set_extendedData(self, extendedData): self.extendedData = extendedData - def get_functionSet(self): return self.functionSet - def set_functionSet(self, functionSet): self.functionSet = functionSet - def get_logEventCode(self): return self.logEventCode - def set_logEventCode(self, logEventCode): self.logEventCode = logEventCode - def get_logEventID(self): return self.logEventID - def set_logEventID(self, logEventID): self.logEventID = logEventID - def get_logEventPEN(self): return self.logEventPEN - def set_logEventPEN(self, logEventPEN): self.logEventPEN = logEventPEN - def get_profileID(self): return self.profileID - def set_profileID(self, profileID): self.profileID = profileID - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.createdDateTime is not None or - self.extendedData is not None or - self.functionSet is not None or - self.logEventCode is not None or - self.logEventID is not None or - self.logEventPEN is not None or - self.profileID is not None or - super(LogEvent, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LogEvent', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LogEvent') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LogEvent', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LogEvent'): - super(LogEvent, self).exportAttributes(outfile, level, already_processed, namespace_, name_='LogEvent') - def exportChildren(self, outfile, level, namespace_='', name_='LogEvent', fromsubclass_=False, pretty_print=True): - super(LogEvent, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.createdDateTime is not None: - self.createdDateTime.export(outfile, level, namespace_, name_='createdDateTime', pretty_print=pretty_print) - if self.extendedData is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sextendedData>%s%s' % (namespace_, self.gds_format_integer(self.extendedData, input_name='extendedData'), namespace_, eol_)) - if self.functionSet is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sfunctionSet>%s%s' % (namespace_, self.gds_format_integer(self.functionSet, input_name='functionSet'), namespace_, eol_)) - if self.logEventCode is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slogEventCode>%s%s' % (namespace_, self.gds_format_integer(self.logEventCode, input_name='logEventCode'), namespace_, eol_)) - if self.logEventID is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slogEventID>%s%s' % (namespace_, self.gds_format_integer(self.logEventID, input_name='logEventID'), namespace_, eol_)) - if self.logEventPEN is not None: - self.logEventPEN.export(outfile, level, namespace_, name_='logEventPEN', pretty_print=pretty_print) - if self.profileID is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sprofileID>%s%s' % (namespace_, self.gds_format_integer(self.profileID, input_name='profileID'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='LogEvent'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(LogEvent, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(LogEvent, self).exportLiteralChildren(outfile, level, name_) - if self.createdDateTime is not None: - showIndent(outfile, level) - outfile.write('createdDateTime=model_.TimeType(\n') - self.createdDateTime.exportLiteral(outfile, level, name_='createdDateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.extendedData is not None: - showIndent(outfile, level) - outfile.write('extendedData=%d,\n' % self.extendedData) - if self.functionSet is not None: - showIndent(outfile, level) - outfile.write('functionSet=%d,\n' % self.functionSet) - if self.logEventCode is not None: - showIndent(outfile, level) - outfile.write('logEventCode=%d,\n' % self.logEventCode) - if self.logEventID is not None: - showIndent(outfile, level) - outfile.write('logEventID=%d,\n' % self.logEventID) - if self.logEventPEN is not None: - showIndent(outfile, level) - outfile.write('logEventPEN=model_.PENType(\n') - self.logEventPEN.exportLiteral(outfile, level, name_='logEventPEN') - showIndent(outfile, level) - outfile.write('),\n') - if self.profileID is not None: - showIndent(outfile, level) - outfile.write('profileID=%d,\n' % self.profileID) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(LogEvent, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'createdDateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.createdDateTime = obj_ - obj_.original_tagname_ = 'createdDateTime' - elif nodeName_ == 'extendedData': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'extendedData') - self.extendedData = ival_ - self.validate_UInt32(self.extendedData) # validate type UInt32 - elif nodeName_ == 'functionSet': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'functionSet') - self.functionSet = ival_ - self.validate_UInt8(self.functionSet) # validate type UInt8 - elif nodeName_ == 'logEventCode': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'logEventCode') - self.logEventCode = ival_ - self.validate_UInt8(self.logEventCode) # validate type UInt8 - elif nodeName_ == 'logEventID': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'logEventID') - self.logEventID = ival_ - self.validate_UInt16(self.logEventID) # validate type UInt16 - elif nodeName_ == 'logEventPEN': - obj_ = PENType.factory() - obj_.build(child_) - self.logEventPEN = obj_ - obj_.original_tagname_ = 'logEventPEN' - elif nodeName_ == 'profileID': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'profileID') - self.profileID = ival_ - self.validate_UInt8(self.profileID) # validate type UInt8 - super(LogEvent, self).buildChildren(child_, node, nodeName_, True) -# end class LogEvent - - -class RPLSourceRoutesList(List): - """List or RPL source routes if the hosting device is the DODAGroot""" - subclass = None - superclass = List - def __init__(self, RPLSourceRoutes=None): - self.original_tagname_ = None - super(RPLSourceRoutesList, self).__init__() - if RPLSourceRoutes is None: - self.RPLSourceRoutes = [] - else: - self.RPLSourceRoutes = RPLSourceRoutes - def factory(*args_, **kwargs_): - if RPLSourceRoutesList.subclass: - return RPLSourceRoutesList.subclass(*args_, **kwargs_) - else: - return RPLSourceRoutesList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_RPLSourceRoutes(self): return self.RPLSourceRoutes - def set_RPLSourceRoutes(self, RPLSourceRoutes): self.RPLSourceRoutes = RPLSourceRoutes - def add_RPLSourceRoutes(self, value): self.RPLSourceRoutes.append(value) - def insert_RPLSourceRoutes_at(self, index, value): self.RPLSourceRoutes.insert(index, value) - def replace_RPLSourceRoutes_at(self, index, value): self.RPLSourceRoutes[index] = value - def hasContent_(self): - if ( - self.RPLSourceRoutes or - super(RPLSourceRoutesList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RPLSourceRoutesList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RPLSourceRoutesList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RPLSourceRoutesList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RPLSourceRoutesList'): - super(RPLSourceRoutesList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RPLSourceRoutesList') - def exportChildren(self, outfile, level, namespace_='', name_='RPLSourceRoutesList', fromsubclass_=False, pretty_print=True): - super(RPLSourceRoutesList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for RPLSourceRoutes_ in self.RPLSourceRoutes: - RPLSourceRoutes_.export(outfile, level, namespace_, name_='RPLSourceRoutes', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='RPLSourceRoutesList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RPLSourceRoutesList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RPLSourceRoutesList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('RPLSourceRoutes=[\n') - level += 1 - for RPLSourceRoutes_ in self.RPLSourceRoutes: - showIndent(outfile, level) - outfile.write('model_.RPLSourceRoutes(\n') - RPLSourceRoutes_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RPLSourceRoutesList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'RPLSourceRoutes': - obj_ = RPLSourceRoutes.factory() - obj_.build(child_) - self.RPLSourceRoutes.append(obj_) - obj_.original_tagname_ = 'RPLSourceRoutes' - super(RPLSourceRoutesList, self).buildChildren(child_, node, nodeName_, True) -# end class RPLSourceRoutesList - - -class RPLSourceRoutes(Resource): - """A RPL source routes object.""" - subclass = None - superclass = Resource - def __init__(self, DestAddress=None, SourceRoute=None): - self.original_tagname_ = None - super(RPLSourceRoutes, self).__init__() - self.DestAddress = DestAddress - self.SourceRoute = SourceRoute - def factory(*args_, **kwargs_): - if RPLSourceRoutes.subclass: - return RPLSourceRoutes.subclass(*args_, **kwargs_) - else: - return RPLSourceRoutes(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DestAddress(self): return self.DestAddress - def set_DestAddress(self, DestAddress): self.DestAddress = DestAddress - def get_SourceRoute(self): return self.SourceRoute - def set_SourceRoute(self, SourceRoute): self.SourceRoute = SourceRoute - def validate_HexBinary128(self, value): - # Validate type HexBinary128, a restriction on xs:hexBinary. - pass - def hasContent_(self): - if ( - self.DestAddress is not None or - self.SourceRoute is not None or - super(RPLSourceRoutes, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RPLSourceRoutes', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RPLSourceRoutes') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RPLSourceRoutes', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RPLSourceRoutes'): - super(RPLSourceRoutes, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RPLSourceRoutes') - def exportChildren(self, outfile, level, namespace_='', name_='RPLSourceRoutes', fromsubclass_=False, pretty_print=True): - super(RPLSourceRoutes, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.DestAddress is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sDestAddress>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.DestAddress).encode(ExternalEncoding), input_name='DestAddress'), namespace_, eol_)) - if self.SourceRoute is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sSourceRoute>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.SourceRoute).encode(ExternalEncoding), input_name='SourceRoute'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='RPLSourceRoutes'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RPLSourceRoutes, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RPLSourceRoutes, self).exportLiteralChildren(outfile, level, name_) - if self.DestAddress is not None: - showIndent(outfile, level) - outfile.write('DestAddress=%s,\n' % quote_python(self.DestAddress).encode(ExternalEncoding)) - if self.SourceRoute is not None: - showIndent(outfile, level) - outfile.write('SourceRoute=%s,\n' % quote_python(self.SourceRoute).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RPLSourceRoutes, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DestAddress': - DestAddress_ = child_.text - DestAddress_ = self.gds_validate_string(DestAddress_, node, 'DestAddress') - self.DestAddress = DestAddress_ - self.validate_HexBinary128(self.DestAddress) # validate type HexBinary128 - elif nodeName_ == 'SourceRoute': - SourceRoute_ = child_.text - SourceRoute_ = self.gds_validate_string(SourceRoute_, node, 'SourceRoute') - self.SourceRoute = SourceRoute_ - self.validate_HexBinary128(self.SourceRoute) # validate type HexBinary128 - super(RPLSourceRoutes, self).buildChildren(child_, node, nodeName_, True) -# end class RPLSourceRoutes - - -class RPLInstanceList(List): - """List of RPLInstances associated with the IPinterface.""" - subclass = None - superclass = List - def __init__(self, RPLInstance=None): - self.original_tagname_ = None - super(RPLInstanceList, self).__init__() - if RPLInstance is None: - self.RPLInstance = [] - else: - self.RPLInstance = RPLInstance - def factory(*args_, **kwargs_): - if RPLInstanceList.subclass: - return RPLInstanceList.subclass(*args_, **kwargs_) - else: - return RPLInstanceList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_RPLInstance(self): return self.RPLInstance - def set_RPLInstance(self, RPLInstance): self.RPLInstance = RPLInstance - def add_RPLInstance(self, value): self.RPLInstance.append(value) - def insert_RPLInstance_at(self, index, value): self.RPLInstance.insert(index, value) - def replace_RPLInstance_at(self, index, value): self.RPLInstance[index] = value - def hasContent_(self): - if ( - self.RPLInstance or - super(RPLInstanceList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RPLInstanceList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RPLInstanceList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RPLInstanceList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RPLInstanceList'): - super(RPLInstanceList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RPLInstanceList') - def exportChildren(self, outfile, level, namespace_='', name_='RPLInstanceList', fromsubclass_=False, pretty_print=True): - super(RPLInstanceList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for RPLInstance_ in self.RPLInstance: - RPLInstance_.export(outfile, level, namespace_, name_='RPLInstance', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='RPLInstanceList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RPLInstanceList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RPLInstanceList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('RPLInstance=[\n') - level += 1 - for RPLInstance_ in self.RPLInstance: - showIndent(outfile, level) - outfile.write('model_.RPLInstance(\n') - RPLInstance_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RPLInstanceList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'RPLInstance': - obj_ = RPLInstance.factory() - obj_.build(child_) - self.RPLInstance.append(obj_) - obj_.original_tagname_ = 'RPLInstance' - super(RPLInstanceList, self).buildChildren(child_, node, nodeName_, True) -# end class RPLInstanceList - - -class RPLInstance(Resource): - """Specific RPLInstance resource. This resource may be thought of as - network status information for a specific RPL instance - associated with IPInterface.""" - subclass = None - superclass = Resource - def __init__(self, DODAGid=None, DODAGroot=None, flags=None, groundedFlag=None, MOP=None, PRF=None, rank=None, RPLInstanceID=None, RPLSourceRoutesListLink=None, versionNumber=None): - self.original_tagname_ = None - super(RPLInstance, self).__init__() - self.DODAGid = DODAGid - self.DODAGroot = DODAGroot - self.flags = flags - self.groundedFlag = groundedFlag - self.MOP = MOP - self.PRF = PRF - self.rank = rank - self.RPLInstanceID = RPLInstanceID - self.RPLSourceRoutesListLink = RPLSourceRoutesListLink - self.versionNumber = versionNumber - def factory(*args_, **kwargs_): - if RPLInstance.subclass: - return RPLInstance.subclass(*args_, **kwargs_) - else: - return RPLInstance(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DODAGid(self): return self.DODAGid - def set_DODAGid(self, DODAGid): self.DODAGid = DODAGid - def get_DODAGroot(self): return self.DODAGroot - def set_DODAGroot(self, DODAGroot): self.DODAGroot = DODAGroot - def get_flags(self): return self.flags - def set_flags(self, flags): self.flags = flags - def get_groundedFlag(self): return self.groundedFlag - def set_groundedFlag(self, groundedFlag): self.groundedFlag = groundedFlag - def get_MOP(self): return self.MOP - def set_MOP(self, MOP): self.MOP = MOP - def get_PRF(self): return self.PRF - def set_PRF(self, PRF): self.PRF = PRF - def get_rank(self): return self.rank - def set_rank(self, rank): self.rank = rank - def get_RPLInstanceID(self): return self.RPLInstanceID - def set_RPLInstanceID(self, RPLInstanceID): self.RPLInstanceID = RPLInstanceID - def get_RPLSourceRoutesListLink(self): return self.RPLSourceRoutesListLink - def set_RPLSourceRoutesListLink(self, RPLSourceRoutesListLink): self.RPLSourceRoutesListLink = RPLSourceRoutesListLink - def get_versionNumber(self): return self.versionNumber - def set_versionNumber(self, versionNumber): self.versionNumber = versionNumber - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.DODAGid is not None or - self.DODAGroot is not None or - self.flags is not None or - self.groundedFlag is not None or - self.MOP is not None or - self.PRF is not None or - self.rank is not None or - self.RPLInstanceID is not None or - self.RPLSourceRoutesListLink is not None or - self.versionNumber is not None or - super(RPLInstance, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='RPLInstance', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='RPLInstance') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='RPLInstance', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='RPLInstance'): - super(RPLInstance, self).exportAttributes(outfile, level, already_processed, namespace_, name_='RPLInstance') - def exportChildren(self, outfile, level, namespace_='', name_='RPLInstance', fromsubclass_=False, pretty_print=True): - super(RPLInstance, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.DODAGid is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sDODAGid>%s%s' % (namespace_, self.gds_format_integer(self.DODAGid, input_name='DODAGid'), namespace_, eol_)) - if self.DODAGroot is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sDODAGroot>%s%s' % (namespace_, self.gds_format_boolean(self.DODAGroot, input_name='DODAGroot'), namespace_, eol_)) - if self.flags is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sflags>%s%s' % (namespace_, self.gds_format_integer(self.flags, input_name='flags'), namespace_, eol_)) - if self.groundedFlag is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sgroundedFlag>%s%s' % (namespace_, self.gds_format_boolean(self.groundedFlag, input_name='groundedFlag'), namespace_, eol_)) - if self.MOP is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sMOP>%s%s' % (namespace_, self.gds_format_integer(self.MOP, input_name='MOP'), namespace_, eol_)) - if self.PRF is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sPRF>%s%s' % (namespace_, self.gds_format_integer(self.PRF, input_name='PRF'), namespace_, eol_)) - if self.rank is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%srank>%s%s' % (namespace_, self.gds_format_integer(self.rank, input_name='rank'), namespace_, eol_)) - if self.RPLInstanceID is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sRPLInstanceID>%s%s' % (namespace_, self.gds_format_integer(self.RPLInstanceID, input_name='RPLInstanceID'), namespace_, eol_)) - if self.RPLSourceRoutesListLink is not None: - self.RPLSourceRoutesListLink.export(outfile, level, namespace_, name_='RPLSourceRoutesListLink', pretty_print=pretty_print) - if self.versionNumber is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sversionNumber>%s%s' % (namespace_, self.gds_format_integer(self.versionNumber, input_name='versionNumber'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='RPLInstance'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(RPLInstance, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(RPLInstance, self).exportLiteralChildren(outfile, level, name_) - if self.DODAGid is not None: - showIndent(outfile, level) - outfile.write('DODAGid=%d,\n' % self.DODAGid) - if self.DODAGroot is not None: - showIndent(outfile, level) - outfile.write('DODAGroot=%s,\n' % self.DODAGroot) - if self.flags is not None: - showIndent(outfile, level) - outfile.write('flags=%d,\n' % self.flags) - if self.groundedFlag is not None: - showIndent(outfile, level) - outfile.write('groundedFlag=%s,\n' % self.groundedFlag) - if self.MOP is not None: - showIndent(outfile, level) - outfile.write('MOP=%d,\n' % self.MOP) - if self.PRF is not None: - showIndent(outfile, level) - outfile.write('PRF=%d,\n' % self.PRF) - if self.rank is not None: - showIndent(outfile, level) - outfile.write('rank=%d,\n' % self.rank) - if self.RPLInstanceID is not None: - showIndent(outfile, level) - outfile.write('RPLInstanceID=%d,\n' % self.RPLInstanceID) - if self.RPLSourceRoutesListLink is not None: - showIndent(outfile, level) - outfile.write('RPLSourceRoutesListLink=model_.RPLSourceRoutesListLink(\n') - self.RPLSourceRoutesListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.versionNumber is not None: - showIndent(outfile, level) - outfile.write('versionNumber=%d,\n' % self.versionNumber) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(RPLInstance, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DODAGid': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'DODAGid') - self.DODAGid = ival_ - self.validate_UInt8(self.DODAGid) # validate type UInt8 - elif nodeName_ == 'DODAGroot': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'DODAGroot') - self.DODAGroot = ival_ - elif nodeName_ == 'flags': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'flags') - self.flags = ival_ - self.validate_UInt8(self.flags) # validate type UInt8 - elif nodeName_ == 'groundedFlag': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'groundedFlag') - self.groundedFlag = ival_ - elif nodeName_ == 'MOP': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'MOP') - self.MOP = ival_ - self.validate_UInt8(self.MOP) # validate type UInt8 - elif nodeName_ == 'PRF': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'PRF') - self.PRF = ival_ - self.validate_UInt8(self.PRF) # validate type UInt8 - elif nodeName_ == 'rank': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'rank') - self.rank = ival_ - self.validate_UInt16(self.rank) # validate type UInt16 - elif nodeName_ == 'RPLInstanceID': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'RPLInstanceID') - self.RPLInstanceID = ival_ - self.validate_UInt8(self.RPLInstanceID) # validate type UInt8 - elif nodeName_ == 'RPLSourceRoutesListLink': - obj_ = RPLSourceRoutesListLink.factory() - obj_.build(child_) - self.RPLSourceRoutesListLink = obj_ - obj_.original_tagname_ = 'RPLSourceRoutesListLink' - elif nodeName_ == 'versionNumber': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'versionNumber') - self.versionNumber = ival_ - self.validate_UInt8(self.versionNumber) # validate type UInt8 - super(RPLInstance, self).buildChildren(child_, node, nodeName_, True) -# end class RPLInstance - - -class NeighborList(List): - """List of 15.4 neighbors.""" - subclass = None - superclass = List - def __init__(self, Neighbor=None): - self.original_tagname_ = None - super(NeighborList, self).__init__() - if Neighbor is None: - self.Neighbor = [] - else: - self.Neighbor = Neighbor - def factory(*args_, **kwargs_): - if NeighborList.subclass: - return NeighborList.subclass(*args_, **kwargs_) - else: - return NeighborList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Neighbor(self): return self.Neighbor - def set_Neighbor(self, Neighbor): self.Neighbor = Neighbor - def add_Neighbor(self, value): self.Neighbor.append(value) - def insert_Neighbor_at(self, index, value): self.Neighbor.insert(index, value) - def replace_Neighbor_at(self, index, value): self.Neighbor[index] = value - def hasContent_(self): - if ( - self.Neighbor or - super(NeighborList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='NeighborList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='NeighborList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='NeighborList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='NeighborList'): - super(NeighborList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='NeighborList') - def exportChildren(self, outfile, level, namespace_='', name_='NeighborList', fromsubclass_=False, pretty_print=True): - super(NeighborList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Neighbor_ in self.Neighbor: - Neighbor_.export(outfile, level, namespace_, name_='Neighbor', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='NeighborList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(NeighborList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(NeighborList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('Neighbor=[\n') - level += 1 - for Neighbor_ in self.Neighbor: - showIndent(outfile, level) - outfile.write('model_.Neighbor(\n') - Neighbor_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(NeighborList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Neighbor': - obj_ = Neighbor.factory() - obj_.build(child_) - self.Neighbor.append(obj_) - obj_.original_tagname_ = 'Neighbor' - super(NeighborList, self).buildChildren(child_, node, nodeName_, True) -# end class NeighborList - - -class Neighbor(Resource): - """Contains 802.15.4 link layer specific attributes.""" - subclass = None - superclass = Resource - def __init__(self, isChild=None, linkQuality=None, shortAddress=None): - self.original_tagname_ = None - super(Neighbor, self).__init__() - self.isChild = isChild - self.linkQuality = linkQuality - self.shortAddress = shortAddress - def factory(*args_, **kwargs_): - if Neighbor.subclass: - return Neighbor.subclass(*args_, **kwargs_) - else: - return Neighbor(*args_, **kwargs_) - factory = staticmethod(factory) - def get_isChild(self): return self.isChild - def set_isChild(self, isChild): self.isChild = isChild - def get_linkQuality(self): return self.linkQuality - def set_linkQuality(self, linkQuality): self.linkQuality = linkQuality - def get_shortAddress(self): return self.shortAddress - def set_shortAddress(self, shortAddress): self.shortAddress = shortAddress - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.isChild is not None or - self.linkQuality is not None or - self.shortAddress is not None or - super(Neighbor, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Neighbor', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Neighbor') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Neighbor', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Neighbor'): - super(Neighbor, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Neighbor') - def exportChildren(self, outfile, level, namespace_='', name_='Neighbor', fromsubclass_=False, pretty_print=True): - super(Neighbor, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.isChild is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sisChild>%s%s' % (namespace_, self.gds_format_boolean(self.isChild, input_name='isChild'), namespace_, eol_)) - if self.linkQuality is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slinkQuality>%s%s' % (namespace_, self.gds_format_integer(self.linkQuality, input_name='linkQuality'), namespace_, eol_)) - if self.shortAddress is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sshortAddress>%s%s' % (namespace_, self.gds_format_integer(self.shortAddress, input_name='shortAddress'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Neighbor'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Neighbor, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Neighbor, self).exportLiteralChildren(outfile, level, name_) - if self.isChild is not None: - showIndent(outfile, level) - outfile.write('isChild=%s,\n' % self.isChild) - if self.linkQuality is not None: - showIndent(outfile, level) - outfile.write('linkQuality=%d,\n' % self.linkQuality) - if self.shortAddress is not None: - showIndent(outfile, level) - outfile.write('shortAddress=%d,\n' % self.shortAddress) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Neighbor, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'isChild': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'isChild') - self.isChild = ival_ - elif nodeName_ == 'linkQuality': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'linkQuality') - self.linkQuality = ival_ - self.validate_UInt8(self.linkQuality) # validate type UInt8 - elif nodeName_ == 'shortAddress': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'shortAddress') - self.shortAddress = ival_ - self.validate_UInt16(self.shortAddress) # validate type UInt16 - super(Neighbor, self).buildChildren(child_, node, nodeName_, True) -# end class Neighbor - - -class LLInterfaceList(List): - """List of LLInterface instances.""" - subclass = None - superclass = List - def __init__(self, LLInterface=None): - self.original_tagname_ = None - super(LLInterfaceList, self).__init__() - if LLInterface is None: - self.LLInterface = [] - else: - self.LLInterface = LLInterface - def factory(*args_, **kwargs_): - if LLInterfaceList.subclass: - return LLInterfaceList.subclass(*args_, **kwargs_) - else: - return LLInterfaceList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_LLInterface(self): return self.LLInterface - def set_LLInterface(self, LLInterface): self.LLInterface = LLInterface - def add_LLInterface(self, value): self.LLInterface.append(value) - def insert_LLInterface_at(self, index, value): self.LLInterface.insert(index, value) - def replace_LLInterface_at(self, index, value): self.LLInterface[index] = value - def hasContent_(self): - if ( - self.LLInterface or - super(LLInterfaceList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LLInterfaceList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LLInterfaceList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LLInterfaceList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LLInterfaceList'): - super(LLInterfaceList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='LLInterfaceList') - def exportChildren(self, outfile, level, namespace_='', name_='LLInterfaceList', fromsubclass_=False, pretty_print=True): - super(LLInterfaceList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for LLInterface_ in self.LLInterface: - LLInterface_.export(outfile, level, namespace_, name_='LLInterface', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='LLInterfaceList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(LLInterfaceList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(LLInterfaceList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('LLInterface=[\n') - level += 1 - for LLInterface_ in self.LLInterface: - showIndent(outfile, level) - outfile.write('model_.LLInterface(\n') - LLInterface_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(LLInterfaceList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'LLInterface': - obj_ = LLInterface.factory() - obj_.build(child_) - self.LLInterface.append(obj_) - obj_.original_tagname_ = 'LLInterface' - super(LLInterfaceList, self).buildChildren(child_, node, nodeName_, True) -# end class LLInterfaceList - - -class LLInterface(Resource): - """A link-layer interface object.""" - subclass = None - superclass = Resource - def __init__(self, CRCerrors=None, EUI64=None, IEEE_802_15_4=None, linkLayerType=None, LLAckNotRx=None, LLCSMAFail=None, LLFramesDropRx=None, LLFramesDropTx=None, LLFramesRx=None, LLFramesTx=None, LLMediaAccessFail=None, LLOctetsRx=None, LLOctetsTx=None, LLRetryCount=None, LLSecurityErrorRx=None, loWPAN=None): - self.original_tagname_ = None - super(LLInterface, self).__init__() - self.CRCerrors = CRCerrors - self.EUI64 = EUI64 - self.IEEE_802_15_4 = IEEE_802_15_4 - self.linkLayerType = linkLayerType - self.LLAckNotRx = LLAckNotRx - self.LLCSMAFail = LLCSMAFail - self.LLFramesDropRx = LLFramesDropRx - self.LLFramesDropTx = LLFramesDropTx - self.LLFramesRx = LLFramesRx - self.LLFramesTx = LLFramesTx - self.LLMediaAccessFail = LLMediaAccessFail - self.LLOctetsRx = LLOctetsRx - self.LLOctetsTx = LLOctetsTx - self.LLRetryCount = LLRetryCount - self.LLSecurityErrorRx = LLSecurityErrorRx - self.loWPAN = loWPAN - def factory(*args_, **kwargs_): - if LLInterface.subclass: - return LLInterface.subclass(*args_, **kwargs_) - else: - return LLInterface(*args_, **kwargs_) - factory = staticmethod(factory) - def get_CRCerrors(self): return self.CRCerrors - def set_CRCerrors(self, CRCerrors): self.CRCerrors = CRCerrors - def get_EUI64(self): return self.EUI64 - def set_EUI64(self, EUI64): self.EUI64 = EUI64 - def get_IEEE_802_15_4(self): return self.IEEE_802_15_4 - def set_IEEE_802_15_4(self, IEEE_802_15_4): self.IEEE_802_15_4 = IEEE_802_15_4 - def get_linkLayerType(self): return self.linkLayerType - def set_linkLayerType(self, linkLayerType): self.linkLayerType = linkLayerType - def get_LLAckNotRx(self): return self.LLAckNotRx - def set_LLAckNotRx(self, LLAckNotRx): self.LLAckNotRx = LLAckNotRx - def get_LLCSMAFail(self): return self.LLCSMAFail - def set_LLCSMAFail(self, LLCSMAFail): self.LLCSMAFail = LLCSMAFail - def get_LLFramesDropRx(self): return self.LLFramesDropRx - def set_LLFramesDropRx(self, LLFramesDropRx): self.LLFramesDropRx = LLFramesDropRx - def get_LLFramesDropTx(self): return self.LLFramesDropTx - def set_LLFramesDropTx(self, LLFramesDropTx): self.LLFramesDropTx = LLFramesDropTx - def get_LLFramesRx(self): return self.LLFramesRx - def set_LLFramesRx(self, LLFramesRx): self.LLFramesRx = LLFramesRx - def get_LLFramesTx(self): return self.LLFramesTx - def set_LLFramesTx(self, LLFramesTx): self.LLFramesTx = LLFramesTx - def get_LLMediaAccessFail(self): return self.LLMediaAccessFail - def set_LLMediaAccessFail(self, LLMediaAccessFail): self.LLMediaAccessFail = LLMediaAccessFail - def get_LLOctetsRx(self): return self.LLOctetsRx - def set_LLOctetsRx(self, LLOctetsRx): self.LLOctetsRx = LLOctetsRx - def get_LLOctetsTx(self): return self.LLOctetsTx - def set_LLOctetsTx(self, LLOctetsTx): self.LLOctetsTx = LLOctetsTx - def get_LLRetryCount(self): return self.LLRetryCount - def set_LLRetryCount(self, LLRetryCount): self.LLRetryCount = LLRetryCount - def get_LLSecurityErrorRx(self): return self.LLSecurityErrorRx - def set_LLSecurityErrorRx(self, LLSecurityErrorRx): self.LLSecurityErrorRx = LLSecurityErrorRx - def get_loWPAN(self): return self.loWPAN - def set_loWPAN(self, loWPAN): self.loWPAN = loWPAN - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def validate_HexBinary64(self, value): - # Validate type HexBinary64, a restriction on xs:hexBinary. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.CRCerrors is not None or - self.EUI64 is not None or - self.IEEE_802_15_4 is not None or - self.linkLayerType is not None or - self.LLAckNotRx is not None or - self.LLCSMAFail is not None or - self.LLFramesDropRx is not None or - self.LLFramesDropTx is not None or - self.LLFramesRx is not None or - self.LLFramesTx is not None or - self.LLMediaAccessFail is not None or - self.LLOctetsRx is not None or - self.LLOctetsTx is not None or - self.LLRetryCount is not None or - self.LLSecurityErrorRx is not None or - self.loWPAN is not None or - super(LLInterface, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='LLInterface', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='LLInterface') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='LLInterface', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='LLInterface'): - super(LLInterface, self).exportAttributes(outfile, level, already_processed, namespace_, name_='LLInterface') - def exportChildren(self, outfile, level, namespace_='', name_='LLInterface', fromsubclass_=False, pretty_print=True): - super(LLInterface, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.CRCerrors is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sCRCerrors>%s%s' % (namespace_, self.gds_format_integer(self.CRCerrors, input_name='CRCerrors'), namespace_, eol_)) - if self.EUI64 is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sEUI64>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.EUI64).encode(ExternalEncoding), input_name='EUI64'), namespace_, eol_)) - if self.IEEE_802_15_4 is not None: - self.IEEE_802_15_4.export(outfile, level, namespace_, name_='IEEE_802_15_4', pretty_print=pretty_print) - if self.linkLayerType is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slinkLayerType>%s%s' % (namespace_, self.gds_format_integer(self.linkLayerType, input_name='linkLayerType'), namespace_, eol_)) - if self.LLAckNotRx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLAckNotRx>%s%s' % (namespace_, self.gds_format_integer(self.LLAckNotRx, input_name='LLAckNotRx'), namespace_, eol_)) - if self.LLCSMAFail is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLCSMAFail>%s%s' % (namespace_, self.gds_format_integer(self.LLCSMAFail, input_name='LLCSMAFail'), namespace_, eol_)) - if self.LLFramesDropRx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLFramesDropRx>%s%s' % (namespace_, self.gds_format_integer(self.LLFramesDropRx, input_name='LLFramesDropRx'), namespace_, eol_)) - if self.LLFramesDropTx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLFramesDropTx>%s%s' % (namespace_, self.gds_format_integer(self.LLFramesDropTx, input_name='LLFramesDropTx'), namespace_, eol_)) - if self.LLFramesRx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLFramesRx>%s%s' % (namespace_, self.gds_format_integer(self.LLFramesRx, input_name='LLFramesRx'), namespace_, eol_)) - if self.LLFramesTx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLFramesTx>%s%s' % (namespace_, self.gds_format_integer(self.LLFramesTx, input_name='LLFramesTx'), namespace_, eol_)) - if self.LLMediaAccessFail is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLMediaAccessFail>%s%s' % (namespace_, self.gds_format_integer(self.LLMediaAccessFail, input_name='LLMediaAccessFail'), namespace_, eol_)) - if self.LLOctetsRx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLOctetsRx>%s%s' % (namespace_, self.gds_format_integer(self.LLOctetsRx, input_name='LLOctetsRx'), namespace_, eol_)) - if self.LLOctetsTx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLOctetsTx>%s%s' % (namespace_, self.gds_format_integer(self.LLOctetsTx, input_name='LLOctetsTx'), namespace_, eol_)) - if self.LLRetryCount is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLRetryCount>%s%s' % (namespace_, self.gds_format_integer(self.LLRetryCount, input_name='LLRetryCount'), namespace_, eol_)) - if self.LLSecurityErrorRx is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sLLSecurityErrorRx>%s%s' % (namespace_, self.gds_format_integer(self.LLSecurityErrorRx, input_name='LLSecurityErrorRx'), namespace_, eol_)) - if self.loWPAN is not None: - self.loWPAN.export(outfile, level, namespace_, name_='loWPAN', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='LLInterface'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(LLInterface, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(LLInterface, self).exportLiteralChildren(outfile, level, name_) - if self.CRCerrors is not None: - showIndent(outfile, level) - outfile.write('CRCerrors=%d,\n' % self.CRCerrors) - if self.EUI64 is not None: - showIndent(outfile, level) - outfile.write('EUI64=%s,\n' % quote_python(self.EUI64).encode(ExternalEncoding)) - if self.IEEE_802_15_4 is not None: - showIndent(outfile, level) - outfile.write('IEEE_802_15_4=model_.IEEE_802_15_4(\n') - self.IEEE_802_15_4.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.linkLayerType is not None: - showIndent(outfile, level) - outfile.write('linkLayerType=%d,\n' % self.linkLayerType) - if self.LLAckNotRx is not None: - showIndent(outfile, level) - outfile.write('LLAckNotRx=%d,\n' % self.LLAckNotRx) - if self.LLCSMAFail is not None: - showIndent(outfile, level) - outfile.write('LLCSMAFail=%d,\n' % self.LLCSMAFail) - if self.LLFramesDropRx is not None: - showIndent(outfile, level) - outfile.write('LLFramesDropRx=%d,\n' % self.LLFramesDropRx) - if self.LLFramesDropTx is not None: - showIndent(outfile, level) - outfile.write('LLFramesDropTx=%d,\n' % self.LLFramesDropTx) - if self.LLFramesRx is not None: - showIndent(outfile, level) - outfile.write('LLFramesRx=%d,\n' % self.LLFramesRx) - if self.LLFramesTx is not None: - showIndent(outfile, level) - outfile.write('LLFramesTx=%d,\n' % self.LLFramesTx) - if self.LLMediaAccessFail is not None: - showIndent(outfile, level) - outfile.write('LLMediaAccessFail=%d,\n' % self.LLMediaAccessFail) - if self.LLOctetsRx is not None: - showIndent(outfile, level) - outfile.write('LLOctetsRx=%d,\n' % self.LLOctetsRx) - if self.LLOctetsTx is not None: - showIndent(outfile, level) - outfile.write('LLOctetsTx=%d,\n' % self.LLOctetsTx) - if self.LLRetryCount is not None: - showIndent(outfile, level) - outfile.write('LLRetryCount=%d,\n' % self.LLRetryCount) - if self.LLSecurityErrorRx is not None: - showIndent(outfile, level) - outfile.write('LLSecurityErrorRx=%d,\n' % self.LLSecurityErrorRx) - if self.loWPAN is not None: - showIndent(outfile, level) - outfile.write('loWPAN=model_.loWPAN(\n') - self.loWPAN.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(LLInterface, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'CRCerrors': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'CRCerrors') - self.CRCerrors = ival_ - self.validate_UInt32(self.CRCerrors) # validate type UInt32 - elif nodeName_ == 'EUI64': - EUI64_ = child_.text - EUI64_ = self.gds_validate_string(EUI64_, node, 'EUI64') - self.EUI64 = EUI64_ - self.validate_HexBinary64(self.EUI64) # validate type HexBinary64 - elif nodeName_ == 'IEEE_802_15_4': - obj_ = IEEE_802_15_4.factory() - obj_.build(child_) - self.IEEE_802_15_4 = obj_ - obj_.original_tagname_ = 'IEEE_802_15_4' - elif nodeName_ == 'linkLayerType': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'linkLayerType') - self.linkLayerType = ival_ - self.validate_UInt8(self.linkLayerType) # validate type UInt8 - elif nodeName_ == 'LLAckNotRx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLAckNotRx') - self.LLAckNotRx = ival_ - self.validate_UInt32(self.LLAckNotRx) # validate type UInt32 - elif nodeName_ == 'LLCSMAFail': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLCSMAFail') - self.LLCSMAFail = ival_ - self.validate_UInt32(self.LLCSMAFail) # validate type UInt32 - elif nodeName_ == 'LLFramesDropRx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLFramesDropRx') - self.LLFramesDropRx = ival_ - self.validate_UInt32(self.LLFramesDropRx) # validate type UInt32 - elif nodeName_ == 'LLFramesDropTx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLFramesDropTx') - self.LLFramesDropTx = ival_ - self.validate_UInt32(self.LLFramesDropTx) # validate type UInt32 - elif nodeName_ == 'LLFramesRx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLFramesRx') - self.LLFramesRx = ival_ - self.validate_UInt32(self.LLFramesRx) # validate type UInt32 - elif nodeName_ == 'LLFramesTx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLFramesTx') - self.LLFramesTx = ival_ - self.validate_UInt32(self.LLFramesTx) # validate type UInt32 - elif nodeName_ == 'LLMediaAccessFail': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLMediaAccessFail') - self.LLMediaAccessFail = ival_ - self.validate_UInt32(self.LLMediaAccessFail) # validate type UInt32 - elif nodeName_ == 'LLOctetsRx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLOctetsRx') - self.LLOctetsRx = ival_ - self.validate_UInt32(self.LLOctetsRx) # validate type UInt32 - elif nodeName_ == 'LLOctetsTx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLOctetsTx') - self.LLOctetsTx = ival_ - self.validate_UInt32(self.LLOctetsTx) # validate type UInt32 - elif nodeName_ == 'LLRetryCount': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLRetryCount') - self.LLRetryCount = ival_ - self.validate_UInt32(self.LLRetryCount) # validate type UInt32 - elif nodeName_ == 'LLSecurityErrorRx': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'LLSecurityErrorRx') - self.LLSecurityErrorRx = ival_ - self.validate_UInt32(self.LLSecurityErrorRx) # validate type UInt32 - elif nodeName_ == 'loWPAN': - obj_ = loWPAN.factory() - obj_.build(child_) - self.loWPAN = obj_ - obj_.original_tagname_ = 'loWPAN' - super(LLInterface, self).buildChildren(child_, node, nodeName_, True) -# end class LLInterface - - -class IPInterfaceList(List): - """List of IPInterface instances.""" - subclass = None - superclass = List - def __init__(self, IPInterface=None): - self.original_tagname_ = None - super(IPInterfaceList, self).__init__() - if IPInterface is None: - self.IPInterface = [] - else: - self.IPInterface = IPInterface - def factory(*args_, **kwargs_): - if IPInterfaceList.subclass: - return IPInterfaceList.subclass(*args_, **kwargs_) - else: - return IPInterfaceList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_IPInterface(self): return self.IPInterface - def set_IPInterface(self, IPInterface): self.IPInterface = IPInterface - def add_IPInterface(self, value): self.IPInterface.append(value) - def insert_IPInterface_at(self, index, value): self.IPInterface.insert(index, value) - def replace_IPInterface_at(self, index, value): self.IPInterface[index] = value - def hasContent_(self): - if ( - self.IPInterface or - super(IPInterfaceList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='IPInterfaceList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='IPInterfaceList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='IPInterfaceList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='IPInterfaceList'): - super(IPInterfaceList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='IPInterfaceList') - def exportChildren(self, outfile, level, namespace_='', name_='IPInterfaceList', fromsubclass_=False, pretty_print=True): - super(IPInterfaceList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for IPInterface_ in self.IPInterface: - IPInterface_.export(outfile, level, namespace_, name_='IPInterface', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='IPInterfaceList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(IPInterfaceList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(IPInterfaceList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('IPInterface=[\n') - level += 1 - for IPInterface_ in self.IPInterface: - showIndent(outfile, level) - outfile.write('model_.IPInterface(\n') - IPInterface_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(IPInterfaceList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'IPInterface': - obj_ = IPInterface.factory() - obj_.build(child_) - self.IPInterface.append(obj_) - obj_.original_tagname_ = 'IPInterface' - super(IPInterfaceList, self).buildChildren(child_, node, nodeName_, True) -# end class IPInterfaceList - - -class IPInterface(Resource): - """Specific IPInterface resource. This resource may be thought of as - network status information for a specific network (IP) layer - interface.""" - subclass = None - superclass = Resource - def __init__(self, ifDescr=None, ifHighSpeed=None, ifInBroadcastPkts=None, ifIndex=None, ifInDiscards=None, ifInErrors=None, ifInMulticastPkts=None, ifInOctets=None, ifInUcastPkts=None, ifInUnknownProtos=None, ifMtu=None, ifName=None, ifOperStatus=None, ifOutBroadcastPkts=None, ifOutDiscards=None, ifOutErrors=None, ifOutMulticastPkts=None, ifOutOctets=None, ifOutUcastPkts=None, ifPromiscuousMode=None, ifSpeed=None, ifType=None, IPAddrListLink=None, lastResetTime=None, lastUpdatedTime=None, LLInterfaceListLink=None): - self.original_tagname_ = None - super(IPInterface, self).__init__() - self.ifDescr = ifDescr - self.ifHighSpeed = ifHighSpeed - self.ifInBroadcastPkts = ifInBroadcastPkts - self.ifIndex = ifIndex - self.ifInDiscards = ifInDiscards - self.ifInErrors = ifInErrors - self.ifInMulticastPkts = ifInMulticastPkts - self.ifInOctets = ifInOctets - self.ifInUcastPkts = ifInUcastPkts - self.ifInUnknownProtos = ifInUnknownProtos - self.ifMtu = ifMtu - self.ifName = ifName - self.ifOperStatus = ifOperStatus - self.ifOutBroadcastPkts = ifOutBroadcastPkts - self.ifOutDiscards = ifOutDiscards - self.ifOutErrors = ifOutErrors - self.ifOutMulticastPkts = ifOutMulticastPkts - self.ifOutOctets = ifOutOctets - self.ifOutUcastPkts = ifOutUcastPkts - self.ifPromiscuousMode = ifPromiscuousMode - self.ifSpeed = ifSpeed - self.ifType = ifType - self.IPAddrListLink = IPAddrListLink - self.lastResetTime = lastResetTime - self.lastUpdatedTime = lastUpdatedTime - self.LLInterfaceListLink = LLInterfaceListLink - def factory(*args_, **kwargs_): - if IPInterface.subclass: - return IPInterface.subclass(*args_, **kwargs_) - else: - return IPInterface(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ifDescr(self): return self.ifDescr - def set_ifDescr(self, ifDescr): self.ifDescr = ifDescr - def get_ifHighSpeed(self): return self.ifHighSpeed - def set_ifHighSpeed(self, ifHighSpeed): self.ifHighSpeed = ifHighSpeed - def get_ifInBroadcastPkts(self): return self.ifInBroadcastPkts - def set_ifInBroadcastPkts(self, ifInBroadcastPkts): self.ifInBroadcastPkts = ifInBroadcastPkts - def get_ifIndex(self): return self.ifIndex - def set_ifIndex(self, ifIndex): self.ifIndex = ifIndex - def get_ifInDiscards(self): return self.ifInDiscards - def set_ifInDiscards(self, ifInDiscards): self.ifInDiscards = ifInDiscards - def get_ifInErrors(self): return self.ifInErrors - def set_ifInErrors(self, ifInErrors): self.ifInErrors = ifInErrors - def get_ifInMulticastPkts(self): return self.ifInMulticastPkts - def set_ifInMulticastPkts(self, ifInMulticastPkts): self.ifInMulticastPkts = ifInMulticastPkts - def get_ifInOctets(self): return self.ifInOctets - def set_ifInOctets(self, ifInOctets): self.ifInOctets = ifInOctets - def get_ifInUcastPkts(self): return self.ifInUcastPkts - def set_ifInUcastPkts(self, ifInUcastPkts): self.ifInUcastPkts = ifInUcastPkts - def get_ifInUnknownProtos(self): return self.ifInUnknownProtos - def set_ifInUnknownProtos(self, ifInUnknownProtos): self.ifInUnknownProtos = ifInUnknownProtos - def get_ifMtu(self): return self.ifMtu - def set_ifMtu(self, ifMtu): self.ifMtu = ifMtu - def get_ifName(self): return self.ifName - def set_ifName(self, ifName): self.ifName = ifName - def get_ifOperStatus(self): return self.ifOperStatus - def set_ifOperStatus(self, ifOperStatus): self.ifOperStatus = ifOperStatus - def get_ifOutBroadcastPkts(self): return self.ifOutBroadcastPkts - def set_ifOutBroadcastPkts(self, ifOutBroadcastPkts): self.ifOutBroadcastPkts = ifOutBroadcastPkts - def get_ifOutDiscards(self): return self.ifOutDiscards - def set_ifOutDiscards(self, ifOutDiscards): self.ifOutDiscards = ifOutDiscards - def get_ifOutErrors(self): return self.ifOutErrors - def set_ifOutErrors(self, ifOutErrors): self.ifOutErrors = ifOutErrors - def get_ifOutMulticastPkts(self): return self.ifOutMulticastPkts - def set_ifOutMulticastPkts(self, ifOutMulticastPkts): self.ifOutMulticastPkts = ifOutMulticastPkts - def get_ifOutOctets(self): return self.ifOutOctets - def set_ifOutOctets(self, ifOutOctets): self.ifOutOctets = ifOutOctets - def get_ifOutUcastPkts(self): return self.ifOutUcastPkts - def set_ifOutUcastPkts(self, ifOutUcastPkts): self.ifOutUcastPkts = ifOutUcastPkts - def get_ifPromiscuousMode(self): return self.ifPromiscuousMode - def set_ifPromiscuousMode(self, ifPromiscuousMode): self.ifPromiscuousMode = ifPromiscuousMode - def get_ifSpeed(self): return self.ifSpeed - def set_ifSpeed(self, ifSpeed): self.ifSpeed = ifSpeed - def get_ifType(self): return self.ifType - def set_ifType(self, ifType): self.ifType = ifType - def get_IPAddrListLink(self): return self.IPAddrListLink - def set_IPAddrListLink(self, IPAddrListLink): self.IPAddrListLink = IPAddrListLink - def get_lastResetTime(self): return self.lastResetTime - def set_lastResetTime(self, lastResetTime): self.lastResetTime = lastResetTime - def get_lastUpdatedTime(self): return self.lastUpdatedTime - def set_lastUpdatedTime(self, lastUpdatedTime): self.lastUpdatedTime = lastUpdatedTime - def get_LLInterfaceListLink(self): return self.LLInterfaceListLink - def set_LLInterfaceListLink(self, LLInterfaceListLink): self.LLInterfaceListLink = LLInterfaceListLink - def validate_String192(self, value): - # Validate type String192, a restriction on xs:string. - pass - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def validate_String16(self, value): - # Validate type String16, a restriction on xs:string. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def validate_Int64(self, value): - # Validate type Int64, a restriction on xs:long. - pass - def hasContent_(self): - if ( - self.ifDescr is not None or - self.ifHighSpeed is not None or - self.ifInBroadcastPkts is not None or - self.ifIndex is not None or - self.ifInDiscards is not None or - self.ifInErrors is not None or - self.ifInMulticastPkts is not None or - self.ifInOctets is not None or - self.ifInUcastPkts is not None or - self.ifInUnknownProtos is not None or - self.ifMtu is not None or - self.ifName is not None or - self.ifOperStatus is not None or - self.ifOutBroadcastPkts is not None or - self.ifOutDiscards is not None or - self.ifOutErrors is not None or - self.ifOutMulticastPkts is not None or - self.ifOutOctets is not None or - self.ifOutUcastPkts is not None or - self.ifPromiscuousMode is not None or - self.ifSpeed is not None or - self.ifType is not None or - self.IPAddrListLink is not None or - self.lastResetTime is not None or - self.lastUpdatedTime is not None or - self.LLInterfaceListLink is not None or - super(IPInterface, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='IPInterface', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='IPInterface') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='IPInterface', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='IPInterface'): - super(IPInterface, self).exportAttributes(outfile, level, already_processed, namespace_, name_='IPInterface') - def exportChildren(self, outfile, level, namespace_='', name_='IPInterface', fromsubclass_=False, pretty_print=True): - super(IPInterface, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ifDescr is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifDescr>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.ifDescr).encode(ExternalEncoding), input_name='ifDescr'), namespace_, eol_)) - if self.ifHighSpeed is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifHighSpeed>%s%s' % (namespace_, self.gds_format_integer(self.ifHighSpeed, input_name='ifHighSpeed'), namespace_, eol_)) - if self.ifInBroadcastPkts is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifInBroadcastPkts>%s%s' % (namespace_, self.gds_format_integer(self.ifInBroadcastPkts, input_name='ifInBroadcastPkts'), namespace_, eol_)) - if self.ifIndex is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifIndex>%s%s' % (namespace_, self.gds_format_integer(self.ifIndex, input_name='ifIndex'), namespace_, eol_)) - if self.ifInDiscards is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifInDiscards>%s%s' % (namespace_, self.gds_format_integer(self.ifInDiscards, input_name='ifInDiscards'), namespace_, eol_)) - if self.ifInErrors is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifInErrors>%s%s' % (namespace_, self.gds_format_integer(self.ifInErrors, input_name='ifInErrors'), namespace_, eol_)) - if self.ifInMulticastPkts is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifInMulticastPkts>%s%s' % (namespace_, self.gds_format_integer(self.ifInMulticastPkts, input_name='ifInMulticastPkts'), namespace_, eol_)) - if self.ifInOctets is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifInOctets>%s%s' % (namespace_, self.gds_format_integer(self.ifInOctets, input_name='ifInOctets'), namespace_, eol_)) - if self.ifInUcastPkts is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifInUcastPkts>%s%s' % (namespace_, self.gds_format_integer(self.ifInUcastPkts, input_name='ifInUcastPkts'), namespace_, eol_)) - if self.ifInUnknownProtos is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifInUnknownProtos>%s%s' % (namespace_, self.gds_format_integer(self.ifInUnknownProtos, input_name='ifInUnknownProtos'), namespace_, eol_)) - if self.ifMtu is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifMtu>%s%s' % (namespace_, self.gds_format_integer(self.ifMtu, input_name='ifMtu'), namespace_, eol_)) - if self.ifName is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifName>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.ifName).encode(ExternalEncoding), input_name='ifName'), namespace_, eol_)) - if self.ifOperStatus is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifOperStatus>%s%s' % (namespace_, self.gds_format_integer(self.ifOperStatus, input_name='ifOperStatus'), namespace_, eol_)) - if self.ifOutBroadcastPkts is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifOutBroadcastPkts>%s%s' % (namespace_, self.gds_format_integer(self.ifOutBroadcastPkts, input_name='ifOutBroadcastPkts'), namespace_, eol_)) - if self.ifOutDiscards is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifOutDiscards>%s%s' % (namespace_, self.gds_format_integer(self.ifOutDiscards, input_name='ifOutDiscards'), namespace_, eol_)) - if self.ifOutErrors is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifOutErrors>%s%s' % (namespace_, self.gds_format_integer(self.ifOutErrors, input_name='ifOutErrors'), namespace_, eol_)) - if self.ifOutMulticastPkts is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifOutMulticastPkts>%s%s' % (namespace_, self.gds_format_integer(self.ifOutMulticastPkts, input_name='ifOutMulticastPkts'), namespace_, eol_)) - if self.ifOutOctets is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifOutOctets>%s%s' % (namespace_, self.gds_format_integer(self.ifOutOctets, input_name='ifOutOctets'), namespace_, eol_)) - if self.ifOutUcastPkts is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifOutUcastPkts>%s%s' % (namespace_, self.gds_format_integer(self.ifOutUcastPkts, input_name='ifOutUcastPkts'), namespace_, eol_)) - if self.ifPromiscuousMode is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifPromiscuousMode>%s%s' % (namespace_, self.gds_format_boolean(self.ifPromiscuousMode, input_name='ifPromiscuousMode'), namespace_, eol_)) - if self.ifSpeed is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifSpeed>%s%s' % (namespace_, self.gds_format_integer(self.ifSpeed, input_name='ifSpeed'), namespace_, eol_)) - if self.ifType is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sifType>%s%s' % (namespace_, self.gds_format_integer(self.ifType, input_name='ifType'), namespace_, eol_)) - if self.IPAddrListLink is not None: - self.IPAddrListLink.export(outfile, level, namespace_, name_='IPAddrListLink', pretty_print=pretty_print) - if self.lastResetTime is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slastResetTime>%s%s' % (namespace_, self.gds_format_integer(self.lastResetTime, input_name='lastResetTime'), namespace_, eol_)) - if self.lastUpdatedTime is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slastUpdatedTime>%s%s' % (namespace_, self.gds_format_integer(self.lastUpdatedTime, input_name='lastUpdatedTime'), namespace_, eol_)) - if self.LLInterfaceListLink is not None: - self.LLInterfaceListLink.export(outfile, level, namespace_, name_='LLInterfaceListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='IPInterface'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(IPInterface, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(IPInterface, self).exportLiteralChildren(outfile, level, name_) - if self.ifDescr is not None: - showIndent(outfile, level) - outfile.write('ifDescr=%s,\n' % quote_python(self.ifDescr).encode(ExternalEncoding)) - if self.ifHighSpeed is not None: - showIndent(outfile, level) - outfile.write('ifHighSpeed=%d,\n' % self.ifHighSpeed) - if self.ifInBroadcastPkts is not None: - showIndent(outfile, level) - outfile.write('ifInBroadcastPkts=%d,\n' % self.ifInBroadcastPkts) - if self.ifIndex is not None: - showIndent(outfile, level) - outfile.write('ifIndex=%d,\n' % self.ifIndex) - if self.ifInDiscards is not None: - showIndent(outfile, level) - outfile.write('ifInDiscards=%d,\n' % self.ifInDiscards) - if self.ifInErrors is not None: - showIndent(outfile, level) - outfile.write('ifInErrors=%d,\n' % self.ifInErrors) - if self.ifInMulticastPkts is not None: - showIndent(outfile, level) - outfile.write('ifInMulticastPkts=%d,\n' % self.ifInMulticastPkts) - if self.ifInOctets is not None: - showIndent(outfile, level) - outfile.write('ifInOctets=%d,\n' % self.ifInOctets) - if self.ifInUcastPkts is not None: - showIndent(outfile, level) - outfile.write('ifInUcastPkts=%d,\n' % self.ifInUcastPkts) - if self.ifInUnknownProtos is not None: - showIndent(outfile, level) - outfile.write('ifInUnknownProtos=%d,\n' % self.ifInUnknownProtos) - if self.ifMtu is not None: - showIndent(outfile, level) - outfile.write('ifMtu=%d,\n' % self.ifMtu) - if self.ifName is not None: - showIndent(outfile, level) - outfile.write('ifName=%s,\n' % quote_python(self.ifName).encode(ExternalEncoding)) - if self.ifOperStatus is not None: - showIndent(outfile, level) - outfile.write('ifOperStatus=%d,\n' % self.ifOperStatus) - if self.ifOutBroadcastPkts is not None: - showIndent(outfile, level) - outfile.write('ifOutBroadcastPkts=%d,\n' % self.ifOutBroadcastPkts) - if self.ifOutDiscards is not None: - showIndent(outfile, level) - outfile.write('ifOutDiscards=%d,\n' % self.ifOutDiscards) - if self.ifOutErrors is not None: - showIndent(outfile, level) - outfile.write('ifOutErrors=%d,\n' % self.ifOutErrors) - if self.ifOutMulticastPkts is not None: - showIndent(outfile, level) - outfile.write('ifOutMulticastPkts=%d,\n' % self.ifOutMulticastPkts) - if self.ifOutOctets is not None: - showIndent(outfile, level) - outfile.write('ifOutOctets=%d,\n' % self.ifOutOctets) - if self.ifOutUcastPkts is not None: - showIndent(outfile, level) - outfile.write('ifOutUcastPkts=%d,\n' % self.ifOutUcastPkts) - if self.ifPromiscuousMode is not None: - showIndent(outfile, level) - outfile.write('ifPromiscuousMode=%s,\n' % self.ifPromiscuousMode) - if self.ifSpeed is not None: - showIndent(outfile, level) - outfile.write('ifSpeed=%d,\n' % self.ifSpeed) - if self.ifType is not None: - showIndent(outfile, level) - outfile.write('ifType=%d,\n' % self.ifType) - if self.IPAddrListLink is not None: - showIndent(outfile, level) - outfile.write('IPAddrListLink=model_.IPAddrListLink(\n') - self.IPAddrListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.lastResetTime is not None: - showIndent(outfile, level) - outfile.write('lastResetTime=%d,\n' % self.lastResetTime) - if self.lastUpdatedTime is not None: - showIndent(outfile, level) - outfile.write('lastUpdatedTime=%d,\n' % self.lastUpdatedTime) - if self.LLInterfaceListLink is not None: - showIndent(outfile, level) - outfile.write('LLInterfaceListLink=model_.LLInterfaceListLink(\n') - self.LLInterfaceListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(IPInterface, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ifDescr': - ifDescr_ = child_.text - ifDescr_ = self.gds_validate_string(ifDescr_, node, 'ifDescr') - self.ifDescr = ifDescr_ - self.validate_String192(self.ifDescr) # validate type String192 - elif nodeName_ == 'ifHighSpeed': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifHighSpeed') - self.ifHighSpeed = ival_ - self.validate_UInt32(self.ifHighSpeed) # validate type UInt32 - elif nodeName_ == 'ifInBroadcastPkts': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifInBroadcastPkts') - self.ifInBroadcastPkts = ival_ - self.validate_UInt32(self.ifInBroadcastPkts) # validate type UInt32 - elif nodeName_ == 'ifIndex': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifIndex') - self.ifIndex = ival_ - self.validate_UInt32(self.ifIndex) # validate type UInt32 - elif nodeName_ == 'ifInDiscards': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifInDiscards') - self.ifInDiscards = ival_ - self.validate_UInt32(self.ifInDiscards) # validate type UInt32 - elif nodeName_ == 'ifInErrors': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifInErrors') - self.ifInErrors = ival_ - self.validate_UInt32(self.ifInErrors) # validate type UInt32 - elif nodeName_ == 'ifInMulticastPkts': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifInMulticastPkts') - self.ifInMulticastPkts = ival_ - self.validate_UInt32(self.ifInMulticastPkts) # validate type UInt32 - elif nodeName_ == 'ifInOctets': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifInOctets') - self.ifInOctets = ival_ - self.validate_UInt32(self.ifInOctets) # validate type UInt32 - elif nodeName_ == 'ifInUcastPkts': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifInUcastPkts') - self.ifInUcastPkts = ival_ - self.validate_UInt32(self.ifInUcastPkts) # validate type UInt32 - elif nodeName_ == 'ifInUnknownProtos': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifInUnknownProtos') - self.ifInUnknownProtos = ival_ - self.validate_UInt32(self.ifInUnknownProtos) # validate type UInt32 - elif nodeName_ == 'ifMtu': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifMtu') - self.ifMtu = ival_ - self.validate_UInt32(self.ifMtu) # validate type UInt32 - elif nodeName_ == 'ifName': - ifName_ = child_.text - ifName_ = self.gds_validate_string(ifName_, node, 'ifName') - self.ifName = ifName_ - self.validate_String16(self.ifName) # validate type String16 - elif nodeName_ == 'ifOperStatus': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifOperStatus') - self.ifOperStatus = ival_ - self.validate_UInt8(self.ifOperStatus) # validate type UInt8 - elif nodeName_ == 'ifOutBroadcastPkts': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifOutBroadcastPkts') - self.ifOutBroadcastPkts = ival_ - self.validate_UInt32(self.ifOutBroadcastPkts) # validate type UInt32 - elif nodeName_ == 'ifOutDiscards': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifOutDiscards') - self.ifOutDiscards = ival_ - self.validate_UInt32(self.ifOutDiscards) # validate type UInt32 - elif nodeName_ == 'ifOutErrors': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifOutErrors') - self.ifOutErrors = ival_ - self.validate_UInt32(self.ifOutErrors) # validate type UInt32 - elif nodeName_ == 'ifOutMulticastPkts': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifOutMulticastPkts') - self.ifOutMulticastPkts = ival_ - self.validate_UInt32(self.ifOutMulticastPkts) # validate type UInt32 - elif nodeName_ == 'ifOutOctets': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifOutOctets') - self.ifOutOctets = ival_ - self.validate_UInt32(self.ifOutOctets) # validate type UInt32 - elif nodeName_ == 'ifOutUcastPkts': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifOutUcastPkts') - self.ifOutUcastPkts = ival_ - self.validate_UInt32(self.ifOutUcastPkts) # validate type UInt32 - elif nodeName_ == 'ifPromiscuousMode': - sval_ = child_.text - if sval_ in ('true', '1'): - ival_ = True - elif sval_ in ('false', '0'): - ival_ = False - else: - raise_parse_error(child_, 'requires boolean') - ival_ = self.gds_validate_boolean(ival_, node, 'ifPromiscuousMode') - self.ifPromiscuousMode = ival_ - elif nodeName_ == 'ifSpeed': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifSpeed') - self.ifSpeed = ival_ - self.validate_UInt32(self.ifSpeed) # validate type UInt32 - elif nodeName_ == 'ifType': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'ifType') - self.ifType = ival_ - self.validate_UInt16(self.ifType) # validate type UInt16 - elif nodeName_ == 'IPAddrListLink': - obj_ = IPAddrListLink.factory() - obj_.build(child_) - self.IPAddrListLink = obj_ - obj_.original_tagname_ = 'IPAddrListLink' - elif nodeName_ == 'lastResetTime': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'lastResetTime') - self.lastResetTime = ival_ - self.validate_Int64(self.lastResetTime) # validate type Int64 - elif nodeName_ == 'lastUpdatedTime': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'lastUpdatedTime') - self.lastUpdatedTime = ival_ - self.validate_Int64(self.lastUpdatedTime) # validate type Int64 - elif nodeName_ == 'LLInterfaceListLink': - obj_ = LLInterfaceListLink.factory() - obj_.build(child_) - self.LLInterfaceListLink = obj_ - obj_.original_tagname_ = 'LLInterfaceListLink' - super(IPInterface, self).buildChildren(child_, node, nodeName_, True) -# end class IPInterface - - -class IPAddrList(List): - """List of IPAddr instances.""" - subclass = None - superclass = List - def __init__(self, IPAddr=None): - self.original_tagname_ = None - super(IPAddrList, self).__init__() - if IPAddr is None: - self.IPAddr = [] - else: - self.IPAddr = IPAddr - def factory(*args_, **kwargs_): - if IPAddrList.subclass: - return IPAddrList.subclass(*args_, **kwargs_) - else: - return IPAddrList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_IPAddr(self): return self.IPAddr - def set_IPAddr(self, IPAddr): self.IPAddr = IPAddr - def add_IPAddr(self, value): self.IPAddr.append(value) - def insert_IPAddr_at(self, index, value): self.IPAddr.insert(index, value) - def replace_IPAddr_at(self, index, value): self.IPAddr[index] = value - def hasContent_(self): - if ( - self.IPAddr or - super(IPAddrList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='IPAddrList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='IPAddrList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='IPAddrList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='IPAddrList'): - super(IPAddrList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='IPAddrList') - def exportChildren(self, outfile, level, namespace_='', name_='IPAddrList', fromsubclass_=False, pretty_print=True): - super(IPAddrList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for IPAddr_ in self.IPAddr: - IPAddr_.export(outfile, level, namespace_, name_='IPAddr', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='IPAddrList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(IPAddrList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(IPAddrList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('IPAddr=[\n') - level += 1 - for IPAddr_ in self.IPAddr: - showIndent(outfile, level) - outfile.write('model_.IPAddr(\n') - IPAddr_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(IPAddrList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'IPAddr': - obj_ = IPAddr.factory() - obj_.build(child_) - self.IPAddr.append(obj_) - obj_.original_tagname_ = 'IPAddr' - super(IPAddrList, self).buildChildren(child_, node, nodeName_, True) -# end class IPAddrList - - -class IPAddr(Resource): - """An Internet Protocol address object.""" - subclass = None - superclass = Resource - def __init__(self, address=None, RPLInstanceListLink=None): - self.original_tagname_ = None - super(IPAddr, self).__init__() - self.address = address - self.RPLInstanceListLink = RPLInstanceListLink - def factory(*args_, **kwargs_): - if IPAddr.subclass: - return IPAddr.subclass(*args_, **kwargs_) - else: - return IPAddr(*args_, **kwargs_) - factory = staticmethod(factory) - def get_address(self): return self.address - def set_address(self, address): self.address = address - def get_RPLInstanceListLink(self): return self.RPLInstanceListLink - def set_RPLInstanceListLink(self, RPLInstanceListLink): self.RPLInstanceListLink = RPLInstanceListLink - def validate_HexBinary128(self, value): - # Validate type HexBinary128, a restriction on xs:hexBinary. - pass - def hasContent_(self): - if ( - self.address is not None or - self.RPLInstanceListLink is not None or - super(IPAddr, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='IPAddr', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='IPAddr') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='IPAddr', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='IPAddr'): - super(IPAddr, self).exportAttributes(outfile, level, already_processed, namespace_, name_='IPAddr') - def exportChildren(self, outfile, level, namespace_='', name_='IPAddr', fromsubclass_=False, pretty_print=True): - super(IPAddr, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.address is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%saddress>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.address).encode(ExternalEncoding), input_name='address'), namespace_, eol_)) - if self.RPLInstanceListLink is not None: - self.RPLInstanceListLink.export(outfile, level, namespace_, name_='RPLInstanceListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='IPAddr'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(IPAddr, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(IPAddr, self).exportLiteralChildren(outfile, level, name_) - if self.address is not None: - showIndent(outfile, level) - outfile.write('address=%s,\n' % quote_python(self.address).encode(ExternalEncoding)) - if self.RPLInstanceListLink is not None: - showIndent(outfile, level) - outfile.write('RPLInstanceListLink=model_.RPLInstanceListLink(\n') - self.RPLInstanceListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(IPAddr, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'address': - address_ = child_.text - address_ = self.gds_validate_string(address_, node, 'address') - self.address = address_ - self.validate_HexBinary128(self.address) # validate type HexBinary128 - elif nodeName_ == 'RPLInstanceListLink': - obj_ = RPLInstanceListLink.factory() - obj_.build(child_) - self.RPLInstanceListLink = obj_ - obj_.original_tagname_ = 'RPLInstanceListLink' - super(IPAddr, self).buildChildren(child_, node, nodeName_, True) -# end class IPAddr - - -class PowerStatus(Resource): - """Contains the status of the device's power sources""" - subclass = None - superclass = Resource - def __init__(self, batteryStatus=None, changedTime=None, currentPowerSource=None, estimatedChargeRemaining=None, estimatedTimeRemaining=None, PEVInfo=None, sessionTimeOnBattery=None, totalTimeOnBattery=None): - self.original_tagname_ = None - super(PowerStatus, self).__init__() - self.batteryStatus = batteryStatus - self.changedTime = changedTime - self.currentPowerSource = currentPowerSource - self.estimatedChargeRemaining = estimatedChargeRemaining - self.estimatedTimeRemaining = estimatedTimeRemaining - self.PEVInfo = PEVInfo - self.sessionTimeOnBattery = sessionTimeOnBattery - self.totalTimeOnBattery = totalTimeOnBattery - def factory(*args_, **kwargs_): - if PowerStatus.subclass: - return PowerStatus.subclass(*args_, **kwargs_) - else: - return PowerStatus(*args_, **kwargs_) - factory = staticmethod(factory) - def get_batteryStatus(self): return self.batteryStatus - def set_batteryStatus(self, batteryStatus): self.batteryStatus = batteryStatus - def get_changedTime(self): return self.changedTime - def set_changedTime(self, changedTime): self.changedTime = changedTime - def get_currentPowerSource(self): return self.currentPowerSource - def set_currentPowerSource(self, currentPowerSource): self.currentPowerSource = currentPowerSource - def get_estimatedChargeRemaining(self): return self.estimatedChargeRemaining - def set_estimatedChargeRemaining(self, estimatedChargeRemaining): self.estimatedChargeRemaining = estimatedChargeRemaining - def get_estimatedTimeRemaining(self): return self.estimatedTimeRemaining - def set_estimatedTimeRemaining(self, estimatedTimeRemaining): self.estimatedTimeRemaining = estimatedTimeRemaining - def get_PEVInfo(self): return self.PEVInfo - def set_PEVInfo(self, PEVInfo): self.PEVInfo = PEVInfo - def get_sessionTimeOnBattery(self): return self.sessionTimeOnBattery - def set_sessionTimeOnBattery(self, sessionTimeOnBattery): self.sessionTimeOnBattery = sessionTimeOnBattery - def get_totalTimeOnBattery(self): return self.totalTimeOnBattery - def set_totalTimeOnBattery(self, totalTimeOnBattery): self.totalTimeOnBattery = totalTimeOnBattery - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def hasContent_(self): - if ( - self.batteryStatus is not None or - self.changedTime is not None or - self.currentPowerSource is not None or - self.estimatedChargeRemaining is not None or - self.estimatedTimeRemaining is not None or - self.PEVInfo is not None or - self.sessionTimeOnBattery is not None or - self.totalTimeOnBattery is not None or - super(PowerStatus, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PowerStatus', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PowerStatus') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PowerStatus', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PowerStatus'): - super(PowerStatus, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PowerStatus') - def exportChildren(self, outfile, level, namespace_='', name_='PowerStatus', fromsubclass_=False, pretty_print=True): - super(PowerStatus, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.batteryStatus is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sbatteryStatus>%s%s' % (namespace_, self.gds_format_integer(self.batteryStatus, input_name='batteryStatus'), namespace_, eol_)) - if self.changedTime is not None: - self.changedTime.export(outfile, level, namespace_, name_='changedTime', pretty_print=pretty_print) - if self.currentPowerSource is not None: - self.currentPowerSource.export(outfile, level, namespace_, name_='currentPowerSource', pretty_print=pretty_print) - if self.estimatedChargeRemaining is not None: - self.estimatedChargeRemaining.export(outfile, level, namespace_, name_='estimatedChargeRemaining', pretty_print=pretty_print) - if self.estimatedTimeRemaining is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sestimatedTimeRemaining>%s%s' % (namespace_, self.gds_format_integer(self.estimatedTimeRemaining, input_name='estimatedTimeRemaining'), namespace_, eol_)) - if self.PEVInfo is not None: - self.PEVInfo.export(outfile, level, namespace_, name_='PEVInfo', pretty_print=pretty_print) - if self.sessionTimeOnBattery is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssessionTimeOnBattery>%s%s' % (namespace_, self.gds_format_integer(self.sessionTimeOnBattery, input_name='sessionTimeOnBattery'), namespace_, eol_)) - if self.totalTimeOnBattery is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%stotalTimeOnBattery>%s%s' % (namespace_, self.gds_format_integer(self.totalTimeOnBattery, input_name='totalTimeOnBattery'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='PowerStatus'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PowerStatus, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PowerStatus, self).exportLiteralChildren(outfile, level, name_) - if self.batteryStatus is not None: - showIndent(outfile, level) - outfile.write('batteryStatus=%d,\n' % self.batteryStatus) - if self.changedTime is not None: - showIndent(outfile, level) - outfile.write('changedTime=model_.TimeType(\n') - self.changedTime.exportLiteral(outfile, level, name_='changedTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.currentPowerSource is not None: - showIndent(outfile, level) - outfile.write('currentPowerSource=model_.PowerSourceType(\n') - self.currentPowerSource.exportLiteral(outfile, level, name_='currentPowerSource') - showIndent(outfile, level) - outfile.write('),\n') - if self.estimatedChargeRemaining is not None: - showIndent(outfile, level) - outfile.write('estimatedChargeRemaining=model_.PerCent(\n') - self.estimatedChargeRemaining.exportLiteral(outfile, level, name_='estimatedChargeRemaining') - showIndent(outfile, level) - outfile.write('),\n') - if self.estimatedTimeRemaining is not None: - showIndent(outfile, level) - outfile.write('estimatedTimeRemaining=%d,\n' % self.estimatedTimeRemaining) - if self.PEVInfo is not None: - showIndent(outfile, level) - outfile.write('PEVInfo=model_.PEVInfo(\n') - self.PEVInfo.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.sessionTimeOnBattery is not None: - showIndent(outfile, level) - outfile.write('sessionTimeOnBattery=%d,\n' % self.sessionTimeOnBattery) - if self.totalTimeOnBattery is not None: - showIndent(outfile, level) - outfile.write('totalTimeOnBattery=%d,\n' % self.totalTimeOnBattery) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PowerStatus, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'batteryStatus': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'batteryStatus') - self.batteryStatus = ival_ - self.validate_UInt8(self.batteryStatus) # validate type UInt8 - elif nodeName_ == 'changedTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.changedTime = obj_ - obj_.original_tagname_ = 'changedTime' - elif nodeName_ == 'currentPowerSource': - obj_ = PowerSourceType.factory() - obj_.build(child_) - self.currentPowerSource = obj_ - obj_.original_tagname_ = 'currentPowerSource' - elif nodeName_ == 'estimatedChargeRemaining': - obj_ = PerCent.factory() - obj_.build(child_) - self.estimatedChargeRemaining = obj_ - obj_.original_tagname_ = 'estimatedChargeRemaining' - elif nodeName_ == 'estimatedTimeRemaining': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'estimatedTimeRemaining') - self.estimatedTimeRemaining = ival_ - self.validate_UInt32(self.estimatedTimeRemaining) # validate type UInt32 - elif nodeName_ == 'PEVInfo': - obj_ = PEVInfo.factory() - obj_.build(child_) - self.PEVInfo = obj_ - obj_.original_tagname_ = 'PEVInfo' - elif nodeName_ == 'sessionTimeOnBattery': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'sessionTimeOnBattery') - self.sessionTimeOnBattery = ival_ - self.validate_UInt32(self.sessionTimeOnBattery) # validate type UInt32 - elif nodeName_ == 'totalTimeOnBattery': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'totalTimeOnBattery') - self.totalTimeOnBattery = ival_ - self.validate_UInt32(self.totalTimeOnBattery) # validate type UInt32 - super(PowerStatus, self).buildChildren(child_, node, nodeName_, True) -# end class PowerStatus - - -class SupportedLocaleList(List): - """A List element to hold SupportedLocale objects.""" - subclass = None - superclass = List - def __init__(self, SupportedLocale=None): - self.original_tagname_ = None - super(SupportedLocaleList, self).__init__() - if SupportedLocale is None: - self.SupportedLocale = [] - else: - self.SupportedLocale = SupportedLocale - def factory(*args_, **kwargs_): - if SupportedLocaleList.subclass: - return SupportedLocaleList.subclass(*args_, **kwargs_) - else: - return SupportedLocaleList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_SupportedLocale(self): return self.SupportedLocale - def set_SupportedLocale(self, SupportedLocale): self.SupportedLocale = SupportedLocale - def add_SupportedLocale(self, value): self.SupportedLocale.append(value) - def insert_SupportedLocale_at(self, index, value): self.SupportedLocale.insert(index, value) - def replace_SupportedLocale_at(self, index, value): self.SupportedLocale[index] = value - def hasContent_(self): - if ( - self.SupportedLocale or - super(SupportedLocaleList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SupportedLocaleList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SupportedLocaleList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SupportedLocaleList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SupportedLocaleList'): - super(SupportedLocaleList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SupportedLocaleList') - def exportChildren(self, outfile, level, namespace_='', name_='SupportedLocaleList', fromsubclass_=False, pretty_print=True): - super(SupportedLocaleList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for SupportedLocale_ in self.SupportedLocale: - SupportedLocale_.export(outfile, level, namespace_, name_='SupportedLocale', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='SupportedLocaleList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SupportedLocaleList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SupportedLocaleList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('SupportedLocale=[\n') - level += 1 - for SupportedLocale_ in self.SupportedLocale: - showIndent(outfile, level) - outfile.write('model_.SupportedLocale(\n') - SupportedLocale_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SupportedLocaleList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'SupportedLocale': - obj_ = SupportedLocale.factory() - obj_.build(child_) - self.SupportedLocale.append(obj_) - obj_.original_tagname_ = 'SupportedLocale' - super(SupportedLocaleList, self).buildChildren(child_, node, nodeName_, True) -# end class SupportedLocaleList - - -class SupportedLocale(Resource): - """Specifies a locale that is supported""" - subclass = None - superclass = Resource - def __init__(self, locale=None): - self.original_tagname_ = None - super(SupportedLocale, self).__init__() - self.locale = locale - def factory(*args_, **kwargs_): - if SupportedLocale.subclass: - return SupportedLocale.subclass(*args_, **kwargs_) - else: - return SupportedLocale(*args_, **kwargs_) - factory = staticmethod(factory) - def get_locale(self): return self.locale - def set_locale(self, locale): self.locale = locale - def hasContent_(self): - if ( - self.locale is not None or - super(SupportedLocale, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SupportedLocale', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SupportedLocale') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SupportedLocale', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SupportedLocale'): - super(SupportedLocale, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SupportedLocale') - def exportChildren(self, outfile, level, namespace_='', name_='SupportedLocale', fromsubclass_=False, pretty_print=True): - super(SupportedLocale, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.locale is not None: - self.locale.export(outfile, level, namespace_, name_='locale', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='SupportedLocale'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SupportedLocale, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SupportedLocale, self).exportLiteralChildren(outfile, level, name_) - if self.locale is not None: - showIndent(outfile, level) - outfile.write('locale=model_.LocaleType(\n') - self.locale.exportLiteral(outfile, level, name_='locale') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SupportedLocale, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'locale': - obj_ = LocaleType.factory() - obj_.build(child_) - self.locale = obj_ - obj_.original_tagname_ = 'locale' - super(SupportedLocale, self).buildChildren(child_, node, nodeName_, True) -# end class SupportedLocale - - -class DeviceInformation(Resource): - """Contains identification and other information about the device that - changes very infrequently, typically only when updates are - applied, if ever.""" - subclass = None - superclass = Resource - def __init__(self, DRLCCapabilities=None, functionsImplemented=None, lFDI=None, mfDate=None, mfHwVer=None, mfID=None, mfInfo=None, mfModel=None, mfSerNum=None, primaryPower=None, secondaryPower=None, SupportedLocaleListLink=None, swActTime=None, swVer=None): - self.original_tagname_ = None - super(DeviceInformation, self).__init__() - self.DRLCCapabilities = DRLCCapabilities - self.functionsImplemented = functionsImplemented - self.lFDI = lFDI - self.mfDate = mfDate - self.mfHwVer = mfHwVer - self.mfID = mfID - self.mfInfo = mfInfo - self.mfModel = mfModel - self.mfSerNum = mfSerNum - self.primaryPower = primaryPower - self.secondaryPower = secondaryPower - self.SupportedLocaleListLink = SupportedLocaleListLink - self.swActTime = swActTime - self.swVer = swVer - def factory(*args_, **kwargs_): - if DeviceInformation.subclass: - return DeviceInformation.subclass(*args_, **kwargs_) - else: - return DeviceInformation(*args_, **kwargs_) - factory = staticmethod(factory) - def get_DRLCCapabilities(self): return self.DRLCCapabilities - def set_DRLCCapabilities(self, DRLCCapabilities): self.DRLCCapabilities = DRLCCapabilities - def get_functionsImplemented(self): return self.functionsImplemented - def set_functionsImplemented(self, functionsImplemented): self.functionsImplemented = functionsImplemented - def get_lFDI(self): return self.lFDI - def set_lFDI(self, lFDI): self.lFDI = lFDI - def get_mfDate(self): return self.mfDate - def set_mfDate(self, mfDate): self.mfDate = mfDate - def get_mfHwVer(self): return self.mfHwVer - def set_mfHwVer(self, mfHwVer): self.mfHwVer = mfHwVer - def get_mfID(self): return self.mfID - def set_mfID(self, mfID): self.mfID = mfID - def get_mfInfo(self): return self.mfInfo - def set_mfInfo(self, mfInfo): self.mfInfo = mfInfo - def get_mfModel(self): return self.mfModel - def set_mfModel(self, mfModel): self.mfModel = mfModel - def get_mfSerNum(self): return self.mfSerNum - def set_mfSerNum(self, mfSerNum): self.mfSerNum = mfSerNum - def get_primaryPower(self): return self.primaryPower - def set_primaryPower(self, primaryPower): self.primaryPower = primaryPower - def get_secondaryPower(self): return self.secondaryPower - def set_secondaryPower(self, secondaryPower): self.secondaryPower = secondaryPower - def get_SupportedLocaleListLink(self): return self.SupportedLocaleListLink - def set_SupportedLocaleListLink(self, SupportedLocaleListLink): self.SupportedLocaleListLink = SupportedLocaleListLink - def get_swActTime(self): return self.swActTime - def set_swActTime(self, swActTime): self.swActTime = swActTime - def get_swVer(self): return self.swVer - def set_swVer(self, swVer): self.swVer = swVer - def validate_HexBinary64(self, value): - # Validate type HexBinary64, a restriction on xs:hexBinary. - pass - def validate_HexBinary160(self, value): - # Validate type HexBinary160, a restriction on xs:hexBinary. - pass - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def hasContent_(self): - if ( - self.DRLCCapabilities is not None or - self.functionsImplemented is not None or - self.lFDI is not None or - self.mfDate is not None or - self.mfHwVer is not None or - self.mfID is not None or - self.mfInfo is not None or - self.mfModel is not None or - self.mfSerNum is not None or - self.primaryPower is not None or - self.secondaryPower is not None or - self.SupportedLocaleListLink is not None or - self.swActTime is not None or - self.swVer is not None or - super(DeviceInformation, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DeviceInformation', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceInformation') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DeviceInformation', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DeviceInformation'): - super(DeviceInformation, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceInformation') - def exportChildren(self, outfile, level, namespace_='', name_='DeviceInformation', fromsubclass_=False, pretty_print=True): - super(DeviceInformation, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.DRLCCapabilities is not None: - self.DRLCCapabilities.export(outfile, level, namespace_, name_='DRLCCapabilities', pretty_print=pretty_print) - if self.functionsImplemented is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sfunctionsImplemented>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.functionsImplemented).encode(ExternalEncoding), input_name='functionsImplemented'), namespace_, eol_)) - if self.lFDI is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slFDI>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.lFDI).encode(ExternalEncoding), input_name='lFDI'), namespace_, eol_)) - if self.mfDate is not None: - self.mfDate.export(outfile, level, namespace_, name_='mfDate', pretty_print=pretty_print) - if self.mfHwVer is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smfHwVer>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mfHwVer).encode(ExternalEncoding), input_name='mfHwVer'), namespace_, eol_)) - if self.mfID is not None: - self.mfID.export(outfile, level, namespace_, name_='mfID', pretty_print=pretty_print) - if self.mfInfo is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smfInfo>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mfInfo).encode(ExternalEncoding), input_name='mfInfo'), namespace_, eol_)) - if self.mfModel is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smfModel>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mfModel).encode(ExternalEncoding), input_name='mfModel'), namespace_, eol_)) - if self.mfSerNum is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%smfSerNum>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mfSerNum).encode(ExternalEncoding), input_name='mfSerNum'), namespace_, eol_)) - if self.primaryPower is not None: - self.primaryPower.export(outfile, level, namespace_, name_='primaryPower', pretty_print=pretty_print) - if self.secondaryPower is not None: - self.secondaryPower.export(outfile, level, namespace_, name_='secondaryPower', pretty_print=pretty_print) - if self.SupportedLocaleListLink is not None: - self.SupportedLocaleListLink.export(outfile, level, namespace_, name_='SupportedLocaleListLink', pretty_print=pretty_print) - if self.swActTime is not None: - self.swActTime.export(outfile, level, namespace_, name_='swActTime', pretty_print=pretty_print) - if self.swVer is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sswVer>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.swVer).encode(ExternalEncoding), input_name='swVer'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='DeviceInformation'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DeviceInformation, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DeviceInformation, self).exportLiteralChildren(outfile, level, name_) - if self.DRLCCapabilities is not None: - showIndent(outfile, level) - outfile.write('DRLCCapabilities=model_.DRLCCapabilities(\n') - self.DRLCCapabilities.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.functionsImplemented is not None: - showIndent(outfile, level) - outfile.write('functionsImplemented=%s,\n' % quote_python(self.functionsImplemented).encode(ExternalEncoding)) - if self.lFDI is not None: - showIndent(outfile, level) - outfile.write('lFDI=%s,\n' % quote_python(self.lFDI).encode(ExternalEncoding)) - if self.mfDate is not None: - showIndent(outfile, level) - outfile.write('mfDate=model_.TimeType(\n') - self.mfDate.exportLiteral(outfile, level, name_='mfDate') - showIndent(outfile, level) - outfile.write('),\n') - if self.mfHwVer is not None: - showIndent(outfile, level) - outfile.write('mfHwVer=%s,\n' % quote_python(self.mfHwVer).encode(ExternalEncoding)) - if self.mfID is not None: - showIndent(outfile, level) - outfile.write('mfID=model_.PENType(\n') - self.mfID.exportLiteral(outfile, level, name_='mfID') - showIndent(outfile, level) - outfile.write('),\n') - if self.mfInfo is not None: - showIndent(outfile, level) - outfile.write('mfInfo=%s,\n' % quote_python(self.mfInfo).encode(ExternalEncoding)) - if self.mfModel is not None: - showIndent(outfile, level) - outfile.write('mfModel=%s,\n' % quote_python(self.mfModel).encode(ExternalEncoding)) - if self.mfSerNum is not None: - showIndent(outfile, level) - outfile.write('mfSerNum=%s,\n' % quote_python(self.mfSerNum).encode(ExternalEncoding)) - if self.primaryPower is not None: - showIndent(outfile, level) - outfile.write('primaryPower=model_.PowerSourceType(\n') - self.primaryPower.exportLiteral(outfile, level, name_='primaryPower') - showIndent(outfile, level) - outfile.write('),\n') - if self.secondaryPower is not None: - showIndent(outfile, level) - outfile.write('secondaryPower=model_.PowerSourceType(\n') - self.secondaryPower.exportLiteral(outfile, level, name_='secondaryPower') - showIndent(outfile, level) - outfile.write('),\n') - if self.SupportedLocaleListLink is not None: - showIndent(outfile, level) - outfile.write('SupportedLocaleListLink=model_.SupportedLocaleListLink(\n') - self.SupportedLocaleListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.swActTime is not None: - showIndent(outfile, level) - outfile.write('swActTime=model_.TimeType(\n') - self.swActTime.exportLiteral(outfile, level, name_='swActTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.swVer is not None: - showIndent(outfile, level) - outfile.write('swVer=%s,\n' % quote_python(self.swVer).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DeviceInformation, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'DRLCCapabilities': - obj_ = DRLCCapabilities.factory() - obj_.build(child_) - self.DRLCCapabilities = obj_ - obj_.original_tagname_ = 'DRLCCapabilities' - elif nodeName_ == 'functionsImplemented': - functionsImplemented_ = child_.text - functionsImplemented_ = self.gds_validate_string(functionsImplemented_, node, 'functionsImplemented') - self.functionsImplemented = functionsImplemented_ - self.validate_HexBinary64(self.functionsImplemented) # validate type HexBinary64 - elif nodeName_ == 'lFDI': - lFDI_ = child_.text - lFDI_ = self.gds_validate_string(lFDI_, node, 'lFDI') - self.lFDI = lFDI_ - self.validate_HexBinary160(self.lFDI) # validate type HexBinary160 - elif nodeName_ == 'mfDate': - obj_ = TimeType.factory() - obj_.build(child_) - self.mfDate = obj_ - obj_.original_tagname_ = 'mfDate' - elif nodeName_ == 'mfHwVer': - mfHwVer_ = child_.text - mfHwVer_ = self.gds_validate_string(mfHwVer_, node, 'mfHwVer') - self.mfHwVer = mfHwVer_ - self.validate_String32(self.mfHwVer) # validate type String32 - elif nodeName_ == 'mfID': - obj_ = PENType.factory() - obj_.build(child_) - self.mfID = obj_ - obj_.original_tagname_ = 'mfID' - elif nodeName_ == 'mfInfo': - mfInfo_ = child_.text - mfInfo_ = self.gds_validate_string(mfInfo_, node, 'mfInfo') - self.mfInfo = mfInfo_ - self.validate_String32(self.mfInfo) # validate type String32 - elif nodeName_ == 'mfModel': - mfModel_ = child_.text - mfModel_ = self.gds_validate_string(mfModel_, node, 'mfModel') - self.mfModel = mfModel_ - self.validate_String32(self.mfModel) # validate type String32 - elif nodeName_ == 'mfSerNum': - mfSerNum_ = child_.text - mfSerNum_ = self.gds_validate_string(mfSerNum_, node, 'mfSerNum') - self.mfSerNum = mfSerNum_ - self.validate_String32(self.mfSerNum) # validate type String32 - elif nodeName_ == 'primaryPower': - obj_ = PowerSourceType.factory() - obj_.build(child_) - self.primaryPower = obj_ - obj_.original_tagname_ = 'primaryPower' - elif nodeName_ == 'secondaryPower': - obj_ = PowerSourceType.factory() - obj_.build(child_) - self.secondaryPower = obj_ - obj_.original_tagname_ = 'secondaryPower' - elif nodeName_ == 'SupportedLocaleListLink': - obj_ = SupportedLocaleListLink.factory() - obj_.build(child_) - self.SupportedLocaleListLink = obj_ - obj_.original_tagname_ = 'SupportedLocaleListLink' - elif nodeName_ == 'swActTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.swActTime = obj_ - obj_.original_tagname_ = 'swActTime' - elif nodeName_ == 'swVer': - swVer_ = child_.text - swVer_ = self.gds_validate_string(swVer_, node, 'swVer') - self.swVer = swVer_ - self.validate_String32(self.swVer) # validate type String32 - super(DeviceInformation, self).buildChildren(child_, node, nodeName_, True) -# end class DeviceInformation - - -class Time(Resource): - """Contains the representation of time, constantly updated.""" - subclass = None - superclass = Resource - def __init__(self, currentTime=None, dstEndTime=None, dstOffset=None, dstStartTime=None, localTime=None, quality=None, tzOffset=None): - self.original_tagname_ = None - super(Time, self).__init__() - self.currentTime = currentTime - self.dstEndTime = dstEndTime - self.dstOffset = dstOffset - self.dstStartTime = dstStartTime - self.localTime = localTime - self.quality = quality - self.tzOffset = tzOffset - def factory(*args_, **kwargs_): - if Time.subclass: - return Time.subclass(*args_, **kwargs_) - else: - return Time(*args_, **kwargs_) - factory = staticmethod(factory) - def get_currentTime(self): return self.currentTime - def set_currentTime(self, currentTime): self.currentTime = currentTime - def get_dstEndTime(self): return self.dstEndTime - def set_dstEndTime(self, dstEndTime): self.dstEndTime = dstEndTime - def get_dstOffset(self): return self.dstOffset - def set_dstOffset(self, dstOffset): self.dstOffset = dstOffset - def get_dstStartTime(self): return self.dstStartTime - def set_dstStartTime(self, dstStartTime): self.dstStartTime = dstStartTime - def get_localTime(self): return self.localTime - def set_localTime(self, localTime): self.localTime = localTime - def get_quality(self): return self.quality - def set_quality(self, quality): self.quality = quality - def get_tzOffset(self): return self.tzOffset - def set_tzOffset(self, tzOffset): self.tzOffset = tzOffset - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.currentTime is not None or - self.dstEndTime is not None or - self.dstOffset is not None or - self.dstStartTime is not None or - self.localTime is not None or - self.quality is not None or - self.tzOffset is not None or - super(Time, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Time', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Time') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Time', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Time'): - super(Time, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Time') - def exportChildren(self, outfile, level, namespace_='', name_='Time', fromsubclass_=False, pretty_print=True): - super(Time, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.currentTime is not None: - self.currentTime.export(outfile, level, namespace_, name_='currentTime', pretty_print=pretty_print) - if self.dstEndTime is not None: - self.dstEndTime.export(outfile, level, namespace_, name_='dstEndTime', pretty_print=pretty_print) - if self.dstOffset is not None: - self.dstOffset.export(outfile, level, namespace_, name_='dstOffset', pretty_print=pretty_print) - if self.dstStartTime is not None: - self.dstStartTime.export(outfile, level, namespace_, name_='dstStartTime', pretty_print=pretty_print) - if self.localTime is not None: - self.localTime.export(outfile, level, namespace_, name_='localTime', pretty_print=pretty_print) - if self.quality is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%squality>%s%s' % (namespace_, self.gds_format_integer(self.quality, input_name='quality'), namespace_, eol_)) - if self.tzOffset is not None: - self.tzOffset.export(outfile, level, namespace_, name_='tzOffset', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='Time'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Time, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Time, self).exportLiteralChildren(outfile, level, name_) - if self.currentTime is not None: - showIndent(outfile, level) - outfile.write('currentTime=model_.TimeType(\n') - self.currentTime.exportLiteral(outfile, level, name_='currentTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.dstEndTime is not None: - showIndent(outfile, level) - outfile.write('dstEndTime=model_.TimeType(\n') - self.dstEndTime.exportLiteral(outfile, level, name_='dstEndTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.dstOffset is not None: - showIndent(outfile, level) - outfile.write('dstOffset=model_.TimeOffsetType(\n') - self.dstOffset.exportLiteral(outfile, level, name_='dstOffset') - showIndent(outfile, level) - outfile.write('),\n') - if self.dstStartTime is not None: - showIndent(outfile, level) - outfile.write('dstStartTime=model_.TimeType(\n') - self.dstStartTime.exportLiteral(outfile, level, name_='dstStartTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.localTime is not None: - showIndent(outfile, level) - outfile.write('localTime=model_.TimeType(\n') - self.localTime.exportLiteral(outfile, level, name_='localTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.quality is not None: - showIndent(outfile, level) - outfile.write('quality=%d,\n' % self.quality) - if self.tzOffset is not None: - showIndent(outfile, level) - outfile.write('tzOffset=model_.TimeOffsetType(\n') - self.tzOffset.exportLiteral(outfile, level, name_='tzOffset') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Time, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'currentTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.currentTime = obj_ - obj_.original_tagname_ = 'currentTime' - elif nodeName_ == 'dstEndTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dstEndTime = obj_ - obj_.original_tagname_ = 'dstEndTime' - elif nodeName_ == 'dstOffset': - obj_ = TimeOffsetType.factory() - obj_.build(child_) - self.dstOffset = obj_ - obj_.original_tagname_ = 'dstOffset' - elif nodeName_ == 'dstStartTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.dstStartTime = obj_ - obj_.original_tagname_ = 'dstStartTime' - elif nodeName_ == 'localTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.localTime = obj_ - obj_.original_tagname_ = 'localTime' - elif nodeName_ == 'quality': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'quality') - self.quality = ival_ - self.validate_UInt8(self.quality) # validate type UInt8 - elif nodeName_ == 'tzOffset': - obj_ = TimeOffsetType.factory() - obj_.build(child_) - self.tzOffset = obj_ - obj_.original_tagname_ = 'tzOffset' - super(Time, self).buildChildren(child_, node, nodeName_, True) -# end class Time - - -class ResponseSetList(List): - """A List element to hold ResponseSet objects.""" - subclass = None - superclass = List - def __init__(self, ResponseSet=None): - self.original_tagname_ = None - super(ResponseSetList, self).__init__() - if ResponseSet is None: - self.ResponseSet = [] - else: - self.ResponseSet = ResponseSet - def factory(*args_, **kwargs_): - if ResponseSetList.subclass: - return ResponseSetList.subclass(*args_, **kwargs_) - else: - return ResponseSetList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ResponseSet(self): return self.ResponseSet - def set_ResponseSet(self, ResponseSet): self.ResponseSet = ResponseSet - def add_ResponseSet(self, value): self.ResponseSet.append(value) - def insert_ResponseSet_at(self, index, value): self.ResponseSet.insert(index, value) - def replace_ResponseSet_at(self, index, value): self.ResponseSet[index] = value - def hasContent_(self): - if ( - self.ResponseSet or - super(ResponseSetList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ResponseSetList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseSetList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ResponseSetList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ResponseSetList'): - super(ResponseSetList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseSetList') - def exportChildren(self, outfile, level, namespace_='', name_='ResponseSetList', fromsubclass_=False, pretty_print=True): - super(ResponseSetList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for ResponseSet_ in self.ResponseSet: - ResponseSet_.export(outfile, level, namespace_, name_='ResponseSet', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ResponseSetList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ResponseSetList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ResponseSetList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('ResponseSet=[\n') - level += 1 - for ResponseSet_ in self.ResponseSet: - showIndent(outfile, level) - outfile.write('model_.ResponseSet(\n') - ResponseSet_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ResponseSetList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ResponseSet': - obj_ = ResponseSet.factory() - obj_.build(child_) - self.ResponseSet.append(obj_) - obj_.original_tagname_ = 'ResponseSet' - super(ResponseSetList, self).buildChildren(child_, node, nodeName_, True) -# end class ResponseSetList - - -class ResponseSet(IdentifiedObject): - """A container for a ResponseList.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, ResponseListLink=None): - self.original_tagname_ = None - super(ResponseSet, self).__init__() - self.ResponseListLink = ResponseListLink - def factory(*args_, **kwargs_): - if ResponseSet.subclass: - return ResponseSet.subclass(*args_, **kwargs_) - else: - return ResponseSet(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ResponseListLink(self): return self.ResponseListLink - def set_ResponseListLink(self, ResponseListLink): self.ResponseListLink = ResponseListLink - def hasContent_(self): - if ( - self.ResponseListLink is not None or - super(ResponseSet, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ResponseSet', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseSet') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ResponseSet', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ResponseSet'): - super(ResponseSet, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseSet') - def exportChildren(self, outfile, level, namespace_='', name_='ResponseSet', fromsubclass_=False, pretty_print=True): - super(ResponseSet, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ResponseListLink is not None: - self.ResponseListLink.export(outfile, level, namespace_, name_='ResponseListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ResponseSet'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ResponseSet, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ResponseSet, self).exportLiteralChildren(outfile, level, name_) - if self.ResponseListLink is not None: - showIndent(outfile, level) - outfile.write('ResponseListLink=model_.ResponseListLink(\n') - self.ResponseListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ResponseSet, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ResponseListLink': - obj_ = ResponseListLink.factory() - obj_.build(child_) - self.ResponseListLink = obj_ - obj_.original_tagname_ = 'ResponseListLink' - super(ResponseSet, self).buildChildren(child_, node, nodeName_, True) -# end class ResponseSet - - -class ResponseList(List): - """A List element to hold Response objects.""" - subclass = None - superclass = List - def __init__(self, Response=None): - self.original_tagname_ = None - super(ResponseList, self).__init__() - if Response is None: - self.Response = [] - else: - self.Response = Response - def factory(*args_, **kwargs_): - if ResponseList.subclass: - return ResponseList.subclass(*args_, **kwargs_) - else: - return ResponseList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Response(self): return self.Response - def set_Response(self, Response): self.Response = Response - def add_Response(self, value): self.Response.append(value) - def insert_Response_at(self, index, value): self.Response.insert(index, value) - def replace_Response_at(self, index, value): self.Response[index] = value - def hasContent_(self): - if ( - self.Response or - super(ResponseList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ResponseList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ResponseList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ResponseList'): - super(ResponseList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ResponseList') - def exportChildren(self, outfile, level, namespace_='', name_='ResponseList', fromsubclass_=False, pretty_print=True): - super(ResponseList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Response_ in self.Response: - Response_.export(outfile, level, namespace_, name_='Response', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ResponseList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ResponseList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ResponseList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('Response=[\n') - level += 1 - for Response_ in self.Response: - showIndent(outfile, level) - outfile.write('model_.Response(\n') - Response_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ResponseList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Response': - class_obj_ = self.get_class_obj_(child_, Response) - obj_ = class_obj_.factory() - obj_.build(child_) - self.Response.append(obj_) - obj_.original_tagname_ = 'Response' - super(ResponseList, self).buildChildren(child_, node, nodeName_, True) -# end class ResponseList - - -class Response(Resource): - """The Response object is the generic response data repository for - functions which do not have additional specific data (e.g. DRLC - has additional data fields (SetPoint) where Price and Text event - do not).""" - subclass = None - superclass = Resource - def __init__(self, createdDateTime=None, endDeviceLFDI=None, status=None, subject=None): - self.original_tagname_ = None - super(Response, self).__init__() - self.createdDateTime = createdDateTime - self.endDeviceLFDI = endDeviceLFDI - self.status = status - self.subject = subject - def factory(*args_, **kwargs_): - if Response.subclass: - return Response.subclass(*args_, **kwargs_) - else: - return Response(*args_, **kwargs_) - factory = staticmethod(factory) - def get_createdDateTime(self): return self.createdDateTime - def set_createdDateTime(self, createdDateTime): self.createdDateTime = createdDateTime - def get_endDeviceLFDI(self): return self.endDeviceLFDI - def set_endDeviceLFDI(self, endDeviceLFDI): self.endDeviceLFDI = endDeviceLFDI - def get_status(self): return self.status - def set_status(self, status): self.status = status - def get_subject(self): return self.subject - def set_subject(self, subject): self.subject = subject - def validate_HexBinary160(self, value): - # Validate type HexBinary160, a restriction on xs:hexBinary. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.createdDateTime is not None or - self.endDeviceLFDI is not None or - self.status is not None or - self.subject is not None or - super(Response, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Response', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Response') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Response', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Response'): - super(Response, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Response') - def exportChildren(self, outfile, level, namespace_='', name_='Response', fromsubclass_=False, pretty_print=True): - super(Response, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.createdDateTime is not None: - self.createdDateTime.export(outfile, level, namespace_, name_='createdDateTime', pretty_print=pretty_print) - if self.endDeviceLFDI is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sendDeviceLFDI>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.endDeviceLFDI).encode(ExternalEncoding), input_name='endDeviceLFDI'), namespace_, eol_)) - if self.status is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sstatus>%s%s' % (namespace_, self.gds_format_integer(self.status, input_name='status'), namespace_, eol_)) - if self.subject is not None: - self.subject.export(outfile, level, namespace_, name_='subject', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='Response'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Response, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Response, self).exportLiteralChildren(outfile, level, name_) - if self.createdDateTime is not None: - showIndent(outfile, level) - outfile.write('createdDateTime=model_.TimeType(\n') - self.createdDateTime.exportLiteral(outfile, level, name_='createdDateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.endDeviceLFDI is not None: - showIndent(outfile, level) - outfile.write('endDeviceLFDI=%s,\n' % quote_python(self.endDeviceLFDI).encode(ExternalEncoding)) - if self.status is not None: - showIndent(outfile, level) - outfile.write('status=%d,\n' % self.status) - if self.subject is not None: - showIndent(outfile, level) - outfile.write('subject=model_.mRIDType(\n') - self.subject.exportLiteral(outfile, level, name_='subject') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Response, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'createdDateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.createdDateTime = obj_ - obj_.original_tagname_ = 'createdDateTime' - elif nodeName_ == 'endDeviceLFDI': - endDeviceLFDI_ = child_.text - endDeviceLFDI_ = self.gds_validate_string(endDeviceLFDI_, node, 'endDeviceLFDI') - self.endDeviceLFDI = endDeviceLFDI_ - self.validate_HexBinary160(self.endDeviceLFDI) # validate type HexBinary160 - elif nodeName_ == 'status': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'status') - self.status = ival_ - self.validate_UInt8(self.status) # validate type UInt8 - elif nodeName_ == 'subject': - obj_ = mRIDType.factory() - obj_.build(child_) - self.subject = obj_ - obj_.original_tagname_ = 'subject' - super(Response, self).buildChildren(child_, node, nodeName_, True) -# end class Response - - -class PriceResponse(Response): - """A response related to a price message.""" - subclass = None - superclass = Response - def __init__(self): - self.original_tagname_ = None - super(PriceResponse, self).__init__() - def factory(*args_, **kwargs_): - if PriceResponse.subclass: - return PriceResponse.subclass(*args_, **kwargs_) - else: - return PriceResponse(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(PriceResponse, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='PriceResponse', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='PriceResponse') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='PriceResponse', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='PriceResponse'): - super(PriceResponse, self).exportAttributes(outfile, level, already_processed, namespace_, name_='PriceResponse') - def exportChildren(self, outfile, level, namespace_='', name_='PriceResponse', fromsubclass_=False, pretty_print=True): - super(PriceResponse, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='PriceResponse'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(PriceResponse, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(PriceResponse, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(PriceResponse, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(PriceResponse, self).buildChildren(child_, node, nodeName_, True) - pass -# end class PriceResponse - - -class DrResponse(Response): - """A response to a Demand Response Load Control (EndDeviceControl) - message.""" - subclass = None - superclass = Response - def __init__(self, ApplianceLoadReduction=None, AppliedTargetReduction=None, DutyCycle=None, Offset=None, overrideDuration=None, SetPoint=None): - self.original_tagname_ = None - super(DrResponse, self).__init__() - self.ApplianceLoadReduction = ApplianceLoadReduction - self.AppliedTargetReduction = AppliedTargetReduction - self.DutyCycle = DutyCycle - self.Offset = Offset - self.overrideDuration = overrideDuration - self.SetPoint = SetPoint - def factory(*args_, **kwargs_): - if DrResponse.subclass: - return DrResponse.subclass(*args_, **kwargs_) - else: - return DrResponse(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ApplianceLoadReduction(self): return self.ApplianceLoadReduction - def set_ApplianceLoadReduction(self, ApplianceLoadReduction): self.ApplianceLoadReduction = ApplianceLoadReduction - def get_AppliedTargetReduction(self): return self.AppliedTargetReduction - def set_AppliedTargetReduction(self, AppliedTargetReduction): self.AppliedTargetReduction = AppliedTargetReduction - def get_DutyCycle(self): return self.DutyCycle - def set_DutyCycle(self, DutyCycle): self.DutyCycle = DutyCycle - def get_Offset(self): return self.Offset - def set_Offset(self, Offset): self.Offset = Offset - def get_overrideDuration(self): return self.overrideDuration - def set_overrideDuration(self, overrideDuration): self.overrideDuration = overrideDuration - def get_SetPoint(self): return self.SetPoint - def set_SetPoint(self, SetPoint): self.SetPoint = SetPoint - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.ApplianceLoadReduction is not None or - self.AppliedTargetReduction is not None or - self.DutyCycle is not None or - self.Offset is not None or - self.overrideDuration is not None or - self.SetPoint is not None or - super(DrResponse, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DrResponse', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DrResponse') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DrResponse', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DrResponse'): - super(DrResponse, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DrResponse') - def exportChildren(self, outfile, level, namespace_='', name_='DrResponse', fromsubclass_=False, pretty_print=True): - super(DrResponse, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ApplianceLoadReduction is not None: - self.ApplianceLoadReduction.export(outfile, level, namespace_, name_='ApplianceLoadReduction', pretty_print=pretty_print) - if self.AppliedTargetReduction is not None: - self.AppliedTargetReduction.export(outfile, level, namespace_, name_='AppliedTargetReduction', pretty_print=pretty_print) - if self.DutyCycle is not None: - self.DutyCycle.export(outfile, level, namespace_, name_='DutyCycle', pretty_print=pretty_print) - if self.Offset is not None: - self.Offset.export(outfile, level, namespace_, name_='Offset', pretty_print=pretty_print) - if self.overrideDuration is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%soverrideDuration>%s%s' % (namespace_, self.gds_format_integer(self.overrideDuration, input_name='overrideDuration'), namespace_, eol_)) - if self.SetPoint is not None: - self.SetPoint.export(outfile, level, namespace_, name_='SetPoint', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DrResponse'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DrResponse, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DrResponse, self).exportLiteralChildren(outfile, level, name_) - if self.ApplianceLoadReduction is not None: - showIndent(outfile, level) - outfile.write('ApplianceLoadReduction=model_.ApplianceLoadReduction(\n') - self.ApplianceLoadReduction.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.AppliedTargetReduction is not None: - showIndent(outfile, level) - outfile.write('AppliedTargetReduction=model_.AppliedTargetReduction(\n') - self.AppliedTargetReduction.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DutyCycle is not None: - showIndent(outfile, level) - outfile.write('DutyCycle=model_.DutyCycle(\n') - self.DutyCycle.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.Offset is not None: - showIndent(outfile, level) - outfile.write('Offset=model_.Offset(\n') - self.Offset.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.overrideDuration is not None: - showIndent(outfile, level) - outfile.write('overrideDuration=%d,\n' % self.overrideDuration) - if self.SetPoint is not None: - showIndent(outfile, level) - outfile.write('SetPoint=model_.SetPoint(\n') - self.SetPoint.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DrResponse, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ApplianceLoadReduction': - obj_ = ApplianceLoadReduction.factory() - obj_.build(child_) - self.ApplianceLoadReduction = obj_ - obj_.original_tagname_ = 'ApplianceLoadReduction' - elif nodeName_ == 'AppliedTargetReduction': - obj_ = AppliedTargetReduction.factory() - obj_.build(child_) - self.AppliedTargetReduction = obj_ - obj_.original_tagname_ = 'AppliedTargetReduction' - elif nodeName_ == 'DutyCycle': - obj_ = DutyCycle.factory() - obj_.build(child_) - self.DutyCycle = obj_ - obj_.original_tagname_ = 'DutyCycle' - elif nodeName_ == 'Offset': - obj_ = Offset.factory() - obj_.build(child_) - self.Offset = obj_ - obj_.original_tagname_ = 'Offset' - elif nodeName_ == 'overrideDuration': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'overrideDuration') - self.overrideDuration = ival_ - self.validate_UInt16(self.overrideDuration) # validate type UInt16 - elif nodeName_ == 'SetPoint': - obj_ = SetPoint.factory() - obj_.build(child_) - self.SetPoint = obj_ - obj_.original_tagname_ = 'SetPoint' - super(DrResponse, self).buildChildren(child_, node, nodeName_, True) -# end class DrResponse - - -class NotificationList(List): - """A List element to hold Notification objects.""" - subclass = None - superclass = List - def __init__(self, Notification=None): - self.original_tagname_ = None - super(NotificationList, self).__init__() - if Notification is None: - self.Notification = [] - else: - self.Notification = Notification - def factory(*args_, **kwargs_): - if NotificationList.subclass: - return NotificationList.subclass(*args_, **kwargs_) - else: - return NotificationList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Notification(self): return self.Notification - def set_Notification(self, Notification): self.Notification = Notification - def add_Notification(self, value): self.Notification.append(value) - def insert_Notification_at(self, index, value): self.Notification.insert(index, value) - def replace_Notification_at(self, index, value): self.Notification[index] = value - def hasContent_(self): - if ( - self.Notification or - super(NotificationList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='NotificationList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='NotificationList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='NotificationList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='NotificationList'): - super(NotificationList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='NotificationList') - def exportChildren(self, outfile, level, namespace_='', name_='NotificationList', fromsubclass_=False, pretty_print=True): - super(NotificationList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Notification_ in self.Notification: - Notification_.export(outfile, level, namespace_, name_='Notification', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='NotificationList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(NotificationList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(NotificationList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('Notification=[\n') - level += 1 - for Notification_ in self.Notification: - showIndent(outfile, level) - outfile.write('model_.Notification(\n') - Notification_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(NotificationList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Notification': - obj_ = Notification.factory() - obj_.build(child_) - self.Notification.append(obj_) - obj_.original_tagname_ = 'Notification' - super(NotificationList, self).buildChildren(child_, node, nodeName_, True) -# end class NotificationList - - -class SubscriptionList(List): - """A List element to hold Subscription objects.""" - subclass = None - superclass = List - def __init__(self, Subscription=None): - self.original_tagname_ = None - super(SubscriptionList, self).__init__() - if Subscription is None: - self.Subscription = [] - else: - self.Subscription = Subscription - def factory(*args_, **kwargs_): - if SubscriptionList.subclass: - return SubscriptionList.subclass(*args_, **kwargs_) - else: - return SubscriptionList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Subscription(self): return self.Subscription - def set_Subscription(self, Subscription): self.Subscription = Subscription - def add_Subscription(self, value): self.Subscription.append(value) - def insert_Subscription_at(self, index, value): self.Subscription.insert(index, value) - def replace_Subscription_at(self, index, value): self.Subscription[index] = value - def hasContent_(self): - if ( - self.Subscription or - super(SubscriptionList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SubscriptionList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SubscriptionList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SubscriptionList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SubscriptionList'): - super(SubscriptionList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SubscriptionList') - def exportChildren(self, outfile, level, namespace_='', name_='SubscriptionList', fromsubclass_=False, pretty_print=True): - super(SubscriptionList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Subscription_ in self.Subscription: - Subscription_.export(outfile, level, namespace_, name_='Subscription', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='SubscriptionList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SubscriptionList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SubscriptionList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('Subscription=[\n') - level += 1 - for Subscription_ in self.Subscription: - showIndent(outfile, level) - outfile.write('model_.Subscription(\n') - Subscription_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SubscriptionList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Subscription': - obj_ = Subscription.factory() - obj_.build(child_) - self.Subscription.append(obj_) - obj_.original_tagname_ = 'Subscription' - super(SubscriptionList, self).buildChildren(child_, node, nodeName_, True) -# end class SubscriptionList - - -class SubscriptionBase(Resource): - """Holds the information related to a client subscription to receive - updates to a resource automatically. The actual resources may be - passed in the Notification by specifying a specific xsi:type for - the Resource and passing the full representation.""" - subclass = None - superclass = Resource - def __init__(self, subscribedResource=None): - self.original_tagname_ = None - super(SubscriptionBase, self).__init__() - self.subscribedResource = subscribedResource - def factory(*args_, **kwargs_): - if SubscriptionBase.subclass: - return SubscriptionBase.subclass(*args_, **kwargs_) - else: - return SubscriptionBase(*args_, **kwargs_) - factory = staticmethod(factory) - def get_subscribedResource(self): return self.subscribedResource - def set_subscribedResource(self, subscribedResource): self.subscribedResource = subscribedResource - def hasContent_(self): - if ( - self.subscribedResource is not None or - super(SubscriptionBase, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SubscriptionBase', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SubscriptionBase') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SubscriptionBase', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SubscriptionBase'): - super(SubscriptionBase, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SubscriptionBase') - def exportChildren(self, outfile, level, namespace_='', name_='SubscriptionBase', fromsubclass_=False, pretty_print=True): - super(SubscriptionBase, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.subscribedResource is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssubscribedResource>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.subscribedResource).encode(ExternalEncoding), input_name='subscribedResource'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='SubscriptionBase'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SubscriptionBase, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SubscriptionBase, self).exportLiteralChildren(outfile, level, name_) - if self.subscribedResource is not None: - showIndent(outfile, level) - outfile.write('subscribedResource=%s,\n' % quote_python(self.subscribedResource).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SubscriptionBase, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'subscribedResource': - subscribedResource_ = child_.text - subscribedResource_ = self.gds_validate_string(subscribedResource_, node, 'subscribedResource') - self.subscribedResource = subscribedResource_ - super(SubscriptionBase, self).buildChildren(child_, node, nodeName_, True) -# end class SubscriptionBase - - -class FunctionSetAssignmentsList(SubscribableList): - """A List element to hold FunctionSetAssignments objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, FunctionSetAssignments=None): - self.original_tagname_ = None - super(FunctionSetAssignmentsList, self).__init__() - if FunctionSetAssignments is None: - self.FunctionSetAssignments = [] - else: - self.FunctionSetAssignments = FunctionSetAssignments - def factory(*args_, **kwargs_): - if FunctionSetAssignmentsList.subclass: - return FunctionSetAssignmentsList.subclass(*args_, **kwargs_) - else: - return FunctionSetAssignmentsList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_FunctionSetAssignments(self): return self.FunctionSetAssignments - def set_FunctionSetAssignments(self, FunctionSetAssignments): self.FunctionSetAssignments = FunctionSetAssignments - def add_FunctionSetAssignments(self, value): self.FunctionSetAssignments.append(value) - def insert_FunctionSetAssignments_at(self, index, value): self.FunctionSetAssignments.insert(index, value) - def replace_FunctionSetAssignments_at(self, index, value): self.FunctionSetAssignments[index] = value - def hasContent_(self): - if ( - self.FunctionSetAssignments or - super(FunctionSetAssignmentsList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FunctionSetAssignmentsList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FunctionSetAssignmentsList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FunctionSetAssignmentsList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FunctionSetAssignmentsList'): - super(FunctionSetAssignmentsList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FunctionSetAssignmentsList') - def exportChildren(self, outfile, level, namespace_='', name_='FunctionSetAssignmentsList', fromsubclass_=False, pretty_print=True): - super(FunctionSetAssignmentsList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for FunctionSetAssignments_ in self.FunctionSetAssignments: - FunctionSetAssignments_.export(outfile, level, namespace_, name_='FunctionSetAssignments', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FunctionSetAssignmentsList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FunctionSetAssignmentsList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FunctionSetAssignmentsList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('FunctionSetAssignments=[\n') - level += 1 - for FunctionSetAssignments_ in self.FunctionSetAssignments: - showIndent(outfile, level) - outfile.write('model_.FunctionSetAssignments(\n') - FunctionSetAssignments_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FunctionSetAssignmentsList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'FunctionSetAssignments': - obj_ = FunctionSetAssignments.factory() - obj_.build(child_) - self.FunctionSetAssignments.append(obj_) - obj_.original_tagname_ = 'FunctionSetAssignments' - super(FunctionSetAssignmentsList, self).buildChildren(child_, node, nodeName_, True) -# end class FunctionSetAssignmentsList - - -class FunctionSetAssignmentsBase(Resource): - """Defines a collection of function set instances that are to be used - by one or more devices as indicated by the EndDevice object(s) - of the server.""" - subclass = None - superclass = Resource - def __init__(self, CustomerAccountListLink=None, DemandResponseProgramListLink=None, DERProgramListLink=None, FileListLink=None, MessagingProgramListLink=None, PrepaymentListLink=None, ResponseSetListLink=None, TariffProfileListLink=None, TimeLink=None, UsagePointListLink=None): - self.original_tagname_ = None - super(FunctionSetAssignmentsBase, self).__init__() - self.CustomerAccountListLink = CustomerAccountListLink - self.DemandResponseProgramListLink = DemandResponseProgramListLink - self.DERProgramListLink = DERProgramListLink - self.FileListLink = FileListLink - self.MessagingProgramListLink = MessagingProgramListLink - self.PrepaymentListLink = PrepaymentListLink - self.ResponseSetListLink = ResponseSetListLink - self.TariffProfileListLink = TariffProfileListLink - self.TimeLink = TimeLink - self.UsagePointListLink = UsagePointListLink - def factory(*args_, **kwargs_): - if FunctionSetAssignmentsBase.subclass: - return FunctionSetAssignmentsBase.subclass(*args_, **kwargs_) - else: - return FunctionSetAssignmentsBase(*args_, **kwargs_) - factory = staticmethod(factory) - def get_CustomerAccountListLink(self): return self.CustomerAccountListLink - def set_CustomerAccountListLink(self, CustomerAccountListLink): self.CustomerAccountListLink = CustomerAccountListLink - def get_DemandResponseProgramListLink(self): return self.DemandResponseProgramListLink - def set_DemandResponseProgramListLink(self, DemandResponseProgramListLink): self.DemandResponseProgramListLink = DemandResponseProgramListLink - def get_DERProgramListLink(self): return self.DERProgramListLink - def set_DERProgramListLink(self, DERProgramListLink): self.DERProgramListLink = DERProgramListLink - def get_FileListLink(self): return self.FileListLink - def set_FileListLink(self, FileListLink): self.FileListLink = FileListLink - def get_MessagingProgramListLink(self): return self.MessagingProgramListLink - def set_MessagingProgramListLink(self, MessagingProgramListLink): self.MessagingProgramListLink = MessagingProgramListLink - def get_PrepaymentListLink(self): return self.PrepaymentListLink - def set_PrepaymentListLink(self, PrepaymentListLink): self.PrepaymentListLink = PrepaymentListLink - def get_ResponseSetListLink(self): return self.ResponseSetListLink - def set_ResponseSetListLink(self, ResponseSetListLink): self.ResponseSetListLink = ResponseSetListLink - def get_TariffProfileListLink(self): return self.TariffProfileListLink - def set_TariffProfileListLink(self, TariffProfileListLink): self.TariffProfileListLink = TariffProfileListLink - def get_TimeLink(self): return self.TimeLink - def set_TimeLink(self, TimeLink): self.TimeLink = TimeLink - def get_UsagePointListLink(self): return self.UsagePointListLink - def set_UsagePointListLink(self, UsagePointListLink): self.UsagePointListLink = UsagePointListLink - def hasContent_(self): - if ( - self.CustomerAccountListLink is not None or - self.DemandResponseProgramListLink is not None or - self.DERProgramListLink is not None or - self.FileListLink is not None or - self.MessagingProgramListLink is not None or - self.PrepaymentListLink is not None or - self.ResponseSetListLink is not None or - self.TariffProfileListLink is not None or - self.TimeLink is not None or - self.UsagePointListLink is not None or - super(FunctionSetAssignmentsBase, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FunctionSetAssignmentsBase', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FunctionSetAssignmentsBase') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FunctionSetAssignmentsBase', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FunctionSetAssignmentsBase'): - super(FunctionSetAssignmentsBase, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FunctionSetAssignmentsBase') - def exportChildren(self, outfile, level, namespace_='', name_='FunctionSetAssignmentsBase', fromsubclass_=False, pretty_print=True): - super(FunctionSetAssignmentsBase, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.CustomerAccountListLink is not None: - self.CustomerAccountListLink.export(outfile, level, namespace_, name_='CustomerAccountListLink', pretty_print=pretty_print) - if self.DemandResponseProgramListLink is not None: - self.DemandResponseProgramListLink.export(outfile, level, namespace_, name_='DemandResponseProgramListLink', pretty_print=pretty_print) - if self.DERProgramListLink is not None: - self.DERProgramListLink.export(outfile, level, namespace_, name_='DERProgramListLink', pretty_print=pretty_print) - if self.FileListLink is not None: - self.FileListLink.export(outfile, level, namespace_, name_='FileListLink', pretty_print=pretty_print) - if self.MessagingProgramListLink is not None: - self.MessagingProgramListLink.export(outfile, level, namespace_, name_='MessagingProgramListLink', pretty_print=pretty_print) - if self.PrepaymentListLink is not None: - self.PrepaymentListLink.export(outfile, level, namespace_, name_='PrepaymentListLink', pretty_print=pretty_print) - if self.ResponseSetListLink is not None: - self.ResponseSetListLink.export(outfile, level, namespace_, name_='ResponseSetListLink', pretty_print=pretty_print) - if self.TariffProfileListLink is not None: - self.TariffProfileListLink.export(outfile, level, namespace_, name_='TariffProfileListLink', pretty_print=pretty_print) - if self.TimeLink is not None: - self.TimeLink.export(outfile, level, namespace_, name_='TimeLink', pretty_print=pretty_print) - if self.UsagePointListLink is not None: - self.UsagePointListLink.export(outfile, level, namespace_, name_='UsagePointListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FunctionSetAssignmentsBase'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(FunctionSetAssignmentsBase, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FunctionSetAssignmentsBase, self).exportLiteralChildren(outfile, level, name_) - if self.CustomerAccountListLink is not None: - showIndent(outfile, level) - outfile.write('CustomerAccountListLink=model_.CustomerAccountListLink(\n') - self.CustomerAccountListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DemandResponseProgramListLink is not None: - showIndent(outfile, level) - outfile.write('DemandResponseProgramListLink=model_.DemandResponseProgramListLink(\n') - self.DemandResponseProgramListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DERProgramListLink is not None: - showIndent(outfile, level) - outfile.write('DERProgramListLink=model_.DERProgramListLink(\n') - self.DERProgramListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.FileListLink is not None: - showIndent(outfile, level) - outfile.write('FileListLink=model_.FileListLink(\n') - self.FileListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.MessagingProgramListLink is not None: - showIndent(outfile, level) - outfile.write('MessagingProgramListLink=model_.MessagingProgramListLink(\n') - self.MessagingProgramListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.PrepaymentListLink is not None: - showIndent(outfile, level) - outfile.write('PrepaymentListLink=model_.PrepaymentListLink(\n') - self.PrepaymentListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ResponseSetListLink is not None: - showIndent(outfile, level) - outfile.write('ResponseSetListLink=model_.ResponseSetListLink(\n') - self.ResponseSetListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.TariffProfileListLink is not None: - showIndent(outfile, level) - outfile.write('TariffProfileListLink=model_.TariffProfileListLink(\n') - self.TariffProfileListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.TimeLink is not None: - showIndent(outfile, level) - outfile.write('TimeLink=model_.TimeLink(\n') - self.TimeLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.UsagePointListLink is not None: - showIndent(outfile, level) - outfile.write('UsagePointListLink=model_.UsagePointListLink(\n') - self.UsagePointListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(FunctionSetAssignmentsBase, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'CustomerAccountListLink': - obj_ = CustomerAccountListLink.factory() - obj_.build(child_) - self.CustomerAccountListLink = obj_ - obj_.original_tagname_ = 'CustomerAccountListLink' - elif nodeName_ == 'DemandResponseProgramListLink': - obj_ = DemandResponseProgramListLink.factory() - obj_.build(child_) - self.DemandResponseProgramListLink = obj_ - obj_.original_tagname_ = 'DemandResponseProgramListLink' - elif nodeName_ == 'DERProgramListLink': - obj_ = DERProgramListLink.factory() - obj_.build(child_) - self.DERProgramListLink = obj_ - obj_.original_tagname_ = 'DERProgramListLink' - elif nodeName_ == 'FileListLink': - obj_ = FileListLink.factory() - obj_.build(child_) - self.FileListLink = obj_ - obj_.original_tagname_ = 'FileListLink' - elif nodeName_ == 'MessagingProgramListLink': - obj_ = MessagingProgramListLink.factory() - obj_.build(child_) - self.MessagingProgramListLink = obj_ - obj_.original_tagname_ = 'MessagingProgramListLink' - elif nodeName_ == 'PrepaymentListLink': - obj_ = PrepaymentListLink.factory() - obj_.build(child_) - self.PrepaymentListLink = obj_ - obj_.original_tagname_ = 'PrepaymentListLink' - elif nodeName_ == 'ResponseSetListLink': - obj_ = ResponseSetListLink.factory() - obj_.build(child_) - self.ResponseSetListLink = obj_ - obj_.original_tagname_ = 'ResponseSetListLink' - elif nodeName_ == 'TariffProfileListLink': - obj_ = TariffProfileListLink.factory() - obj_.build(child_) - self.TariffProfileListLink = obj_ - obj_.original_tagname_ = 'TariffProfileListLink' - elif nodeName_ == 'TimeLink': - obj_ = TimeLink.factory() - obj_.build(child_) - self.TimeLink = obj_ - obj_.original_tagname_ = 'TimeLink' - elif nodeName_ == 'UsagePointListLink': - obj_ = UsagePointListLink.factory() - obj_.build(child_) - self.UsagePointListLink = obj_ - obj_.original_tagname_ = 'UsagePointListLink' - super(FunctionSetAssignmentsBase, self).buildChildren(child_, node, nodeName_, True) -# end class FunctionSetAssignmentsBase - - -class Registration(Resource): - """Registration represents an authorization to access the resources on - a host.""" - subclass = None - superclass = Resource - def __init__(self, dateTimeRegistered=None, pIN=None): - self.original_tagname_ = None - super(Registration, self).__init__() - self.dateTimeRegistered = dateTimeRegistered - self.pIN = pIN - def factory(*args_, **kwargs_): - if Registration.subclass: - return Registration.subclass(*args_, **kwargs_) - else: - return Registration(*args_, **kwargs_) - factory = staticmethod(factory) - def get_dateTimeRegistered(self): return self.dateTimeRegistered - def set_dateTimeRegistered(self, dateTimeRegistered): self.dateTimeRegistered = dateTimeRegistered - def get_pIN(self): return self.pIN - def set_pIN(self, pIN): self.pIN = pIN - def hasContent_(self): - if ( - self.dateTimeRegistered is not None or - self.pIN is not None or - super(Registration, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Registration', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Registration') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Registration', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Registration'): - super(Registration, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Registration') - def exportChildren(self, outfile, level, namespace_='', name_='Registration', fromsubclass_=False, pretty_print=True): - super(Registration, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.dateTimeRegistered is not None: - self.dateTimeRegistered.export(outfile, level, namespace_, name_='dateTimeRegistered', pretty_print=pretty_print) - if self.pIN is not None: - self.pIN.export(outfile, level, namespace_, name_='pIN', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='Registration'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Registration, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Registration, self).exportLiteralChildren(outfile, level, name_) - if self.dateTimeRegistered is not None: - showIndent(outfile, level) - outfile.write('dateTimeRegistered=model_.TimeType(\n') - self.dateTimeRegistered.exportLiteral(outfile, level, name_='dateTimeRegistered') - showIndent(outfile, level) - outfile.write('),\n') - if self.pIN is not None: - showIndent(outfile, level) - outfile.write('pIN=model_.PINType(\n') - self.pIN.exportLiteral(outfile, level, name_='pIN') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Registration, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'dateTimeRegistered': - obj_ = TimeType.factory() - obj_.build(child_) - self.dateTimeRegistered = obj_ - obj_.original_tagname_ = 'dateTimeRegistered' - elif nodeName_ == 'pIN': - obj_ = PINType.factory() - obj_.build(child_) - self.pIN = obj_ - obj_.original_tagname_ = 'pIN' - super(Registration, self).buildChildren(child_, node, nodeName_, True) -# end class Registration - - -class EndDeviceList(SubscribableList): - """A List element to hold EndDevice objects.""" - subclass = None - superclass = SubscribableList - def __init__(self, EndDevice=None): - self.original_tagname_ = None - super(EndDeviceList, self).__init__() - if EndDevice is None: - self.EndDevice = [] - else: - self.EndDevice = EndDevice - def factory(*args_, **kwargs_): - if EndDeviceList.subclass: - return EndDeviceList.subclass(*args_, **kwargs_) - else: - return EndDeviceList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_EndDevice(self): return self.EndDevice - def set_EndDevice(self, EndDevice): self.EndDevice = EndDevice - def add_EndDevice(self, value): self.EndDevice.append(value) - def insert_EndDevice_at(self, index, value): self.EndDevice.insert(index, value) - def replace_EndDevice_at(self, index, value): self.EndDevice[index] = value - def hasContent_(self): - if ( - self.EndDevice or - super(EndDeviceList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EndDeviceList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EndDeviceList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EndDeviceList'): - super(EndDeviceList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='EndDeviceList') - def exportChildren(self, outfile, level, namespace_='', name_='EndDeviceList', fromsubclass_=False, pretty_print=True): - super(EndDeviceList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for EndDevice_ in self.EndDevice: - EndDevice_.export(outfile, level, namespace_, name_='EndDevice', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='EndDeviceList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(EndDeviceList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(EndDeviceList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('EndDevice=[\n') - level += 1 - for EndDevice_ in self.EndDevice: - showIndent(outfile, level) - outfile.write('model_.EndDevice(\n') - EndDevice_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(EndDeviceList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'EndDevice': - obj_ = EndDevice.factory() - obj_.build(child_) - self.EndDevice.append(obj_) - obj_.original_tagname_ = 'EndDevice' - super(EndDeviceList, self).buildChildren(child_, node, nodeName_, True) -# end class EndDeviceList - - -class DeviceStatus(Resource): - """Status of device""" - subclass = None - superclass = Resource - def __init__(self, changedTime=None, onCount=None, opState=None, opTime=None, Temperature=None, TimeLink=None): - self.original_tagname_ = None - super(DeviceStatus, self).__init__() - self.changedTime = changedTime - self.onCount = onCount - self.opState = opState - self.opTime = opTime - if Temperature is None: - self.Temperature = [] - else: - self.Temperature = Temperature - self.TimeLink = TimeLink - def factory(*args_, **kwargs_): - if DeviceStatus.subclass: - return DeviceStatus.subclass(*args_, **kwargs_) - else: - return DeviceStatus(*args_, **kwargs_) - factory = staticmethod(factory) - def get_changedTime(self): return self.changedTime - def set_changedTime(self, changedTime): self.changedTime = changedTime - def get_onCount(self): return self.onCount - def set_onCount(self, onCount): self.onCount = onCount - def get_opState(self): return self.opState - def set_opState(self, opState): self.opState = opState - def get_opTime(self): return self.opTime - def set_opTime(self, opTime): self.opTime = opTime - def get_Temperature(self): return self.Temperature - def set_Temperature(self, Temperature): self.Temperature = Temperature - def add_Temperature(self, value): self.Temperature.append(value) - def insert_Temperature_at(self, index, value): self.Temperature.insert(index, value) - def replace_Temperature_at(self, index, value): self.Temperature[index] = value - def get_TimeLink(self): return self.TimeLink - def set_TimeLink(self, TimeLink): self.TimeLink = TimeLink - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_UInt32(self, value): - # Validate type UInt32, a restriction on xs:unsignedInt. - pass - def hasContent_(self): - if ( - self.changedTime is not None or - self.onCount is not None or - self.opState is not None or - self.opTime is not None or - self.Temperature or - self.TimeLink is not None or - super(DeviceStatus, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DeviceStatus', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceStatus') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DeviceStatus', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DeviceStatus'): - super(DeviceStatus, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceStatus') - def exportChildren(self, outfile, level, namespace_='', name_='DeviceStatus', fromsubclass_=False, pretty_print=True): - super(DeviceStatus, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.changedTime is not None: - self.changedTime.export(outfile, level, namespace_, name_='changedTime', pretty_print=pretty_print) - if self.onCount is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sonCount>%s%s' % (namespace_, self.gds_format_integer(self.onCount, input_name='onCount'), namespace_, eol_)) - if self.opState is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sopState>%s%s' % (namespace_, self.gds_format_integer(self.opState, input_name='opState'), namespace_, eol_)) - if self.opTime is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sopTime>%s%s' % (namespace_, self.gds_format_integer(self.opTime, input_name='opTime'), namespace_, eol_)) - for Temperature_ in self.Temperature: - Temperature_.export(outfile, level, namespace_, name_='Temperature', pretty_print=pretty_print) - if self.TimeLink is not None: - self.TimeLink.export(outfile, level, namespace_, name_='TimeLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DeviceStatus'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DeviceStatus, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DeviceStatus, self).exportLiteralChildren(outfile, level, name_) - if self.changedTime is not None: - showIndent(outfile, level) - outfile.write('changedTime=model_.TimeType(\n') - self.changedTime.exportLiteral(outfile, level, name_='changedTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.onCount is not None: - showIndent(outfile, level) - outfile.write('onCount=%d,\n' % self.onCount) - if self.opState is not None: - showIndent(outfile, level) - outfile.write('opState=%d,\n' % self.opState) - if self.opTime is not None: - showIndent(outfile, level) - outfile.write('opTime=%d,\n' % self.opTime) - showIndent(outfile, level) - outfile.write('Temperature=[\n') - level += 1 - for Temperature_ in self.Temperature: - showIndent(outfile, level) - outfile.write('model_.Temperature(\n') - Temperature_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - if self.TimeLink is not None: - showIndent(outfile, level) - outfile.write('TimeLink=model_.TimeLink(\n') - self.TimeLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DeviceStatus, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'changedTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.changedTime = obj_ - obj_.original_tagname_ = 'changedTime' - elif nodeName_ == 'onCount': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'onCount') - self.onCount = ival_ - self.validate_UInt16(self.onCount) # validate type UInt16 - elif nodeName_ == 'opState': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'opState') - self.opState = ival_ - self.validate_UInt8(self.opState) # validate type UInt8 - elif nodeName_ == 'opTime': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'opTime') - self.opTime = ival_ - self.validate_UInt32(self.opTime) # validate type UInt32 - elif nodeName_ == 'Temperature': - obj_ = Temperature.factory() - obj_.build(child_) - self.Temperature.append(obj_) - obj_.original_tagname_ = 'Temperature' - elif nodeName_ == 'TimeLink': - obj_ = TimeLink.factory() - obj_.build(child_) - self.TimeLink = obj_ - obj_.original_tagname_ = 'TimeLink' - super(DeviceStatus, self).buildChildren(child_, node, nodeName_, True) -# end class DeviceStatus - - -class AbstractDevice(SubscribableResource): - """The EndDevice providing the resources available within the - DeviceCapabilities.""" - subclass = None - superclass = SubscribableResource - def __init__(self, ConfigurationLink=None, DERListLink=None, DeviceInformationLink=None, DeviceStatusLink=None, FileStatusLink=None, IPInterfaceListLink=None, LoadShedAvailabilityLink=None, loadShedDeviceCategory=None, LogEventListLink=None, PowerStatusLink=None, sFDI=None): - self.original_tagname_ = None - super(AbstractDevice, self).__init__() - self.ConfigurationLink = ConfigurationLink - self.DERListLink = DERListLink - self.DeviceInformationLink = DeviceInformationLink - self.DeviceStatusLink = DeviceStatusLink - self.FileStatusLink = FileStatusLink - self.IPInterfaceListLink = IPInterfaceListLink - self.LoadShedAvailabilityLink = LoadShedAvailabilityLink - self.loadShedDeviceCategory = loadShedDeviceCategory - self.LogEventListLink = LogEventListLink - self.PowerStatusLink = PowerStatusLink - self.sFDI = sFDI - def factory(*args_, **kwargs_): - if AbstractDevice.subclass: - return AbstractDevice.subclass(*args_, **kwargs_) - else: - return AbstractDevice(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ConfigurationLink(self): return self.ConfigurationLink - def set_ConfigurationLink(self, ConfigurationLink): self.ConfigurationLink = ConfigurationLink - def get_DERListLink(self): return self.DERListLink - def set_DERListLink(self, DERListLink): self.DERListLink = DERListLink - def get_DeviceInformationLink(self): return self.DeviceInformationLink - def set_DeviceInformationLink(self, DeviceInformationLink): self.DeviceInformationLink = DeviceInformationLink - def get_DeviceStatusLink(self): return self.DeviceStatusLink - def set_DeviceStatusLink(self, DeviceStatusLink): self.DeviceStatusLink = DeviceStatusLink - def get_FileStatusLink(self): return self.FileStatusLink - def set_FileStatusLink(self, FileStatusLink): self.FileStatusLink = FileStatusLink - def get_IPInterfaceListLink(self): return self.IPInterfaceListLink - def set_IPInterfaceListLink(self, IPInterfaceListLink): self.IPInterfaceListLink = IPInterfaceListLink - def get_LoadShedAvailabilityLink(self): return self.LoadShedAvailabilityLink - def set_LoadShedAvailabilityLink(self, LoadShedAvailabilityLink): self.LoadShedAvailabilityLink = LoadShedAvailabilityLink - def get_loadShedDeviceCategory(self): return self.loadShedDeviceCategory - def set_loadShedDeviceCategory(self, loadShedDeviceCategory): self.loadShedDeviceCategory = loadShedDeviceCategory - def get_LogEventListLink(self): return self.LogEventListLink - def set_LogEventListLink(self, LogEventListLink): self.LogEventListLink = LogEventListLink - def get_PowerStatusLink(self): return self.PowerStatusLink - def set_PowerStatusLink(self, PowerStatusLink): self.PowerStatusLink = PowerStatusLink - def get_sFDI(self): return self.sFDI - def set_sFDI(self, sFDI): self.sFDI = sFDI - def hasContent_(self): - if ( - self.ConfigurationLink is not None or - self.DERListLink is not None or - self.DeviceInformationLink is not None or - self.DeviceStatusLink is not None or - self.FileStatusLink is not None or - self.IPInterfaceListLink is not None or - self.LoadShedAvailabilityLink is not None or - self.loadShedDeviceCategory is not None or - self.LogEventListLink is not None or - self.PowerStatusLink is not None or - self.sFDI is not None or - super(AbstractDevice, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='AbstractDevice', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='AbstractDevice') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='AbstractDevice', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AbstractDevice'): - super(AbstractDevice, self).exportAttributes(outfile, level, already_processed, namespace_, name_='AbstractDevice') - def exportChildren(self, outfile, level, namespace_='', name_='AbstractDevice', fromsubclass_=False, pretty_print=True): - super(AbstractDevice, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ConfigurationLink is not None: - self.ConfigurationLink.export(outfile, level, namespace_, name_='ConfigurationLink', pretty_print=pretty_print) - if self.DERListLink is not None: - self.DERListLink.export(outfile, level, namespace_, name_='DERListLink', pretty_print=pretty_print) - if self.DeviceInformationLink is not None: - self.DeviceInformationLink.export(outfile, level, namespace_, name_='DeviceInformationLink', pretty_print=pretty_print) - if self.DeviceStatusLink is not None: - self.DeviceStatusLink.export(outfile, level, namespace_, name_='DeviceStatusLink', pretty_print=pretty_print) - if self.FileStatusLink is not None: - self.FileStatusLink.export(outfile, level, namespace_, name_='FileStatusLink', pretty_print=pretty_print) - if self.IPInterfaceListLink is not None: - self.IPInterfaceListLink.export(outfile, level, namespace_, name_='IPInterfaceListLink', pretty_print=pretty_print) - if self.LoadShedAvailabilityLink is not None: - self.LoadShedAvailabilityLink.export(outfile, level, namespace_, name_='LoadShedAvailabilityLink', pretty_print=pretty_print) - if self.loadShedDeviceCategory is not None: - self.loadShedDeviceCategory.export(outfile, level, namespace_, name_='loadShedDeviceCategory', pretty_print=pretty_print) - if self.LogEventListLink is not None: - self.LogEventListLink.export(outfile, level, namespace_, name_='LogEventListLink', pretty_print=pretty_print) - if self.PowerStatusLink is not None: - self.PowerStatusLink.export(outfile, level, namespace_, name_='PowerStatusLink', pretty_print=pretty_print) - if self.sFDI is not None: - self.sFDI.export(outfile, level, namespace_, name_='sFDI', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='AbstractDevice'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(AbstractDevice, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(AbstractDevice, self).exportLiteralChildren(outfile, level, name_) - if self.ConfigurationLink is not None: - showIndent(outfile, level) - outfile.write('ConfigurationLink=model_.ConfigurationLink(\n') - self.ConfigurationLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DERListLink is not None: - showIndent(outfile, level) - outfile.write('DERListLink=model_.DERListLink(\n') - self.DERListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DeviceInformationLink is not None: - showIndent(outfile, level) - outfile.write('DeviceInformationLink=model_.DeviceInformationLink(\n') - self.DeviceInformationLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.DeviceStatusLink is not None: - showIndent(outfile, level) - outfile.write('DeviceStatusLink=model_.DeviceStatusLink(\n') - self.DeviceStatusLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.FileStatusLink is not None: - showIndent(outfile, level) - outfile.write('FileStatusLink=model_.FileStatusLink(\n') - self.FileStatusLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.IPInterfaceListLink is not None: - showIndent(outfile, level) - outfile.write('IPInterfaceListLink=model_.IPInterfaceListLink(\n') - self.IPInterfaceListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.LoadShedAvailabilityLink is not None: - showIndent(outfile, level) - outfile.write('LoadShedAvailabilityLink=model_.LoadShedAvailabilityLink(\n') - self.LoadShedAvailabilityLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.loadShedDeviceCategory is not None: - showIndent(outfile, level) - outfile.write('loadShedDeviceCategory=model_.DeviceCategoryType(\n') - self.loadShedDeviceCategory.exportLiteral(outfile, level, name_='loadShedDeviceCategory') - showIndent(outfile, level) - outfile.write('),\n') - if self.LogEventListLink is not None: - showIndent(outfile, level) - outfile.write('LogEventListLink=model_.LogEventListLink(\n') - self.LogEventListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.PowerStatusLink is not None: - showIndent(outfile, level) - outfile.write('PowerStatusLink=model_.PowerStatusLink(\n') - self.PowerStatusLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.sFDI is not None: - showIndent(outfile, level) - outfile.write('sFDI=model_.SFDIType(\n') - self.sFDI.exportLiteral(outfile, level, name_='sFDI') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(AbstractDevice, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ConfigurationLink': - obj_ = ConfigurationLink.factory() - obj_.build(child_) - self.ConfigurationLink = obj_ - obj_.original_tagname_ = 'ConfigurationLink' - elif nodeName_ == 'DERListLink': - obj_ = DERListLink.factory() - obj_.build(child_) - self.DERListLink = obj_ - obj_.original_tagname_ = 'DERListLink' - elif nodeName_ == 'DeviceInformationLink': - obj_ = DeviceInformationLink.factory() - obj_.build(child_) - self.DeviceInformationLink = obj_ - obj_.original_tagname_ = 'DeviceInformationLink' - elif nodeName_ == 'DeviceStatusLink': - obj_ = DeviceStatusLink.factory() - obj_.build(child_) - self.DeviceStatusLink = obj_ - obj_.original_tagname_ = 'DeviceStatusLink' - elif nodeName_ == 'FileStatusLink': - obj_ = FileStatusLink.factory() - obj_.build(child_) - self.FileStatusLink = obj_ - obj_.original_tagname_ = 'FileStatusLink' - elif nodeName_ == 'IPInterfaceListLink': - obj_ = IPInterfaceListLink.factory() - obj_.build(child_) - self.IPInterfaceListLink = obj_ - obj_.original_tagname_ = 'IPInterfaceListLink' - elif nodeName_ == 'LoadShedAvailabilityLink': - obj_ = LoadShedAvailabilityLink.factory() - obj_.build(child_) - self.LoadShedAvailabilityLink = obj_ - obj_.original_tagname_ = 'LoadShedAvailabilityLink' - elif nodeName_ == 'loadShedDeviceCategory': - obj_ = DeviceCategoryType.factory() - obj_.build(child_) - self.loadShedDeviceCategory = obj_ - obj_.original_tagname_ = 'loadShedDeviceCategory' - elif nodeName_ == 'LogEventListLink': - obj_ = LogEventListLink.factory() - obj_.build(child_) - self.LogEventListLink = obj_ - obj_.original_tagname_ = 'LogEventListLink' - elif nodeName_ == 'PowerStatusLink': - obj_ = PowerStatusLink.factory() - obj_.build(child_) - self.PowerStatusLink = obj_ - obj_.original_tagname_ = 'PowerStatusLink' - elif nodeName_ == 'sFDI': - obj_ = SFDIType.factory() - obj_.build(child_) - self.sFDI = obj_ - obj_.original_tagname_ = 'sFDI' - super(AbstractDevice, self).buildChildren(child_, node, nodeName_, True) -# end class AbstractDevice - - -class DeviceCapability(FunctionSetAssignmentsBase): - """Returned by the URI provided by DNS-SD, to allow clients to find the - URIs to the resources in which they are interested.""" - subclass = None - superclass = FunctionSetAssignmentsBase - def __init__(self, EndDeviceListLink=None, MirrorUsagePointListLink=None, SelfDeviceLink=None): - self.original_tagname_ = None - super(DeviceCapability, self).__init__() - self.EndDeviceListLink = EndDeviceListLink - self.MirrorUsagePointListLink = MirrorUsagePointListLink - self.SelfDeviceLink = SelfDeviceLink - def factory(*args_, **kwargs_): - if DeviceCapability.subclass: - return DeviceCapability.subclass(*args_, **kwargs_) - else: - return DeviceCapability(*args_, **kwargs_) - factory = staticmethod(factory) - def get_EndDeviceListLink(self): return self.EndDeviceListLink - def set_EndDeviceListLink(self, EndDeviceListLink): self.EndDeviceListLink = EndDeviceListLink - def get_MirrorUsagePointListLink(self): return self.MirrorUsagePointListLink - def set_MirrorUsagePointListLink(self, MirrorUsagePointListLink): self.MirrorUsagePointListLink = MirrorUsagePointListLink - def get_SelfDeviceLink(self): return self.SelfDeviceLink - def set_SelfDeviceLink(self, SelfDeviceLink): self.SelfDeviceLink = SelfDeviceLink - def hasContent_(self): - if ( - self.EndDeviceListLink is not None or - self.MirrorUsagePointListLink is not None or - self.SelfDeviceLink is not None or - super(DeviceCapability, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='DeviceCapability', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceCapability') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='DeviceCapability', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='DeviceCapability'): - super(DeviceCapability, self).exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceCapability') - def exportChildren(self, outfile, level, namespace_='', name_='DeviceCapability', fromsubclass_=False, pretty_print=True): - super(DeviceCapability, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.EndDeviceListLink is not None: - self.EndDeviceListLink.export(outfile, level, namespace_, name_='EndDeviceListLink', pretty_print=pretty_print) - if self.MirrorUsagePointListLink is not None: - self.MirrorUsagePointListLink.export(outfile, level, namespace_, name_='MirrorUsagePointListLink', pretty_print=pretty_print) - if self.SelfDeviceLink is not None: - self.SelfDeviceLink.export(outfile, level, namespace_, name_='SelfDeviceLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='DeviceCapability'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(DeviceCapability, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(DeviceCapability, self).exportLiteralChildren(outfile, level, name_) - if self.EndDeviceListLink is not None: - showIndent(outfile, level) - outfile.write('EndDeviceListLink=model_.EndDeviceListLink(\n') - self.EndDeviceListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.MirrorUsagePointListLink is not None: - showIndent(outfile, level) - outfile.write('MirrorUsagePointListLink=model_.MirrorUsagePointListLink(\n') - self.MirrorUsagePointListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.SelfDeviceLink is not None: - showIndent(outfile, level) - outfile.write('SelfDeviceLink=model_.SelfDeviceLink(\n') - self.SelfDeviceLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(DeviceCapability, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'EndDeviceListLink': - obj_ = EndDeviceListLink.factory() - obj_.build(child_) - self.EndDeviceListLink = obj_ - obj_.original_tagname_ = 'EndDeviceListLink' - elif nodeName_ == 'MirrorUsagePointListLink': - obj_ = MirrorUsagePointListLink.factory() - obj_.build(child_) - self.MirrorUsagePointListLink = obj_ - obj_.original_tagname_ = 'MirrorUsagePointListLink' - elif nodeName_ == 'SelfDeviceLink': - obj_ = SelfDeviceLink.factory() - obj_.build(child_) - self.SelfDeviceLink = obj_ - obj_.original_tagname_ = 'SelfDeviceLink' - super(DeviceCapability, self).buildChildren(child_, node, nodeName_, True) -# end class DeviceCapability - - -class UsagePointBase(IdentifiedObject): - """Logical point on a network at which consumption or production is - either physically measured (e.g. metered) or estimated (e.g. - unmetered street lights). A container for associating - ReadingType, Readings and ReadingSets.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, roleFlags=None, serviceCategoryKind=None, status=None): - self.original_tagname_ = None - super(UsagePointBase, self).__init__() - self.roleFlags = roleFlags - self.serviceCategoryKind = serviceCategoryKind - self.status = status - def factory(*args_, **kwargs_): - if UsagePointBase.subclass: - return UsagePointBase.subclass(*args_, **kwargs_) - else: - return UsagePointBase(*args_, **kwargs_) - factory = staticmethod(factory) - def get_roleFlags(self): return self.roleFlags - def set_roleFlags(self, roleFlags): self.roleFlags = roleFlags - def get_serviceCategoryKind(self): return self.serviceCategoryKind - def set_serviceCategoryKind(self, serviceCategoryKind): self.serviceCategoryKind = serviceCategoryKind - def get_status(self): return self.status - def set_status(self, status): self.status = status - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.roleFlags is not None or - self.serviceCategoryKind is not None or - self.status is not None or - super(UsagePointBase, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UsagePointBase', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePointBase') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='UsagePointBase', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UsagePointBase'): - super(UsagePointBase, self).exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePointBase') - def exportChildren(self, outfile, level, namespace_='', name_='UsagePointBase', fromsubclass_=False, pretty_print=True): - super(UsagePointBase, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.roleFlags is not None: - self.roleFlags.export(outfile, level, namespace_, name_='roleFlags', pretty_print=pretty_print) - if self.serviceCategoryKind is not None: - self.serviceCategoryKind.export(outfile, level, namespace_, name_='serviceCategoryKind', pretty_print=pretty_print) - if self.status is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sstatus>%s%s' % (namespace_, self.gds_format_integer(self.status, input_name='status'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='UsagePointBase'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(UsagePointBase, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(UsagePointBase, self).exportLiteralChildren(outfile, level, name_) - if self.roleFlags is not None: - showIndent(outfile, level) - outfile.write('roleFlags=model_.RoleFlagsType(\n') - self.roleFlags.exportLiteral(outfile, level, name_='roleFlags') - showIndent(outfile, level) - outfile.write('),\n') - if self.serviceCategoryKind is not None: - showIndent(outfile, level) - outfile.write('serviceCategoryKind=model_.ServiceKind(\n') - self.serviceCategoryKind.exportLiteral(outfile, level, name_='serviceCategoryKind') - showIndent(outfile, level) - outfile.write('),\n') - if self.status is not None: - showIndent(outfile, level) - outfile.write('status=%d,\n' % self.status) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(UsagePointBase, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'roleFlags': - obj_ = RoleFlagsType.factory() - obj_.build(child_) - self.roleFlags = obj_ - obj_.original_tagname_ = 'roleFlags' - elif nodeName_ == 'serviceCategoryKind': - obj_ = ServiceKind.factory() - obj_.build(child_) - self.serviceCategoryKind = obj_ - obj_.original_tagname_ = 'serviceCategoryKind' - elif nodeName_ == 'status': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'status') - self.status = ival_ - self.validate_UInt8(self.status) # validate type UInt8 - super(UsagePointBase, self).buildChildren(child_, node, nodeName_, True) -# end class UsagePointBase - - -class ReadingSetBase(IdentifiedObject): - """A set of Readings of the ReadingType indicated by the parent - MeterReading. ReadingBase is abstract, used to define the - elements common to ReadingSet and IntervalBlock.""" - subclass = None - superclass = IdentifiedObject - def __init__(self, timePeriod=None): - self.original_tagname_ = None - super(ReadingSetBase, self).__init__() - self.timePeriod = timePeriod - def factory(*args_, **kwargs_): - if ReadingSetBase.subclass: - return ReadingSetBase.subclass(*args_, **kwargs_) - else: - return ReadingSetBase(*args_, **kwargs_) - factory = staticmethod(factory) - def get_timePeriod(self): return self.timePeriod - def set_timePeriod(self, timePeriod): self.timePeriod = timePeriod - def hasContent_(self): - if ( - self.timePeriod is not None or - super(ReadingSetBase, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingSetBase', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingSetBase') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingSetBase', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingSetBase'): - super(ReadingSetBase, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingSetBase') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingSetBase', fromsubclass_=False, pretty_print=True): - super(ReadingSetBase, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.timePeriod is not None: - self.timePeriod.export(outfile, level, namespace_, name_='timePeriod', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ReadingSetBase'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingSetBase, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingSetBase, self).exportLiteralChildren(outfile, level, name_) - if self.timePeriod is not None: - showIndent(outfile, level) - outfile.write('timePeriod=model_.DateTimeInterval(\n') - self.timePeriod.exportLiteral(outfile, level, name_='timePeriod') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingSetBase, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'timePeriod': - obj_ = DateTimeInterval.factory() - obj_.build(child_) - self.timePeriod = obj_ - obj_.original_tagname_ = 'timePeriod' - super(ReadingSetBase, self).buildChildren(child_, node, nodeName_, True) -# end class ReadingSetBase - - -class MirrorUsagePointList(List): - """A List of MirrorUsagePoint instances.""" - subclass = None - superclass = List - def __init__(self, MirrorUsagePoint=None): - self.original_tagname_ = None - super(MirrorUsagePointList, self).__init__() - if MirrorUsagePoint is None: - self.MirrorUsagePoint = [] - else: - self.MirrorUsagePoint = MirrorUsagePoint - def factory(*args_, **kwargs_): - if MirrorUsagePointList.subclass: - return MirrorUsagePointList.subclass(*args_, **kwargs_) - else: - return MirrorUsagePointList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_MirrorUsagePoint(self): return self.MirrorUsagePoint - def set_MirrorUsagePoint(self, MirrorUsagePoint): self.MirrorUsagePoint = MirrorUsagePoint - def add_MirrorUsagePoint(self, value): self.MirrorUsagePoint.append(value) - def insert_MirrorUsagePoint_at(self, index, value): self.MirrorUsagePoint.insert(index, value) - def replace_MirrorUsagePoint_at(self, index, value): self.MirrorUsagePoint[index] = value - def hasContent_(self): - if ( - self.MirrorUsagePoint or - super(MirrorUsagePointList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MirrorUsagePointList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorUsagePointList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MirrorUsagePointList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MirrorUsagePointList'): - super(MirrorUsagePointList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorUsagePointList') - def exportChildren(self, outfile, level, namespace_='', name_='MirrorUsagePointList', fromsubclass_=False, pretty_print=True): - super(MirrorUsagePointList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for MirrorUsagePoint_ in self.MirrorUsagePoint: - MirrorUsagePoint_.export(outfile, level, namespace_, name_='MirrorUsagePoint', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MirrorUsagePointList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MirrorUsagePointList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MirrorUsagePointList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('MirrorUsagePoint=[\n') - level += 1 - for MirrorUsagePoint_ in self.MirrorUsagePoint: - showIndent(outfile, level) - outfile.write('model_.MirrorUsagePoint(\n') - MirrorUsagePoint_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MirrorUsagePointList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'MirrorUsagePoint': - obj_ = MirrorUsagePoint.factory() - obj_.build(child_) - self.MirrorUsagePoint.append(obj_) - obj_.original_tagname_ = 'MirrorUsagePoint' - super(MirrorUsagePointList, self).buildChildren(child_, node, nodeName_, True) -# end class MirrorUsagePointList - - -class MirrorUsagePoint(UsagePointBase): - """A parallel to UsagePoint to support mirroring""" - subclass = None - superclass = UsagePointBase - def __init__(self, deviceLFDI=None, MirrorMeterReading=None): - self.original_tagname_ = None - super(MirrorUsagePoint, self).__init__() - self.deviceLFDI = deviceLFDI - if MirrorMeterReading is None: - self.MirrorMeterReading = [] - else: - self.MirrorMeterReading = MirrorMeterReading - def factory(*args_, **kwargs_): - if MirrorUsagePoint.subclass: - return MirrorUsagePoint.subclass(*args_, **kwargs_) - else: - return MirrorUsagePoint(*args_, **kwargs_) - factory = staticmethod(factory) - def get_deviceLFDI(self): return self.deviceLFDI - def set_deviceLFDI(self, deviceLFDI): self.deviceLFDI = deviceLFDI - def get_MirrorMeterReading(self): return self.MirrorMeterReading - def set_MirrorMeterReading(self, MirrorMeterReading): self.MirrorMeterReading = MirrorMeterReading - def add_MirrorMeterReading(self, value): self.MirrorMeterReading.append(value) - def insert_MirrorMeterReading_at(self, index, value): self.MirrorMeterReading.insert(index, value) - def replace_MirrorMeterReading_at(self, index, value): self.MirrorMeterReading[index] = value - def validate_HexBinary160(self, value): - # Validate type HexBinary160, a restriction on xs:hexBinary. - pass - def hasContent_(self): - if ( - self.deviceLFDI is not None or - self.MirrorMeterReading or - super(MirrorUsagePoint, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MirrorUsagePoint', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorUsagePoint') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MirrorUsagePoint', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MirrorUsagePoint'): - super(MirrorUsagePoint, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorUsagePoint') - def exportChildren(self, outfile, level, namespace_='', name_='MirrorUsagePoint', fromsubclass_=False, pretty_print=True): - super(MirrorUsagePoint, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.deviceLFDI is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdeviceLFDI>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.deviceLFDI).encode(ExternalEncoding), input_name='deviceLFDI'), namespace_, eol_)) - for MirrorMeterReading_ in self.MirrorMeterReading: - MirrorMeterReading_.export(outfile, level, namespace_, name_='MirrorMeterReading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MirrorUsagePoint'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MirrorUsagePoint, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MirrorUsagePoint, self).exportLiteralChildren(outfile, level, name_) - if self.deviceLFDI is not None: - showIndent(outfile, level) - outfile.write('deviceLFDI=%s,\n' % quote_python(self.deviceLFDI).encode(ExternalEncoding)) - showIndent(outfile, level) - outfile.write('MirrorMeterReading=[\n') - level += 1 - for MirrorMeterReading_ in self.MirrorMeterReading: - showIndent(outfile, level) - outfile.write('model_.MirrorMeterReading(\n') - MirrorMeterReading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MirrorUsagePoint, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'deviceLFDI': - deviceLFDI_ = child_.text - deviceLFDI_ = self.gds_validate_string(deviceLFDI_, node, 'deviceLFDI') - self.deviceLFDI = deviceLFDI_ - self.validate_HexBinary160(self.deviceLFDI) # validate type HexBinary160 - elif nodeName_ == 'MirrorMeterReading': - obj_ = MirrorMeterReading.factory() - obj_.build(child_) - self.MirrorMeterReading.append(obj_) - obj_.original_tagname_ = 'MirrorMeterReading' - super(MirrorUsagePoint, self).buildChildren(child_, node, nodeName_, True) -# end class MirrorUsagePoint - - -class MirrorReadingSet(ReadingSetBase): - """A set of Readings of the ReadingType indicated by the parent - MeterReading.""" - subclass = None - superclass = ReadingSetBase - def __init__(self, Reading=None): - self.original_tagname_ = None - super(MirrorReadingSet, self).__init__() - if Reading is None: - self.Reading = [] - else: - self.Reading = Reading - def factory(*args_, **kwargs_): - if MirrorReadingSet.subclass: - return MirrorReadingSet.subclass(*args_, **kwargs_) - else: - return MirrorReadingSet(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Reading(self): return self.Reading - def set_Reading(self, Reading): self.Reading = Reading - def add_Reading(self, value): self.Reading.append(value) - def insert_Reading_at(self, index, value): self.Reading.insert(index, value) - def replace_Reading_at(self, index, value): self.Reading[index] = value - def hasContent_(self): - if ( - self.Reading or - super(MirrorReadingSet, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MirrorReadingSet', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorReadingSet') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MirrorReadingSet', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MirrorReadingSet'): - super(MirrorReadingSet, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorReadingSet') - def exportChildren(self, outfile, level, namespace_='', name_='MirrorReadingSet', fromsubclass_=False, pretty_print=True): - super(MirrorReadingSet, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for Reading_ in self.Reading: - Reading_.export(outfile, level, namespace_, name_='Reading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MirrorReadingSet'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MirrorReadingSet, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MirrorReadingSet, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('Reading=[\n') - level += 1 - for Reading_ in self.Reading: - showIndent(outfile, level) - outfile.write('model_.Reading(\n') - Reading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MirrorReadingSet, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Reading': - obj_ = Reading.factory() - obj_.build(child_) - self.Reading.append(obj_) - obj_.original_tagname_ = 'Reading' - super(MirrorReadingSet, self).buildChildren(child_, node, nodeName_, True) -# end class MirrorReadingSet - - -class MeterReadingBase(IdentifiedObject): - """A container for associating ReadingType, Readings and ReadingSets.""" - subclass = None - superclass = IdentifiedObject - def __init__(self): - self.original_tagname_ = None - super(MeterReadingBase, self).__init__() - def factory(*args_, **kwargs_): - if MeterReadingBase.subclass: - return MeterReadingBase.subclass(*args_, **kwargs_) - else: - return MeterReadingBase(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(MeterReadingBase, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MeterReadingBase', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReadingBase') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MeterReadingBase', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MeterReadingBase'): - super(MeterReadingBase, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReadingBase') - def exportChildren(self, outfile, level, namespace_='', name_='MeterReadingBase', fromsubclass_=False, pretty_print=True): - super(MeterReadingBase, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='MeterReadingBase'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MeterReadingBase, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MeterReadingBase, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MeterReadingBase, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(MeterReadingBase, self).buildChildren(child_, node, nodeName_, True) - pass -# end class MeterReadingBase - - -class MirrorMeterReadingList(List): - """A List of MirrorMeterReading instances.""" - subclass = None - superclass = List - def __init__(self, MirrorMeterReading=None): - self.original_tagname_ = None - super(MirrorMeterReadingList, self).__init__() - if MirrorMeterReading is None: - self.MirrorMeterReading = [] - else: - self.MirrorMeterReading = MirrorMeterReading - def factory(*args_, **kwargs_): - if MirrorMeterReadingList.subclass: - return MirrorMeterReadingList.subclass(*args_, **kwargs_) - else: - return MirrorMeterReadingList(*args_, **kwargs_) - factory = staticmethod(factory) - def get_MirrorMeterReading(self): return self.MirrorMeterReading - def set_MirrorMeterReading(self, MirrorMeterReading): self.MirrorMeterReading = MirrorMeterReading - def add_MirrorMeterReading(self, value): self.MirrorMeterReading.append(value) - def insert_MirrorMeterReading_at(self, index, value): self.MirrorMeterReading.insert(index, value) - def replace_MirrorMeterReading_at(self, index, value): self.MirrorMeterReading[index] = value - def hasContent_(self): - if ( - self.MirrorMeterReading or - super(MirrorMeterReadingList, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MirrorMeterReadingList', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorMeterReadingList') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MirrorMeterReadingList', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MirrorMeterReadingList'): - super(MirrorMeterReadingList, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorMeterReadingList') - def exportChildren(self, outfile, level, namespace_='', name_='MirrorMeterReadingList', fromsubclass_=False, pretty_print=True): - super(MirrorMeterReadingList, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - for MirrorMeterReading_ in self.MirrorMeterReading: - MirrorMeterReading_.export(outfile, level, namespace_, name_='MirrorMeterReading', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MirrorMeterReadingList'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MirrorMeterReadingList, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MirrorMeterReadingList, self).exportLiteralChildren(outfile, level, name_) - showIndent(outfile, level) - outfile.write('MirrorMeterReading=[\n') - level += 1 - for MirrorMeterReading_ in self.MirrorMeterReading: - showIndent(outfile, level) - outfile.write('model_.MirrorMeterReading(\n') - MirrorMeterReading_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MirrorMeterReadingList, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'MirrorMeterReading': - obj_ = MirrorMeterReading.factory() - obj_.build(child_) - self.MirrorMeterReading.append(obj_) - obj_.original_tagname_ = 'MirrorMeterReading' - super(MirrorMeterReadingList, self).buildChildren(child_, node, nodeName_, True) -# end class MirrorMeterReadingList - - -class MirrorMeterReading(MeterReadingBase): - """Mimic of MeterReading used for managing mirrors.""" - subclass = None - superclass = MeterReadingBase - def __init__(self, lastUpdateTime=None, MirrorReadingSet=None, nextUpdateTime=None, Reading=None, ReadingType=None): - self.original_tagname_ = None - super(MirrorMeterReading, self).__init__() - self.lastUpdateTime = lastUpdateTime - if MirrorReadingSet is None: - self.MirrorReadingSet = [] - else: - self.MirrorReadingSet = MirrorReadingSet - self.nextUpdateTime = nextUpdateTime - self.Reading = Reading - self.ReadingType = ReadingType - def factory(*args_, **kwargs_): - if MirrorMeterReading.subclass: - return MirrorMeterReading.subclass(*args_, **kwargs_) - else: - return MirrorMeterReading(*args_, **kwargs_) - factory = staticmethod(factory) - def get_lastUpdateTime(self): return self.lastUpdateTime - def set_lastUpdateTime(self, lastUpdateTime): self.lastUpdateTime = lastUpdateTime - def get_MirrorReadingSet(self): return self.MirrorReadingSet - def set_MirrorReadingSet(self, MirrorReadingSet): self.MirrorReadingSet = MirrorReadingSet - def add_MirrorReadingSet(self, value): self.MirrorReadingSet.append(value) - def insert_MirrorReadingSet_at(self, index, value): self.MirrorReadingSet.insert(index, value) - def replace_MirrorReadingSet_at(self, index, value): self.MirrorReadingSet[index] = value - def get_nextUpdateTime(self): return self.nextUpdateTime - def set_nextUpdateTime(self, nextUpdateTime): self.nextUpdateTime = nextUpdateTime - def get_Reading(self): return self.Reading - def set_Reading(self, Reading): self.Reading = Reading - def get_ReadingType(self): return self.ReadingType - def set_ReadingType(self, ReadingType): self.ReadingType = ReadingType - def hasContent_(self): - if ( - self.lastUpdateTime is not None or - self.MirrorReadingSet or - self.nextUpdateTime is not None or - self.Reading is not None or - self.ReadingType is not None or - super(MirrorMeterReading, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MirrorMeterReading', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorMeterReading') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MirrorMeterReading', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MirrorMeterReading'): - super(MirrorMeterReading, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MirrorMeterReading') - def exportChildren(self, outfile, level, namespace_='', name_='MirrorMeterReading', fromsubclass_=False, pretty_print=True): - super(MirrorMeterReading, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.lastUpdateTime is not None: - self.lastUpdateTime.export(outfile, level, namespace_, name_='lastUpdateTime', pretty_print=pretty_print) - for MirrorReadingSet_ in self.MirrorReadingSet: - MirrorReadingSet_.export(outfile, level, namespace_, name_='MirrorReadingSet', pretty_print=pretty_print) - if self.nextUpdateTime is not None: - self.nextUpdateTime.export(outfile, level, namespace_, name_='nextUpdateTime', pretty_print=pretty_print) - if self.Reading is not None: - self.Reading.export(outfile, level, namespace_, name_='Reading', pretty_print=pretty_print) - if self.ReadingType is not None: - self.ReadingType.export(outfile, level, namespace_, name_='ReadingType', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MirrorMeterReading'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MirrorMeterReading, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MirrorMeterReading, self).exportLiteralChildren(outfile, level, name_) - if self.lastUpdateTime is not None: - showIndent(outfile, level) - outfile.write('lastUpdateTime=model_.TimeType(\n') - self.lastUpdateTime.exportLiteral(outfile, level, name_='lastUpdateTime') - showIndent(outfile, level) - outfile.write('),\n') - showIndent(outfile, level) - outfile.write('MirrorReadingSet=[\n') - level += 1 - for MirrorReadingSet_ in self.MirrorReadingSet: - showIndent(outfile, level) - outfile.write('model_.MirrorReadingSet(\n') - MirrorReadingSet_.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - level -= 1 - showIndent(outfile, level) - outfile.write('],\n') - if self.nextUpdateTime is not None: - showIndent(outfile, level) - outfile.write('nextUpdateTime=model_.TimeType(\n') - self.nextUpdateTime.exportLiteral(outfile, level, name_='nextUpdateTime') - showIndent(outfile, level) - outfile.write('),\n') - if self.Reading is not None: - showIndent(outfile, level) - outfile.write('Reading=model_.Reading(\n') - self.Reading.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ReadingType is not None: - showIndent(outfile, level) - outfile.write('ReadingType=model_.ReadingType(\n') - self.ReadingType.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MirrorMeterReading, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'lastUpdateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.lastUpdateTime = obj_ - obj_.original_tagname_ = 'lastUpdateTime' - elif nodeName_ == 'MirrorReadingSet': - obj_ = MirrorReadingSet.factory() - obj_.build(child_) - self.MirrorReadingSet.append(obj_) - obj_.original_tagname_ = 'MirrorReadingSet' - elif nodeName_ == 'nextUpdateTime': - obj_ = TimeType.factory() - obj_.build(child_) - self.nextUpdateTime = obj_ - obj_.original_tagname_ = 'nextUpdateTime' - elif nodeName_ == 'Reading': - obj_ = Reading.factory() - obj_.build(child_) - self.Reading = obj_ - obj_.original_tagname_ = 'Reading' - elif nodeName_ == 'ReadingType': - obj_ = ReadingType.factory() - obj_.build(child_) - self.ReadingType = obj_ - obj_.original_tagname_ = 'ReadingType' - super(MirrorMeterReading, self).buildChildren(child_, node, nodeName_, True) -# end class MirrorMeterReading - - -class BillingReadingSet(ReadingSetBase): - """Time sequence of readings of the same reading type.""" - subclass = None - superclass = ReadingSetBase - def __init__(self, BillingReadingListLink=None): - self.original_tagname_ = None - super(BillingReadingSet, self).__init__() - self.BillingReadingListLink = BillingReadingListLink - def factory(*args_, **kwargs_): - if BillingReadingSet.subclass: - return BillingReadingSet.subclass(*args_, **kwargs_) - else: - return BillingReadingSet(*args_, **kwargs_) - factory = staticmethod(factory) - def get_BillingReadingListLink(self): return self.BillingReadingListLink - def set_BillingReadingListLink(self, BillingReadingListLink): self.BillingReadingListLink = BillingReadingListLink - def hasContent_(self): - if ( - self.BillingReadingListLink is not None or - super(BillingReadingSet, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingReadingSet', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingSet') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingReadingSet', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingReadingSet'): - super(BillingReadingSet, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingReadingSet') - def exportChildren(self, outfile, level, namespace_='', name_='BillingReadingSet', fromsubclass_=False, pretty_print=True): - super(BillingReadingSet, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.BillingReadingListLink is not None: - self.BillingReadingListLink.export(outfile, level, namespace_, name_='BillingReadingListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='BillingReadingSet'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingReadingSet, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingReadingSet, self).exportLiteralChildren(outfile, level, name_) - if self.BillingReadingListLink is not None: - showIndent(outfile, level) - outfile.write('BillingReadingListLink=model_.BillingReadingListLink(\n') - self.BillingReadingListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingReadingSet, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'BillingReadingListLink': - obj_ = BillingReadingListLink.factory() - obj_.build(child_) - self.BillingReadingListLink = obj_ - obj_.original_tagname_ = 'BillingReadingListLink' - super(BillingReadingSet, self).buildChildren(child_, node, nodeName_, True) -# end class BillingReadingSet - - -class BillingMeterReadingBase(MeterReadingBase): - """Contains historical, target, and projection readings of various - types, possibly associated with charges.""" - subclass = None - superclass = MeterReadingBase - def __init__(self, BillingReadingSetListLink=None, ReadingTypeLink=None): - self.original_tagname_ = None - super(BillingMeterReadingBase, self).__init__() - self.BillingReadingSetListLink = BillingReadingSetListLink - self.ReadingTypeLink = ReadingTypeLink - def factory(*args_, **kwargs_): - if BillingMeterReadingBase.subclass: - return BillingMeterReadingBase.subclass(*args_, **kwargs_) - else: - return BillingMeterReadingBase(*args_, **kwargs_) - factory = staticmethod(factory) - def get_BillingReadingSetListLink(self): return self.BillingReadingSetListLink - def set_BillingReadingSetListLink(self, BillingReadingSetListLink): self.BillingReadingSetListLink = BillingReadingSetListLink - def get_ReadingTypeLink(self): return self.ReadingTypeLink - def set_ReadingTypeLink(self, ReadingTypeLink): self.ReadingTypeLink = ReadingTypeLink - def hasContent_(self): - if ( - self.BillingReadingSetListLink is not None or - self.ReadingTypeLink is not None or - super(BillingMeterReadingBase, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='BillingMeterReadingBase', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='BillingMeterReadingBase') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='BillingMeterReadingBase', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='BillingMeterReadingBase'): - super(BillingMeterReadingBase, self).exportAttributes(outfile, level, already_processed, namespace_, name_='BillingMeterReadingBase') - def exportChildren(self, outfile, level, namespace_='', name_='BillingMeterReadingBase', fromsubclass_=False, pretty_print=True): - super(BillingMeterReadingBase, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.BillingReadingSetListLink is not None: - self.BillingReadingSetListLink.export(outfile, level, namespace_, name_='BillingReadingSetListLink', pretty_print=pretty_print) - if self.ReadingTypeLink is not None: - self.ReadingTypeLink.export(outfile, level, namespace_, name_='ReadingTypeLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='BillingMeterReadingBase'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(BillingMeterReadingBase, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(BillingMeterReadingBase, self).exportLiteralChildren(outfile, level, name_) - if self.BillingReadingSetListLink is not None: - showIndent(outfile, level) - outfile.write('BillingReadingSetListLink=model_.BillingReadingSetListLink(\n') - self.BillingReadingSetListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ReadingTypeLink is not None: - showIndent(outfile, level) - outfile.write('ReadingTypeLink=model_.ReadingTypeLink(\n') - self.ReadingTypeLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(BillingMeterReadingBase, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'BillingReadingSetListLink': - obj_ = BillingReadingSetListLink.factory() - obj_.build(child_) - self.BillingReadingSetListLink = obj_ - obj_.original_tagname_ = 'BillingReadingSetListLink' - elif nodeName_ == 'ReadingTypeLink': - obj_ = ReadingTypeLink.factory() - obj_.build(child_) - self.ReadingTypeLink = obj_ - obj_.original_tagname_ = 'ReadingTypeLink' - super(BillingMeterReadingBase, self).buildChildren(child_, node, nodeName_, True) -# end class BillingMeterReadingBase - - -class UsagePoint(UsagePointBase): - """Logical point on a network at which consumption or production is - either physically measured (e.g. metered) or estimated (e.g. - unmetered street lights).""" - subclass = None - superclass = UsagePointBase - def __init__(self, MeterReadingListLink=None): - self.original_tagname_ = None - super(UsagePoint, self).__init__() - self.MeterReadingListLink = MeterReadingListLink - def factory(*args_, **kwargs_): - if UsagePoint.subclass: - return UsagePoint.subclass(*args_, **kwargs_) - else: - return UsagePoint(*args_, **kwargs_) - factory = staticmethod(factory) - def get_MeterReadingListLink(self): return self.MeterReadingListLink - def set_MeterReadingListLink(self, MeterReadingListLink): self.MeterReadingListLink = MeterReadingListLink - def hasContent_(self): - if ( - self.MeterReadingListLink is not None or - super(UsagePoint, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='UsagePoint', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePoint') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='UsagePoint', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='UsagePoint'): - super(UsagePoint, self).exportAttributes(outfile, level, already_processed, namespace_, name_='UsagePoint') - def exportChildren(self, outfile, level, namespace_='', name_='UsagePoint', fromsubclass_=False, pretty_print=True): - super(UsagePoint, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.MeterReadingListLink is not None: - self.MeterReadingListLink.export(outfile, level, namespace_, name_='MeterReadingListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='UsagePoint'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(UsagePoint, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(UsagePoint, self).exportLiteralChildren(outfile, level, name_) - if self.MeterReadingListLink is not None: - showIndent(outfile, level) - outfile.write('MeterReadingListLink=model_.MeterReadingListLink(\n') - self.MeterReadingListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(UsagePoint, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'MeterReadingListLink': - obj_ = MeterReadingListLink.factory() - obj_.build(child_) - self.MeterReadingListLink = obj_ - obj_.original_tagname_ = 'MeterReadingListLink' - super(UsagePoint, self).buildChildren(child_, node, nodeName_, True) -# end class UsagePoint - - -class ReadingSet(ReadingSetBase): - """A set of Readings of the ReadingType indicated by the parent - MeterReading.""" - subclass = None - superclass = ReadingSetBase - def __init__(self, ReadingListLink=None): - self.original_tagname_ = None - super(ReadingSet, self).__init__() - self.ReadingListLink = ReadingListLink - def factory(*args_, **kwargs_): - if ReadingSet.subclass: - return ReadingSet.subclass(*args_, **kwargs_) - else: - return ReadingSet(*args_, **kwargs_) - factory = staticmethod(factory) - def get_ReadingListLink(self): return self.ReadingListLink - def set_ReadingListLink(self, ReadingListLink): self.ReadingListLink = ReadingListLink - def hasContent_(self): - if ( - self.ReadingListLink is not None or - super(ReadingSet, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ReadingSet', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingSet') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ReadingSet', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ReadingSet'): - super(ReadingSet, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ReadingSet') - def exportChildren(self, outfile, level, namespace_='', name_='ReadingSet', fromsubclass_=False, pretty_print=True): - super(ReadingSet, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.ReadingListLink is not None: - self.ReadingListLink.export(outfile, level, namespace_, name_='ReadingListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='ReadingSet'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ReadingSet, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ReadingSet, self).exportLiteralChildren(outfile, level, name_) - if self.ReadingListLink is not None: - showIndent(outfile, level) - outfile.write('ReadingListLink=model_.ReadingListLink(\n') - self.ReadingListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ReadingSet, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'ReadingListLink': - obj_ = ReadingListLink.factory() - obj_.build(child_) - self.ReadingListLink = obj_ - obj_.original_tagname_ = 'ReadingListLink' - super(ReadingSet, self).buildChildren(child_, node, nodeName_, True) -# end class ReadingSet - - -class MeterReading(MeterReadingBase): - """Set of values obtained from the meter.""" - subclass = None - superclass = MeterReadingBase - def __init__(self, RateComponentListLink=None, ReadingLink=None, ReadingSetListLink=None, ReadingTypeLink=None): - self.original_tagname_ = None - super(MeterReading, self).__init__() - self.RateComponentListLink = RateComponentListLink - self.ReadingLink = ReadingLink - self.ReadingSetListLink = ReadingSetListLink - self.ReadingTypeLink = ReadingTypeLink - def factory(*args_, **kwargs_): - if MeterReading.subclass: - return MeterReading.subclass(*args_, **kwargs_) - else: - return MeterReading(*args_, **kwargs_) - factory = staticmethod(factory) - def get_RateComponentListLink(self): return self.RateComponentListLink - def set_RateComponentListLink(self, RateComponentListLink): self.RateComponentListLink = RateComponentListLink - def get_ReadingLink(self): return self.ReadingLink - def set_ReadingLink(self, ReadingLink): self.ReadingLink = ReadingLink - def get_ReadingSetListLink(self): return self.ReadingSetListLink - def set_ReadingSetListLink(self, ReadingSetListLink): self.ReadingSetListLink = ReadingSetListLink - def get_ReadingTypeLink(self): return self.ReadingTypeLink - def set_ReadingTypeLink(self, ReadingTypeLink): self.ReadingTypeLink = ReadingTypeLink - def hasContent_(self): - if ( - self.RateComponentListLink is not None or - self.ReadingLink is not None or - self.ReadingSetListLink is not None or - self.ReadingTypeLink is not None or - super(MeterReading, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='MeterReading', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReading') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='MeterReading', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='MeterReading'): - super(MeterReading, self).exportAttributes(outfile, level, already_processed, namespace_, name_='MeterReading') - def exportChildren(self, outfile, level, namespace_='', name_='MeterReading', fromsubclass_=False, pretty_print=True): - super(MeterReading, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.RateComponentListLink is not None: - self.RateComponentListLink.export(outfile, level, namespace_, name_='RateComponentListLink', pretty_print=pretty_print) - if self.ReadingLink is not None: - self.ReadingLink.export(outfile, level, namespace_, name_='ReadingLink', pretty_print=pretty_print) - if self.ReadingSetListLink is not None: - self.ReadingSetListLink.export(outfile, level, namespace_, name_='ReadingSetListLink', pretty_print=pretty_print) - if self.ReadingTypeLink is not None: - self.ReadingTypeLink.export(outfile, level, namespace_, name_='ReadingTypeLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='MeterReading'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(MeterReading, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(MeterReading, self).exportLiteralChildren(outfile, level, name_) - if self.RateComponentListLink is not None: - showIndent(outfile, level) - outfile.write('RateComponentListLink=model_.RateComponentListLink(\n') - self.RateComponentListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ReadingLink is not None: - showIndent(outfile, level) - outfile.write('ReadingLink=model_.ReadingLink(\n') - self.ReadingLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ReadingSetListLink is not None: - showIndent(outfile, level) - outfile.write('ReadingSetListLink=model_.ReadingSetListLink(\n') - self.ReadingSetListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.ReadingTypeLink is not None: - showIndent(outfile, level) - outfile.write('ReadingTypeLink=model_.ReadingTypeLink(\n') - self.ReadingTypeLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(MeterReading, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'RateComponentListLink': - obj_ = RateComponentListLink.factory() - obj_.build(child_) - self.RateComponentListLink = obj_ - obj_.original_tagname_ = 'RateComponentListLink' - elif nodeName_ == 'ReadingLink': - obj_ = ReadingLink.factory() - obj_.build(child_) - self.ReadingLink = obj_ - obj_.original_tagname_ = 'ReadingLink' - elif nodeName_ == 'ReadingSetListLink': - obj_ = ReadingSetListLink.factory() - obj_.build(child_) - self.ReadingSetListLink = obj_ - obj_.original_tagname_ = 'ReadingSetListLink' - elif nodeName_ == 'ReadingTypeLink': - obj_ = ReadingTypeLink.factory() - obj_.build(child_) - self.ReadingTypeLink = obj_ - obj_.original_tagname_ = 'ReadingTypeLink' - super(MeterReading, self).buildChildren(child_, node, nodeName_, True) -# end class MeterReading - - -class TextResponse(Response): - """A response to a text message""" - subclass = None - superclass = Response - def __init__(self): - self.original_tagname_ = None - super(TextResponse, self).__init__() - def factory(*args_, **kwargs_): - if TextResponse.subclass: - return TextResponse.subclass(*args_, **kwargs_) - else: - return TextResponse(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(TextResponse, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TextResponse', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TextResponse') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TextResponse', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TextResponse'): - super(TextResponse, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TextResponse') - def exportChildren(self, outfile, level, namespace_='', name_='TextResponse', fromsubclass_=False, pretty_print=True): - super(TextResponse, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='TextResponse'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TextResponse, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TextResponse, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TextResponse, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(TextResponse, self).buildChildren(child_, node, nodeName_, True) - pass -# end class TextResponse - - -class Notification(SubscriptionBase): - """Holds the information related to a client subscription to receive - updates to a resource automatically. The actual resources may be - passed in the Notification by specifying a specific xsi:type for - the Resource and passing the full representation.""" - subclass = None - superclass = SubscriptionBase - def __init__(self, newResourceURI=None, Resource=None, status=None, subscriptionURI=None): - self.original_tagname_ = None - super(Notification, self).__init__() - self.newResourceURI = newResourceURI - self.Resource = Resource - self.status = status - self.subscriptionURI = subscriptionURI - def factory(*args_, **kwargs_): - if Notification.subclass: - return Notification.subclass(*args_, **kwargs_) - else: - return Notification(*args_, **kwargs_) - factory = staticmethod(factory) - def get_newResourceURI(self): return self.newResourceURI - def set_newResourceURI(self, newResourceURI): self.newResourceURI = newResourceURI - def get_Resource(self): return self.Resource - def set_Resource(self, Resource): self.Resource = Resource - def get_status(self): return self.status - def set_status(self, status): self.status = status - def get_subscriptionURI(self): return self.subscriptionURI - def set_subscriptionURI(self, subscriptionURI): self.subscriptionURI = subscriptionURI - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def hasContent_(self): - if ( - self.newResourceURI is not None or - self.Resource is not None or - self.status is not None or - self.subscriptionURI is not None or - super(Notification, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Notification', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Notification') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Notification', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Notification'): - super(Notification, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Notification') - def exportChildren(self, outfile, level, namespace_='', name_='Notification', fromsubclass_=False, pretty_print=True): - super(Notification, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.newResourceURI is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%snewResourceURI>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.newResourceURI).encode(ExternalEncoding), input_name='newResourceURI'), namespace_, eol_)) - if self.Resource is not None: - self.Resource.export(outfile, level, namespace_, name_='Resource', pretty_print=pretty_print) - if self.status is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sstatus>%s%s' % (namespace_, self.gds_format_integer(self.status, input_name='status'), namespace_, eol_)) - if self.subscriptionURI is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%ssubscriptionURI>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.subscriptionURI).encode(ExternalEncoding), input_name='subscriptionURI'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Notification'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Notification, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Notification, self).exportLiteralChildren(outfile, level, name_) - if self.newResourceURI is not None: - showIndent(outfile, level) - outfile.write('newResourceURI=%s,\n' % quote_python(self.newResourceURI).encode(ExternalEncoding)) - if self.Resource is not None: - showIndent(outfile, level) - outfile.write('Resource=model_.Resource(\n') - self.Resource.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.status is not None: - showIndent(outfile, level) - outfile.write('status=%d,\n' % self.status) - if self.subscriptionURI is not None: - showIndent(outfile, level) - outfile.write('subscriptionURI=%s,\n' % quote_python(self.subscriptionURI).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Notification, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'newResourceURI': - newResourceURI_ = child_.text - newResourceURI_ = self.gds_validate_string(newResourceURI_, node, 'newResourceURI') - self.newResourceURI = newResourceURI_ - elif nodeName_ == 'Resource': - class_obj_ = self.get_class_obj_(child_, Resource) - obj_ = class_obj_.factory() - obj_.build(child_) - self.Resource = obj_ - obj_.original_tagname_ = 'Resource' - elif nodeName_ == 'status': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'status') - self.status = ival_ - self.validate_UInt8(self.status) # validate type UInt8 - elif nodeName_ == 'subscriptionURI': - subscriptionURI_ = child_.text - subscriptionURI_ = self.gds_validate_string(subscriptionURI_, node, 'subscriptionURI') - self.subscriptionURI = subscriptionURI_ - super(Notification, self).buildChildren(child_, node, nodeName_, True) -# end class Notification - - -class Subscription(SubscriptionBase): - """Holds the information related to a client subscription to receive - updates to a resource automatically.""" - subclass = None - superclass = SubscriptionBase - def __init__(self, Condition=None, encoding=None, level=None, limit=None, notificationURI=None): - self.original_tagname_ = None - super(Subscription, self).__init__() - self.Condition = Condition - self.encoding = encoding - self.level = level - self.limit = limit - self.notificationURI = notificationURI - def factory(*args_, **kwargs_): - if Subscription.subclass: - return Subscription.subclass(*args_, **kwargs_) - else: - return Subscription(*args_, **kwargs_) - factory = staticmethod(factory) - def get_Condition(self): return self.Condition - def set_Condition(self, Condition): self.Condition = Condition - def get_encoding(self): return self.encoding - def set_encoding(self, encoding): self.encoding = encoding - def get_level(self): return self.level - def set_level(self, level): self.level = level - def get_limit(self): return self.limit - def set_limit(self, limit): self.limit = limit - def get_notificationURI(self): return self.notificationURI - def set_notificationURI(self, notificationURI): self.notificationURI = notificationURI - def validate_UInt8(self, value): - # Validate type UInt8, a restriction on xs:unsignedByte. - pass - def validate_String16(self, value): - # Validate type String16, a restriction on xs:string. - pass - def validate_UInt16(self, value): - # Validate type UInt16, a restriction on xs:unsignedShort. - pass - def hasContent_(self): - if ( - self.Condition is not None or - self.encoding is not None or - self.level is not None or - self.limit is not None or - self.notificationURI is not None or - super(Subscription, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='Subscription', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='Subscription') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='Subscription', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='Subscription'): - super(Subscription, self).exportAttributes(outfile, level, already_processed, namespace_, name_='Subscription') - def exportChildren(self, outfile, level, namespace_='', name_='Subscription', fromsubclass_=False, pretty_print=True): - super(Subscription, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.Condition is not None: - self.Condition.export(outfile, level, namespace_, name_='Condition', pretty_print=pretty_print) - if self.encoding is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sencoding>%s%s' % (namespace_, self.gds_format_integer(self.encoding, input_name='encoding'), namespace_, eol_)) - if self.level is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slevel>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.level).encode(ExternalEncoding), input_name='level'), namespace_, eol_)) - if self.limit is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%slimit>%s%s' % (namespace_, self.gds_format_integer(self.limit, input_name='limit'), namespace_, eol_)) - if self.notificationURI is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%snotificationURI>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.notificationURI).encode(ExternalEncoding), input_name='notificationURI'), namespace_, eol_)) - def exportLiteral(self, outfile, level, name_='Subscription'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(Subscription, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(Subscription, self).exportLiteralChildren(outfile, level, name_) - if self.Condition is not None: - showIndent(outfile, level) - outfile.write('Condition=model_.Condition(\n') - self.Condition.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.encoding is not None: - showIndent(outfile, level) - outfile.write('encoding=%d,\n' % self.encoding) - if self.level is not None: - showIndent(outfile, level) - outfile.write('level=%s,\n' % quote_python(self.level).encode(ExternalEncoding)) - if self.limit is not None: - showIndent(outfile, level) - outfile.write('limit=%d,\n' % self.limit) - if self.notificationURI is not None: - showIndent(outfile, level) - outfile.write('notificationURI=%s,\n' % quote_python(self.notificationURI).encode(ExternalEncoding)) - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(Subscription, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'Condition': - obj_ = Condition.factory() - obj_.build(child_) - self.Condition = obj_ - obj_.original_tagname_ = 'Condition' - elif nodeName_ == 'encoding': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'encoding') - self.encoding = ival_ - self.validate_UInt8(self.encoding) # validate type UInt8 - elif nodeName_ == 'level': - level_ = child_.text - level_ = self.gds_validate_string(level_, node, 'level') - self.level = level_ - self.validate_String16(self.level) # validate type String16 - elif nodeName_ == 'limit': - sval_ = child_.text - try: - ival_ = int(sval_) - except (TypeError, ValueError) as exp: - raise_parse_error(child_, 'requires integer: %s' % exp) - ival_ = self.gds_validate_integer(ival_, node, 'limit') - self.limit = ival_ - self.validate_UInt16(self.limit) # validate type UInt16 - elif nodeName_ == 'notificationURI': - notificationURI_ = child_.text - notificationURI_ = self.gds_validate_string(notificationURI_, node, 'notificationURI') - self.notificationURI = notificationURI_ - super(Subscription, self).buildChildren(child_, node, nodeName_, True) -# end class Subscription - - -class FunctionSetAssignments(FunctionSetAssignmentsBase): - """Provides an identifiable, subscribable collection of resources for a - particular device to consume.Indicates whether or not - subscriptions are supported for this resource, and whether or - not conditional (thresholds) are supported. If not specified, is - "not subscribable" (0).""" - subclass = None - superclass = FunctionSetAssignmentsBase - def __init__(self, subscribable='0', mRID=None, description=None, version=None): - self.original_tagname_ = None - super(FunctionSetAssignments, self).__init__() - self.subscribable = _cast(None, subscribable) - self.mRID = mRID - self.description = description - self.version = version - def factory(*args_, **kwargs_): - if FunctionSetAssignments.subclass: - return FunctionSetAssignments.subclass(*args_, **kwargs_) - else: - return FunctionSetAssignments(*args_, **kwargs_) - factory = staticmethod(factory) - def get_mRID(self): return self.mRID - def set_mRID(self, mRID): self.mRID = mRID - def get_description(self): return self.description - def set_description(self, description): self.description = description - def get_version(self): return self.version - def set_version(self, version): self.version = version - def get_subscribable(self): return self.subscribable - def set_subscribable(self, subscribable): self.subscribable = subscribable - def validate_String32(self, value): - # Validate type String32, a restriction on xs:string. - pass - def validate_SubscribableType(self, value): - # Validate type SubscribableType, a restriction on UInt8. - pass - def hasContent_(self): - if ( - self.mRID is not None or - self.description is not None or - self.version is not None or - super(FunctionSetAssignments, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='FunctionSetAssignments', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='FunctionSetAssignments') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='FunctionSetAssignments', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='FunctionSetAssignments'): - super(FunctionSetAssignments, self).exportAttributes(outfile, level, already_processed, namespace_, name_='FunctionSetAssignments') - if self.subscribable is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - outfile.write(' subscribable=%s' % (quote_attrib(self.subscribable), )) - def exportChildren(self, outfile, level, namespace_='', name_='FunctionSetAssignments', fromsubclass_=False, pretty_print=True): - super(FunctionSetAssignments, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.mRID is not None: - self.mRID.export(outfile, level, namespace_, name_='mRID', pretty_print=pretty_print) - if self.description is not None: - showIndent(outfile, level, pretty_print) - outfile.write('<%sdescription>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.description).encode(ExternalEncoding), input_name='description'), namespace_, eol_)) - if self.version is not None: - self.version.export(outfile, level, namespace_, name_='version', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='FunctionSetAssignments'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - if self.subscribable is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - showIndent(outfile, level) - outfile.write('subscribable=%d,\n' % (self.subscribable,)) - super(FunctionSetAssignments, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(FunctionSetAssignments, self).exportLiteralChildren(outfile, level, name_) - if self.mRID is not None: - showIndent(outfile, level) - outfile.write('mRID=model_.mRIDType(\n') - self.mRID.exportLiteral(outfile, level, name_='mRID') - showIndent(outfile, level) - outfile.write('),\n') - if self.description is not None: - showIndent(outfile, level) - outfile.write('description=%s,\n' % quote_python(self.description).encode(ExternalEncoding)) - if self.version is not None: - showIndent(outfile, level) - outfile.write('version=model_.VersionType(\n') - self.version.exportLiteral(outfile, level, name_='version') - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - value = find_attr_value_('subscribable', node) - if value is not None and 'subscribable' not in already_processed: - already_processed.add('subscribable') - self.subscribable = value - self.validate_SubscribableType(self.subscribable) # validate type SubscribableType - super(FunctionSetAssignments, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'mRID': - obj_ = mRIDType.factory() - obj_.build(child_) - self.mRID = obj_ - obj_.original_tagname_ = 'mRID' - elif nodeName_ == 'description': - description_ = child_.text - description_ = self.gds_validate_string(description_, node, 'description') - self.description = description_ - self.validate_String32(self.description) # validate type String32 - elif nodeName_ == 'version': - obj_ = VersionType.factory() - obj_.build(child_) - self.version = obj_ - obj_.original_tagname_ = 'version' - super(FunctionSetAssignments, self).buildChildren(child_, node, nodeName_, True) -# end class FunctionSetAssignments - - -class SelfDevice(AbstractDevice): - """The EndDevice providing the resources available within the - DeviceCapabilities.""" - subclass = None - superclass = AbstractDevice - def __init__(self): - self.original_tagname_ = None - super(SelfDevice, self).__init__() - def factory(*args_, **kwargs_): - if SelfDevice.subclass: - return SelfDevice.subclass(*args_, **kwargs_) - else: - return SelfDevice(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(SelfDevice, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='SelfDevice', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='SelfDevice') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='SelfDevice', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SelfDevice'): - super(SelfDevice, self).exportAttributes(outfile, level, already_processed, namespace_, name_='SelfDevice') - def exportChildren(self, outfile, level, namespace_='', name_='SelfDevice', fromsubclass_=False, pretty_print=True): - super(SelfDevice, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='SelfDevice'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(SelfDevice, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(SelfDevice, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(SelfDevice, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(SelfDevice, self).buildChildren(child_, node, nodeName_, True) - pass -# end class SelfDevice - - -class EndDevice(AbstractDevice): - """Asset container that performs one or more end device functions. - Contains information about individual devices in the network.""" - subclass = None - superclass = AbstractDevice - def __init__(self, FlowReservationRequestListLink=None, FlowReservationResponseListLink=None, FunctionSetAssignmentsListLink=None, RegistrationLink=None, SubscriptionListLink=None): - self.original_tagname_ = None - super(EndDevice, self).__init__() - self.FlowReservationRequestListLink = FlowReservationRequestListLink - self.FlowReservationResponseListLink = FlowReservationResponseListLink - self.FunctionSetAssignmentsListLink = FunctionSetAssignmentsListLink - self.RegistrationLink = RegistrationLink - self.SubscriptionListLink = SubscriptionListLink - def factory(*args_, **kwargs_): - if EndDevice.subclass: - return EndDevice.subclass(*args_, **kwargs_) - else: - return EndDevice(*args_, **kwargs_) - factory = staticmethod(factory) - def get_FlowReservationRequestListLink(self): return self.FlowReservationRequestListLink - def set_FlowReservationRequestListLink(self, FlowReservationRequestListLink): self.FlowReservationRequestListLink = FlowReservationRequestListLink - def get_FlowReservationResponseListLink(self): return self.FlowReservationResponseListLink - def set_FlowReservationResponseListLink(self, FlowReservationResponseListLink): self.FlowReservationResponseListLink = FlowReservationResponseListLink - def get_FunctionSetAssignmentsListLink(self): return self.FunctionSetAssignmentsListLink - def set_FunctionSetAssignmentsListLink(self, FunctionSetAssignmentsListLink): self.FunctionSetAssignmentsListLink = FunctionSetAssignmentsListLink - def get_RegistrationLink(self): return self.RegistrationLink - def set_RegistrationLink(self, RegistrationLink): self.RegistrationLink = RegistrationLink - def get_SubscriptionListLink(self): return self.SubscriptionListLink - def set_SubscriptionListLink(self, SubscriptionListLink): self.SubscriptionListLink = SubscriptionListLink - def hasContent_(self): - if ( - self.FlowReservationRequestListLink is not None or - self.FlowReservationResponseListLink is not None or - self.FunctionSetAssignmentsListLink is not None or - self.RegistrationLink is not None or - self.SubscriptionListLink is not None or - super(EndDevice, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='EndDevice', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='EndDevice') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='EndDevice', pretty_print=pretty_print) - showIndent(outfile, level, pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='EndDevice'): - super(EndDevice, self).exportAttributes(outfile, level, already_processed, namespace_, name_='EndDevice') - def exportChildren(self, outfile, level, namespace_='', name_='EndDevice', fromsubclass_=False, pretty_print=True): - super(EndDevice, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.FlowReservationRequestListLink is not None: - self.FlowReservationRequestListLink.export(outfile, level, namespace_, name_='FlowReservationRequestListLink', pretty_print=pretty_print) - if self.FlowReservationResponseListLink is not None: - self.FlowReservationResponseListLink.export(outfile, level, namespace_, name_='FlowReservationResponseListLink', pretty_print=pretty_print) - if self.FunctionSetAssignmentsListLink is not None: - self.FunctionSetAssignmentsListLink.export(outfile, level, namespace_, name_='FunctionSetAssignmentsListLink', pretty_print=pretty_print) - if self.RegistrationLink is not None: - self.RegistrationLink.export(outfile, level, namespace_, name_='RegistrationLink', pretty_print=pretty_print) - if self.SubscriptionListLink is not None: - self.SubscriptionListLink.export(outfile, level, namespace_, name_='SubscriptionListLink', pretty_print=pretty_print) - def exportLiteral(self, outfile, level, name_='EndDevice'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(EndDevice, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(EndDevice, self).exportLiteralChildren(outfile, level, name_) - if self.FlowReservationRequestListLink is not None: - showIndent(outfile, level) - outfile.write('FlowReservationRequestListLink=model_.FlowReservationRequestListLink(\n') - self.FlowReservationRequestListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.FlowReservationResponseListLink is not None: - showIndent(outfile, level) - outfile.write('FlowReservationResponseListLink=model_.FlowReservationResponseListLink(\n') - self.FlowReservationResponseListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.FunctionSetAssignmentsListLink is not None: - showIndent(outfile, level) - outfile.write('FunctionSetAssignmentsListLink=model_.FunctionSetAssignmentsListLink(\n') - self.FunctionSetAssignmentsListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.RegistrationLink is not None: - showIndent(outfile, level) - outfile.write('RegistrationLink=model_.RegistrationLink(\n') - self.RegistrationLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - if self.SubscriptionListLink is not None: - showIndent(outfile, level) - outfile.write('SubscriptionListLink=model_.SubscriptionListLink(\n') - self.SubscriptionListLink.exportLiteral(outfile, level) - showIndent(outfile, level) - outfile.write('),\n') - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(EndDevice, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - if nodeName_ == 'FlowReservationRequestListLink': - obj_ = FlowReservationRequestListLink.factory() - obj_.build(child_) - self.FlowReservationRequestListLink = obj_ - obj_.original_tagname_ = 'FlowReservationRequestListLink' - elif nodeName_ == 'FlowReservationResponseListLink': - obj_ = FlowReservationResponseListLink.factory() - obj_.build(child_) - self.FlowReservationResponseListLink = obj_ - obj_.original_tagname_ = 'FlowReservationResponseListLink' - elif nodeName_ == 'FunctionSetAssignmentsListLink': - obj_ = FunctionSetAssignmentsListLink.factory() - obj_.build(child_) - self.FunctionSetAssignmentsListLink = obj_ - obj_.original_tagname_ = 'FunctionSetAssignmentsListLink' - elif nodeName_ == 'RegistrationLink': - obj_ = RegistrationLink.factory() - obj_.build(child_) - self.RegistrationLink = obj_ - obj_.original_tagname_ = 'RegistrationLink' - elif nodeName_ == 'SubscriptionListLink': - obj_ = SubscriptionListLink.factory() - obj_.build(child_) - self.SubscriptionListLink = obj_ - obj_.original_tagname_ = 'SubscriptionListLink' - super(EndDevice, self).buildChildren(child_, node, nodeName_, True) -# end class EndDevice - - -class TargetReading(BillingMeterReadingBase): - """Contains readings that specify a target or goal, such as a - consumption target, to which billing incentives or other - contractual ramifications may be associated.""" - subclass = None - superclass = BillingMeterReadingBase - def __init__(self): - self.original_tagname_ = None - super(TargetReading, self).__init__() - def factory(*args_, **kwargs_): - if TargetReading.subclass: - return TargetReading.subclass(*args_, **kwargs_) - else: - return TargetReading(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(TargetReading, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='TargetReading', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='TargetReading') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='TargetReading', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='TargetReading'): - super(TargetReading, self).exportAttributes(outfile, level, already_processed, namespace_, name_='TargetReading') - def exportChildren(self, outfile, level, namespace_='', name_='TargetReading', fromsubclass_=False, pretty_print=True): - super(TargetReading, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='TargetReading'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(TargetReading, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(TargetReading, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(TargetReading, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(TargetReading, self).buildChildren(child_, node, nodeName_, True) - pass -# end class TargetReading - - -class ProjectionReading(BillingMeterReadingBase): - """Contains values that forecast a future reading for the time or - interval specified.""" - subclass = None - superclass = BillingMeterReadingBase - def __init__(self): - self.original_tagname_ = None - super(ProjectionReading, self).__init__() - def factory(*args_, **kwargs_): - if ProjectionReading.subclass: - return ProjectionReading.subclass(*args_, **kwargs_) - else: - return ProjectionReading(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(ProjectionReading, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='ProjectionReading', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='ProjectionReading') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='ProjectionReading', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ProjectionReading'): - super(ProjectionReading, self).exportAttributes(outfile, level, already_processed, namespace_, name_='ProjectionReading') - def exportChildren(self, outfile, level, namespace_='', name_='ProjectionReading', fromsubclass_=False, pretty_print=True): - super(ProjectionReading, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='ProjectionReading'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(ProjectionReading, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(ProjectionReading, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(ProjectionReading, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(ProjectionReading, self).buildChildren(child_, node, nodeName_, True) - pass -# end class ProjectionReading - - -class HistoricalReading(BillingMeterReadingBase): - """To be used to present readings that have been processed and possibly - corrected (as allowed, due to missing or incorrect data) by - backend systems. This includes quality codes valid, verified, - estimated, and derived / corrected.""" - subclass = None - superclass = BillingMeterReadingBase - def __init__(self): - self.original_tagname_ = None - super(HistoricalReading, self).__init__() - def factory(*args_, **kwargs_): - if HistoricalReading.subclass: - return HistoricalReading.subclass(*args_, **kwargs_) - else: - return HistoricalReading(*args_, **kwargs_) - factory = staticmethod(factory) - def hasContent_(self): - if ( - super(HistoricalReading, self).hasContent_() - ): - return True - else: - return False - def export(self, outfile, level, namespace_='', name_='HistoricalReading', namespacedef_='', pretty_print=True): - if pretty_print: - eol_ = '\n' - else: - eol_ = '' - if self.original_tagname_ is not None: - name_ = self.original_tagname_ - showIndent(outfile, level, pretty_print) - outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) - already_processed = set() - self.exportAttributes(outfile, level, already_processed, namespace_, name_='HistoricalReading') - if self.hasContent_(): - outfile.write('>%s' % (eol_, )) - self.exportChildren(outfile, level + 1, namespace_='', name_='HistoricalReading', pretty_print=pretty_print) - outfile.write('%s' % (namespace_, name_, eol_)) - else: - outfile.write('/>%s' % (eol_, )) - def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='HistoricalReading'): - super(HistoricalReading, self).exportAttributes(outfile, level, already_processed, namespace_, name_='HistoricalReading') - def exportChildren(self, outfile, level, namespace_='', name_='HistoricalReading', fromsubclass_=False, pretty_print=True): - super(HistoricalReading, self).exportChildren(outfile, level, namespace_, name_, True, pretty_print=pretty_print) - pass - def exportLiteral(self, outfile, level, name_='HistoricalReading'): - level += 1 - already_processed = set() - self.exportLiteralAttributes(outfile, level, already_processed, name_) - if self.hasContent_(): - self.exportLiteralChildren(outfile, level, name_) - def exportLiteralAttributes(self, outfile, level, already_processed, name_): - super(HistoricalReading, self).exportLiteralAttributes(outfile, level, already_processed, name_) - def exportLiteralChildren(self, outfile, level, name_): - super(HistoricalReading, self).exportLiteralChildren(outfile, level, name_) - pass - def build(self, node): - already_processed = set() - self.buildAttributes(node, node.attrib, already_processed) - for child in node: - nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] - self.buildChildren(child, node, nodeName_) - return self - def buildAttributes(self, node, attrs, already_processed): - super(HistoricalReading, self).buildAttributes(node, attrs, already_processed) - def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): - super(HistoricalReading, self).buildChildren(child_, node, nodeName_, True) - pass -# end class HistoricalReading - - -GDSClassesMapping = { - 'energyRequested': SignedRealEnergy, - 'rtgA': CurrentRMS, - 'setVRefOfs': VoltageRMS, - 'availableCredit': AccountingUnit, - 'secondaryPower': PowerSourceType, - 'rtgW': ActivePower, - 'primaryPower': PowerSourceType, - 'creditStatus': CreditStatusType, - 'opModVoltWatt': DERCurveLink, - 'pricePowerOfTenMultiplier': PowerOfTenMultiplierType, - 'opModVoltVAr': DERCurveLink, - 'maxForwardPower': ActivePower, - 'localControlModeStatus': LocalControlModeStatusType, - 'dstStartRule': DstRuleType, - 'xMultiplier': PowerOfTenMultiplierType, - 'lowEmergencyCreditWarningLevel': AccountingUnit, - 'sheddablePercent': PerCent, - 'flowRateEndLimit': UnitValueType, - 'accumulationBehaviour': AccumulationBehaviourType, - 'yMultiplier': PowerOfTenMultiplierType, - 'uom': UomType, - 'touTier': TOUType, - 'refType': DERUnitRefType, - 'activateTime': TimeType, - 'opModFixedW': PerCent, - 'lowerLimit': DERCurveLink, - 'rtgMinPF': UnsignedFixedPointType, - 'setMinPFNeg': FixedPointType, - 'swActTime': TimeType, - 'reservePercent': PerCent, - 'flowDirection': FlowDirectionType, - 'setMaxDischargeRate': ActivePower, - 'costKind': CostKindType, - 'serviceStatus': ServiceStatusType, - 'rtgVArNeg': ReactivePower, - 'timeChargingStatusPEV': TimeType, - 'curveType': DERCurveType, - 'monetaryUnit': CurrencyCode, - 'energyRequestNow': RealEnergy, - 'estimatedChargeRemaining': PerCent, - 'dateTime': TimeType, - 'genConnectStatus': ConnectStatusType, - 'prepayMode': PrepayModeType, - 'timeChargeIsNeeded': TimeType, - 'upperLimit': DERCurveLink, - 'powerOfTenMultiplier': PowerOfTenMultiplierType, - 'lastUpdateTime': TimeType, - 'locale': LocaleType, - 'serviceCategoryKind': ServiceKind, - 'opModHVRT': CurvePairType, - 'serviceChange': ServiceChange, - 'value': PerCent, - 'logEventPEN': PENType, - 'timePeriod': DateTimeInterval, - 'subject': mRIDType, - 'sFDI': SFDIType, - 'flowRateStartLimit': UnitValueType, - 'chargingPowerNow': ActivePower, - 'version': VersionType, - 'mfID': PENType, - 'creditExpiryLevel': AccountingUnit, - 'setMaxVArNeg': ReactivePower, - 'multiplier': PowerOfTenMultiplierType, - 'randomizeStart': OneHourRangeType, - 'setMinPF': UnsignedFixedPointType, - 'rtgMaxChargeRate': ActivePower, - 'availabilityUpdatePercentChangeThreshold': PerCent, - 'dstEndTime': TimeType, - 'deviceCategory': DeviceCategoryType, - 'dateTimeRegistered': TimeType, - 'rtgAh': AmpereHour, - 'manufacturerStatus': ManufacturerStatusType, - 'statusTimeStamp': TimeType, - 'opModWattPF': DERCurveLink, - 'conversionFactor': UnitValueType, - 'mfDate': TimeType, - 'statWAvail': ActivePower, - 'currentPowerSource': PowerSourceType, - 'modesSupported': DERControlType, - 'opModFixedPF': FixedPowerFactor, - 'energyAvailable': RealEnergy, - 'sheddablePower': ActivePower, - 'changedTime': TimeType, - 'unit': UomType, - 'intervalRequested': DateTimeInterval, - 'start': TimeType, - 'consumptionBlock': ConsumptionBlockType, - 'setMaxW': ActivePower, - 'priority': PriorityType, - 'setMaxVA': ApparentPower, - 'creditTypeInUse': CreditTypeType, - 'dstEndRule': DstRuleType, - 'rtgVA': ApparentPower, - 'type': DERType, - 'potentiallySupersededTime': TimeType, - 'powerRequested': ActivePower, - 'rtgVAr': ReactivePower, - 'rtgWh': WattHour, - 'setMaxChargeRate': ActivePower, - 'stateOfChargeStatus': StateOfChargeStatusType, - 'emergencyCredit': AccountingUnit, - 'dstStartTime': TimeType, - 'updatedTime': TimeType, - 'kind': ChargeKind, - 'energyUnit': RealEnergy, - 'dstOffset': TimeOffsetType, - 'batteryInstallTime': TimeType, - 'creationTime': TimeType, - 'lowCreditWarningLevel': AccountingUnit, - 'availabilityUpdatePowerChangeThreshold': ActivePower, - 'powerAvailable': ActivePower, - 'inverterStatus': InverterStatusType, - 'statusTime': TimeType, - 'nextUpdateTime': TimeType, - 'primacy': PrimacyType, - 'tzOffset': TimeOffsetType, - 'nextRequestAttempt': TimeType, - 'newStatus': ServiceStatusType, - 'creditType': CreditTypeType, - 'roleFlags': RoleFlagsType, - 'effectiveTime': TimeType, - 'readingTime': TimeType, - 'loadShedDeviceCategory': DeviceCategoryType, - 'creditAmount': AccountingUnit, - 'setMaxVAr': ReactivePower, - 'currency': CurrencyCode, - 'setVRef': VoltageRMS, - 'currentLocale': LocaleType, - 'mRID': mRIDType, - 'targetStateOfCharge': PerCent, - 'maxDemand': ActivePower, - 'opModLVRT': CurvePairType, - 'storConnectStatus': ConnectStatusType, - 'opModFixedVAr': FixedVAr, - 'storageModeStatus': StorageModeStatusType, - 'rtgMinPFNeg': FixedPointType, - 'pIN': PINType, - 'emergencyCreditStatus': CreditStatusType, - 'randomizeDuration': OneHourRangeType, - 'yRefType': DERUnitRefType, - 'opModFixedFlow': SignedPerCent, - 'statVArAvail': ReactivePower, - 'startTime': TimeType, - 'phase': PhaseCode, - 'rtgMaxDischargeRate': ActivePower, - 'calorificValue': UnitValueType, - 'localTime': TimeType, - 'commodity': CommodityType, - 'currentTime': TimeType, - 'createdDateTime': TimeType, - 'dataQualifier': DataQualifierType, - 'interval': DateTimeInterval, - 'averageEnergy': RealEnergy, - 'operationalModeStatus': OperationalModeStatusType, - 'creditTypeChange': CreditTypeChange, - 'reserveChargePercent': PerCent, - 'opModFreqWatt': DERCurveLink, - 'newType': CreditTypeType, -} - - -USAGE_TEXT = """ -Usage: python .py [ -s ] -""" - - -def usage(): - print(USAGE_TEXT) - sys.exit(1) - - -def get_root_tag(node): - tag = Tag_pattern_.match(node.tag).groups()[-1] - rootClass = GDSClassesMapping.get(tag) - if rootClass is None: - rootClass = globals().get(tag) - return tag, rootClass - - -def parse(inFileName, silence=False): - doc = parsexml_(inFileName) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'DeviceCapability' - rootClass = DeviceCapability - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('\n') - rootObj.export( - sys.stdout, 0, name_=rootTag, - namespacedef_='', - pretty_print=True) - return rootObj - - -def parseEtree(inFileName, silence=False): - doc = parsexml_(inFileName) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'DeviceCapability' - rootClass = DeviceCapability - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - mapping = {} - rootElement = rootObj.to_etree(None, name_=rootTag, mapping_=mapping) - reverse_mapping = rootObj.gds_reverse_node_mapping(mapping) - if not silence: - content = etree_.tostring( - rootElement, pretty_print=True, - xml_declaration=True, encoding="utf-8") - sys.stdout.write(content) - sys.stdout.write('\n') - return rootObj, rootElement, mapping, reverse_mapping - - -def parseString(inString, silence=False): - from io import StringIO - doc = parsexml_(StringIO(inString)) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'DeviceCapability' - rootClass = DeviceCapability - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('\n') - rootObj.export( - sys.stdout, 0, name_=rootTag, - namespacedef_='') - return rootObj - - -def parseLiteral(inFileName, silence=False): - doc = parsexml_(inFileName) - rootNode = doc.getroot() - rootTag, rootClass = get_root_tag(rootNode) - if rootClass is None: - rootTag = 'DeviceCapability' - rootClass = DeviceCapability - rootObj = rootClass.factory() - rootObj.build(rootNode) - # Enable Python to collect the space used by the DOM. - doc = None - if not silence: - sys.stdout.write('#from xsd_models import *\n\n') - sys.stdout.write('import xsd_models as model_\n\n') - sys.stdout.write('rootObj = model_.rootClass(\n') - rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) - sys.stdout.write(')\n') - return rootObj - - -def main(): - args = sys.argv[1:] - if len(args) == 1: - parse(args[0]) - else: - usage() - - -if __name__ == '__main__': - #import pdb; pdb.set_trace() - main() - - -__all__ = [ - "AbstractDevice", - "AbstractFlowReservation", - "AccountBalance", - "AccountBalanceLink", - "AccountingUnit", - "AccumulationBehaviourType", - "ActiveBillingPeriodListLink", - "ActiveCreditRegisterListLink", - "ActiveDERControlListLink", - "ActiveEndDeviceControlListLink", - "ActiveFlowReservationListLink", - "ActivePower", - "ActiveProjectionReadingListLink", - "ActiveSupplyInterruptionOverrideListLink", - "ActiveTargetReadingListLink", - "ActiveTextMessageListLink", - "ActiveTimeTariffIntervalListLink", - "AmpereHour", - "ApparentPower", - "ApplianceLoadReduction", - "ApplianceLoadReductionType", - "AppliedTargetReduction", - "AssociatedDERProgramListLink", - "AssociatedUsagePointLink", - "BillingMeterReadingBase", - "BillingPeriod", - "BillingPeriodList", - "BillingPeriodListLink", - "BillingReading", - "BillingReadingList", - "BillingReadingListLink", - "BillingReadingSet", - "BillingReadingSetList", - "BillingReadingSetListLink", - "Charge", - "ChargeKind", - "CommodityType", - "Condition", - "Configuration", - "ConfigurationLink", - "ConnectStatusType", - "ConsumptionBlockType", - "ConsumptionTariffInterval", - "ConsumptionTariffIntervalList", - "ConsumptionTariffIntervalListLink", - "CostKindType", - "CreditRegister", - "CreditRegisterList", - "CreditRegisterListLink", - "CreditStatusType", - "CreditTypeChange", - "CreditTypeType", - "CurrencyCode", - "CurrentDERProgramLink", - "CurrentRMS", - "CurveData", - "CurvePairType", - "CustomerAccount", - "CustomerAccountLink", - "CustomerAccountList", - "CustomerAccountListLink", - "CustomerAgreement", - "CustomerAgreementList", - "CustomerAgreementListLink", - "DER", - "DERAvailability", - "DERAvailabilityLink", - "DERCapability", - "DERCapabilityLink", - "DERControl", - "DERControlBase", - "DERControlList", - "DERControlListLink", - "DERControlType", - "DERCurve", - "DERCurveLink", - "DERCurveList", - "DERCurveListLink", - "DERCurveType", - "DERLink", - "DERList", - "DERListLink", - "DERProgram", - "DERProgramLink", - "DERProgramList", - "DERProgramListLink", - "DERSettings", - "DERSettingsLink", - "DERStatus", - "DERStatusLink", - "DERType", - "DERUnitRefType", - "DRLCCapabilities", - "DataQualifierType", - "DateTimeInterval", - "DefaultDERControl", - "DefaultDERControlLink", - "DemandResponseProgram", - "DemandResponseProgramLink", - "DemandResponseProgramList", - "DemandResponseProgramListLink", - "DeviceCapability", - "DeviceCapabilityLink", - "DeviceCategoryType", - "DeviceInformation", - "DeviceInformationLink", - "DeviceStatus", - "DeviceStatusLink", - "DrResponse", - "DstRuleType", - "DutyCycle", - "EndDevice", - "EndDeviceControl", - "EndDeviceControlList", - "EndDeviceControlListLink", - "EndDeviceLink", - "EndDeviceList", - "EndDeviceListLink", - "EnvironmentalCost", - "Error", - "Event", - "EventStatus", - "File", - "FileLink", - "FileList", - "FileListLink", - "FileStatus", - "FileStatusLink", - "FixedPointType", - "FixedPowerFactor", - "FixedVAr", - "FlowDirectionType", - "FlowReservationRequest", - "FlowReservationRequestList", - "FlowReservationRequestListLink", - "FlowReservationResponse", - "FlowReservationResponseList", - "FlowReservationResponseListLink", - "FunctionSetAssignments", - "FunctionSetAssignmentsBase", - "FunctionSetAssignmentsList", - "FunctionSetAssignmentsListLink", - "HistoricalReading", - "HistoricalReadingList", - "HistoricalReadingListLink", - "IEEE_802_15_4", - "IPAddr", - "IPAddrList", - "IPAddrListLink", - "IPInterface", - "IPInterfaceList", - "IPInterfaceListLink", - "IdentifiedObject", - "InverterStatusType", - "KindType", - "LLInterface", - "LLInterfaceList", - "LLInterfaceListLink", - "Link", - "List", - "ListLink", - "LoadShedAvailability", - "LoadShedAvailabilityLink", - "LocalControlModeStatusType", - "LocaleType", - "LogEvent", - "LogEventList", - "LogEventListLink", - "ManufacturerStatusType", - "MessagingProgram", - "MessagingProgramList", - "MessagingProgramListLink", - "MeterReading", - "MeterReadingBase", - "MeterReadingLink", - "MeterReadingList", - "MeterReadingListLink", - "MirrorMeterReading", - "MirrorMeterReadingList", - "MirrorReadingSet", - "MirrorUsagePoint", - "MirrorUsagePointList", - "MirrorUsagePointListLink", - "Neighbor", - "NeighborList", - "NeighborListLink", - "Notification", - "NotificationList", - "NotificationListLink", - "Offset", - "OneHourRangeType", - "OperationalModeStatusType", - "PENType", - "PEVInfo", - "PINType", - "PerCent", - "PhaseCode", - "PowerConfiguration", - "PowerOfTenMultiplierType", - "PowerSourceType", - "PowerStatus", - "PowerStatusLink", - "PrepayModeType", - "PrepayOperationStatus", - "PrepayOperationStatusLink", - "Prepayment", - "PrepaymentLink", - "PrepaymentList", - "PrepaymentListLink", - "PriceResponse", - "PriceResponseCfg", - "PriceResponseCfgList", - "PriceResponseCfgListLink", - "PrimacyType", - "PriorityType", - "ProjectionReading", - "ProjectionReadingList", - "ProjectionReadingListLink", - "RPLInstance", - "RPLInstanceList", - "RPLInstanceListLink", - "RPLSourceRoutes", - "RPLSourceRoutesList", - "RPLSourceRoutesListLink", - "RandomizableEvent", - "RateComponent", - "RateComponentLink", - "RateComponentList", - "RateComponentListLink", - "ReactivePower", - "Reading", - "ReadingBase", - "ReadingLink", - "ReadingList", - "ReadingListLink", - "ReadingSet", - "ReadingSetBase", - "ReadingSetList", - "ReadingSetListLink", - "ReadingType", - "ReadingTypeLink", - "RealEnergy", - "Registration", - "RegistrationLink", - "RequestStatus", - "Resource", - "RespondableIdentifiedObject", - "RespondableResource", - "RespondableSubscribableIdentifiedObject", - "Response", - "ResponseList", - "ResponseListLink", - "ResponseSet", - "ResponseSetList", - "ResponseSetListLink", - "RoleFlagsType", - "SFDIType", - "SelfDevice", - "SelfDeviceLink", - "ServiceChange", - "ServiceKind", - "ServiceStatusType", - "ServiceSupplier", - "ServiceSupplierLink", - "ServiceSupplierList", - "SetPoint", - "SignedPerCent", - "SignedRealEnergy", - "StateOfChargeStatusType", - "StorageModeStatusType", - "SubscribableIdentifiedObject", - "SubscribableList", - "SubscribableResource", - "Subscription", - "SubscriptionBase", - "SubscriptionList", - "SubscriptionListLink", - "SupplyInterruptionOverride", - "SupplyInterruptionOverrideList", - "SupplyInterruptionOverrideListLink", - "SupportedLocale", - "SupportedLocaleList", - "SupportedLocaleListLink", - "TOUType", - "TargetReading", - "TargetReadingList", - "TargetReadingListLink", - "TargetReduction", - "TariffProfile", - "TariffProfileLink", - "TariffProfileList", - "TariffProfileListLink", - "Temperature", - "TextMessage", - "TextMessageList", - "TextMessageListLink", - "TextResponse", - "Time", - "TimeConfiguration", - "TimeLink", - "TimeOffsetType", - "TimeTariffInterval", - "TimeTariffIntervalList", - "TimeTariffIntervalListLink", - "TimeType", - "UnitType", - "UnitValueType", - "UnsignedFixedPointType", - "UomType", - "UsagePoint", - "UsagePointBase", - "UsagePointLink", - "UsagePointList", - "UsagePointListLink", - "VersionType", - "VoltageRMS", - "WattHour", - "loWPAN", - "mRIDType" -] diff --git a/services/core/IEEE2030_5Agent/README.md b/services/core/IEEE2030_5Agent/README.md deleted file mode 100644 index 62792c4b82..0000000000 --- a/services/core/IEEE2030_5Agent/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# IEEE2030_5 Agent -Agent that handles IEEE 2030.5 communication. -IEEE2030_5Agent uses the VOLTTRON web service to communicate with IEEE 2030.5 end devices. -End device configuration is outlined in the agent config file. - -IEEE 2030.5 data is exposed via get_point(), get_points() and set_point() calls. -A IEEE 2030.5 device driver (IEEE2030_5.py under PlatformDriverAgent) can be configured, -which gets and sets data by sending RPCs to this agent. - -For further information about this subsystem, please see the VOLTTRON -IEEE 2030.5 DER Support specification, which is located in VOLTTRON readthedocs -under specifications/IEEE2030_5_agent.html. - -## Configuration - -``` {.python} -{ - "devices": [ - { - "sfdi": "097935300833", - "lfdi": "247bd68e3378fe57ba604e3c8bdf9e3f78a3d743", - "load_shed_device_category": "0200", - "pin_code": "130178" - }, - { - "sfdi": "111576577659", - "lfdi": "2990c58a59935a7d5838c952b1a453c967341a07", - "load_shed_device_category": "0200", - "pin_code": "130178" - } - ], - "IEEE2030_5_server_sfdi": "413707194130", - "IEEE2030_5_server_lfdi": "29834592834729384728374562039847629", - "load_shed_device_category": "0020", - "timezone": "America/Los_Angeles" -} -``` diff --git a/services/core/IEEE2030_5Agent/config b/services/core/IEEE2030_5Agent/config deleted file mode 100644 index ba7fef49ba..0000000000 --- a/services/core/IEEE2030_5Agent/config +++ /dev/null @@ -1,20 +0,0 @@ -{ - "devices": [ - { - "sfdi": "097935300833", - "lfdi": "247bd68e3378fe57ba604e3c8bdf9e3f78a3d743", - "load_shed_device_category": "0200", - "pin_code": "130178" - }, - { - "sfdi": "111576577659", - "lfdi": "2990c58a59935a7d5838c952b1a453c967341a07", - "load_shed_device_category": "0200", - "pin_code": "130178" - } - ], - "IEEE2030_5_server_sfdi": "413707194130", - "IEEE2030_5_server_lfdi": "29834592834729384728374562039847629", - "load_shed_device_category": "0020", - "timezone": "America/Los_Angeles" -} diff --git a/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/IEEE2030_5drivertest.config b/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/IEEE2030_5drivertest.config deleted file mode 100644 index 7fd4f416c8..0000000000 --- a/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/IEEE2030_5drivertest.config +++ /dev/null @@ -1,3 +0,0 @@ -{ - "agentid": "IEEE2030_5drivertest" -} diff --git a/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/__init__.py b/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/setup.py b/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/setup.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/test_agent/__init__.py b/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/test_agent/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/test_agent/agent.py b/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/test_agent/agent.py deleted file mode 100644 index 6f23f157e7..0000000000 --- a/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/test_agent/agent.py +++ /dev/null @@ -1,449 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2020, Battelle Memorial Institute. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 -# }}} - -import gevent -import logging -import requests -import sys - -from volttron.platform.vip.agent import Agent, Core -from volttron.platform.agent import utils -from volttron.platform.agent.known_identities import PLATFORM_DRIVER - -_log = logging.getLogger(__name__) -utils.setup_logging() - -__version__ = '1.0' - -CYCLE_TIME = 3 # Seconds between sets of get_point/set_point calls - -ALL_POINTS = [ - 'b1_Md', - 'b1_Opt', - 'b1_SN', - 'b1_Vr', - 'b113_A', - 'b113_DCA', - 'b113_DCV', - 'b113_DCW', - 'b113_PF', - 'b113_WH', - 'b120_AhrRtg', - 'b120_ARtg', - 'b120_MaxChaRte', - 'b120_MaxDisChaRte', - 'b120_WHRtg', - 'b120_WRtg', - 'b121_WMax', - 'b122_ActWh', - 'b122_StorConn', - 'b124_WChaMax', - 'b403_Tmp', - 'b404_DCW', - 'b404_DCWh', - 'b802_LocRemCtl', - 'b802_SoC', - 'b802_State'] - -DEVICE_INFORMATION = """ - 0145 - 5509D69F8B353595206AD71B47E27906318EA367 - 1388566800 - MF-HW: 1.0.0 - 37250 - Mf Information - Mf Model - 1234567890 - 2 - 0 - 1416107035 - 9bc8e7b_modified - -""" - -DER_SETTINGS = """ - 55000 - - 1 - 2 - - - 3 - 4 - - - 1 - 1 - - true - 1416307137 -""" - -DER_STATUS = """ - 1416270124 - - 1416270124 - 777 - - - 1416270124 - 777 - - - 1416270124 - 777 - - - 1416270124 - 777 - -""" - -DER_AVAILABILITY = """ - 55036 - 3 - 1416304442 - 10000 - 10000 - - 1 - 1 - -""" - -DER_CAPABILITY = """ - 01 - - 1 - 35 - - - 1 - 33 - - - 1 - 22 - - - 1 - 1 - - - 1 - 1 - - - 1 - 1 - - - 1 - 123 - - 85 -""" - -POWER_STATUS = """ - 0 - 1416266598 - 3 - 1 - 0 - - - 0 - 3000 - - - 0 - 6100 - - - 3 - 7 - - 4337 - 1000 - 1516266598 - 1516266598 - - 2 - 2 -""" - -MUP = """ - 0600006CC8 - Gas Mirroring - 13 - 1 - 1 - 247bd68e3378fe57ba604e3c8bdf9e3f78a3d743 - - 0700006CC8 - Cumulative Reading for Gas - - 125 - - - 9 - 7 - 0 - 1 - 3 - 119 - - - - 0800006CC8 - Interval Readings for Gas - - 4 - 7 - 0 - 1 - 3 - 119 - - - - 0900006CC8 - InstantPackCurrent - - 125 - - - - 0900006CC8 - LineVoltageAvg - - 125 - - - - 0900006CC8 - PhasePowerAvg - - 125 - - - - 1000006CC8 - PhasePFA - - 126 - - - - 1100006CC8 - EnergyIMP - - 127 - - - - 1300006CC8 - InstantPackTemp - - 128 - - - 9 - 7 - 0 - 1 - 3 - 119 - - -""" - -MUP2 = """ - 0600006CC8 - Gas Mirroring - 13 - 1 - 1 - 247bd68e3378fe57ba604e3c8bdf9e3f78a3d743 - - 1200006CC8 - EnergyEXP - - 128 - - -""" - -MMR = """ - 6D6D72099BBDE9156400000000009182 - PhaseCurrentAvg - - - 0 - 2216441 - - 24 - - - 12 - 0 - 12 - 0 - 0 - 0 - 0 - 23 - -""" - -ASSERTED_VALUES = { - 'b1_Md': 'Mf Model', - 'b1_Opt': '247bd68e3378fe57ba604e3c8bdf9e3f78a3d743', - 'b1_SN': '097935300833', - 'b1_Vr': 'MF-HW: 1.0.0', - 'b113_A': '24.0', - 'b113_DCA': '125.0', - 'b113_DCV': '125.0', - 'b113_DCW': '125.0', - 'b113_PF': '126.0', - 'b113_WH': '127.0', - 'b120_AhrRtg': '350.0', - 'b120_ARtg': '330.0', - 'b120_MaxChaRte': '220.0', - 'b120_MaxDisChaRte': '10.0', - 'b120_WHRtg': '1230.0', - 'b120_WRtg': '10.0', - 'b121_WMax': '20.0', - 'b122_ActWh': '128.0', - 'b122_StorConn': '777', - 'b124_WChaMax': '10.0', - 'b403_Tmp': '128000.0', - 'b404_DCW': '3000.0', - 'b404_DCWh': '305.755555556', - 'b802_LocRemCtl': '777', - 'b802_SoC': '7.77', - 'b802_State': '777'} - -TEST_WEB_ADDRESS = 'http://127.0.0.1:8080' -DEFAULT_DRIVER = 'IEEE2030_5_1' - - -class IEEE2030_5DriverTestAgent(Agent): - """ - Test the IEEE 2030.5 driver (not a pytest regression test). - - Load a test data set by posting XML to IEEE2030_5Agent (assumed to be at port 8080 on the local host). - Periodically send get_point for each point on the IEEE 2030.5 driver. - Also send a set_point call to its der_control point, setting a power dispatch value. - - This agent can be installed as follows: - export VIP_SOCKET="ipc://$VOLTTRON_HOME/run/vip.socket" - export IEEE2030_5_TEST_ROOT=$VOLTTRON_ROOT/services/core/IEEE2030_5Agent/tests/IEEE2030_5DriverTestAgent/test_agent - cd $VOLTTRON_ROOT - python scripts/install-agent.py \ - -s $IEEE2030_5_TEST_ROOT \ - -i IEEE2030_5testagent \ - -c $IEEE2030_5_TEST_ROOT/IEEE2030_5drivertest.config \ - -t IEEE2030_5testagent \ - -f - """ - - def __init__(self, **kwargs): - super(IEEE2030_5DriverTestAgent, self).__init__(**kwargs) - self.default_config = {} - self.vip.config.set_default("config", self.default_config) - self.vip.config.subscribe(self.configure, actions=["NEW", "UPDATE"], pattern="config") - - def configure(self, config_name, action, contents): - config = self.default_config.copy() - config.update(contents) - - @Core.receiver('onstart') - def onstart(self, sender, **kwargs): - self.core.spawn(self.send_and_receive_points) - - def send_and_receive_points(self): - self.post_test_data() - while True: - self.set_point('b124_WChaMax', ASSERTED_VALUES['b124_WChaMax']) - for point_name in ALL_POINTS: - expected_value = ASSERTED_VALUES[point_name] - received_value = self.get_point(point_name) - assert received_value == expected_value - gevent.sleep(CYCLE_TIME) - - @staticmethod - def post_test_data(): - """Post XML test data for a IEEE 2030.5 resource to the IEEE2030_5Agent.""" - headers = {'content-type': 'application/sep+xml'} - requests.post('{}/dcap/edev/0/di'.format(TEST_WEB_ADDRESS), data=DEVICE_INFORMATION, headers=headers) - requests.post('{}/dcap/edev/0/der/1/derg'.format(TEST_WEB_ADDRESS), data=DER_SETTINGS, headers=headers) - requests.post('{}/dcap/edev/0/der/1/ders'.format(TEST_WEB_ADDRESS), data=DER_STATUS, headers=headers) - requests.post('{}/dcap/edev/0/der/1/dera'.format(TEST_WEB_ADDRESS), data=DER_AVAILABILITY, headers=headers) - requests.post('{}/dcap/edev/0/der/1/dercap'.format(TEST_WEB_ADDRESS), data=DER_CAPABILITY, headers=headers) - requests.post('{}/dcap/edev/0/ps'.format(TEST_WEB_ADDRESS), data=POWER_STATUS, headers=headers) - requests.post('{}/dcap/mup'.format(TEST_WEB_ADDRESS), data=MUP, headers=headers) - requests.post('{}/dcap/mup/0'.format(TEST_WEB_ADDRESS), data=MUP2, headers=headers) - requests.post('{}/dcap/mup/0'.format(TEST_WEB_ADDRESS), data=MMR, headers=headers) - - def get_point(self, point_name, driver_name=None): - """Issue a get_point RPC call for the named point and return the result.""" - driver = driver_name if driver_name else DEFAULT_DRIVER - response = self.vip.rpc.call(PLATFORM_DRIVER, 'get_point', driver, point_name).get(timeout=10) - _log.debug('{}: Sent get_point for {}, received {}'.format(driver, point_name, response)) - return response - - def set_point(self, point_name, value, driver_name=None): - """Issue a set_point RPC call for the named point and value, and return the result.""" - driver = driver_name if driver_name else DEFAULT_DRIVER - self.vip.rpc.call(PLATFORM_DRIVER, 'set_point', driver, point_name, value) - _log.debug('{}: Sent set_point for {} = {}'.format(driver, point_name, value)) - - -def test_IEEE2030_5_agent(config_path, **kwargs): - return IEEE2030_5DriverTestAgent(**kwargs) - - -def main(): - utils.vip_main(test_IEEE2030_5_agent, identity='IEEE2030_5testagent', version=__version__) - -if __name__ == '__main__': - try: - sys.exit(main()) - except KeyboardInterrupt: - pass diff --git a/services/core/IEEE2030_5Agent/tests/der.dera.PUT.xml b/services/core/IEEE2030_5Agent/tests/der.dera.PUT.xml deleted file mode 100644 index 3875af85ed..0000000000 --- a/services/core/IEEE2030_5Agent/tests/der.dera.PUT.xml +++ /dev/null @@ -1,11 +0,0 @@ - - 55036 - 3 - 1416304442 - 10000 - 10000 - - 1 - 1 - - \ No newline at end of file diff --git a/services/core/IEEE2030_5Agent/tests/der.dercap.PUT.xml b/services/core/IEEE2030_5Agent/tests/der.dercap.PUT.xml deleted file mode 100644 index 49510006fc..0000000000 --- a/services/core/IEEE2030_5Agent/tests/der.dercap.PUT.xml +++ /dev/null @@ -1,32 +0,0 @@ - - 01 - - 1 - 35 - - - 1 - 33 - - - 1 - 22 - - - 1 - 1 - - - 1 - 1 - - - 1 - 1 - - - 1 - 123 - - 85 - diff --git a/services/core/IEEE2030_5Agent/tests/der.derg.PUT.xml b/services/core/IEEE2030_5Agent/tests/der.derg.PUT.xml deleted file mode 100644 index ed10f419df..0000000000 --- a/services/core/IEEE2030_5Agent/tests/der.derg.PUT.xml +++ /dev/null @@ -1,17 +0,0 @@ - - 55000 - - 1 - 2 - - - 3 - 4 - - - 1 - 1 - - true - 1416307137 - \ No newline at end of file diff --git a/services/core/IEEE2030_5Agent/tests/der.ders.PUT.xml b/services/core/IEEE2030_5Agent/tests/der.ders.PUT.xml deleted file mode 100644 index 699d09a611..0000000000 --- a/services/core/IEEE2030_5Agent/tests/der.ders.PUT.xml +++ /dev/null @@ -1,19 +0,0 @@ - - 1416270124 - - 1416270124 - 777 - - - 1416270124 - 777 - - - 1416270124 - 777 - - - 1416270124 - 777 - - diff --git a/services/core/IEEE2030_5Agent/tests/edev.di.PUT.xml b/services/core/IEEE2030_5Agent/tests/edev.di.PUT.xml deleted file mode 100644 index f7472b9806..0000000000 --- a/services/core/IEEE2030_5Agent/tests/edev.di.PUT.xml +++ /dev/null @@ -1,14 +0,0 @@ - - 0145 - 5509D69F8B353595206AD71B47E27906318EA367 - 1388566800 - MF-HW: 1.0.0 - 37250 - Mf Information - Mf Model - 1234567890 - 2 - 0 - 1416107035 - 9bc8e7b_modified - diff --git a/services/core/IEEE2030_5Agent/tests/edev.dstat.PUT.xml b/services/core/IEEE2030_5Agent/tests/edev.dstat.PUT.xml deleted file mode 100644 index a15a50171d..0000000000 --- a/services/core/IEEE2030_5Agent/tests/edev.dstat.PUT.xml +++ /dev/null @@ -1,6 +0,0 @@ - - 1416266460 - 5 - 0 - 0 - \ No newline at end of file diff --git a/services/core/IEEE2030_5Agent/tests/edev.ps.PUT.xml b/services/core/IEEE2030_5Agent/tests/edev.ps.PUT.xml deleted file mode 100644 index fa06647f1d..0000000000 --- a/services/core/IEEE2030_5Agent/tests/edev.ps.PUT.xml +++ /dev/null @@ -1,27 +0,0 @@ - - 0 - 1416266598 - 3 - 1 - 0 - - - 0 - 3000 - - - 0 - 6100 - - - 3 - 7 - - 4337 - 1000 - 1516266598 - 1516266598 - - 2 - 2 - diff --git a/services/core/IEEE2030_5Agent/tests/mup.mmr.PUT.xml b/services/core/IEEE2030_5Agent/tests/mup.mmr.PUT.xml deleted file mode 100644 index c14bed6d8f..0000000000 --- a/services/core/IEEE2030_5Agent/tests/mup.mmr.PUT.xml +++ /dev/null @@ -1,21 +0,0 @@ - - 6D6D72099BBDE9156400000000009182 - PhaseCurrentAvg - - - 0 - 2216441 - - 24 - - - 12 - 0 - 12 - 0 - 0 - 0 - 0 - 23 - - \ No newline at end of file diff --git a/services/core/IEEE2030_5Agent/tests/mup.mup.PUT.xml b/services/core/IEEE2030_5Agent/tests/mup.mup.PUT.xml deleted file mode 100644 index 8c06c88533..0000000000 --- a/services/core/IEEE2030_5Agent/tests/mup.mup.PUT.xml +++ /dev/null @@ -1,85 +0,0 @@ - - 0600006CC8 - Gas Mirroring - 13 - 1 - 1 - 247bd68e3378fe57ba604e3c8bdf9e3f78a3d743 - - 0700006CC8 - Cumulative Reading for Gas - - 125 - - - 9 - 7 - 0 - 1 - 3 - 119 - - - - 0800006CC8 - Interval Readings for Gas - - 4 - 7 - 0 - 1 - 3 - 119 - - - - 0900006CC8 - InstantPackCurrent - - 125 - - - - 0900006CC8 - LineVoltageAvg - - 125 - - - - 0900006CC8 - PhasePowerAvg - - 125 - - - - 1000006CC8 - PhasePFA - - 126 - - - - 1100006CC8 - EnergyIMP - - 127 - - - - 1300006CC8 - InstantPackTemp - - 128 - - - 9 - 7 - 0 - 1 - 3 - 119 - - - \ No newline at end of file diff --git a/services/core/IEEE2030_5Agent/tests/mup.mup2.PUT.xml b/services/core/IEEE2030_5Agent/tests/mup.mup2.PUT.xml deleted file mode 100644 index 7cdd1c5e04..0000000000 --- a/services/core/IEEE2030_5Agent/tests/mup.mup2.PUT.xml +++ /dev/null @@ -1,15 +0,0 @@ - - 0600006CC8 - Gas Mirroring - 13 - 1 - 1 - 247bd68e3378fe57ba604e3c8bdf9e3f78a3d743 - - 1200006CC8 - EnergyEXP - - 128 - - - \ No newline at end of file diff --git a/services/core/IEEE2030_5Agent/tests/test_IEEE2030_5_agent.py b/services/core/IEEE2030_5Agent/tests/test_IEEE2030_5_agent.py deleted file mode 100644 index f1d94b8ce3..0000000000 --- a/services/core/IEEE2030_5Agent/tests/test_IEEE2030_5_agent.py +++ /dev/null @@ -1,291 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2020, Battelle Memorial Institute. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 -# }}} - -import pytest -import gevent -import requests - -from volttron.platform import get_services_core -from IEEE2030_5.end_device import IEEE2030_5Parser -from volttron.platform.agent.known_identities import PLATFORM_DRIVER - -DRIVER_NAME = 'IEEE2030_5' -DEVICE_ID = "097935300833" - -TEST_IEEE2030_5_CONFIG = { - "devices": [ - { - "sfdi": "097935300833", - "lfdi": "247bd68e3378fe57ba604e3c8bdf9e3f78a3d743", - "load_shed_device_category": "0200", - "pin_code": "130178" - }, - { - "sfdi": "111576577659", - "lfdi": "2990c58a59935a7d5838c952b1a453c967341a07", - "load_shed_device_category": "0200", - "pin_code": "130178" - } - ], - "IEEE2030_5_server_sfdi": "413707194130", - "IEEE2030_5_server_lfdi": "29834592834729384728374562039847629", - "load_shed_device_category": "0020", - "timezone": "America/Los_Angeles" -} - -REGISTRY_CONFIG_STRING = """Volttron Point Name,IEEE2030_5 Resource Name,IEEE2030_5 Field Name,Units,Writable,Default -b1_Md,DeviceInformation,mfModel,NA,FALSE,NA -b1_Opt,DeviceInformation,lFDI,NA,FALSE,NA -b1_SN,DeviceInformation,sFDI,NA,FALSE,NA -b1_Vr,DeviceInformation,mfHwVer,NA,FALSE,NA -b113_A,MirrorMeterReading,PhaseCurrentAvg,A,FALSE,NA -b113_DCA,MirrorMeterReading,InstantPackCurrent,A,FALSE,NA -b113_DCV,MirrorMeterReading,LineVoltageAvg,V,FALSE,NA -b113_DCW,MirrorMeterReading,PhasePowerAvg,W,FALSE,NA -b113_PF,MirrorMeterReading,PhasePFA,%,FALSE,NA -b113_WH,MirrorMeterReading,EnergyIMP,Wh,FALSE,NA -b120_AhrRtg,DERCapability,rtgAh,Ah,FALSE,NA -b120_ARtg,DERCapability,rtgA,A,FALSE,NA -b120_MaxChaRte,DERCapability,rtgMaxChargeRate,W,FALSE,NA -b120_MaxDisChaRte,DERCapability,rtgMaxDischargeRate,W,FALSE,NA -b120_WHRtg,DERCapability,rtgWh,Wh,FALSE,NA -b120_WRtg,DERCapability,rtgW,W,FALSE,NA -b121_WMax,DERSettings,setMaxChargeRate,W,FALSE,NA -b122_ActWh,MirrorMeterReading,EnergyEXP,Wh,FALSE,NA -b122_StorConn,DERStatus,storConnectStatus,NA,FALSE,NA -b124_WChaMax,DERControl,DERControlBase.opModFixedFlow,W,TRUE,NA -b403_Tmp,MirrorMeterReading,InstantPackTemp,C,FALSE,NA -b404_DCW,PowerStatus,PEVInfo.chargingPowerNow,W,FALSE,NA -b404_DCWh,DERAvailability,SOC,Wh,FALSE,NA -b802_LocRemCtl,DERStatus,localControlModeStatus,NA,FALSE,NA -b802_SoC,DERStatus,inverterStatus,%,FALSE,NA -b802_State,DERStatus,stateOfChargeStatus,NA,FALSE,NA""" - -web_address = "" - - -@pytest.fixture(scope="module") -def agent(request, volttron_instance_module_web): - - test_agent = volttron_instance_module_web.build_agent(identity="test_agent") - capabilities = {'edit_config_store': {'identity': PLATFORM_DRIVER}} - volttron_instance_module_web.add_capabilities(test_agent.core.publickey, capabilities) - # Configure a IEEE 2030.5 device in the Platform Driver - test_agent.vip.rpc.call('config.store', 'manage_delete_store', PLATFORM_DRIVER).get(timeout=10) - test_agent.vip.rpc.call('config.store', 'manage_store', PLATFORM_DRIVER, - 'devices/{}'.format(DRIVER_NAME), - """{ - "driver_config": { - "sfdi": "097935300833", - "IEEE2030_5_agent_id": "test_IEEE2030_5agent" - }, - "campus": "campus", - "building": "building", - "unit": "IEEE2030_5", - "driver_type": "IEEE2030_5", - "registry_config": "config://IEEE2030_5.csv", - "interval": 15, - "timezone": "US/Pacific", - "heart_beat_point": "Heartbeat" - }""", - 'json').get(timeout=10) - test_agent.vip.rpc.call('config.store', 'manage_store', PLATFORM_DRIVER, - 'IEEE2030_5.csv', - REGISTRY_CONFIG_STRING, - 'csv').get(timeout=10) - - # Install and start a IEEE2030_5Agent - IEEE2030_5_id = volttron_instance_module_web.install_agent(agent_dir=get_services_core("IEEE2030_5Agent"), - config_file=TEST_IEEE2030_5_CONFIG, - vip_identity='test_IEEE2030_5agent', - start=True) - print('IEEE2030_5 agent id: ', IEEE2030_5_id) - - # Install and start a PlatformDriverAgent - md_id = volttron_instance_module_web.install_agent(agent_dir=get_services_core("PlatformDriverAgent"), - config_file={}, - start=True) - print('platform driver agent id: ', md_id) - - global web_address - web_address = volttron_instance_module_web.bind_web_address - - def stop(): - volttron_instance_module_web.stop_agent(md_id) - volttron_instance_module_web.stop_agent(IEEE2030_5_id) - test_agent.core.stop() - - gevent.sleep(3) # wait for agents and devices to start - - request.addfinalizer(stop) - - return test_agent - - -class TestIEEE2030_5Agent: - """Regression tests for the IEEE 2030.5 Agent.""" - - def test_get_urls(self, agent): - """Test that a requests.get succeeds (200 status) for various URLs.""" - assert requests.get('{}/dcap'.format(web_address)).status_code == 200 - self.IEEE2030_5_http_get('tm') - self.IEEE2030_5_http_get('edev') - self.IEEE2030_5_http_get('sdev') - self.IEEE2030_5_http_get('sdev/di') - self.IEEE2030_5_http_get('sdev/log') - self.IEEE2030_5_http_get('edev/0') - self.IEEE2030_5_http_get('edev/0/reg') - self.IEEE2030_5_http_get('edev/0/fsa') - self.IEEE2030_5_http_get('edev/0/der') - self.IEEE2030_5_http_get('edev/0/der/1') - - def test_set_di(self, agent): - """Test that DeviceInformation can be fetched after it's been set.""" - assert self.IEEE2030_5_http_get('edev/0/di').mfInfo is None - assert self.get_point(agent, 'b1_Vr') is None - assert self.get_point(agent, 'b1_Md') is None - assert self.IEEE2030_5_http_put('edev/0/di', 'edev.di').status_code == 204 - assert self.IEEE2030_5_http_get('edev/0/di').mfInfo == 'Mf Information' - assert self.get_point(agent, 'b1_Vr') == 'MF-HW: 1.0.0' - assert self.get_point(agent, 'b1_Md') == 'Mf Model' - - def test_set_dstat(self, agent): - """Test that DeviceStatus can be fetched after it's been set.""" - self.IEEE2030_5_http_get('edev/0/dstat') - assert self.IEEE2030_5_http_put('edev/0/dstat', 'edev.dstat').status_code == 204 - assert self.IEEE2030_5_http_get('edev/0/dstat').onCount == 5 - - def test_set_ps(self, agent): - """Test that PowerStatus can be fetched after it's been set.""" - assert self.IEEE2030_5_http_get('edev/0/ps').totalTimeOnBattery is None - assert self.IEEE2030_5_http_put('edev/0/ps', 'edev.ps').status_code == 204 - assert self.IEEE2030_5_http_get('edev/0/ps').totalTimeOnBattery == 2 - - def test_get_derc(self, agent): - """Test that DERControl can be used to dispatch a power setting.""" - self.IEEE2030_5_http_get('edev/0/derc/1') - self.set_point(agent, 'b124_WChaMax', 30) - # The next assert would fail -- DERControlBase.opModFixedFlow returns None - # assert self.get_point(agent, 'b124_WChaMax') == 30 - - def test_set_dercap(self, agent): - """Test that DERCapability can be fetched after it's been set.""" - assert self.IEEE2030_5_http_get('edev/0/der/1/dercap').type_ is None - assert self.IEEE2030_5_http_put('edev/0/der/1/dercap', 'der.dercap').status_code == 204 - assert self.IEEE2030_5_http_get('edev/0/der/1/dercap').type_.get_valueOf_() == '85' - - def test_set_derg(self, agent): - """Test that DERSettings can be fetched after it's been set.""" - assert self.IEEE2030_5_http_get('edev/0/der/1/derg').setGradW is None - assert self.get_point(agent, 'b121_WMax') is None - assert self.IEEE2030_5_http_put('edev/0/der/1/derg', 'der.derg').status_code == 204 - assert self.IEEE2030_5_http_get('edev/0/der/1/derg').setGradW == 55000 - assert self.get_point(agent, 'b121_WMax') == 20.0 - - def test_set_dera(self, agent): - """Test that DERAvailability can be fetched after it's been set.""" - assert self.IEEE2030_5_http_get('edev/0/der/1/dera').maxChargeDuration is None - assert self.get_point(agent, 'b404_DCWh') is None - assert self.IEEE2030_5_http_put('edev/0/der/1/dera', 'der.dera').status_code == 204 - assert self.IEEE2030_5_http_get('edev/0/der/1/dera').maxChargeDuration == 3 - assert self.get_point(agent, 'b404_DCWh') == 305.7555555555556 - - def test_set_ders(self, agent): - """Test that DERStatus can be fetched after it's been set.""" - assert self.IEEE2030_5_http_get('edev/0/der/1/ders').stateOfChargeStatus is None - assert self.get_point(agent, 'b802_State') is None - assert self.get_point(agent, 'b802_LocRemCtl') is None - assert self.get_point(agent, 'b802_SoC') is None - assert self.get_point(agent, 'b122_StorConn') is None - assert self.IEEE2030_5_http_put('edev/0/der/1/ders', 'der.ders').status_code == 204 - assert self.IEEE2030_5_http_get('edev/0/der/1/ders').stateOfChargeStatus.value.get_valueOf_() == '777' - assert self.get_point(agent, 'b802_State') == 7.77 - assert self.get_point(agent, 'b802_LocRemCtl') == 777 - assert self.get_point(agent, 'b802_SoC') == 777 - assert self.get_point(agent, 'b122_StorConn') == 777 - - def test_mup(self, agent): - """Test that metrics can be fetched from a MirrorUsagePoint.""" - self.IEEE2030_5_http_get('mup') - assert self.IEEE2030_5_http_put('mup', 'mup.mup').status_code == 201 - assert self.IEEE2030_5_http_get('mup').MirrorUsagePoint[0].description == 'Gas Mirroring' - self.IEEE2030_5_http_put('mup/0', 'mup.mmr') - self.IEEE2030_5_http_get('mup') - assert self.get_point(agent, 'b113_A') == 24.0 - assert self.get_point(agent, 'b122_ActWh') is None - self.IEEE2030_5_http_put('mup/0', 'mup.mup2') - assert self.get_point(agent, 'b122_ActWh') == 128 - - @staticmethod - def get_point(agent, point_name): - """Ask IEEE2030_5Agent for a point value for a IEEE 2030.5 resource.""" - return agent.vip.rpc.call('test_IEEE2030_5agent', 'get_point', DEVICE_ID, point_name).get(timeout=10) - - @staticmethod - def set_point(agent, point_name, value): - """Use IEEE2030_5Agent to set a point value for a IEEE 2030.5 resource.""" - return agent.vip.rpc.call('test_IEEE2030_5agent', 'set_point', DEVICE_ID, point_name, value).get(timeout=10) - - @staticmethod - def IEEE2030_5_http_get(IEEE2030_5_resource_name): - """ - Issue a web request to GET data for a IEEE 2030.5 resource. - - :param IEEE2030_5_resource_name: The distinguishing part of the name of the IEEE 2030.5 resource as it appears - in the URL. - :return: XML - """ - r = requests.get('{}/dcap/{}'.format(web_address, IEEE2030_5_resource_name)) - assert r.status_code == 200 - return IEEE2030_5Parser.parse(r.text.encode('ascii', 'ignore')) - - @staticmethod - def IEEE2030_5_http_put(IEEE2030_5_resource_name, IEEE2030_5_filename): - """ - Issue a web request to PUT data for a IEEE 2030.5 resource, using the contents of an XML file. - - @param IEEE2030_5_resource_name: The distinguishing part of the name of the IEEE 2030.5 resource as it appears - in the URL. - @param IEEE2030_5_filename: The distinguishing part of the IEEE 2030.5 sample data file name. - """ - url = '{}/dcap/{}'.format(web_address, IEEE2030_5_resource_name) - headers = {'content-type': 'application/IEEE2030_5+xml'} - return requests.post(url, - data=open(get_services_core("IEEE2030_5Agent/tests/{}.PUT.xml").format(IEEE2030_5_filename), - 'rb'), - headers=headers) diff --git a/services/core/IEEE2030_5Agent/tests/test_IEEE2030_5_driver.py b/services/core/IEEE2030_5Agent/tests/test_IEEE2030_5_driver.py deleted file mode 100644 index 40e76206ac..0000000000 --- a/services/core/IEEE2030_5Agent/tests/test_IEEE2030_5_driver.py +++ /dev/null @@ -1,232 +0,0 @@ -# -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: -# -# Copyright 2020, Battelle Memorial Institute. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. -# -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 -# }}} - -import time -import pytest -import gevent -import requests - -from volttron.platform import get_services_core - -DRIVER_NAME = 'IEEE2030_5' -DEVICE_ID = "097935300833" - -TEST_CONFIG = { - "devices": [ - { - "sfdi": "097935300833", - "lfdi": "247bd68e3378fe57ba604e3c8bdf9e3f78a3d743", - "load_shed_device_category": "0200", - "pin_code": "130178" - }, - { - "sfdi": "111576577659", - "lfdi": "2990c58a59935a7d5838c952b1a453c967341a07", - "load_shed_device_category": "0200", - "pin_code": "130178" - } - ], - "IEEE2030_5_server_sfdi": "413707194130", - "IEEE2030_5_server_lfdi": "29834592834729384728374562039847629", - "load_shed_device_category": "0020", - "timezone": "America/Los_Angeles" -} - -REGISTRY_CONFIG_STRING = """Volttron Point Name,IEEE2030_5 Resource Name,IEEE2030_5 Field Name,Units,Writable,Default -b1_Md,DeviceInformation,mfModel,NA,FALSE,NA -b1_Opt,DeviceInformation,lFDI,NA,FALSE,NA -b1_SN,DeviceInformation,sFDI,NA,FALSE,NA -b1_Vr,DeviceInformation,mfHwVer,NA,FALSE,NA -b113_A,MirrorMeterReading,PhaseCurrentAvg,NA,FALSE,NA -b113_DCA,MirrorMeterReading,InstantPackCurrent,A,FALSE,NA -b113_DCV,MirrorMeterReading,LineVoltageAvg,V,FALSE,NA -b113_DCW,MirrorMeterReading,PhasePowerAvg,W,FALSE,NA -b113_PF,MirrorMeterReading,PhasePFA,%,FALSE,NA -b113_WH,MirrorMeterReading,EnergyIMP,Wh,FALSE,NA -b120_AhrRtg,DERCapability,rtgAh,Ah,FALSE,NA -b120_ARtg,DERCapability,rtgA,A,FALSE,NA -b120_MaxChaRte,DERCapability,rtgMaxChargeRate,W,FALSE,NA -b120_MaxDisChaRte,DERCapability,rtgMaxDischargeRate,W,FALSE,NA -b120_WHRtg,DERCapability,rtgWh,Wh,FALSE,NA -b120_WRtg,DERCapability,rtgW,W,FALSE,NA -b121_WMax,DERSettings,setMaxChargeRate,W,FALSE,NA -b122_ActWh,MirrorMeterReading,EnergyEXP,Wh,FALSE,NA -b122_StorConn,DERStatus,storConnectStatus,NA,FALSE,NA -b124_WChaMax,DERControl,DERControlBase.opModFixedFlow,W,TRUE,NA -b403_Tmp,MirrorMeterReading,InstantPackTemp,C,FALSE,NA -b404_DCW,PowerStatus,PEVInfo.chargingPowerNow,W,FALSE,NA -b404_DCWh,DERAvailability,SOC,Wh,FALSE,NA -b802_LocRemCtl,DERStatus,localControlModeStatus,NA,FALSE,NA -b802_SoC,DERStatus,inverterStatus,%,FALSE,NA -b802_State,DERStatus,stateOfChargeStatus,NA,FALSE,NA""" - -ASSERTED_VALUES = { - 'b1_Md': 'Mf Model', - 'b1_SN': '097935300833', - 'b1_Vr': 'MF-HW: 1.0.0', - 'b113_A': '24.0', - 'b113_DCA': '125.0', - 'b113_DCV': '125.0', - 'b113_DCW': '125.0', - 'b113_PF': '126.0', - 'b113_WH': '127.0', - 'b120_AhrRtg': '350.0', - 'b120_ARtg': '330.0', - 'b120_MaxChaRte': '220.0', - 'b120_MaxDisChaRte': '10.0', - 'b120_WHRtg': '1230.0', - 'b120_WRtg': '10.0', - 'b121_WMax': '20.0', - 'b122_ActWh': '128.0', - 'b122_StorConn': '777', - 'b124_WChaMax': '10.0', - 'b403_Tmp': '128000.0', - 'b404_DCW': '3000.0', - 'b404_DCWh': '305.755555556', - 'b802_LocRemCtl': '777', - 'b802_SoC': '777', - 'b802_State': '7.77'} - -web_address = "" - - -@pytest.fixture(scope="module") -def agent(request, volttron_instance_module_web): - test_agent = volttron_instance_module_web.build_agent() - - # Configure a IEEE 2030.5 device in the Platform Driver - test_agent.vip.rpc.call('config.store', 'manage_delete_store', 'platform.driver').get(timeout=10) - test_agent.vip.rpc.call('config.store', 'manage_store', 'platform.driver', - 'devices/{}'.format(DRIVER_NAME), - """{ - "driver_config": { - "sfdi": "097935300833", - "IEEE2030_5_agent_id": "test_IEEE2030_5agent" - }, - "campus": "campus", - "building": "building", - "unit": "IEEE2030_5", - "driver_type": "IEEE2030_5", - "registry_config": "config://IEEE2030_5.csv", - "interval": 15, - "timezone": "US/Pacific", - "heart_beat_point": "Heartbeat" - }""", - 'json').get(timeout=10) - test_agent.vip.rpc.call('config.store', 'manage_store', 'platform.driver', - 'IEEE2030_5.csv', - REGISTRY_CONFIG_STRING, - 'csv').get(timeout=10) - - # Install and start a PlatformDriverAgent - md_id = volttron_instance_module_web.install_agent(agent_dir=get_services_core("PlatformDriverAgent"), - config_file={}, - start=True) - print('platform driver agent id: ', md_id) - - # Install and start a IEEE2030_5Agent - IEEE2030_5_id = volttron_instance_module_web.install_agent(agent_dir=get_services_core("IEEE2030_5Agent"), - config_file=TEST_CONFIG, - vip_identity='test_IEEE2030_5agent', - start=True) - print('IEEE 2030.5 agent id: ', IEEE2030_5_id) - - global web_address - web_address = volttron_instance_module_web.bind_web_address - - def stop(): - volttron_instance_module_web.stop_agent(md_id) - volttron_instance_module_web.stop_agent(IEEE2030_5_id) - test_agent.core.stop() - - gevent.sleep(10) # wait for agents and devices to start - - request.addfinalizer(stop) - - return test_agent - - -class TestIEEE2030_5Driver: - """Regression tests for the IEEE 2030.5 driver.""" - - def test_all_points(self, agent): - self.put_IEEE2030_5_data('edev/0/di', 'edev.di') # device_information - self.put_IEEE2030_5_data('edev/0/der/1/derg', 'der.derg') # der_settings - self.put_IEEE2030_5_data('edev/0/der/1/ders', 'der.ders') # der_status - self.put_IEEE2030_5_data('edev/0/der/1/dera', 'der.dera') # der_availability - self.put_IEEE2030_5_data('edev/0/der/1/dercap', 'der.dercap') # der_capabililty - self.put_IEEE2030_5_data('edev/0/ps', 'edev.ps') # power_status - self.put_IEEE2030_5_data('mup', 'mup.mup') # mup - self.put_IEEE2030_5_data('mup/0', 'mup.mup2') # mup (update) - self.put_IEEE2030_5_data('mup/0', 'mup.mmr') # mmr - - # Wait a few seconds to allow the HTTP requests to be processed (asynchronously?) - time.sleep(5) - - # Set the one settable point, the dispatched power value, and test that it comes back on a get_point - dispatch_point_name = 'b124_WChaMax' - dispatched_value = ASSERTED_VALUES[dispatch_point_name] - self.set_point(agent, dispatch_point_name, dispatched_value) - assert self.get_point(agent, dispatch_point_name) == dispatched_value - - # Test that each point has the test value that was posted to it - for point_name, expected_value in ASSERTED_VALUES.items(): - assert self.get_point(agent, point_name) == expected_value - - @staticmethod - def get_point(test_agent, point_name): - return test_agent.vip.rpc.call('platform.driver', 'get_point', DRIVER_NAME, point_name).get(timeout=10) - - @staticmethod - def set_point(test_agent, point_name, value): - return test_agent.vip.rpc.call('platform.driver', 'set_point', DRIVER_NAME, point_name, value).get(timeout=10) - - @staticmethod - def put_IEEE2030_5_data(IEEE2030_5_resource_name, IEEE2030_5_filename): - """ - PUT data for a IEEE 2030.5 resource, using the contents of an XML file in the current directory. - - @param IEEE2030_5_resource_name: The distinguishing part of the name of the IEEE 2030.5 resource as it appears - in the URL. - @param IEEE2030_5_filename: The distinguishing part of the IEEE 2030.5 sample data file name. - """ - url = '{}/dcap/{}'.format(web_address, IEEE2030_5_resource_name) - headers = {'content-type': 'application/sep+xml'} - requests.post(url, - data=open(get_services_core("IEEE2030_5Agent/tests/{}.PUT.xml".format(IEEE2030_5_filename)), 'rb'), - headers=headers) diff --git a/services/core/IEEE_2030_5/AGENTDEMO.md b/services/core/IEEE_2030_5/AGENTDEMO.md new file mode 100644 index 0000000000..2929eadcca --- /dev/null +++ b/services/core/IEEE_2030_5/AGENTDEMO.md @@ -0,0 +1,226 @@ + +# Demo for 2030.5 Agent # + +This document provides a walkthrough of a demonstration where an inverter publishes data points +to the VOLTTRON message bus. The 2030.5 agent receives these data points, creates MirrorUsagePoints, +and POSTs MirrorMeterReadings to the 2030.5 server. Additionally, the demo allows users to create a +DERControl event. When this event is activated, the agent logs messages to the 2030.5 server. + +To run the demo, you will need to have three terminal windows open. The first terminal runs the main +VOLTTRON process. The second terminal runs the 2030.5 server. The third terminal runs the agent demo +via a web interface. For the purposes of this document, we assume that you have cloned the volttron +repository to a location referred to as VOLTTRON_ROOT. + +The setup process involves configuring the 2030.5 server, setting up the VOLTTRON instance, and +finally launching the web-based demo. + +## Setting up the 2030.5 Server ## + +We will be using a 2030.5 server developed by a team at PNNL. The GridAPPS-D team has created this +server, which is available at . The version used while +creating this demo is version 0.0.2a14. The source code is currently in a private repository, but +it will be made public in the future. + +1. Open a new terminal and create a new virtual environment to install the gridappsd server. Please + note that this directory should be separate from the main volttron directory. + + ```bash + > mkdir 2030_5_server + > cd 2030_5_server + + # creates an environment 'serverenv' in the current directory + > python3 -m venv serverenv + + > source serverenv/bin/activate + + (serverenv)> pip install gridappsd-2030-5 + ``` + +1. Now, you need to adjust the `openssl.cnf` file to match your specific requirements. You can also + use the default settings. This file is used to create self-signed certificates for the client to + use. + + Copy the openssl.cnf and server.yml files from the $VOLTTRON_ROOT/services/core/IEEE_2030_5/demo + directory to the newly created 2030_5_server directory. After copying the current directory should + look like the following. + + ```bash + (serverenv)> ls -l + serverenv/ + openssl.cnf + server.yml + ``` + +1. Next, modify the `server.yml` file. The default `server.yml` file includes a device (id: dev1) and + a DERProgram. It's important to note that `dev1` must be present for the demo to run smoothly. + +1. Finally, start the server from the activated `serverenv`. This step will generate development + certificates for you. By default, the certificates will be stored in `~/tls`. You can change this + location in the `server.yml` configuration file, however the agent configuration file will also need + to be changed. + + ```bash + (serverenv)> 2030_5_server server.yml --no-validate + + # without creating certificates + # (serverenv)> 2030_5_server server.yml --no-validate --no-create-certs + ``` + +## Demo Requirements ## + +This demo requires you to start a default VOLTTRON instance from the command line. This command will +run VOLTTRON in the background and write to a `volttron.log` file. + +1. First, navigate to the VOLTTRON_ROOT directory and activate the virtual environment. + + ```bash + > cd $VOLTTRON_ROOT + > source env/bin/activate + ``` + +1. Next, start the VOLTTRON instance. + + ```bash + (volttron)> ./start-volttron + ``` + +1. If you want to monitor the VOLTTRON log, you can use the following command: + + ```bash + (volttron)> tail -f volttron.log + ``` + + >**Warning** + >If monitoring the log then open a new command prompt before continuing and follow step 1 + >before continuing. + +1. Install a platform.driver agent + + ```bash + (volttron)> vctl install services/core/PlatformDriverAgent --start + ``` + +1. Verify the platform.driver agent is running + + ```bash + (volttron)> vctl status + UUID AGENT IDENTITY TAG STATUS HEALTH + da2c1f0d-6c platform_driveragent-4.0 platform.driver running [476936] + ``` + +1. Add config store files to the platform.driver. + + ```bash + (volttron)> vctl config store 'platform.driver' 'devices/inverter1' 'services/core/IEEE_2030_5/demo/devices.inverter1.config' + (volttron)> vctl config store 'platform.driver' 'inverter1.points.csv' 'services/core/IEEE_2030_5/demo/inverter1.points.csv' --csv + ``` + +1. Add config store entries for the 2030.5 agent. We will use the identity `ed1`` for the agent. + + ```bash + (volttron)> vctl config store 'ed1' inverter_sample.csv services/core/IEEE_2030_5/inverter_sample.csv --csv + ``` + +1. Install and start the 2030.5 agent. + + ```bash + (volttron)> vctl install services/core/IEEE_2030_5/ --vip-identity ed1 --start --agent-config services/core/IEEE_2030_5/example.config.yml + ``` + +1. Finally start the web based demo. This should open a webpage allowing one + to test the functionality of the 2030.5 agent. By default it will open at . + If this does not work you can browse to and that should work as well. + + ```bash + (volttron)> cd services/core/IEEE_2030_5 + (volttron)> pip install -r requirements_demo.txt + (volttron)> python demo/webgui.py + ... + ``` + +## The Demo ## + +Once you start the demo, you'll see the local time displayed at the top, followed by the 2030.5 GMT +time represented as an integer. This integer representation is how the 2030.5 protocol communicates +datetime values. + +The demo interface includes six tabs: + +### Configuration Tab ### + +The "Configuration Tab" in the demo interface shows the configuration settings for the demo. The values are +set based on your VOLTTRON environment and 2030.5 server configuration + +![Configuration Tab](./demo/images/configuration.png) + +### DER Default Control Tab ### + +The "DER Default Control Tab" in the demo interface allows you to set default operational parameters +for Distributed Energy Resources (DERs). + +In this tab, you can specify the default mode for the inverter to operate in. Once you set the +parameters and click on the "Save" button, these default control settings are sent to the server. +The 2030.5 agent then polls the server and retrieves these default values to control the operation +of the DERs. + +![DER Default Control](./demo/images/default_control.png) + +### New DER Control Tab ### + +The "New DER Control Tab" in the demo interface is used to create new DER Control events. + +In this tab, you can specify the parameters for a new control event, such as the start and end times, +operational mode, and other settings. Once you've set these parameters, you can submit the new +control event. This event is then sent to the server and scheduled for execution. + +![New DER Control](./demo/images/control_entry.png) + +This tab is crucial for scheduling specific control events that override the default operational +parameters set in the "DER Default Control Tab". These events allow for more dynamic and responsive +control of the DERs based on changing conditions or requirements. Using the refresh icon +next to the "DER Control Entry" heading sets the schedule time of the event as current time + 30 seconds. + +### DER Control List Tab ### + +The "DER Control List Tab" in the demo interface provides a comprehensive list of all the DER Control +events that have been scheduled. + +This tab displays the status of each event, whether it's scheduled, active, or completed. It provides +an overview of all the control events, allowing you to monitor their progress and see when they are completed. + +Here's how the interface looks in different states: + +- No Events: ![DER Control List - No Events](./demo/images/control_list_no_events.png) +- Scheduled: ![DER Control List - Scheduled](./demo/images/control_list_scheduled.png) +- Active: ![DER Control List - Active](./demo/images/control_list_active.png) +- Complete: ![DER Control List - Complete](./demo/images/control_list_complete.png) + +This tab is crucial for managing and monitoring the control events that are used to dynamically control +the operation of the DERs. + +### DER Status Tab ### + +The "DER Status Tab" in the demo interface is used to monitor the current status of the DER. + +This tab provides real-time information about the operation of the DER, including their current mode +of operation, power output, and other operational parameters. + +### Usage Point Tab ### + +The "Usage Point Tab" in the demo interface is used to display the usage points. + +Usage points represent a collection of meter readings and are used to monitor the energy consumption +or production at a specific point. This could be a point of consumption like a building or a point of +production like a solar panel array. + +By monitoring the Usage Point Tab, you can get a live view of how much energy is being consumed or +produced at each usage point. This can be useful for energy management, performance monitoring, and +ensuring that the energy production or consumption is as expected. + +![Usage Point](./demo/images/usage_points.png) + + diff --git a/services/core/IEEE_2030_5/README.md b/services/core/IEEE_2030_5/README.md new file mode 100644 index 0000000000..5ef3ee62d0 --- /dev/null +++ b/services/core/IEEE_2030_5/README.md @@ -0,0 +1,279 @@ +# VOLTTRON 2030.5 Agent # + +The VOLTTRON 2030.5 agent facilitates communication between the PlatformDriverAgent and a 2030.5 +server, using the IEEE 2030.5(2018) protocol. The agent's primary role is to manage data exchange +between the PlatformDriverAgent and the 2030.5 server. It creates MirrorUsagePoints and readings on +the 2030.5 server and dispatches control actions to the message bus during DERControl events. + +The following diagram illustrates the data flow for the 2030.5 agent, from the PlatformDriverAgent to the 2030.5 server: + +```mermaid + sequenceDiagram + Agent->>Server: Creates MirrorUsagePoints + Server-->>Client: 201 OK + Agent->>PlatformDriverAgent: Subscribes to Device Data + PlatformDriverAgent->>Agent: Agent Receives Device Data + Agent->>Server: Posts MeterReadings(Device Data) + Agent->>PlatformDriverAgent: Publishes Event Controls +``` + +To see this process in action, please try out the [Agent Demo](AGENTDEMO.md). + +## Agent Configuration Files ## + +The IEEE 2030.5 Agent operates based on the output from the PlatformDriverAgent. This design allows the agent to remain +protocol-agnostic regarding the DER's actual communication protocol. For testing purposes, we provide sample registry +and device point files. These files generate changing numbers for some points and maintain steady set points, similar +to a typical piece of equipment. The agent requires a mapping from the platform driver point to a 2030.5 point to +identify which points are relevant to the 2030.5 protocol. + +### Example Platform Driver Files ### + +A platform driver manages communication with hardware, publishing and setting points using the hardware's specific +protocol (e.g., BACnet, Modbus, DNP3, etc.). The following example uses a fake driver to generate sine and cosine +function values, as well as some steady-state points for setting/getting from the 2030.5 agent. + +[demo/devices.inverter1.config](demo/devices.inverter1.config) + +```python +{ + "driver_config": {}, + # note requires inverter1.points.csv to be in the platform.driver configuration store. + "registry_config":"config://inverter1.points.csv", + "interval": 5, + "timezone": "US/Pacific", + "heart_beat_point": "Heartbeat", + "driver_type": "fakedriver", + "publish_breadth_first_all": false, + "publish_depth_first": false, + "publish_breadth_first": false, + "campus": "devices", + "building": "inverter1" +} +``` + +```shell +vctl config store platform.driver ed1 demo/devices/devices.inverter1.config +``` + +[demo/inverter1.points.csv](demo/inverter1.points.csv) + +**Point Name**|**Volttron Point Name**|**Units**|**Units Details**|**Writable**|**Starting Value**|**Type**|**Notes** +:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----: +Heartbeat|Heartbeat|On/Off|On/Off|TRUE|0|boolean|Point for heartbeat toggle +EKG1|BAT\_SOC|waveform|waveform|TRUE|sin|float|Sine wave for baseline output +EKG2|INV\_REAL\_PWR|waveform|waveform|TRUE|cos|float|Sine wave +EKG3|INV\_REACT\_PWR|waveform|waveform|TRUE|tan|float|Cosine wave +SampleBool3|energized|On / Off|on/off|FALSE|TRUE|boolean|Status indidcator of cooling stage 1 +SampleWritableBool3|connected|On / Off|on/off|TRUE|TRUE|boolean|Status indicator +SampleLong3|INV\_OP\_STATUS\_MODE|Enumeration|1-4|FALSE|3|int|Mode of Inverter +ctrl\_freq\_max|ctrl\_freq\_max| | |TRUE| |int| +ctrl\_volt\_max|ctrl\_volt\_max| | |TRUE| |int| +ctrl\_freq\_min|ctrl\_freq\_min| | |TRUE| |int| +ctrl\_volt\_min|ctrl\_volt\_min| | |TRUE| |int| +ctrl\_ramp\_tms|ctrl\_ramp\_tms| | |TRUE| |int| +ctrl\_rand\_delay|ctrl\_rand\_delay| | |TRUE| |int| +ctrl\_grad\_w|ctrl\_grad\_w| | |TRUE| |int| +ctrl\_soft\_grad\_w|ctrl\_soft\_grad\_w| | |TRUE| |int| +ctrl\_connected|ctrl\_connected| | |TRUE| |boolean| +ctrl\_energized|ctrl\_energized| | |TRUE| |boolean| +ctrl\_fixed\_pf\_absorb\_w|ctrl\_fixed\_pf\_absorb\_w| | |TRUE| |int| +ctrl\_fixed\_pf\_ingect\_w|ctrl\_fixed\_pf\_ingect\_w| | |TRUE| |int| +ctrl\_fixed\_var|ctrl\_fixed\_var| | |TRUE| |int| +ctrl\_fixed\_w|ctrl\_fixed\_w| | |TRUE| |int| +ctrl\_es\_delay|ctrl\_es\_delay| | |TRUE| |int| + +```shell +vctl config store platform.driver inverter1.points.csv demo/devices/inverter1.points.csv --csv +``` + +### Agent Configuration ### + +An example configuration file is at the root of the agent directory (example.config.yml) + +```yaml +# These are required in order for the agent to connect to the server. +cacertfile: ~/tls/certs/ca.crt +keyfile: ~/tls/private/dev1.pem +certfile: ~/tls/certs/dev1.crt +server_hostname: 127.0.0.1 + +# the pin number is used to verify the server is the correct server +pin: 111115 + +# Log the request and responses from the server. +log_req_resp: true + +# SSL defaults to 443 +server_ssl_port: 8443 + +# Number of seconds to poll for new default der settings. +default_der_control_poll: 10 + +MirrorUsagePointList: + # MirrorMeterReading based on Table E.2 IEEE Std 2030.5-18 + - device_point: INV_REAL_PWR + mRID: 5509D69F8B3535950000000000009182 + description: DER Inverter Real Power + roleFlags: 49 + serviceCategoryKind: 0 + status: 0 + MirrorMeterReading: + mRID: 5509D69F8B3535950000000000009183 + description: Real Power(W) Set + ReadingType: + accumulationBehavior: 12 + commodity: 1 + dataQualifier: 2 + intervalLength: 300 + powerOfTenMultiplier: 0 + uom: 38 + - device_point: INV_REAC_PWR + mRID: 5509D69F8B3535950000000000009184 + description: DER Inverter Reactive Power + roleFlags: 49 + serviceCategoryKind: 0 + status: 0 + MirrorMeterReading: + mRID: 5509D69F8B3535950000000000009185 + description: Reactive Power(VAr) Set + ReadingType: + accumulationBehavior: 12 + commodity: 1 + dataQualifier: 2 + intervalLength: 300 + powerOfTenMultiplier: 0 + uom: 38 + +# publishes on the following subscriptions will +# be available to create and POST readings to the +# 2030.5 server. +device_topic: devices/inverter1 + +# Nameplate ratings for this der client will be put to the +# server during startup of the system. +DERCapability: + # modesSupported is a HexBinary31 representation of DERControlType + # See Figure B.34 DER info types for information + # conversion in python is as follows + # "{0:08b}".format(int("500040", 16)) + # '10100000000000001000000' # This is a bitmask + # to generate HexBinary + # hex(int('10100000000000001000000', 2)) + # 0x500040 + modesSupported: 500040 + rtgMaxW: + multiplier: 0 + value: 0 + type: 0 + +DERSettings: + modesEnabled: 100000 + setGradW: 0 + setMaxW: + multiplier: 0 + value: 0 + +# Note this file MUST be in the config store or this agent will not run properly. +point_map: config:///inverter_sample.csv +``` + +See the [inverter_sample.csv](inverter_sample.csv) file. + +In the inverter_sample.csv file we have columns such as the following excerpt. The Point Name +corresponds to an all message published to the device_topic. Only the points with both the +Parameter Type and the Point Name are used when publshing/setting points to the platform.driver. + +| Point Name | Description | Multiplier | MRID | Offset | Parameter Type | Notes | +|------------------------|-------------------|------------|------|--------|---------------------------------------------|---------------------------------------------------| +| ctrl_connected | | | | | DERControlBase::opModConnect | True/False Connected = True, Disconnected = False | +| ctrl_energized | | | | | DERControlBase::opModEnergize | True/False Energized = True, De-Energized = False | +| ctrl_fixed_pf_absorb_w | | | | | DERControlBase::opModFixedPFAbsorbW | | +|------------------------|-------------------|------------|------|--------|---------------------------------------------|---------------------------------------------------| + +## Agent Installation ## + +The 2030.5 agent can be installed and started using an activated terminal from the root of the volttron +git repository. Here are the steps: + +1. Open a terminal and navigate to the root of the volttron git repository. + + ```bash + cd /path/to/volttron + ``` + +1. Activate the virtual environment for volttron. + + ```bash + source env/bin/activate + ``` + +1. Update the config store for the 2030.5 agent. Note we use the identity inverter1 + + ```bash + vctl config store 'inverter1' 'inverter_sample.csv' 'services/core/IEEE_2030_5/inverter_sample.csv' --csv + ``` + +1. Install and start the 2030.5 agent using the `vctl` command. The `--start` option starts the agent + immediately after installation. The `--agent-config` option specifies the configuration file for + the agent. The `--vip-identity` option sets the identity of the agent on the VOLTTRON message bus. + + ```bash + vctl install services/core/IEEE_2030_5 --start --agent-config services/core/IEEE_2030_5/example.config.yml --vip-identity inverter1 + ``` + +This completes the installation and startup of the 2030.5 agent. + +## 2030.5 Protocol ## + +The 2030.5 protocol uses a +REQUEST/RESPONSE pattern meaning that all communication with the 2030.5 server will start with a +REQUEST being sent from the client. + +### Communication ### + +The 2030.5 protocol starts with requests to the server for determining the DERProgram and DERControl +that the client should be using. Once the default and scheduled DERControls are known then the +client can act according to the 2030.5 server's requirements. + +The following diagram illistrates the request and response from the client to the server. + +```mermaid + sequenceDiagram + Client->>Server: /dcap + Server-->Client: DeviceCapabilities + Client->>Server: /edev + Server-->Client: EndDeviceList(1) /* found */ + Client->>Server: /edev/0 + Server-->Client: EndDevice + Client->>Server: /edev/0/fsa + Server-->Client: FunctionSetAssignmentList + Client->>Server: /edev/0/fsa/0 + Server-->Client: FunctionSetAssignment + Client->>Server: /edev/0/fsa/0/derp + Server-->Client: DERProgramList + Client->>Server: /derp/0 + Server-->Client: DERProgram + Client->>Server: /derp/0/derc + Server-->Client: DERControlList + Client->>Server: /derp/0/dderc + Server-->Client: DERDefaultControl + Client->>Server: /derp/0/derca + Server-->Client: DERControlList +``` + +After the DERControls are found the client needs to poll the server for updates. Depending on the +function set, the poll rate could be different. + +## Agent Limitations ## + +This agent is not a fully compliant 2030.5 client, meaning it does not support all of the function sets +within the 2030.5 standard. It provides the following function sets: + +- End Device +- Time +- Distributed Energy Resources +- Metering +- Metering Mirror + +As time goes on it is likely that this list will be extended through user support. diff --git a/services/core/IEEE_2030_5/conftest.py b/services/core/IEEE_2030_5/conftest.py new file mode 100644 index 0000000000..8559470457 --- /dev/null +++ b/services/core/IEEE_2030_5/conftest.py @@ -0,0 +1,6 @@ +import sys + +from volttrontesting.fixtures.volttron_platform_fixtures import * + +# Add system path of the agent's directory +sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) \ No newline at end of file diff --git a/services/core/IEEE_2030_5/demo/devices.inverter1.config b/services/core/IEEE_2030_5/demo/devices.inverter1.config new file mode 100644 index 0000000000..eed61b85c0 --- /dev/null +++ b/services/core/IEEE_2030_5/demo/devices.inverter1.config @@ -0,0 +1,13 @@ +{ + "driver_config": {}, + "registry_config":"config://inverter1.points.csv", + "interval": 5, + "timezone": "US/Pacific", + "heart_beat_point": "Heartbeat", + "driver_type": "fakedriver", + "publish_breadth_first_all": false, + "publish_depth_first": false, + "publish_breadth_first": false, + "campus": "devices", + "building": "inverter1" +} diff --git a/services/core/IEEE_2030_5/demo/images/configuration.png b/services/core/IEEE_2030_5/demo/images/configuration.png new file mode 100644 index 0000000000..ab893c7c6b Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/configuration.png differ diff --git a/services/core/IEEE_2030_5/demo/images/control_active.png b/services/core/IEEE_2030_5/demo/images/control_active.png new file mode 100644 index 0000000000..541d14cf09 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/control_active.png differ diff --git a/services/core/IEEE_2030_5/demo/images/control_complete.png b/services/core/IEEE_2030_5/demo/images/control_complete.png new file mode 100644 index 0000000000..c258a255c1 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/control_complete.png differ diff --git a/services/core/IEEE_2030_5/demo/images/control_entry.png b/services/core/IEEE_2030_5/demo/images/control_entry.png new file mode 100644 index 0000000000..51e2312232 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/control_entry.png differ diff --git a/services/core/IEEE_2030_5/demo/images/control_list_active.png b/services/core/IEEE_2030_5/demo/images/control_list_active.png new file mode 100644 index 0000000000..93ad658bfb Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/control_list_active.png differ diff --git a/services/core/IEEE_2030_5/demo/images/control_list_complete.png b/services/core/IEEE_2030_5/demo/images/control_list_complete.png new file mode 100644 index 0000000000..afaf1f9d9f Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/control_list_complete.png differ diff --git a/services/core/IEEE_2030_5/demo/images/control_list_no_events.png b/services/core/IEEE_2030_5/demo/images/control_list_no_events.png new file mode 100644 index 0000000000..2251299a60 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/control_list_no_events.png differ diff --git a/services/core/IEEE_2030_5/demo/images/control_list_scheduled.png b/services/core/IEEE_2030_5/demo/images/control_list_scheduled.png new file mode 100644 index 0000000000..8442727450 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/control_list_scheduled.png differ diff --git a/services/core/IEEE_2030_5/demo/images/control_scheduled.png b/services/core/IEEE_2030_5/demo/images/control_scheduled.png new file mode 100644 index 0000000000..c17603ccd6 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/control_scheduled.png differ diff --git a/services/core/IEEE_2030_5/demo/images/default_control.png b/services/core/IEEE_2030_5/demo/images/default_control.png new file mode 100644 index 0000000000..7f90dfeb95 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/default_control.png differ diff --git a/services/core/IEEE_2030_5/demo/images/initial_conditions.png b/services/core/IEEE_2030_5/demo/images/initial_conditions.png new file mode 100644 index 0000000000..8b9c40c2f5 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/initial_conditions.png differ diff --git a/services/core/IEEE_2030_5/demo/images/start_agent_and_inverter.png b/services/core/IEEE_2030_5/demo/images/start_agent_and_inverter.png new file mode 100644 index 0000000000..ccf38aa45c Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/start_agent_and_inverter.png differ diff --git a/services/core/IEEE_2030_5/demo/images/usage_points.png b/services/core/IEEE_2030_5/demo/images/usage_points.png new file mode 100755 index 0000000000..2834a12075 Binary files /dev/null and b/services/core/IEEE_2030_5/demo/images/usage_points.png differ diff --git a/services/core/IEEE_2030_5/demo/inverter1.points.csv b/services/core/IEEE_2030_5/demo/inverter1.points.csv new file mode 100644 index 0000000000..2e2cbbfcbb --- /dev/null +++ b/services/core/IEEE_2030_5/demo/inverter1.points.csv @@ -0,0 +1,23 @@ +Point Name,Volttron Point Name,Units,Units Details,Writable,Starting Value,Type,Notes +Heartbeat,Heartbeat,On/Off,On/Off,TRUE,0,boolean,Point for heartbeat toggle +EKG1,BAT_SOC,waveform,waveform,TRUE,sin,float,Sine wave for baseline output +EKG2,INV_REAL_PWR,waveform,waveform,TRUE,cos,float,Sine wave +EKG3,INV_REACT_PWR,waveform,waveform,TRUE,tan,float,Cosine wave +SampleBool3,energized,On / Off,on/off,FALSE,TRUE,boolean,Status indidcator of cooling stage 1 +SampleWritableBool3,connected,On / Off,on/off,TRUE,TRUE,boolean,Status indicator +SampleLong3,INV_OP_STATUS_MODE,Enumeration,1-4,FALSE,3,int,Mode of Inverter +ctrl_freq_max,ctrl_freq_max,,,TRUE,,int, +ctrl_volt_max,ctrl_volt_max,,,TRUE,,int, +ctrl_freq_min,ctrl_freq_min,,,TRUE,,int, +ctrl_volt_min,ctrl_volt_min,,,TRUE,,int, +ctrl_ramp_tms,ctrl_ramp_tms,,,TRUE,,int, +ctrl_rand_delay,ctrl_rand_delay,,,TRUE,,int, +ctrl_grad_w,ctrl_grad_w,,,TRUE,,int, +ctrl_soft_grad_w,ctrl_soft_grad_w,,,TRUE,,int, +ctrl_connected,ctrl_connected,,,TRUE,,boolean, +ctrl_energized,ctrl_energized,,,TRUE,,boolean, +ctrl_fixed_pf_absorb_w,ctrl_fixed_pf_absorb_w,,,TRUE,,int, +ctrl_fixed_pf_ingect_w,ctrl_fixed_pf_ingect_w,,,TRUE,,int, +ctrl_fixed_var,ctrl_fixed_var,,,TRUE,,int, +ctrl_fixed_w,ctrl_fixed_w,,,TRUE,,int, +ctrl_es_delay,ctrl_es_delay,,,TRUE,,int, diff --git a/services/core/IEEE_2030_5/demo/keypair.json b/services/core/IEEE_2030_5/demo/keypair.json new file mode 100644 index 0000000000..77d8dd1527 --- /dev/null +++ b/services/core/IEEE_2030_5/demo/keypair.json @@ -0,0 +1,4 @@ +{ + "public": "YrRnX1ifv5hkctAtNsLMut1j3qr7dPf0gppvwH_53wE", + "secret": "C55SSFUKAM38dXZKjMSolRvFVfILbSTF9JkUQWlP8II" +} diff --git a/services/core/IEEE_2030_5/demo/openssl.cnf b/services/core/IEEE_2030_5/demo/openssl.cnf new file mode 100644 index 0000000000..3febb63be0 --- /dev/null +++ b/services/core/IEEE_2030_5/demo/openssl.cnf @@ -0,0 +1,123 @@ +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +[ CA_default ] +dir = $ENV::HOME/tls # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +database = $dir/index.txt # database index file. + # several certs with same subject. +new_certs_dir = $dir/certs # default place for new certs. +certificate = $dir/certs/ec-cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +private_key = $dir/private/ec-cakey.pem # The private key + +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha256 # use SHA-256 by default +preserve = no # keep passed DN ordering +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = optional +stateOrProvinceName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_md = sha256 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = IN +countryName_min = 2 +countryName_max = 2 +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State +localityName = Locality Name (eg, city) +localityName_default = BANGALORE +0.organizationName = Organization Name (eg, company) +0.organizationName_default = GoLinuxCloud +organizationalUnitName = Organizational Unit Name (eg, section) +commonName = Common Name (eg, your name or your server\'s hostname) +commonName_max = 64 +emailAddress = Email Address +emailAddress_max = 64 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 +unstructuredName = An optional company name + + +[ v3_req ] +# Extensions to add to a certificate request +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] +# Extensions for a typical CA +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer +basicConstraints = critical,CA:true + +[ crl_ext ] +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always \ No newline at end of file diff --git a/services/core/IEEE_2030_5/demo/server.yml b/services/core/IEEE_2030_5/demo/server.yml new file mode 100644 index 0000000000..324e18bd79 --- /dev/null +++ b/services/core/IEEE_2030_5/demo/server.yml @@ -0,0 +1,102 @@ +--- +server: 127.0.0.1 +port: 8443 + + +tls_repository: "~/tls" +openssl_cnf: "openssl.cnf" + +server_mode: enddevices_create_on_start + +# lfdi_mode: Determines what piece of information is used to calculate the lfdi +# +# Options: +# lfdi_mode_from_file - sha256 hash of certificate file's content. +# lfdi_mode_from_cert_fingerprint - sha256 hash of the certificates fingerprint. +# +# default: lfdi_mode_from_cert_fingerprint +#lfdi_mode: lfdi_mode_from_file +lfdi_mode: lfdi_mode_from_cert_fingerprint + +# Create an administrator certificate that can be used from +# browser/api to connect to the platform. +# +# this is important for the demo +generate_admin_cert: True + +log_event_list_poll_rate: 60 +device_capability_poll_rate: 60 +mirror_usage_point_post_rate: 15 + +# Reset storage so no memory when server restarts. +cleanse_storage: true + +# Directory containing data files for the platform. +# This directory will be created if it does not exist. +storage_path: data_store + +# End Device +devices: + # SolarEdge SE6000H HD-Wave SetApp Enabled Inverter + - id: dev1 + # DeviceCategoryType from ieee_2030_5.models.DeviceCategoryType + device_categories: + - OTHER_STORAGE_SYSTEMS + - OTHER_GENERATION_SYSTEMS + pin: 111115 + fsas: + - fsa1 + - fsa2 + ders: + - description: DER 1 + + - id: dev2 + device_categories: + - OTHER_STORAGE_SYSTEMS + - OTHER_GENERATION_SYSTEMS + pin: 111111 + fsas: + - fsa2 + ders: + - description: DER 2 + + +fsas: + - description: fsa1 + programs: + - Program 1 + - description: fsa2 + programs: + - Program 1 + + + +programs: + - description: Program 1 + primacy: 0 + DefaultDERControl: + setESDelay: 30 + setGradW: 1000 + + DERControlBase: + opModConnect: true + opModEnergize: true + +curves: + - description: Curve 1 + curveType: 11 + CurveData: + - xvalue: 99 + yvalue: 50 + - xvalue: 103 + yvalue: -50 + - xvalue: 101 + yvalue: -50 + - xvalue: 97 + yvalue: 50 + rampDecTms: 600 + rampIncTms: 600 + rampPT1Tms: 10 + xMultiplier: 0 + yMultiplier: 0 + yRefType: 3 diff --git a/services/core/IEEE_2030_5/demo/webgui.py b/services/core/IEEE_2030_5/demo/webgui.py new file mode 100644 index 0000000000..cf9fdbf682 --- /dev/null +++ b/services/core/IEEE_2030_5/demo/webgui.py @@ -0,0 +1,962 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +from copy import deepcopy +from pprint import pformat +from parser import ParserError + +import sys +import time +import uuid +import urllib3 +from dataclasses import dataclass, field, fields +from datetime import datetime, timedelta +from pathlib import Path +from typing import Any, Callable, Dict, List, TypeVar +import logging +import xsdata +import pandas as pd + +from volttron.platform.agent.utils import parse_timestamp_string + +urllib3.disable_warnings() + +sys.path.insert(0, str(Path(__file__).absolute().parent.parent.as_posix())) + +import requests +from nicegui import app, ui + +import ieee_2030_5.models as m +from ieee_2030_5 import dataclass_to_xml, xml_to_dataclass + +logging.getLogger('urllib3.connectionpool').setLevel(logging.INFO) +_log = logging.getLogger(__name__) + + +def uuid_2030_5() -> str: + return str(uuid.uuid4()).replace('-', '').upper() + + +def timestamp_to_string(timestamp: int) -> str: + return datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S') + + +def datetime_from_utc_to_local(utc_datetime): + now_timestamp = time.time() + offset = datetime.fromtimestamp(now_timestamp) - datetime.utcfromtimestamp(now_timestamp) + return utc_datetime + offset + + +@dataclass +class Configuration: + agent_2030_5_identity: str = 'ed1' + volttron_home: str = Path('~/.volttron').expanduser().as_posix() + ieee_server: str = 'https://127.0.0.1:8443' + ieee_client_pk: str = Path('~/tls/private/dev1.pem').expanduser().as_posix() + ieee_client_cert: str = Path('~/tls/certs/dev1.crt').expanduser().as_posix() + ieee_ca: str = Path('~/tls/certs/ca.crt').expanduser().as_posix() + + +@dataclass +class WatchFileState: + path: str + exists: bool = False + interval: int = 1 + in_routing: bool = False + + def remove(self): + Path(self.path).unlink(missing_ok=True) + + def check_file(self) -> bool: + return Path(self.path).exists() + + +@dataclass +class PlottedData: + series_labels: List[str] = field(default_factory=list) + series_ts: List[datetime] = field(default_factory=list) + series_values: Dict[str, List[float]] = field(default_factory=dict) + + def df(self) -> pd.DataFrame: + data = {'ts': self.series_ts.copy()} + data.update(self.series_values) + + my_df = pd.DataFrame(data) + my_df.set_index(['ts']) + return my_df + + +# Configuration parameters from the config page +config = Configuration() +# Temp storage for changes on the config page +config_working = Configuration() + +# A session for talking with the 2030.5 server +session = requests.Session() +# A file to watch for updates to output from the agent connected to volttron +# the "watch_devices_to_file.py" output. +#watch_file = WatchFileState(sys.argv[1], interval=3) +program_list = [] + +admin_session = requests.Session() +client_session = requests.Session() + +S = TypeVar('S') +T = TypeVar('T') + + +class PropertyWrapper: + """The PropertyWrapper class handles binding on behalf of the parent object. + + The class handles the binding from/to and formatting/applying when sending the + object to the parent. + """ + + def __init__(self, + backing_obj: T, + parent_obj: S, + parent_property: str, + formatters: Dict[str, Callable] = None, + applyers: Dict[str, Callable] = None): + # The sub object that we need to provide for + self.backing_obj = backing_obj + # The parent object this property is wrapping + self.parent_obj = parent_obj + # The property this object is wrapping on the parent_obj + self.parent_property = parent_property + + if formatters is None: + formatters = {} + + if applyers is None: + applyers = {} + + self.formatters = formatters + self.appliers = applyers + # Transfer the values from the parent to the backing object + if self.parent_obj.__dict__[self.parent_property] is not None: + if isinstance(self.backing_obj, + (m.VoltageRMS, m.ApparentPower, m.CurrentRMS, m.ActivePower, m.FixedVar, + m.FixedPointType, m.ReactivePower, m.AmpereHour, m.WattHour)): + self.backing_obj.__dict__['value'] = self.parent_obj.__dict__[ + self.parent_property].value + + def __setattr__(self, key: str, value: Any): + if key in ('backing_obj', 'parent_obj', 'parent_property', 'formatters', 'appliers'): + self.__dict__[key] = value + else: + if key in self.formatters: + self.backing_obj.__dict__[key] = self.formatters[key](value) + else: + _log.debug(f'Setting on {type(self.backing_obj)} {key} -> {value}') + self.backing_obj.__dict__[key] = value + + def __getattr__(self, key: str) -> Any: + if key in ('data_obj', 'parent_obj', 'parent_property', 'formatters', 'appliers'): + return self.__dict__[key] + else: + return self.backing_obj.__dict__[key] + + def apply_to_parent(self): + other_obj = deepcopy(self.backing_obj) + + if self.appliers: + for k, v in self.appliers.items(): + other_obj.__dict__[k] = self.appliers[k](other_obj.__dict__[k]) + + if self.should_be_none(): + setattr(self.parent_obj, self.parent_property, None) + else: + _log.debug(f'Setting {self.parent_property} to {other_obj}') + setattr(self.parent_obj, self.parent_property, other_obj) + _log.debug(f'Parent obj is {self.parent_obj}') + + def should_be_none(self) -> bool: + """Answers the question whether the parent property should be None. + + Loop over the backing object and if any of the fields are not None then + the answer is False. Otherwise the answer is True. + + :return: True if all fields are None, False otherwise. + """ + for fld in fields(self.backing_obj): + if getattr(self.backing_obj, fld.name): + return False + return True + + +def update_sessions(): + """Update the admin and client sessions with the current configuration.""" + tlsdir = Path(config.ieee_client_cert).parent.parent + admin_session.cert = (str(tlsdir.joinpath('certs/admin.crt')), + str(tlsdir.joinpath('private/admin.pem'))) + client_session.cert = (config.ieee_client_cert, config.ieee_client_pk) + admin_session.verify = config.ieee_ca + client_session.verify = config.ieee_ca + + +def get_from_server(context: str, + admin_request=False, + deserialize=False, + start=None, + after=None, + limit=None): + if admin_request: + session = admin_session + else: + session = client_session + + params = {} + if start is not None: + params['s'] = int(start) + if after is not None: + params['a'] = int(after) + if limit is not None: + params['l'] = int(limit) + + if admin_request: + response = session.get(config.ieee_server + f'/admin/{context}', params=params) + else: + response = session.get(config.ieee_server + f'/{context}', params=params) + + if deserialize: + return xml_to_dataclass(response.text) + return response.text + + +def admin_uri(path: str): + path = path.replace('_', '/') + if path.startswith('/'): + path = path[1:] + return f'{config.ieee_server}/admin/{path}' + + +def __uri__(path: str): + if path.startswith('/'): + path = path[1:] + return f'{config.ieee_server}/{path}' + + +def post_as_admin(path, data): + print(f'POST: {admin_uri(path)}') + assert admin_session.cert + return admin_session.post(admin_uri(path), data=data) + + +def put_as_admin(path, data): + print(f'PUT: {admin_uri(path)}') + assert admin_session.cert + return admin_session.put(admin_uri(path), data=data) + + +def post_as_device(path, data): + print(f'POST: {__uri__(path)}') + return client_session.post(__uri__(path), data=data) + + +def save_config(): + paths_needed = ('volttron_home', 'ieee_client_pk', 'ieee_client_cert', 'ieee_ca') + path_text = ('VOLTTRON home', 'Client PK', 'Client Cert', 'CA') + paths_unavailable = [] + + for index, p in enumerate(paths_needed): + if not Path(getattr(config_working, p)).exists(): + paths_unavailable.append(path_text[index]) + + if paths_unavailable: + ui.notify(f"Missing: {';'.join(paths_unavailable)}", type='warning', position='center') + else: + for fld in fields(config): + setattr(config, fld.name, getattr(config_working, fld.name)) + + update_sessions() + + ui.notify('Configuration Updated') + + +def reset_config(): + for fld in fields(config): + setattr(config_working, fld.name, getattr(config, fld.name)) + + +cards = [] + + +def convert_local_dt_to_utc_timestamp(dt: datetime) -> int: + """Converts a local datetime to a UTC timestamp. + + :param dt: A datetime object in local time. + :type dt: datetime + :return: A UTC timestamp for passing to 2030.5 server. + :rtype: int + """ + # Leaving these commented out as a guide to how we got the answer to the issue. + # _log.debug(f"Start with dt: {dt} at {int(dt.timestamp())}") + # _log.debug(f"get date from ts: {datetime.fromtimestamp(int(dt.timestamp()))}") + gmt_date = datetime.utcfromtimestamp(int(dt.timestamp())) + # _log.debug(f"gmtdate {gmt_date} at {int(gmt_date.timestamp())}") + # _log.debug(f"get gmtdate back: {datetime.fromtimestamp(int(gmt_date.timestamp()))}") + + # _log.debug(f"Converting {dt} to epoch time gmtime") + return int(gmt_date.timestamp()) + + +update_sessions() +dcap: m.DeviceCapability = get_from_server('dcap', deserialize=True) +edl: m.EndDeviceList = get_from_server(dcap.EndDeviceListLink.href, deserialize=True) +edev = edl.EndDevice[0] +ders: m.DERList = get_from_server(edev.DERListLink.href, deserialize=True) +der = ders.DER[0] +program: m.DERProgram = get_from_server(der.CurrentDERProgramLink.href, deserialize=True) + + +def noneable_int_change(obj: object, prop: str, value): + try: + num = int(value.sender.value) + setattr(obj, prop, num) + except (ValueError, TypeError): + if value.sender.value == '': + setattr(obj, prop, None) + + +@ui.refreshable +def render_der_default_control_tab(): + + def refresh_default_control_tab(): + render_der_default_control_tab.refresh() + ui.notify('Refreshed') + + default: m.DefaultDERControl = get_from_server(program.DefaultDERControlLink.href, + deserialize=True) + der_base: m.DERControlBase = default.DERControlBase + if der_base is None: + der_base = m.DERControlBase() + default.DERControlBase = der_base + + wrappers: List[PropertyWrapper] = [] + + with ui.row(): + with ui.column(): + with ui.label('DER Default Control').style('font-size: 200%;'): + ui.button(icon='refresh', + color='white', + on_click=lambda: refresh_default_control_tab()).style( + 'margin:5px; padding: 5px;') + ui.label( + 'Section 10.10 Distributed Energy Resources function set from 20305-2018 IEEE standard.' + ) + + with ui.row().classes('pt-10'): + with ui.column().classes('pr-15'): + ui.input('setESDelay (hundredth of a second)', + on_change=lambda e: noneable_int_change(default, 'setESDelay', e)) \ + .bind_value_from(default, 'setESDelay').classes('w-96') + #.bind_value_from(default, "setESDelay").classes("w-96") + ui.input('setESHighFreq (hundredth of a hertz)', + on_change=lambda e: noneable_int_change(default, 'setESHighFreq', e)) \ + .bind_value_from(default, 'setESHighFreq').classes('w-96') + ui.input('setESHighVolt (hundredth of a volt)', + on_change=lambda e: noneable_int_change(default, 'setESHighVolt', e)) \ + .bind_value_from(default, 'setESHighVolt').classes('w-96') + + with ui.column().classes('pr-15'): + ui.input('setESLowFreq (hundredth of a hertz)', + on_change=lambda e: noneable_int_change(default, 'setESLowFreq', e)) \ + .bind_value_from(default, 'setESLowFreq').classes('w-96') + ui.input('setESLowVolt (hundredth of a volt)', + on_change=lambda e: noneable_int_change(default, 'setESLowVolt', e)) \ + .bind_value_from(default, 'setESLowVolt').classes('w-96') + ui.input('setESRampTms (hundredth of a second)', + on_change=lambda e: noneable_int_change(default, 'setESRampTms', e)) \ + .bind_value_from(default, 'setESRampTms').classes('w-96') + with ui.column(): + + ui.input('setESRandomDelay (hundredth of a second)', + on_change=lambda e: noneable_int_change(default, 'setESRandomDelay', e)) \ + .bind_value_from(default, 'setESRandomDelay').classes('w-96') + ui.input('setGradW (hundredth of a watt)', + on_change=lambda e: noneable_int_change(default, 'setGradW', e)) \ + .bind_value_from(default, 'setGradW').classes('w-96') + ui.input('setSoftGradW (hundredth of a watt)', + on_change=lambda e: noneable_int_change(default, 'setSoftGradW', e)) \ + .bind_value_from(default, 'setSoftGradW').classes('w-96') + + with ui.row().style('margin-top:15px;margin-bottom:15px;'): + ui.label('DER Control Base').style('font-size: 150%;') + + with ui.row(): + with ui.column().classes('pr-20'): + ui.checkbox('opModConnect', value=True).bind_value(der_base, 'opModConnect') + ui.checkbox('opModEnergize', value=True).bind_value(der_base, 'opModEnergize') + + with ui.column().classes('pr-20'): + ui.label('Power Factor Absorb Watts').style('font-size: 125%;') + if der_base.opModFixedPFAbsorbW is None: + der_base.opModFixedPFAbsorbW = m.PowerFactorWithExcitation() + opModFixedPFAbsorbW_wrapper = PropertyWrapper(der_base.opModFixedPFAbsorbW, der_base, + 'opModFixedPFAbsorbW') + wrappers.append(opModFixedPFAbsorbW_wrapper) + ui.input('displacement', on_change=lambda e: noneable_int_change(opModFixedPFAbsorbW_wrapper, 'displacement', e)) \ + .bind_value_from(opModFixedPFAbsorbW_wrapper, 'displacement') + ui.checkbox('excitation', value=False).bind_value(opModFixedPFAbsorbW_wrapper, + 'excitation') + + ui.label('Power Factor Inject Watts').style('font-size: 125%;') + if der_base.opModFixedPFInjectW is None: + der_base.opModFixedPFInjectW = m.PowerFactorWithExcitation() + opModFixedPFInjectW_wrapper = PropertyWrapper(der_base.opModFixedPFInjectW, der_base, + 'opModFixedPFInjectW') + wrappers.append(opModFixedPFInjectW_wrapper) + ui.input('displacement', on_change=lambda e: noneable_int_change(opModFixedPFInjectW_wrapper, 'displacement', e)) \ + .bind_value_from(opModFixedPFInjectW_wrapper, 'displacement') + ui.checkbox('excitation', value=False).bind_value(opModFixedPFInjectW_wrapper, + 'excitation') + + with ui.column().classes('pr-20'): + fixedVar_wrapper = PropertyWrapper(m.FixedVar(), der_base, 'opModFixedVar') + wrappers.append(fixedVar_wrapper) + ui.input('opModFixedVar', on_change=lambda e: noneable_int_change(fixedVar_wrapper, 'value', e)) \ + .bind_value_from(fixedVar_wrapper, 'value') + + # fixedWatt_wrapper = PropertyWrapper(m.WattHour(), der_base, "opModFixedW") + # wrappers.append(fixedWatt_wrapper) + # ui.input("opModFixedW", on_change=lambda e: noneable_int_change(fixedWatt_wrapper, "value", e)) \ + # .bind_value_from(fixedWatt_wrapper, "value") + ui.input('opModFixedW', on_change=lambda e: noneable_int_change(der_base, 'opModFixedW', e)) \ + .bind_value_from(der_base, 'opModFixedW') + + # freqDroop_wrapper = Wrapper(m.FreqDroopType(), der_base, "openLoopTms") + # wrappers.append(freqDroop_wrapper) + # opModFreqDroop = ui.input("opModFreqDroop", + # on_change=lambda e: noneable_int_change(freqDroop_wrapper, "openLoopTms", e)) \ + # .bind_value_from(freqDroop_wrapper, "openLoopTms") + + ui.input('opModMaxLimW', on_change=lambda e: noneable_int_change(der_base, 'opModMaxLimW', e)) \ + .bind_value_from(der_base, 'opModMaxLimW') + + with ui.column().classes('pr-10'): + opModTargetVar_wrapper = PropertyWrapper(m.ReactivePower(), der_base, 'opModTargetVar') + wrappers.append(opModTargetVar_wrapper) + ui.input('opModTargetVar', on_change=lambda e: noneable_int_change(opModTargetVar_wrapper, 'value', e)) \ + .bind_value_from(opModTargetVar_wrapper, 'value') + + opModTargetW_wrapper = PropertyWrapper(m.ActivePower(), der_base, 'opModTargetW') + wrappers.append(opModTargetW_wrapper) + ui.input('opModTargetW', on_change=lambda e: noneable_int_change(opModTargetW_wrapper, 'value', e)) \ + .bind_value_from(opModTargetW_wrapper, 'value') + + # opModVoltVar = ui.input("opModVoltVar", + # on_change=lambda e: noneable_int_change(der_base, "opModVoltVar", e)) \ + # .bind_value_from(der_base, "opModVoltVar") + # opModWattPF = ui.input("opModWattPF", + # on_change=lambda e: noneable_int_change(der_base, "opModWattPF", e)) \ + # .bind_value_from(der_base, "opModWattPF") + ui.input('rampTms', on_change=lambda e: noneable_int_change(der_base, 'rampTms', e)) \ + .bind_value_from(der_base, 'rampTms') + # render_default_control(der_base) + + def store_default_der_control(): + try: + _log.debug(f'Before Apply {der_base}') + _log.debug(default) + for wrapper in wrappers: + _log.debug(f'Wrapper parent object {id(wrapper.parent_obj)} {wrapper.parent_obj}') + wrapper.apply_to_parent() + _log.debug( + f'Wrapper parent object after apply {id(wrapper.parent_obj)} {wrapper.parent_obj}' + ) + + _log.debug(f'After Apply {der_base}') + base_payload = dataclass_to_xml(der_base) + _log.warning(base_payload) + payload = dataclass_to_xml(default) + put_as_admin(program.DefaultDERControlLink.href, payload) + ui.notify('Default DER Control Updated') + render_der_default_control_tab.refresh() + except xsdata.exceptions.ParserError as ex: + ui.notify(ex.message, type='negative') + + with ui.row().classes('pt-10'): + with ui.column(): + ui.button('Save', on_click=lambda: store_default_der_control()) + + +@ui.refreshable +def render_der_status_tab(): + + def do_refresh(): + render_der_status_tab.refresh() + ui.notify('Refreshed') + + settings: m.DERSettings = get_from_server(der.DERSettingsLink.href, deserialize=True) + status: m.DERStatus = get_from_server(der.DERStatusLink.href, deserialize=True) + capabilities: m.DERCapability = get_from_server(der.DERCapabilityLink.href, deserialize=True) + with ui.row(): + with ui.label('DER Status').style('font-size: 200%;'): + ui.button(icon='refresh', color='white', + on_click=lambda: do_refresh()).style('margin:5px; padding: 5px;') + # ui.icon("refresh", size="sm").style("cursor: pointer; vertical-align: center; padding-left: 5px;") \ + # .on_click(lambda: render_der_status_tab.refresh()) + with ui.row(): + with ui.column(): + ui.label('Section 10.10.4.4 DER info resources from 20305-2018 IEEE standard.') + + columns = [{ + 'name': 'key', + 'label': 'Key', + 'field': 'key', + 'required': True + }, { + 'name': 'value', + 'label': 'Value', + 'field': 'value', + 'required': True + }] + + rows = [] + + for fld in fields(status): + if getattr(status, fld.name): + rows.append(dict(key=fld.name, value=str(getattr(status, fld.name)))) + + with ui.row(): + with ui.column(): + ui.label('DER Status').style('font-size: 150%;') + + with ui.row(): + with ui.column(): + ui.table(columns=columns, rows=rows) + + rows = [] + + for fld in fields(settings): + if getattr(settings, fld.name): + rows.append(dict(key=fld.name, value=getattr(settings, fld.name))) + + with ui.row(): + with ui.column(): + ui.label('DER Settings').style('font-size: 150%;') + + with ui.row(): + with ui.column(): + ui.table(columns=columns, rows=rows) + + rows = [] + + for fld in fields(capabilities): + if getattr(capabilities, fld.name): + rows.append(dict(key=fld.name, value=getattr(capabilities, fld.name))) + + with ui.row(): + with ui.column(): + ui.label('DER Capabilities').style('font-size: 150%;') + + with ui.row(): + with ui.column(): + ui.table(columns=columns, rows=rows) + + +@ui.refreshable +def render_der_control_list_tab(): + + def do_refresh(): + render_der_control_list_tab.refresh() + ui.notify('Refreshed') + + control_list: m.DERControlList = get_from_server(program.DERControlListLink.href, + deserialize=True, + limit=1000) + + #active_list: m.DERControlList = get_from_server(program.ActiveDERControlListLink.href, deserialize=True) + + with ui.row(): + with ui.column(): + with ui.label('DER Control List').style('font-size: 200%;'): + ui.button(icon='refresh', color='white', + on_click=lambda: do_refresh()).style('margin:5px; padding: 5px;') + ui.label( + 'Section 10.10 Distributed Energy Resources function set from 20305-2018 IEEE standard.' + ) + + columns = [{ + 'name': 'time', + 'label': 'Event Time', + 'field': 'time', + 'required': True + }, { + 'name': 'duration', + 'label': 'Event Duration', + 'field': 'duration', + 'required': True + }, { + 'name': 'status', + 'label': 'Event Status', + 'field': 'status', + 'required': True + }, { + 'name': 'control', + 'label': 'Control', + 'field': 'control', + 'required': True + }] + + def status_to_string(status: int): + if status == 0: + return 'Scheduled' + elif status == 1: + return 'Active' + elif status == 2: + return 'Cancelled' + elif status == 3: + return 'Supersceded' + elif status == 5: + return 'Completed' + else: + return 'Unknown' + + def build_list_rows(ctrl_list: m.DERControlList): + control_list_rows = [] + + def nonnone(control: m.DERControl): + dct = {} + + for obj, val in control.DERControlBase.__dict__.items(): + if val is not None: + if hasattr(val, 'value'): + val = val.value + elif hasattr(val, 'displacement'): + val = val.displacement + dct[obj] = val + return pformat(dct) + + for ctrl in sorted(ctrl_list.DERControl, key=lambda x: x.interval.start, reverse=True): + if ctrl.interval: + if ctrl.EventStatus is None and ctrl.interval.start and ctrl.interval.duration: + ctrl.EventStatus = m.EventStatus(currentStatus=0) # Scheduled. + local_dt = datetime_from_utc_to_local( + datetime.utcfromtimestamp(ctrl.interval.start)) + + row = { + 'time': local_dt, + 'duration': ctrl.interval.duration, + 'status': status_to_string(ctrl.EventStatus.currentStatus), + 'control': nonnone(ctrl) + } + + control_list_rows.append(row) + return control_list_rows + + with ui.row(): + with ui.column(): + ui.label('Control Events').style('font-size: 150%') + + # with ui.row(): + # with ui.column(): + # ui.table(columns=columns, rows=build_list_rows(active_list, 1)) + + # with ui.row(): + # with ui.column(): + # ui.label("Scheduled Controls").style("font-size: 150%") + + with ui.row(): + with ui.column(): + ui.table(columns=columns, rows=build_list_rows(control_list)) + + # with ui.row(): + # with ui.column(): + # ui.label("Completed Controls").style("font-size: 150%") + + # with ui.row(): + # with ui.column(): + # ui.table(columns=columns, rows=build_list_rows(control_list, 5)) + + +@ui.refreshable +def render_new_der_control_tab(): + # Need to start with the default control base before overwriting values from the new + # base control. + default: m.DefaultDERControl = get_from_server(program.DefaultDERControlLink.href, + deserialize=True) + der_base: m.DERControlBase = default.DERControlBase + wrappers: List[PropertyWrapper] = [] + if der_base is None: + der_base = m.DERControlBase() + default.DERControlBase = der_base + + def do_refresh(): + render_new_der_control_tab.refresh() + ui.notify('Refreshed') + + with ui.row(): + with ui.column(): + with ui.label('DER Control Entry').style('font-size: 200%;'): + ui.button(icon='refresh', color='white', + on_click=lambda: do_refresh()).style('margin:5px; padding: 5px;') + ui.label( + 'Section 10.10 Distributed Energy Resources function set from 20305-2018 IEEE standard.' + ) + + with ui.row().classes('pt-5'): + with ui.column(): + ui.label(f'DERProgram {der.CurrentDERProgramLink.href}').style('font-size: 150%') + + new_control = m.DERControl(mRID=uuid_2030_5(), DERControlBase=der_base) + + def submit_new_control(): + + for wrapper in wrappers: + if not wrapper.should_be_none(): + wrapper.apply_to_parent() + + event_start_time = datetime.fromtimestamp(new_control.interval.start) + + if event_start_time < datetime.utcnow(): + # Focus on the date time input. + ui.notify('Event Start Time must be in the future', type='error') + from_date.run_method('focus') + return + new_control.DERControlBase = der_base + + _log.debug(f'Date Time Sending: {datetime.fromtimestamp(new_control.interval.start)}') + + _log.debug(dataclass_to_xml(new_control)) + response = post_as_admin(program.DERControlListLink.href, + data=dataclass_to_xml(new_control)) + + ui.notify('New Control Complete') + render_der_control_list_tab.refresh() + panels.set_value('dercontrollist') + render_new_der_control_tab.refresh() + + def set_date(obj, prop, e): + try: + dt = parse_timestamp_string(e.value) + setattr(obj, prop, e.value) + except ParserError: + _log.debug(f'Invalid datetime specified: {e.value}') + + with ui.row(): + with ui.column(): + interval_wrapper = PropertyWrapper( + m.DateTimeInterval(duration=30, start=datetime.now() + timedelta(seconds=30)), + new_control, + 'interval', + formatters=dict(start=parse_timestamp_string), + applyers=dict(start=convert_local_dt_to_utc_timestamp)) + wrappers.append(interval_wrapper) + from_date = ui.input('Event Start', value=getattr(interval_wrapper, 'start'), + on_change=lambda e: set_date(interval_wrapper, 'start', e)) \ + .classes('w-96') + duration = ui.number('Duration', min=0, value=getattr(interval_wrapper, 'duration')) \ + .bind_value_from(interval_wrapper, 'duration') + + ui.input('MRID').bind_value(new_control, 'mRID').classes('w-96') + + with ui.column().classes('pr-20'): + ui.checkbox('opModConnect', value=True).bind_value(der_base, 'opModConnect') + ui.checkbox('opModEnergize', value=True).bind_value(der_base, 'opModEnergize') + + with ui.column().classes('pr-20'): + ui.label('Power Factor Absorb Watts').style('font-size: 125%;') + if der_base.opModFixedPFAbsorbW is None: + der_base.opModFixedPFAbsorbW = m.PowerFactorWithExcitation() + opModFixedPFAbsorbW_wrapper = PropertyWrapper(der_base.opModFixedPFAbsorbW, der_base, + 'opModFixedPFAbsorbW') + wrappers.append(opModFixedPFAbsorbW_wrapper) + ui.input('displacement', on_change=lambda e: noneable_int_change(opModFixedPFAbsorbW_wrapper, 'displacement', e)) \ + .bind_value_from(opModFixedPFAbsorbW_wrapper, 'displacement') + ui.checkbox('excitation', value=False).bind_value(opModFixedPFAbsorbW_wrapper, + 'excitation') + + ui.label('Power Factor Inject Watts').style('font-size: 125%;') + if der_base.opModFixedPFInjectW is None: + der_base.opModFixedPFInjectW = m.PowerFactorWithExcitation() + opModFixedPFInjectW_wrapper = PropertyWrapper(der_base.opModFixedPFInjectW, der_base, + 'opModFixedPFInjectW') + wrappers.append(opModFixedPFInjectW_wrapper) + ui.input('displacement', on_change=lambda e: noneable_int_change(opModFixedPFInjectW_wrapper, 'displacement', e)) \ + .bind_value_from(opModFixedPFInjectW_wrapper, 'displacement') + ui.checkbox('excitation', value=False).bind_value(opModFixedPFInjectW_wrapper, + 'excitation') + + with ui.column().classes('pr-20'): + if der_base.opModFixedVar is None: + der_base.opModFixedVar = m.FixedVar() + fixedVar_wrapper = PropertyWrapper(der_base.opModFixedVar, der_base, 'opModFixedVar') + wrappers.append(fixedVar_wrapper) + ui.input('opModFixedVar', on_change=lambda e: noneable_int_change(fixedVar_wrapper, 'value', e)) \ + .bind_value_from(fixedVar_wrapper, 'value') + + # Note this is not using PropertyWrapper because it is defined as an int in the xsd. + ui.input('opModFixedW', on_change=lambda e: noneable_int_change(der_base, 'opModFixedW', e)) \ + .bind_value_from(der_base, 'opModFixedW') + + # freqDroop_wrapper = Wrapper(m.FreqDroopType(), der_base, "openLoopTms") + # wrappers.append(freqDroop_wrapper) + # opModFreqDroop = ui.input("opModFreqDroop", + # on_change=lambda e: noneable_int_change(freqDroop_wrapper, "openLoopTms", e)) \ + # .bind_value_from(freqDroop_wrapper, "openLoopTms") + + ui.input('opModMaxLimW', on_change=lambda e: noneable_int_change(der_base, 'opModMaxLimW', e)) \ + .bind_value_from(der_base, 'opModMaxLimW') + + with ui.column().classes('pr-20'): + if der_base.opModTargetVar is None: + der_base.opModTargetVar = m.ReactivePower() + opModTargetVar_wrapper = PropertyWrapper(der_base.opModTargetVar, der_base, + 'opModTargetVar') + wrappers.append(opModTargetVar_wrapper) + ui.input('opModTargetVar', on_change=lambda e: noneable_int_change(opModTargetVar_wrapper, 'value', e)) \ + .bind_value_from(opModTargetVar_wrapper, 'value') + + if der_base.opModTargetW is None: + der_base.opModTargetW = m.ActivePower() + opModTargetW_wrapper = PropertyWrapper(der_base.opModTargetW, der_base, 'opModTargetW') + wrappers.append(opModTargetW_wrapper) + ui.input('opModTargetW', on_change=lambda e: noneable_int_change(opModTargetW_wrapper, 'value', e)) \ + .bind_value_from(opModTargetW_wrapper, 'value') + + # opModVoltVar = ui.input("opModVoltVar", + # on_change=lambda e: noneable_int_change(der_base, "opModVoltVar", e)) \ + # .bind_value_from(der_base, "opModVoltVar") + # opModWattPF = ui.input("opModWattPF", + # on_change=lambda e: noneable_int_change(der_base, "opModWattPF", e)) \ + # .bind_value_from(der_base, "opModWattPF") + ui.input('rampTms', on_change=lambda e: noneable_int_change(der_base, 'rampTms', e)) \ + .bind_value_from(der_base, 'rampTms') + + # with ui.row().classes("pt-10"): + # with ui.column().classes("pr-20"): + # ui.label("Curve Selection") + # ui.label("TODO") + + with ui.row().classes('pt-20'): + with ui.column(): + ui.button('Sumbit Control', on_click=lambda: submit_new_control()) + + +@ui.refreshable +def render_usage_points_tab(): + + def do_refresh(): + render_usage_points_tab.refresh() + ui.notify('Refreshed') + + usage_points: m.UsagePointList = get_from_server(dcap.UsagePointListLink.href, + deserialize=True, + limit=10) + + nodes = [] + + for upt in usage_points.UsagePoint: + upt_node = {'id': upt.href, 'label': upt.href, 'children': []} + nodes.append(upt_node) + meter_reading: m.MeterReadingList = get_from_server(upt.MeterReadingListLink.href, + deserialize=True, + limit=10) + for mr in meter_reading.MeterReading: + mr_node = {'id': mr.href, 'label': mr.description, 'children': []} + upt_node['children'].append(mr_node) + + if mr.ReadingLink is not None and mr.ReadingLink.href is not None: + readings_list: m.ReadingList = get_from_server(mr.ReadingLink.href, + deserialize=True, + limit=10) + if len(readings_list.Reading) > 0: + reading_node = {'id': reading.href, 'label': 'Readings', 'children': []} + mr_node['children'].append(reading_node) + for reading in readings_list.Reading: + read_node = {'id': reading.href, 'label': reading.href, 'children': []} + reading_node['children'].append(read_node) + + if mr.ReadingSetListLink is not None and mr.ReadingSetListLink.href is not None: + readingset_list: m.ReadingSetList = get_from_server(mr.ReadingSetListLink.href, + deserialize=True, + limit=10) + reading_node = {'id': readingset_list.href, 'label': 'Readings', 'children': []} + mr_node['children'].append(reading_node) + for rs in readingset_list.ReadingSet: + if rs.ReadingListLink is not None and rs.ReadingListLink.href is not None: + reading_list: m.ReadingList = get_from_server(rs.ReadingListLink.href, + deserialize=True, + limit=10) + for rdng in reading_list.Reading: + if rdng.timePeriod is not None: + period = rdng.timePeriod + else: + period = rs.timePeriod + + if period is not None: + period = timestamp_to_string(period.start) + read_node = { + 'id': rdng.href, + 'label': f'{period} Value: {rdng.value}', + 'children': [] + } + reading_node['children'].append(read_node) + + with ui.row(): + with ui.column(): + with ui.label('Usage Points').style('font-size: 200%;'): + ui.button(icon='refresh', color='white', + on_click=lambda: do_refresh()).style('margin:5px; padding: 5px;') + ui.label( + 'Section 10.10 Distributed Energy Resources function set from 20305-2018 IEEE standard.' + ) + with ui.row(): + ui.tree(nodes=nodes) + + +with ui.header(): + current_time_label = ui.label('Current Time') + ui.timer( + 1.0, lambda: current_time_label.set_text( + f'Local Time: {datetime.now().isoformat()} GMT TS: {convert_local_dt_to_utc_timestamp(datetime.now())}' + )) +with ui.tabs().classes('w-full') as tabs: + configuration_tab = ui.tab('configuration', 'Configuration') + der_default_control_tab = ui.tab('derdefaultcontrol', 'DER Default Control') + new_der_control_tab = ui.tab('newdercontrol', 'New DER Control') + der_control_list_tab = ui.tab('dercontrollist', 'DER Control List') + der_status_tab = ui.tab('derstatus', 'DER Status') + usage_point_tab = ui.tab('usage_point', 'Usage Points') + #results_tab = ui.tab("results", "Results") +line_plot = None +with ui.tab_panels(tabs, value=configuration_tab).classes('w-full') as panels: + with ui.tab_panel(configuration_tab): + with ui.row(): + with ui.column(): + ui.input('2030.5 Identity').classes('w-96').bind_value( + config_working, 'agent_2030_5_identity') + ui.input('VOLTTRON home').classes('w-96').bind_value(config_working, + 'volttron_home') + ui.input('EndDevice private').classes('w-96').bind_value( + config_working, 'ieee_client_pk') + ui.input('EndDevice cert').classes('w-96').bind_value( + config_working, 'ieee_client_cert') + ui.input('CA cert').classes('w-96').bind_value(config_working, 'ieee_ca') + + with ui.row().classes('p-10'): + ui.button('Save', on_click=lambda: save_config()) + ui.button('Reset', on_click=lambda: reset_config()) + + with ui.tab_panel(new_der_control_tab): + render_new_der_control_tab() + + with ui.tab_panel(der_default_control_tab): + render_der_default_control_tab() + + with ui.tab_panel(der_control_list_tab): + render_der_control_list_tab() + ui.timer(10, lambda: render_der_control_list_tab.refresh()) + + with ui.tab_panel(der_status_tab): + render_der_status_tab() + + with ui.tab_panel(usage_point_tab): + render_usage_points_tab() + +logging.basicConfig(level=logging.DEBUG) + +excludes = '.*, .py[cod], .sw.*, ~*,*.git,' +ui.run(reload=True, show=False, uvicorn_reload_excludes=excludes) diff --git a/services/core/IEEE_2030_5/example.config.yml b/services/core/IEEE_2030_5/example.config.yml new file mode 100644 index 0000000000..fa85a8583b --- /dev/null +++ b/services/core/IEEE_2030_5/example.config.yml @@ -0,0 +1,84 @@ +# These are required in order for the agent to connect to the server. +cacertfile: ~/tls/certs/ca.crt +keyfile: ~/tls/private/dev1.pem +certfile: ~/tls/certs/dev1.crt +server_hostname: 127.0.0.1 + +# the pin number is used to verify the server is the correct server +pin: 111115 + +# Log the request and responses from the server. +log_req_resp: true + +# SSL defaults to 443 +server_ssl_port: 8443 + +# Number of seconds to poll for new default der settings. +default_der_control_poll: 10 + +MirrorUsagePointList: + # MirrorMeterReading based on Table E.2 IEEE Std 2030.5-18 + - device_point: INV_REAL_PWR + mRID: 5509D69F8B3535950000000000009182 + description: DER Inverter Real Power + roleFlags: 49 + serviceCategoryKind: 0 + status: 0 + MirrorMeterReading: + mRID: 5509D69F8B3535950000000000009183 + description: Real Power(W) Set + ReadingType: + accumulationBehavior: 12 + commodity: 1 + dataQualifier: 2 + intervalLength: 300 + powerOfTenMultiplier: 0 + uom: 38 + - device_point: INV_REAC_PWR + mRID: 5509D69F8B3535950000000000009184 + description: DER Inverter Reactive Power + roleFlags: 49 + serviceCategoryKind: 0 + status: 0 + MirrorMeterReading: + mRID: 5509D69F8B3535950000000000009185 + description: Reactive Power(VAr) Set + ReadingType: + accumulationBehavior: 12 + commodity: 1 + dataQualifier: 2 + intervalLength: 300 + powerOfTenMultiplier: 0 + uom: 38 + +# publishes on the following subscriptions will +# be available to create and POST readings to the +# 2030.5 server. +device_topic: devices/inverter1 + +# Nameplate ratings for this der client will be put to the +# server during startup of the system. +DERCapability: + # modesSupported is a HexBinary31 representation of DERControlType + # See Figure B.34 DER info types for information + # conversion in python is as follows + # "{0:08b}".format(int("500040", 16)) + # '10100000000000001000000' # This is a bitmask + # to generate HexBinary + # hex(int('10100000000000001000000', 2)) + # 0x500040 + modesSupported: 500040 + rtgMaxW: + multiplier: 0 + value: 0 + type: 0 + +DERSettings: + modesEnabled: 100000 + setGradW: 0 + setMaxW: + multiplier: 0 + value: 0 + +# Note this file MUST be in the config store or this agent will not run properly. +point_map: config:///inverter_sample.csv diff --git a/services/core/IEEE_2030_5/ieee_2030_5/__init__.py b/services/core/IEEE_2030_5/ieee_2030_5/__init__.py new file mode 100644 index 0000000000..af7f4fa643 --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/__init__.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any, Dict, List +from dataclasses import dataclass, is_dataclass +from pathlib import Path +from typing import Type, Optional + +from xsdata.formats.dataclass.context import XmlContext +from xsdata.formats.dataclass.parsers.config import ParserConfig +from xsdata.formats.dataclass.parsers.xml import XmlParser +from xsdata.formats.dataclass.serializers import XmlSerializer +from xsdata.formats.dataclass.serializers.config import SerializerConfig + +__xml_context__ = XmlContext() +__parser_config__ = ParserConfig(fail_on_unknown_attributes=False, + fail_on_unknown_properties=False) +__xml_parser__ = XmlParser(config=__parser_config__, context=__xml_context__) +__config__ = SerializerConfig(xml_declaration=False, pretty_print=True) +__serializer__ = XmlSerializer(config=__config__) +__ns_map__ = {None: 'urn:ieee:std:2030.5:ns'} + + +def serialize_dataclass(obj) -> str: + """ + Serializes a dataclass that was created via xsdata to an xml string for + returning to a client. + """ + if not is_dataclass(obj): + raise ValueError('Invalid object, must be a dataclass object.') + + return __serializer__.render(obj, ns_map=__ns_map__) + + +def xml_to_dataclass(xml: str, type: Optional[Type] = None) -> object: + """ + Parse the xml passed and return result from loaded classes. + """ + return __xml_parser__.from_string(xml, type) + + +def dataclass_to_xml(dc) -> str: + return serialize_dataclass(dc) + + +@dataclass +class AllPoints: + points: Dict = field(default_factory=dict) + meta: Dict = field(default_factory=dict) + + def add(self, name: str, value: Any, meta: Dict = {}): + self.points[name] = value + self.meta[name] = meta + + def get(self, name: str) -> Any: + return self.points[name] + + def forbus(self) -> List: + return [self.points, self.meta] + + @staticmethod + def frombus(message: List) -> AllPoints: + assert len(message) == 2, 'Message must have a length of 2' + + points = AllPoints() + + for k, v in message[0].items(): + points.add(name=k, value=v, meta=message[1].get(k)) + + return points + + +import ieee_2030_5.models as models diff --git a/services/core/IEEE_2030_5/ieee_2030_5/agent.py b/services/core/IEEE_2030_5/ieee_2030_5/agent.py new file mode 100644 index 0000000000..7bb765c0bf --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/agent.py @@ -0,0 +1,885 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +from __future__ import annotations +from copy import deepcopy +from dataclasses import dataclass, field, fields +import math +import logging +import sys +from datetime import datetime +from pathlib import Path +from pprint import pformat +from typing import Any, Dict, List + +import ieee_2030_5.models as m +from volttron.platform.agent.known_identities import PLATFORM_DRIVER +from . import AllPoints +from .client import IEEE2030_5_Client + +try: # for modular + from volttron import utils + from volttron.client.messaging.health import STATUS_GOOD + from volttron.client.vip.agent import RPC, Agent, Core, PubSub + from volttron.client.vip.agent.subsystems.query import Query + from volttron.utils.commands import vip_main +except ImportError: + from volttron.platform.agent import utils + from volttron.platform.agent.utils import vip_main + from volttron.platform.vip.agent import RPC, Agent, Core, PubSub + from volttron.platform.vip.agent.subsystems.query import Query + +# from . import __version__ +__version__ = '0.1.0' + +# Setup logging so that it runs within the platform +utils.setup_logging() + +logging.getLogger('ieee_2030_5.client.req_resp').setLevel(logging.INFO) +# The logger for this agent is _log and can be used throughout this file. +_log = logging.getLogger(__name__) + +# These items are global for the agent and will periodically be +# sent to the 2030.5 server based upon the post interval. +DER_SETTINGS = m.DERSettings() +DER_CAPABILITIES = m.DERCapability() +# This is used for default control and control events. +DER_CONTROL_BASE = m.DERControlBase() +# Used for sending status message to the 2030.5 server. +DER_STATUS = m.DERStatus() +# Used for sending default control to the 2030.5 server. +DEFAULT_DER_CONTROL = m.DefaultDERControl() +DEFAULT_DER_CONTROL.DERControlBase = DER_CONTROL_BASE + + +@dataclass +class MappedPoint: + """The MappedPoint class models the mapping points. + + The MappedPoint class allows mapping of points from/to the platform.driver and + 2030.5 objects. + + Only points that have point_on_bus and parameter_type will be mapped. + + The format of the parameter_type is :: where object is one of + DERSettings, DERCapability, DERControlBase, or DERStatus. The property must be + a valid property of the object. + """ + + point_on_bus: str + description: str + multiplier: int + mrid: str + offset: int + parameter_type: str + notes: str + parent_object: object = None + parameter: str = None + value_2030_5: Any = None + changed: bool = False + + def reset_changed(self): + self.changed = False + + def set_value(self, value: Any): + current_value = getattr(self.parent_object, self.parameter) + if value != current_value: + setattr(self.parent_object, self.parameter, value) + self.changed = True + + def __post_init__(self): + """Post initialization of the MappedPoint object. + + This method is called after the object is initialized. It is used to + verify that the parameter_type is valid and that the parent_object and + parameter are set correctly. The parent_object is the object that the + parameter is a property of. + + The parameter_type must be in the format :: where object + is one of DERSettings, DERCapability, DERControlBase, or DERStatus. + """ + params = self.parameter_type.split('::') + + # Only if we have a proper object specifier that we know about + if len(params) == 2: + if params[0] == 'DERSettings': + self.parent_object = DER_SETTINGS + elif params[0] == 'DERCapability': + self.parent_object = DER_CAPABILITIES + elif params[0] == 'DERControlBase': + self.parent_object = DER_CONTROL_BASE + elif params[0] == 'DERStatus': + self.parent_object = DER_STATUS + elif params[0] == 'DefaultDERControl': + self.parent_object = DEFAULT_DER_CONTROL + + assert self.parent_object is not None, f'The parent object type {params[0]} is not known, please check spelling in configuration file.' + assert hasattr( + self.parent_object, params[1] + ), f'{params[0]} does not have property {params[1]}, please check spelling in configuration file.' + self.parameter = params[1] + + @staticmethod + def build_from_csv(data: Dict[str, str]) -> MappedPoint: + """Create a mapped point from a row of data. + + :param data: A row of data from the point_map csv file. + :type data: Dict[str, str] + :return: A mapped point object. + :rtype: MappedPoint + """ + return MappedPoint(point_on_bus=data['Point Name'].strip(), + description=data['Description'].strip(), + multiplier=data['Multiplier'].strip(), + mrid=data['MRID'].strip(), + offset=data['Offset'].strip(), + parameter_type=data['Parameter Type'].strip(), + notes=data['Notes'].strip()) + + +class IEEE_2030_5_Agent(Agent): + """ + IEEE_2030_5_Agent + """ + + def __init__(self, config_path: str, **kwargs): + """Initialize the IEEE 2030.5 agent. + + The IEEE 2030.5 agent is responsible for connecting to the IEEE 2030.5 server and + sending it data from the platform driver. The agent is also responsible for + creating MirrorUsagePoints on the IEEE 2030.5 server and sending data from the + platform driver to the IEEE 2030.5 server based upon those MirrorUsagePoints. + The configuration file holds information in order for the 2030.5 agent to accomplish + these tasks. + + In addition, the 2030.5 agent will poll the IEEE 2030.5 server for DERControl, and + DefaultDERControl objects. The DefaultDERControl object is used to set the default + mode of operation for the DER. When the DefaultDERControl object is updated, the + 2030.5 agent will send the updated values to the platform driver. During a DERControl + event, the 2030.5 agent will send the DERControl object data to the platform driver. + Once the DERControl event has ended, the 2030.5 agent will revert back to the + DefaultDERControl object and send that object to the platform driver. + + The Mapping of points from/to the platform driver and 2030.5 objects is done via the + config store entry point_map field within the configuration file. + + :param config_path: A path to the configuration file that holds the + defaults for the agent and connection to the + IEEE 2030.5 server. + :type config_path: str + """ + super().__init__(**kwargs) + _log.debug('vip_identity: ' + self.core.identity) + + config = utils.load_config(config_path) + + self._cacertfile = Path(config['cacertfile']).expanduser() + self._keyfile = Path(config['keyfile']).expanduser() + self._certfile = Path(config['certfile']).expanduser() + self._pin = config['pin'] + self._log_req_resp = bool(config.get('log_req_resp', False)) + if config['device_topic'].endswith('/all'): + config['device_topic'] = config['device_topic'][:-len('/all')] + self._device_topic = config['device_topic'] + self._control_point = config['device_topic'] + if self._control_point.startswith('devices/'): + self._control_point = self._control_point[len('devices/'):] + self._server_hostname = config['server_hostname'] + self._server_ssl_port = config.get('server_ssl_port', 443) + self._server_http_port = config.get('server_http_port', None) + self._mirror_usage_point_list = config.get('MirrorUsagePointList', []) + self._der_capabilities_info = config.get('DERCapability') + self._der_settings_info = config.get('DERSettings') + self._der_status_info = config.get('DERStatus') + #self._point_map = config.get("point_map") + self._mapped_points: Dict[str, MappedPoint] = {} + self._default_config = { + 'device_topic': self._device_topic, + 'MirrorUsagePointList': self._mirror_usage_point_list, + 'point_map': config.get('point_map'), + 'default_der_control_poll': int(config.get('default_der_control_poll', 60)) + } + self._topic_without_prefix: str = self._device_topic[self._device_topic.find('devices/') + + len('devices/'):] + self._server_usage_points: m.UsagePointList + + self._client = IEEE2030_5_Client(cafile=self._cacertfile, + server_hostname=self._server_hostname, + keyfile=self._keyfile, + certfile=self._certfile, + server_ssl_port=self._server_ssl_port, + pin=self._pin, + log_req_resp=self._log_req_resp) + + # Hook events up to the client so that we can send the correct information on to + # the platform driver. + self._client.der_control_event_started(self._control_event_started) + self._client.der_control_event_ended(self._control_event_ended) + self._client.der_default_control_changed(self._default_control_changed) + + # These objects are constructed from the platform driver's publishes + self._last_settings = m.DERSettings() + self._last_capabilities = m.DERCapability() + self._last_status = m.DERStatus() + + # These variables represent the current state of the der and + self._active_controls: List[m.DERControl] = [] + self._default_der_control: m.DefaultDERControl = None + self._current_control: m.DERControl = None + + try: + self._client.start(config=self._default_config) + except ConnectionRefusedError: + _log.error(f'Could not connect to server {self._server_hostname} agent exiting.') + sys.exit(1) + except ValueError as e: + _log.error(e) + sys.exit(1) + _log.info(self._client.enddevice) + assert self._client.enddevice + ed = self._client.enddevice + self._client.get_der_list() + self._point_to_reading_set: Dict[str, str] = {} + self._mirror_usage_points: Dict[str, m.MirrorUsagePoint] = {} + self._mup_readings: Dict[str, m.MirrorMeterReading] = {} + self._mup_pollRate: int = 60 + self._times_published: Dict[str, int] = {} + + # Set a default configuration to ensure that self.configure is called immediately to setup + # the agent. + self.vip.config.set_default('config', self._default_config) + # Hook self.configure up to changes to the configuration file "config". + self.vip.config.subscribe(self.configure, actions=['NEW', 'UPDATE'], pattern='config') + + def _active_controls_changed(self, active: m.DERControlList): + """Callback when the active controls have changed on the IEEE 2030.5 server. + + :param active: A list of active controls + :type active: m.DERControlList + """ + if not isinstance(active, m.DERControlList): + _log.error('Invalid instance passed to active control changed') + return + _log.debug('Active controls changed') + + def _default_control_changed(self, default_control: m.DefaultDERControl): + """Calback when the default control has changed on the IEEE 2030.5 server. + + @param: default_control: The new default control. + @type: default_control: m.DefaultDERControl + """ + if not isinstance(default_control, m.DefaultDERControl): + _log.error('Invalid instance of default control') + raise ValueError(f'Invalid instance of default control was {type(default_control)}') + + if self._current_control is not None: + _log.info('Default config has been overwritten by event.') + return + _log.info('Sending default control to platform.driver') + + self._default_der_control = default_control + + default_control_points = list( + filter(lambda x: 'DefaultDERControl' in x.parameter_type, + self._mapped_points.values())) + der_base_points = list( + filter(lambda x: 'DERControlBase' in x.parameter_type, self._mapped_points.values())) + + for point in default_control_points: + point_value = getattr(default_control, point.parameter) + + try: + if point_value: + if not isinstance(point_value, (float, int, bool)): + point_value = getattr(point_value, 'value') + + if point_value: + self.vip.rpc.call(PLATFORM_DRIVER, 'set_point', self._control_point, + point.point_on_bus, point_value) + except TypeError: + _log.error(f'Error setting point {point.point_on_bus} to {point_value}') + except KeyError: + _log.error(f'Error setting point {point.point_on_bus} to {point_value}') + + for point in der_base_points: + + point_value = getattr(default_control.DERControlBase, point.parameter) + + try: + if point_value: + if not isinstance(point_value, (float, int, bool)): + point_value = getattr(point_value, 'value') + + if point_value: + self.vip.rpc.call(PLATFORM_DRIVER, 'set_point', self._control_point, + point.point_on_bus, point_value) + except TypeError: + _log.error(f'Error setting point {point.point_on_bus} to {point_value}') + + def _control_event_started(self, control: m.DERControl): + """A control event has started. + + :param control: The control that has started. + :type control: m.DERControl + :raises ValueError: If the control is not an instance of m.DERControl + """ + _log.debug(f"{'='*50}Control event started") + if not isinstance(control, m.DERControl): + _log.error('Invalid control event passed to event_started') + raise ValueError( + f'Invalid type passed to event_started {type(control)} instead of {type(m.DERControl)}' + ) + + self._current_control = control + der_control: m.DERControl = control + # We override some of the base controls with the event controls + der_control_base: m.DERControlBase = None + if self._default_der_control is not None and self._default_der_control.DERControlBase is not None: + der_control_base = deepcopy(self._default_der_control.DERControlBase) + + if der_control_base: + # Overwrite all of the base controls with the controls from the event. + for fld in fields(m.DERControlBase): + setattr(der_control_base, fld.name, getattr(der_control.DERControlBase, fld.name)) + else: + der_control_base = der_control.DERControlBase + + # Retrieve mapped points that we can report on to the platform driver. + # Note this is a DERControlBase prefix in the parameter_type field. + der_base_points = list( + filter(lambda x: 'DERControlBase' in x.parameter_type, self._mapped_points.values())) + + for point in der_base_points: + + point_value = getattr(der_control_base, point.parameter) + + try: + if point_value: + # These are the point types that have a multiplyer assigned to them. + if isinstance(point_value, + (m.VoltageRMS, m.ApparentPower, m.PowerFactor, m.CurrentRMS, + m.ActivePower, m.WattHour, m.ReactivePower, m.FixedPointType)): + if isinstance(point_value, m.PowerFactor): + point_value = point_value.displacement * math.pow( + 10, -point_value.multiplier) + elif point_value.value is not None and point_value.multiplier is not None: + point_value = point_value.value * math.pow(10, -point_value.multiplier) + else: + point_value = None + elif isinstance(point_value, m.FixedVar): + # TODO: Deal with ref type? + point_value = point_value.value + + elif isinstance(point_value, m.DERCurveLink): + # TODO Handle DERCurve Types + ... + elif isinstance(point_value, bool): + point_value = 1 if point_value else 0 + elif isinstance(point_value, m.PowerFactorWithExcitation): + point_value = point_value.displacement + + if point_value: + _log.debug(f'Setting point: {point.point_on_bus} to {point_value}') + self.vip.rpc.call(PLATFORM_DRIVER, 'set_point', point.point_on_bus, + point_value) + except TypeError: + _log.error(f'Error setting point {point.point_on_bus} to {point_value}') + + def _control_event_ended(self, control: m.DERControl): + """Callback when a control event has ended. + + When the control event ends, we need to reset the controls to the default control + specified by the IEEE 2030.5 server. + + :param control: The control that has ended. + :type control: m.DERControl + """ + _log.debug(f"{'='*50}Control event ended") + self._current_control = None + self._default_control_changed(self._default_der_control) + + def configure(self, config_name, action, contents): + """ + Called after the Agent has connected to the message bus. If a configuration exists at startup + this will be called before onstart. + + It is called every time the configuration in the store changes for this agent. + """ + config = self._default_config.copy() + config.update(contents) + + if not config.get('point_map'): + raise ValueError( + 'Must have point_map specified in config store or referenced to a config store entry!' + ) + # Only deal with points that have both on bus point and + # a 2030.5 parameter type + for item in config['point_map']: + if item.get('Point Name').strip() and item.get('Parameter Type').strip(): + if 'DERSettings' in item['Parameter Type'] or \ + 'DERCapability' in item['Parameter Type'] or \ + 'DERStatus' in item['Parameter Type'] or \ + 'DERControlBase' in item['Parameter Type'] or \ + 'DefaultDERControl' in item['Parameter Type']: + + point = MappedPoint.build_from_csv(item) + self._mapped_points[point.point_on_bus] = point + # self._mapped_points[point.parameter_type] = point + else: + _log.debug( + f"Skipping {item['Point Name']} because it does not have a valid Parameter Type" + ) + + try: + device_topic = config['device_topic'] + new_usage_points: Dict[str, m.MirrorUsagePoint] = {} + + for mup in config.get('MirrorUsagePointList', []): + device_topic_point = mup.pop('device_point') + new_usage_points[mup['mRID']] = m.MirrorUsagePoint(**mup) + new_usage_points[mup['mRID']].deviceLFDI = self._client.lfdi + new_usage_points[mup['mRID']].MirrorMeterReading = [] + new_usage_points[mup['mRID']].MirrorMeterReading.append( + m.MirrorMeterReading(**mup['MirrorMeterReading'])) + mup['device_point'] = device_topic_point + + except ValueError as e: + _log.error('ERROR PROCESSING CONFIGURATION: {}'.format(e)) + return + + self.vip.pubsub.unsubscribe(peer='pubsub', + prefix=self._device_topic, + callback=self._data_published) + + self._device_topic = device_topic + self._control_point = device_topic + if self._control_point.startswith('devices/'): + self._control_point = self._control_point[len('devices/'):] + + self._mup_readings.clear() + self._mirror_usage_points.clear() + + ed = self._client.end_device + self._mirror_usage_points.update(new_usage_points) + server_usage_points = self._client.mirror_usage_point_list() + self._mup_pollRate = server_usage_points.pollRate if server_usage_points.pollRate else self._mup_pollRate + + for mup in self._mirror_usage_points.values(): + try: + found = next( + filter(lambda x: x.mRID == mup.mRID, server_usage_points.MirrorUsagePoint)) + except StopIteration: + location = self._client.create_mirror_usage_point(mup) + mup_reading = m.MirrorMeterReading( + mRID=mup.MirrorMeterReading[0].mRID, + href=location, + description=mup.MirrorMeterReading[0].description) + rs = m.MirrorReadingSet(mRID=mup_reading.mRID + '1', + timePeriod=m.DateTimeInterval()) + rs.timePeriod.start = int(round(datetime.utcnow().timestamp())) + rs.timePeriod.duration = self._mup_pollRate + + # new mrid is based upon the mirror reading. + mup_reading.MirrorReadingSet.append(rs) + rs.Reading = [] + + self._mup_readings[mup_reading.mRID] = mup_reading + + self._server_usage_points = self._client.mirror_usage_point_list() + + _log.debug(f'Subscribing to {self._device_topic}') + self.vip.pubsub.subscribe(peer='pubsub', + prefix=self._device_topic, + callback=self._data_published) + + def _cast_multipler(self, value: str) -> int: + try: + return int(value) + except ValueError: + _log.warning(f'Casting multiplier to int failed: {value}') + return 1 + + def _transform_settings(self, points: List[MappedPoint]) -> m.DERSettings: + """Update a DERSettings object so that it is correctly formatted to send to the server. + + The point has a parent_object property that must be a DERSettings object. Each setting + that requires a transition from a single element to a complex element is handled here. + + :param point: The point that is being updated. + :return: The updated DERSettings object. + :rtype: m.DERSettings + :raises AssertionError: If the parent_object is not a DERSettings object. + """ + # all of the settings are in the same envelope so we use the same + # server time for all of them. + server_time = self._client.server_time + settings = None + + for point in points: + assert isinstance( + point.parent_object, + m.DERSettings), f'Parent object is not a DERSettings object: {p.parent_object}' + + settings: m.DERSettings = point.parent_object + + # Transform point values into their correct object types. + if point.parameter == 'setMaxA': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxA = m.CurrentRMS(multiplier=point.multiplier, + value=settings.setMaxA) + + if point.parameter == 'setMaxAh': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxAh = m.AmpereHour(multiplier=point.multiplier, + value=settings.setMaxAh) + + if point.parameter == 'setMaxChargeRateVA': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxChargeRateVA = m.ApparentPower(multiplier=point.multiplier, + value=settings.setMaxChargeRateVA) + + if point.parameter == 'setMaxChargeRateW': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxChargeRateW = m.ActivePower(multiplier=point.multiplier, + value=settings.setMaxChargeRateW) + + if point.parameter == 'setMaxDischargeRateVA': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxDischargeRateVA = m.ApparentPower( + multiplier=point.multiplier, value=settings.setMaxDischargeRateVA) + + if point.parameter == 'setMaxDischargeRateW': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxDischargeRateW = m.ActivePower(multiplier=point.multiplier, + value=settings.setMaxDischargeRateW) + + if point.parameter == 'setMaxV': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxV = m.VoltageRMS(multiplier=point.multiplier, + value=settings.setMaxV) + + if point.parameter == 'setMaxVA': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxVA = m.ApparentPower(multiplier=point.multiplier, + value=settings.setMaxVA) + + if point.parameter == 'setMaxVar': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxVar = m.ReactivePower(multiplier=point.multiplier, + value=settings.setMaxVar) + + if point.parameter == 'setMaxVarNeg': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxVarNeg = m.ReactivePower(multiplier=point.multiplier, + value=settings.setMaxVarNeg) + + if point.parameter == 'setMaxW': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxW = m.ActivePower(multiplier=point.multiplier, + value=settings.setMaxW) + + if point.parameter == 'setMaxWh': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMaxWh = m.WattHour(multiplier=point.multiplier, + value=settings.setMaxWh) + + if point.parameter == 'setMinPFOverExcited': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMinPFOverExcited = m.PowerFactor(multiplier=point.multiplier, + value=settings.setMinPFOverExcited) + + if point.parameter == 'setMinPFUnderExcited': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMinPFUnderExcited = m.PowerFactor(multiplier=point.multiplier, + value=settings.setMinPFUnderExcited) + + if point.parameter == 'setMinV': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setMinV = m.VoltageRMS(multiplier=point.multiplier, + value=settings.setMinV) + + if point.parameter == 'setSoftGradW': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setSoftGradW = m.ActivePower(multiplier=point.multiplier, + value=settings.setSoftGradW) + + if point.parameter == 'setVNom': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setVNom = m.VoltageRMS(multiplier=point.multiplier, + value=settings.setVNom) + + if point.parameter == 'setVRef': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setVRef = m.VoltageRMS(multiplier=point.multiplier, + value=settings.setVRef) + + if point.parameter == 'setVRefOfs': + point.multiplier = self._cast_multipler(point.multiplier) + settings.setVRefOfs = m.VoltageRMS(multiplier=point.multiplier, + value=settings.setVRefOfs) + settings.updatedTime = server_time + + return settings + + def _transform_status(self, points: List[MappedPoint]) -> m.DERStatus: + """Update a derstatus object so that it is correctly formatted to send to the server. + + The point has a parent_object property that must be a DERStatus object. Each setting + that requires a transition from a single element to a complex element is handled here. + + :param point: The point that is being updated. + :return: The updated DERStatus object. + :rtype: m.DERStatus + :raises AssertionError: If the parent_object is not a DERStatus object. + """ + + server_time = self._client.server_time + status = None + + for point in points: + try: + assert isinstance( + point.parent_object, + m.DERStatus), f'Parent object is not a DERStatus object: {p.parent_object}' + + status: m.DERStatus = point.parent_object + + if point.parameter == 'genConnectStatus': + status.genConnectStatus = m.ConnectStatusType(dateTime=server_time, + value=status.genConnectStatus) + + if point.parameter == 'inverterStatus': + status.inverterStatus = m.InverterStatusType(dateTime=server_time, + value=status.inverterStatus) + + if point.parameter == 'localControlModeStatus': + status.localControlModeStatus = m.LocalControlModeStatusType( + dateTime=server_time, value=status.localControlModeStatus) + + if point.parameter == 'manufacturerStatus': + status.manufacturerStatus = m.ManufacturerStatusType( + dateTime=server_time, value=status.manufacturerStatus) + + if point.parameter == 'operationalModeStatus': + status.operationalModeStatus = m.OperationalModeStatusType( + dateTime=server_time, value=status.operationalModeStatus) + + if point.parameter == 'stateOfChargeStatus': + status.stateOfChargeStatus = m.StateOfChargeStatusType( + dateTime=server_time, value=status.stateOfChargeStatus) + + if point.parameter == 'storageModeStatus': + status.storageModeStatus = m.StorageModeStatusType( + dateTime=server_time, value=status.storageModeStatus) + + if point.parameter == 'storConnectStatus': + status.storConnectStatus = m.ConnectStatusType(dateTime=server_time, + value=status.storConnectStatus) + + status.readingTime = server_time + except Exception as e: + _log.error(f'Converting status: {e}') + return status + + def _transform_capabilities(self, points: List[MappedPoint]) -> m.DERCapability: + """Update a DERCapability object so that it is correctly formatted to send to the server. + + The point has a parent_object property that must be a DERCapability object. Each setting + that requires a transition from a single element to a complex element is handled here. + + :param point: The point that is being updated. + :return: The updated DERCapability object. + :rtype: m.DERCapability + :raises AssertionError: If the parent_object is not a DERCapability object. + """ + + server_time = self._client.server_time + capabilities = None + + for point in points: + assert isinstance( + point.parent_object, m.DERCapability + ), f'Parent object is not a DERCapability object: {point.parent_object}' + + capabilities: m.DERCapability = point.parent_object + + if point.parameter == 'rtgMaxA': + capabilities.rtgMaxA = m.CurrentRMS(multiplier=point.multiplier, + value=self.rtgMaxA) + + if point.parameter == 'rtgMaxAh': + capabilities.rtgMaxAh = m.AmpereHour(multiplier=point.multiplier, + value=self.rtgMaxAh) + + if point.parameter == 'rtgMaxChargeRateVA': + capabilities.rtgMaxChargeRateVA = m.ApparentPower(multiplier=point.multiplier, + value=self.rtgMaxChargeRateVA) + + if point.parameter == 'rtgMaxChargeRateW': + capabilities.rtgMaxChargeRateW = m.ActivePower(multiplier=point.multiplier, + value=self.rtgMaxChargeRateW) + + if point.parameter == 'rtgMaxV': + capabilities.rtgMaxV = m.VoltageRMS(multiplier=point.multiplier, + value=self.rtgMaxV) + + if point.parameter == 'rtgMaxVA': + capabilities.rtgMaxVA = m.ApparentPower(multiplier=point.multiplier, + value=self.rtgMaxVA) + + if point.parameter == 'rtgMaxVar': + capabilities.rtgMaxVar = m.ReactivePower(multiplier=point.multiplier, + value=self.rtgMaxVar) + + if point.parameter == 'rtgMaxVarNeg': + capabilities.rtgMaxVarNeg = m.ReactivePower(multiplier=point.multiplier, + value=self.rtgMaxVarNeg) + + if point.parameter == 'rtgMaxW': + capabilities.rtgMaxW = m.ActivePower(multiplier=point.multiplier, + value=self.rtgMaxW) + + if point.parameter == 'rtgMaxWh': + capabilities.rtgMaxWh = m.WattHour(multiplier=point.multiplier, + value=self.rtgMaxWh) + + if point.parameter == 'rtgMinPFOverExcited': + capabilities.rtgMinPFOverExcited = m.PowerFactor(multiplier=point.multiplier, + value=self.rtgMinPFOverExcited) + + if point.parameter == 'rtgMinPFUnderExcited': + capabilities.rtgMinPFUnderExcited = m.PowerFactor(multiplier=point.multiplier, + value=self.rtgMinPFUnderExcited) + + if point.parameter == 'rtgNormalCategory': + capabilities.rtgNormalCategory = m.RtgNormalCategoryType( + dateTime=server_time, value=self.rtgNormalCategory) + + if point.parameter == 'rtgOverExcitedPF': + capabilities.rtgOverExcitedPF = m.PowerFactor(multiplier=point.multiplier, + value=self.rtgOverExcitedPF) + + if point.parameter == 'rtgOverExcitedW': + capabilities.rtgOverExcitedW = m.ActivePower(multiplier=point.multiplier, + value=self.rtgOverExcitedW) + + if point.parameter == 'rtgReactiveSusceptance': + capabilities.rtgReactiveSusceptance = m.ReactiveSusceptance( + multiplier=point.multiplier, value=self.rtgReactiveSusceptance) + + if point.parameter == 'rtgUnderExcitedPF': + capabilities.rtgUnderExcitedPF = m.PowerFactor(multiplier=point.multiplier, + value=self.rtgUnderExcitedPF) + + if point.parameter == 'rtgUnderExcitedW': + capabilities.rtgUnderExcitedW = m.ActivePower(multiplier=point.multiplier, + value=self.rtgUnderExcitedW) + + if point.parameter == 'rtgVNom': + capabilities.rtgVNom = m.VoltageRMS(multiplier=point.multiplier, + value=self.rtgVNom) + + if point.parameter == 'type': + capabilities.type = m.DERTypeType(dateTime=server_time, value=self.type) + + return capabilities + + def _data_published(self, peer, sender, bus, topic, headers, message): + """ + Callback triggered by the device_topic setup using the topic from the agent's config file + """ + _log.debug(f'DATA Received from {sender}') + points = AllPoints.frombus(message) + + current_timestamp: datetime = utils.parse_timestamp_string(headers.get('TimeStamp')) + parent_objects: Dict[type, List[MappedPoint]] = {} + transforms = { + m.DERSettings: (self._transform_settings, self._client.put_der_settings), + m.DERCapability: (self._transform_capabilities, self._client.put_der_capability), + m.DERStatus: (self._transform_status, self._client.put_der_status) + } + + for obj_type in transforms.keys(): + # Create a list of properties that are for each of the types. + parent_objects[obj_type] = list( + filter(lambda x: isinstance(x.parent_object, obj_type), + self._mapped_points.values())) + + # Make sure that there is some points to update. + if parent_objects[obj_type]: + list( + map(lambda x: x.set_value(points.get(x.point_on_bus)), + parent_objects[obj_type])) + + # Do the transform from simple int/floats to complex objects. + sendable = transforms[obj_type][0](parent_objects[obj_type]) + if sendable: + # Send the data to the server. + transforms[obj_type][1](sendable) + + for mp in self._mapped_points.values(): + mp.reset_changed() + + for index, pt in enumerate(self._mirror_usage_point_list): + if pt['device_point'] in points.points: + reading_mRID = pt['MirrorMeterReading']['mRID'] + reading = self._mup_readings[reading_mRID] + for rs_index, rs in enumerate(reading.MirrorReadingSet): + rs = reading.MirrorReadingSet[rs_index] + rs.Reading.append( + m.Reading(timePeriod=m.DateTimeInterval( + start=int(current_timestamp.timestamp())), + value=points.points[pt['device_point']])) + start = rs.timePeriod.start + if start + self._mup_pollRate < self._client.server_time: + self._times_published[reading_mRID] = self._times_published.get( + reading_mRID, 0) + 1 + rs.mRID = '_'.join( + [reading_mRID, str(self._times_published[reading_mRID])]) + + new_reading_href = self._client.post_mirror_reading(reading) + _log.info( + f'New readings({len(rs.Reading)}) posted available at: {new_reading_href}' + ) + rs.Reading.clear() + rs.timePeriod.start = self._client.server_time + rs.timePeriod.duration = self._mup_pollRate + + +def main(): + """ + Main method called during startup of agent. + :return: + """ + try: + vip_main(IEEE_2030_5_Agent, version=__version__) + except Exception as e: + _log.exception('unhandled exception') + + +if __name__ == '__main__': + # Entry point for script + try: + sys.exit(main()) + except KeyboardInterrupt: + pass diff --git a/services/core/IEEE_2030_5/ieee_2030_5/client.py b/services/core/IEEE_2030_5/ieee_2030_5/client.py new file mode 100644 index 0000000000..a3c7b3396c --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/client.py @@ -0,0 +1,764 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +from __future__ import annotations + +import atexit +import http +import logging +import ssl +import subprocess +import threading +import time +import xml.dom.minidom +from dataclasses import dataclass, field +from datetime import datetime +from http.client import HTTPMessage, HTTPSConnection, CannotSendRequest +from os import PathLike +from pathlib import Path +from threading import Semaphore, Timer +from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union +from uuid import uuid4 +import gevent + +import ieee_2030_5.models as m +import xsdata +from blinker import Signal +from ieee_2030_5 import dataclass_to_xml, xml_to_dataclass + +_log = logging.getLogger(__name__) +_log_req_resp = logging.getLogger(f'{__name__}.req_resp') + +TimeType = int +StrPath = Union[str, Path] + + +@dataclass +class TimerSpec: + trigger_after_seconds: int + fn: Callable + args: List = field(default_factory=list) + kwargs: Dict = field(default_factory=dict) + enabled: bool = True + trigger_count: int = 0 + last_trigger_time: int = int(time.mktime(datetime.utcnow().timetuple())) + + def disable(self): + self.enabled = False + + def enable(self): + self.enabled = True + + def reset_count(self): + self.trigger_count = 0 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, TimerSpec): + raise NotImplementedError( + f'Comparison between {self.__class__.__name__} and {type(other)} not implemented') + return self.fn is other.fn + + def trigger(self, current_time: int): + if self.last_trigger_time + self.trigger_after_seconds < current_time: + if self.args and self.kwargs: + self.fn(args=self.args, kwargs=self.kwargs) + elif self.args: + self.fn(args=self.args) + else: + self.fn() + self.trigger_count += 1 + self.last_trigger_time = current_time + + +class _TimerThread(gevent.Greenlet): + tick = Signal('tick') + + def __init__(self): + super().__init__() + self._tick = 0 + + @staticmethod + def user_readable(timestamp: int): + dt = datetime.fromtimestamp(timestamp) + return dt.strftime('%m/%d/%Y, %H:%M:%S') + + def run(self) -> None: + + while True: + self._tick = int(time.mktime(datetime.utcnow().timetuple())) + _TimerThread.tick.send(self._tick) + time.sleep(1) + + +TimerThread = _TimerThread() +TimerThread.daemon = True +TimerThread.start() + + +class IEEE2030_5_Client: + clients: set[IEEE2030_5_Client] = set() + + # noinspection PyUnresolvedReferences + def __init__(self, + cafile: StrPath, + server_hostname: str, + keyfile: StrPath, + certfile: StrPath, + pin: str, + server_ssl_port: Optional[int] = 443, + debug: bool = True, + device_capabilities_endpoint: str = '/dcap', + log_req_resp: bool = True): + + self._cafile: Path = cafile if isinstance(cafile, Path) else Path(cafile) + self._keyfile: Path = keyfile if isinstance(keyfile, Path) else Path(keyfile) + self._certfile: Path = certfile if isinstance(certfile, Path) else Path(certfile) + + self._pin = pin + + # We know that these are Path objects now and have a .exists() function based upon above code. + assert self._cafile.exists( + ), f"cafile doesn't exist ({cafile})" # type: ignore[attr-defined] + assert self._keyfile.exists( + ), f"keyfile doesn't exist ({keyfile})" # type: ignore[attr-defined] + assert self._certfile.exists( + ), f"certfile doesn't exist ({certfile})" # type: ignore[attr-defined] + + self._ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + self._ssl_context.check_hostname = False + self._ssl_context.verify_mode = ssl.CERT_REQUIRED + self._ssl_context.load_verify_locations(cafile=cafile) + + # Loads client information from the passed cert and key files. For + # client side validation. + self._ssl_context.load_cert_chain(certfile=certfile, keyfile=keyfile) + + self._http_conn = HTTPSConnection(host=server_hostname, + port=server_ssl_port, + context=self._ssl_context) + self._response_headers: HTTPMessage + self._response_status = None + self._debug = debug + self._debug = log_req_resp + if not self._debug: + _log_req_resp.setLevel(logging.WARNING) + + self._mup: m.MirrorUsagePointList = None # type: ignore + self._upt: m.UsagePointList = None # type: ignore + + self._dcap_poll_rate: int = 0 + self._dcap_timer: Optional[Timer] = None + self._disconnect: bool = False + + self._timer_specs: Dict[str, TimerSpec] = {} + + # Offset between local udt and server udt + self._time_offset: int = 0 + + self._end_device_map: Dict[str, m.EndDeviceList] = {} + self._end_devices: Dict[str, m.EndDevice] = {} + + self._fsa_map: Dict[str, m.FunctionSetAssignmentsList] = {} + self._fsa: Dict[str, m.FunctionSetAssignments] = {} + + self._der_map: Dict[str, m.DERList] = {} + self._der: Dict[str, m.DER] = {} + + self._der_program_map: Dict[str, m.DERProgramList] = {} + self._der_program: Dict[str, m.DERProgram] = {} + + self._mirror_usage_point_map: Dict[str, m.MirrorUsagePointList] = {} + self._mirror_usage_point: Dict[str, m.MirrorUsagePoint] = {} + + self._usage_point_map: Dict[str, m.UsagePointList] = {} + self._usage_point: Dict[str, m.UsagePoint] = {} + + self._before_dcap_update_signal = Signal('before-dcap-request') + self._after_dcap_update_signal = Signal('before-dcap-request') + self._before_client_start_signal = Signal('before-client-start') + self._after_client_start_signal = Signal('after-client-start') + + self._der_control_event_started_signal = Signal('der-control-event-started') + self._der_control_event_ended_signal = Signal('der-control-event-ended') + + self._default_control_changed = Signal('default-control-changed') + + self._dcap_endpoint = device_capabilities_endpoint + + self._der_default_control: m.DefaultDERControl = m.DefaultDERControl() + self._der_active_controls: m.DERControlList = m.DERControlList() + + self._config: Dict[str, Any] = {} + self._lock = Semaphore() + + IEEE2030_5_Client.clients.add(self) + + def start(self, config: Dict[str, Any]): + """Starts the client connection to the 2030.5 server configured during construction. + """ + self._config = config + self._before_client_start_signal.send(self) + self._update_dcap_tree() + self._after_client_start_signal.send(self) + TimerThread.tick.connect(self._tick) + + def _tick(self, timestamp: int): + """Handles the timer event thread for the client. + + :param timestamp: The current timestamp + :type timestamp: int + """ + if self._lock.acquire(blocking=False): + for ts in self._timer_specs.values(): + ts.trigger(timestamp) + self._lock.release() + + def der_default_control_changed(self, fun: Callable): + self._default_control_changed.connect(fun) + + def der_control_event_started(self, fun: Callable): + self._der_control_event_started_signal.connect(fun) + + def der_control_event_ended(self, fun: Callable): + self._der_control_event_ended_signal.connect(fun) + + def before_dcap_update(self, fun: Callable): + self._before_dcap_update_signal.connect(fun) + + def after_dcap_update(self, fun: Callable): + self._after_dcap_update_signal.connect(fun) + + def after_client_start(self, fun: Callable): + self._after_client_start_signal.connect(fun) + + def before_client_start(self, fun: Callable): + self._before_client_start_signal.connect(fun) + + @property + def server_time(self) -> TimeType: + """Returns the time on the server + + Uses an offset value from the 2030.5 Time function set to determine the + current time on the server. + + :return: A calculated server_time including offset from time endpoint + :rtype: TimeType + """ + return int(time.mktime(datetime.utcnow().timetuple())) + self._time_offset + + def get_der_hrefs(self) -> List[str]: + return list(self._der.keys()) + + def get_der(self, href: str) -> Optional[m.DER]: + return self._der.get(href) + + def get_der_list(self, href: Optional[str] = None) -> m.DERList: + if href is None: + href = self.enddevice.DERListLink.href + resp = self.__get_request__(href) + return self._der_map.get(href) + + def put_der_availability(self, der_href: str, new_availability: m.DERAvailability) -> int: + resp = self.__put__(der_href, dataclass_to_xml(new_availability)) + return resp.status + + def put_der_capability(self, new_capability: m.DERCapability) -> int: + resp = self.__put__( + list(self._der.values())[0].DERCapabilityLink, dataclass_to_xml(new_capability)) + return resp.status + + def put_der_settings(self, new_settings: m.DERSettings) -> int: + resp = self.__put__( + list(self._der.values())[0].DERSettingsLink.href, dataclass_to_xml(new_settings)) + return resp.status + + def put_der_status(self, new_status: m.DERStatus) -> int: + if not isinstance(new_status.operationalModeStatus, m.OperationalModeStatusType): + new_status.operationalModeStatus = m.OperationalModeStatusType( + self.server_time, value=new_status.operationalModeStatus) + + resp = self.__put__( + list(self._der.values())[0].DERStatusLink.href, dataclass_to_xml(new_status)) + return resp.status + + def _send_control_events(self, der_program_href: str): + # Need to check this every 10 seconds for updates to conttrols + program: m.DERProgram = self.__get_request__(der_program_href) + + active: m.DERControlList = self.__get_request__(program.ActiveDERControlListLink.href) + default = self.__get_request__(program.DefaultDERControlLink.href) + active_is_different = False + + to_add = [] + for newderctl in active.DERControl: + found = False + for existingctl in self._der_active_controls.DERControl: + if existingctl.mRID == newderctl.mRID: + found = True + if existingctl == newderctl: + _log.debug(f'Currently in event {newderctl.mRID}') + else: + _log.debug( + 'TODO ->>>>>>>>>>>>>>>>>>>>>>>>>>> Existing mRID should superscede????' + ) + break + if not found: + to_add.append(newderctl) + + for ctrl in to_add: + self._der_control_event_started_signal.send(ctrl) + + to_remove = [] + for existingctl in self._der_active_controls.DERControl: + found = False + for newctrl in active.DERControl: + if newctrl.mRID == existingctl.mRID: + found = True + break + if not found: + to_remove.append(existingctl) + + i = len(self._der_active_controls.DERControl) + while i > 0: + i -= 1 + if self._der_active_controls.DERControl[i] in to_remove: + self._der_control_event_ended_signal.send(self._der_active_controls.DERControl[i]) + self._der_active_controls.DERControl.pop(i) + + self._der_active_controls = active + + if default != self._der_default_control: + self._der_default_control = default + _log.debug('Default control changed....') + self._default_control_changed.send(default) + + # Poll every 60 if default otherwise use setting in config file. + refresh_time = self._config.get('default_der_control_poll', 60) + self._update_timer_spec('der_control_event', + refresh_time, + fn=lambda: self._send_control_events(der_program_href)) + + def _update_dcap_tree(self, endpoint: Optional[str] = None): + """Retrieve device capability + + :param endpoint: _description_, defaults to None + :type endpoint: Optional[str], optional + :raises ValueError: _description_ + :raises RuntimeError: _description_ + :raises ValueError: _description_ + """ + if not endpoint: + endpoint = self._dcap_endpoint + if not endpoint: + raise ValueError('Invalid device_capability_endpoint specified in constructor.') + + self._before_dcap_update_signal.send(self) + + # retrieve device capabilities from the server + dcap: m.DeviceCapability = self.__get_request__(endpoint) + if self._response_status != 200: + raise RuntimeError(dcap) + + self._after_dcap_update_signal.send(self) + + if dcap.pollRate is None: + dcap.pollRate = 900 + + if dcap.EndDeviceListLink is None or dcap.EndDeviceListLink.all == 0: + raise ValueError("Couldn't receive end device model from server. " + 'Check certificates or server configuration.') + + # if time is available then grab and create an offset + if dcap.TimeLink is not None and dcap.TimeLink.href: + _time: m.Time = self.__get_request__(dcap.TimeLink.href) + self._time_offset = int(time.mktime(datetime.utcnow().timetuple())) - _time.currentTime + + if dcap.EndDeviceListLink is not None and dcap.EndDeviceListLink.all > 0: + + self._update_list(dcap.EndDeviceListLink.href, 'EndDevice', self._end_device_map, + self._end_devices) + + for ed in self._end_devices.values(): + + if not self.is_end_device_registered(ed, self._pin): + raise ValueError(f'Device is not registered on this server!') + self._update_list(ed.FunctionSetAssignmentsListLink.href, 'FunctionSetAssignments', + self._fsa_map, self._fsa) + + if ed.DERListLink: + derlist: m.DERList = self.__get_request__(ed.DERListLink.href) + self._der_map[derlist.href] = derlist + for index, der in enumerate(derlist.DER): + self._der[der.href] = der + + if derlist.DER[0].CurrentDERProgramLink: + self._send_control_events(derlist.DER[0].CurrentDERProgramLink.href) + + for fsa in self._fsa.values(): + if fsa.DERProgramListLink: + self._der_program_map[fsa.DERProgramListLink.href] = self.__get_request__( + fsa.DERProgramListLink.href) + program = self._der_program_map[fsa.DERProgramListLink.href] + + if dcap.MirrorUsagePointListLink is not None and dcap.MirrorUsagePointListLink.href: + self._update_list(dcap.MirrorUsagePointListLink.href, 'MirrorUsagePoint', + self._mirror_usage_point_map, self._mirror_usage_point) + + self._dcap = dcap + self._update_timer_spec('dcap', dcap.pollRate, self._update_dcap_tree) + + def _update_timer_spec(self, spec_name: str, rate: int, fn: Callable, *args, **kwargs): + ts = self._timer_specs.get(spec_name) + if ts is None: + ts = self._timer_specs[spec_name] = TimerSpec(rate, fn, args, kwargs) + ts.trigger_after_seconds = rate + + def post_log_event(self, end_device: m.EndDevice, log_event: m.LogEvent): + if not log_event.createdDateTime: + log_event.createdDateTime = self.server_time + + self.request(end_device.LogEventListLink.href, method='POST') + + def _update_list(self, path: str, list_prop: str, outer_map: Dict, inner_map: Dict): + """Update mappings using 2030.5 list nomoclature. + + Example structure for EndDeviceListLink + + EndDeviceListLink.href points to EndDeviceList. + EndDeviceList.EndDevice points to a list of EndDevice objects. + + Args: + + path: Original path of the list (in example EndDeviceListLink.href) + list_prop: The property on the object that holds a list of elements (in example EndDevice) + outer_mapping: Mapping where the original list object is stored by href + inner_mapping: Mapping where the inner objects are stored by href + + """ + my_response = self.__get_request__(path) + + if self._response_status != 200: + raise RuntimeError(my_response) + + if my_response is not None: + href = getattr(my_response, 'href') + outer_map[href] = my_response + for inner in getattr(my_response, list_prop): + href = getattr(inner, 'href') + inner_map[href] = inner + + def _get_device_capabilities(self, endpoint: str) -> m.DeviceCapability: + dcap: m.DeviceCapability = self.__get_request__(endpoint) + if self._response_status != 200: + raise RuntimeError(dcap) + + self._dcap = dcap + + if self._device_cap.pollRate is not None: + self._dcap_poll_rate = self._device_cap.pollRate + else: + self._dcap_poll_rate = 600 + + self._dcap_timer = Timer(self._dcap_poll_rate, self.poll_timer, + (self.device_capability, url)) + self._dcap_timer.start() + + return self._device_cap + + @property + def lfdi(self) -> str: + cmd = ['openssl', 'x509', '-in', str(self._certfile), '-noout', '-fingerprint', '-sha256'] + ret_value = subprocess.check_output(cmd, text=True) + if '=' in ret_value: + ret_value = ret_value.split('=')[1].strip() + + fp = ret_value.replace(':', '') + lfdi = fp[:40] + return lfdi + + @property + def http_conn(self) -> HTTPSConnection: + if self._http_conn.sock is None: + self._http_conn.connect() + return self._http_conn + + @property + def enddevices(self) -> m.EndDeviceList: + return self._end_devices + + @property + def enddevice(self, href: str = '') -> m.EndDevice: + """Retrieve a client's end device based upon the href of the end device. + + Args: + + href: If "" then in single client mode and return the only end device available. + """ + if not href: + href = list(self._end_devices.keys())[0] + + end_device = self._end_devices.get(href) + + return end_device + + def __hash__(self) -> int: + return self._keyfile.read_text().__hash__() # type: ignore[attr-defined] + + def is_end_device_registered(self, end_device: m.EndDevice, pin: int) -> bool: + reg = self.registration(end_device) + return reg.pIN == self._pin + + def new_uuid(self, url: str = '/uuid') -> str: + res = self.__get_request__(url) + return res + + def get_enddevices(self) -> m.EndDeviceList: + return self.__get_request__(self._device_cap.EndDeviceListLink.href) + + def end_device(self, index: Optional[int] = 0) -> m.EndDevice: + if not self._end_devices: + self.end_devices() + + return self._end_devices.EndDevice[index] + + def self_device(self) -> m.EndDevice: + if not self._device_cap: + self.device_capability() + + return self.__get_request__(self._device_cap.SelfDeviceLink.href) + + def function_set_assignment(self) -> m.FunctionSetAssignmentsListLink: + fsa_list = self.__get_request__(self.end_device().FunctionSetAssignmentsListLink.href) + return fsa_list + + def poll_timer(self, fn, args): + if not self._disconnect: + _log.debug(threading.currentThread().name) + fn(args) + threading.currentThread().join() + + def device_capability(self, url: str = '/dcap') -> m.DeviceCapability: + self._device_cap: m.DeviceCapability = self.__get_request__(url) + if self._device_cap.pollRate is not None: + self._dcap_poll_rate = self._device_cap.pollRate + else: + self._dcap_poll_rate = 600 + + _log.debug(f'devcap id {id(self._device_cap)}') + _log.debug(threading.currentThread().name) + _log.debug(f'DCAP: Poll rate: {self._dcap_poll_rate}') + self._dcap_timer = Timer(self._dcap_poll_rate, self.poll_timer, + (self.device_capability, url)) + self._dcap_timer.start() + + return self._device_cap + + def time(self) -> m.Time: + timexml = self.__get_request__(self._device_cap.TimeLink.href) + return timexml + + def der_program_list(self, device: m.EndDevice) -> m.DERProgramList: + fsa: m.FunctionSetAssignments = self.__get_request__( + device.FunctionSetAssignmentsListLink.href) + der_programs_list: m.DERProgramList = self.__get_request__(fsa.DERProgramListLink.href) + + return der_programs_list + + def post_mirror_reading(self, reading: m.MirrorMeterReading) -> str: + data = dataclass_to_xml(reading) + resp = self.__post__(reading.href, data=data) + + if not int(resp.status) >= 200 and int(resp.status) < 300: + _log.error(f'Posting to {reading.href}') + _log.error(f'Response status: {resp.status}') + _log.error(f"{resp.read().decode('utf-8')}") + + return resp.headers['Location'] + + def mirror_usage_point_list(self) -> m.MirrorUsagePointList: + mupl = self._mirror_usage_point_map.get(self._dcap.MirrorUsagePointListLink.href) + + return mupl + + def usage_point_list(self) -> m.UsagePointList: + self._upt = self.__get_request__(self._device_cap.UsagePointListLink.href) + return self._upt + + def registration(self, end_device: m.EndDevice) -> m.Registration: + reg = self.__get_request__(end_device.RegistrationLink.href) + return reg + + def timelink(self): + if self._device_cap is None: + raise ValueError('Request device capability first') + return self.__get_request__(url=self._device_cap.TimeLink.href) + + def disconnect(self): + self._disconnect = True + self._dcap_timer.cancel() + IEEE2030_5_Client.clients.remove(self) + + def request(self, endpoint: str, body: dict = {}, method: str = 'GET', headers: dict = {}): + + if method.upper() == 'GET': + return self.__get_request__(endpoint, body, headers=headers) + + if method.upper() == 'POST': + return self.__post__(endpoint, body, headers=headers) + + def create_mirror_usage_point(self, mirror_usage_point: m.MirrorUsagePoint) -> str: + """Create a new mirror usage point on the server. + + Args: + + mirror_usage_point: Minimal type for MirrorUsagePoint + + Return: + + The location of the new usage point href for posting to. + """ + data = dataclass_to_xml(mirror_usage_point) + resp = self.__post__(self._dcap.MirrorUsagePointListLink.href, data=data) + return resp.headers['Location'] + + def __put__(self, url: str, data: Any, headers: Optional[Dict[str, str]] = None): + if not headers: + headers = {'Content-Type': 'text/xml'} + + if self._debug: + _log_req_resp.debug(f'----> PUT REQUEST\nurl: {url}\nbody: {data}') + + try: + self.http_conn.request(method='PUT', headers=headers, url=url, body=data) + except http.client.CannotSendRequest as ex: + self.http_conn.close() + _log.debug('Reconnecting to server') + self.http_conn.request(method='PUT', headers=headers, url=url, body=data) + + response = self._http_conn.getresponse() + return response + + def __post__(self, url: str, data=None, headers: Optional[Dict[str, str]] = None): + if not headers: + headers = {'Content-Type': 'text/xml'} + + if self._debug: + _log_req_resp.debug(f'----> POST REQUEST\nurl: {url}\nbody: {data}') + + self.http_conn.request(method='POST', headers=headers, url=url, body=data) + response = self._http_conn.getresponse() + response_data = response.read().decode('utf-8') + # response_data = response.read().decode("utf-8") + if response_data and self._debug: + _log_req_resp.debug(f'<---- POST RESPONSE\n{response_data}') + + return response + + def __get_request__(self, url: str, body=None, headers: Optional[Dict] = None): + if headers is None: + headers = {'Connection': 'keep-alive', 'keep-alive': 'timeout=30, max=1000'} + + if self._debug: + _log_req_resp.debug(f'----> GET REQUEST\nurl: {url}\nbody: {body}') + try: + self.http_conn.request(method='GET', url=url, body=body, headers=headers) + except http.client.CannotSendRequest as ex: + self.http_conn.close() + _log.debug('Reconnecting to server') + self.http_conn.request(method='GET', url=url, body=body, headers=headers) + + response = self._http_conn.getresponse() + response_data = response.read().decode('utf-8') + self._response_headers = response.headers + self._response_status = response.status + + response_obj = None + try: + response_obj = xml_to_dataclass(response_data) + resp_xml = xml.dom.minidom.parseString(response_data) + if resp_xml and self._debug: + _log_req_resp.debug(f'<---- GET RESPONSE\n{response_data}') # toprettyxml()}") + + except xsdata.exceptions.ParserError as ex: + if self._debug: + _log_req_resp.debug('<---- GET RESPONSE\n{response_data}') + response_obj = response_data + + return response_obj + + def __close__(self): + self._http_conn.close() + self._ssl_context = None + self._http_conn = None + + +# noinspection PyTypeChecker +def __release_clients__(): + for x in IEEE2030_5_Client.clients: + x.__close__() + IEEE2030_5_Client.clients = None + + +atexit.register(__release_clients__) + +# if __name__ == '__main__': +# SERVER_CA_CERT = Path("~/tls/certs/ca.crt").expanduser().resolve() +# KEY_FILE = Path("~/tls/private/dev1.pem").expanduser().resolve() +# CERT_FILE = Path("~/tls/certs/dev1.crt").expanduser().resolve() + + # headers = {'Connection': 'Keep-Alive', 'Keep-Alive': "max=1000,timeout=30"} + + # h = IEEE_2030_5_Client(cafile=SERVER_CA_CERT, + # server_hostname="127.0.0.1", + # server_ssl_port=8070, + # keyfile=KEY_FILE, + # certfile=CERT_FILE, + # debug=True) + # # h2 = IEEE2030_5_Client(cafile=SERVER_CA_CERT, server_hostname="me.com", ssl_port=8000, + # # keyfile=KEY_FILE, certfile=KEY_FILE) + # dcap = h.device_capability() + # end_devices = h.end_devices() + + # if not end_devices.all > 0: + # print("registering end device.") + # ed_href = h.register_end_device() + # my_ed = h.end_devices() + + # # ed = h.end_devices()[0] + # # resp = h.request("/dcap", headers=headers) + # # print(resp) + # # resp = h.request("/dcap", headers=headers) + # # print(resp) + # #dcap = h.device_capability() + # # get device list + # #dev_list = h.request(dcap.EndDeviceListLink.href).EndDevice + + # #ed = h.request(dev_list[0].href) + # #print(ed) + # # + # # print(dcap.mirror_usage_point_list_link) + # # # print(h.request(dcap.mirror_usage_point_list_link.href)) + # # print(h.request("/dcap", method="post")) + + # # tl = h.timelink() + # #print(IEEE2030_5_Client.clients) diff --git a/services/core/IEEE_2030_5/ieee_2030_5/models/Config.py b/services/core/IEEE_2030_5/ieee_2030_5/models/Config.py new file mode 100644 index 0000000000..8eab0106f1 --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/models/Config.py @@ -0,0 +1,336 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +from __future__ import annotations +from dataclasses import dataclass, field +from typing import List, Optional + +__NAMESPACE__ = 'http://pypi.org/project/xsdata' + + +@dataclass +class TypeName: + + class Meta: + name = 'ClassName' + namespace = 'http://pypi.org/project/xsdata' + + case: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + safePrefix: Optional[str] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class CompoundFields: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + defaultName: Optional[str] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + forceDefaultName: Optional[bool] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + value: Optional[bool] = field(default=None, metadata={ + 'required': True, + }) + + +@dataclass +class ConstantName: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + case: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + safePrefix: Optional[str] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class FieldName: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + case: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + safePrefix: Optional[str] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class Format: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + repr: Optional[bool] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + eq: Optional[bool] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + order: Optional[bool] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + unsafeHash: Optional[bool] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + frozen: Optional[bool] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + slots: Optional[bool] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + kwOnly: Optional[bool] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + value: str = field(default='', metadata={ + 'required': True, + }) + + +@dataclass +class ModuleName: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + case: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + safePrefix: Optional[str] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class PackageName: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + case: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + safePrefix: Optional[str] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class Substitution: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + type_value: Optional[str] = field(default=None, + metadata={ + 'name': 'type', + 'type': 'Attribute', + 'required': True, + }) + search: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + replace: Optional[str] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class Conventions: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + ClassName: Optional[TypeName] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + FieldName: Optional[FieldName] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + ConstantName: Optional[ConstantName] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + ModuleName: Optional[ModuleName] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + PackageName: Optional[PackageName] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class Output: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + maxLineLength: Optional[int] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + Package: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + Format: Optional[Format] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + Structure: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + DocstringStyle: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + FilterStrategy: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + RelativeImports: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + CompoundFields: Optional[CompoundFields] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + PostponedAnnotations: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + UnnestClasses: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + IgnorePatterns: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class Substitutions: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + Substitution: List[Substitution] = field(default_factory=list, + metadata={ + 'type': 'Element', + 'min_occurs': 1, + }) + + +@dataclass +class Config: + + class Meta: + namespace = 'http://pypi.org/project/xsdata' + + version: Optional[float] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + Output: Optional[Output] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + Conventions: Optional[Conventions] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + Substitutions: Optional[Substitutions] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) diff --git a/services/core/IEEE_2030_5/ieee_2030_5/models/__init__.py b/services/core/IEEE_2030_5/ieee_2030_5/models/__init__.py new file mode 100644 index 0000000000..a6800cc1cc --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/models/__init__.py @@ -0,0 +1,394 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +from ieee_2030_5.models.enums import CurveType, DeviceCategoryType, PrimacyType +from ieee_2030_5.models.Config import ( + TypeName, + CompoundFields, + Config, + ConstantName, + Conventions, + FieldName, + Format, + ModuleName, + Output, + PackageName, + Substitution, + Substitutions, +) +from ieee_2030_5.models.enums import CurveType, DeviceCategoryType, PrimacyType +from ieee_2030_5.models.sep import ( + DER, IEEE_802_15_4, AbstractDevice, AccountBalance, AccountBalanceLink, AccountingUnit, + ActiveBillingPeriodListLink, ActiveCreditRegisterListLink, ActiveDERControlListLink, + ActiveEndDeviceControlListLink, ActiveFlowReservationListLink, ActivePower, + ActiveProjectionReadingListLink, ActiveSupplyInterruptionOverrideListLink, + ActiveTargetReadingListLink, ActiveTextMessageListLink, ActiveTimeTariffIntervalListLink, + AmpereHour, ApparentPower, ApplianceLoadReduction, AppliedTargetReduction, + AssociatedDERProgramListLink, AssociatedUsagePointLink, BillingMeterReadingBase, BillingPeriod, + BillingPeriodList, BillingPeriodListLink, BillingReading, BillingReadingList, + BillingReadingListLink, BillingReadingSet, BillingReadingSetList, BillingReadingSetListLink, + Charge, Condition, Configuration, ConfigurationLink, ConnectStatusType, + ConsumptionTariffInterval, ConsumptionTariffIntervalList, ConsumptionTariffIntervalListLink, + CreditRegister, CreditRegisterList, CreditRegisterListLink, CreditTypeChange, + CurrentDERProgramLink, CurrentRMS, CurveData, CustomerAccount, CustomerAccountLink, + CustomerAccountList, CustomerAccountListLink, CustomerAgreement, CustomerAgreementList, + CustomerAgreementListLink, DateTimeInterval, DefaultDERControl, DefaultDERControlLink, + DemandResponseProgram, DemandResponseProgramLink, DemandResponseProgramList, + DemandResponseProgramListLink, DERAvailability, DERAvailabilityLink, DERCapability, + DERCapabilityLink, DERControl, DERControlBase, DERControlList, DERControlListLink, + DERControlResponse, DERCurve, DERCurveLink, DERCurveList, DERCurveListLink, DERLink, DERList, + DERListLink, DERProgram, DERProgramLink, DERProgramList, DERProgramListLink, DERSettings, + DERSettingsLink, DERStatus, DERStatusLink, DeviceCapability, DeviceCapabilityLink, + DeviceInformation, DeviceInformationLink, DeviceStatus, DeviceStatusLink, DRLCCapabilities, + DrResponse, DutyCycle, EndDevice, EndDeviceControl, EndDeviceControlList, + EndDeviceControlListLink, EndDeviceLink, EndDeviceList, EndDeviceListLink, EnvironmentalCost, + Error, Event, EventStatus, File, FileLink, FileList, FileListLink, FileStatus, FileStatusLink, + FixedPointType, FixedVar, FlowReservationRequest, FlowReservationRequestList, + FlowReservationRequestListLink, FlowReservationResponse, FlowReservationResponseList, + FlowReservationResponseListLink, FlowReservationResponseResponse, FreqDroopType, + FunctionSetAssignments, FunctionSetAssignmentsBase, FunctionSetAssignmentsList, + FunctionSetAssignmentsListLink, GPSLocationType, HistoricalReading, HistoricalReadingList, + HistoricalReadingListLink, IdentifiedObject, InverterStatusType, IPAddr, IPAddrList, + IPAddrListLink, IPInterface, IPInterfaceList, IPInterfaceListLink, Link, List_type, ListLink, + LLInterface, LLInterfaceList, LLInterfaceListLink, LoadShedAvailability, + LoadShedAvailabilityList, LoadShedAvailabilityListLink, LocalControlModeStatusType, LogEvent, + LogEventList, LogEventListLink, ManufacturerStatusType, MessagingProgram, MessagingProgramList, + MessagingProgramListLink, MeterReading, MeterReadingBase, MeterReadingLink, MeterReadingList, + MeterReadingListLink, MirrorMeterReading, MirrorMeterReadingList, MirrorReadingSet, + MirrorUsagePoint, MirrorUsagePointList, MirrorUsagePointListLink, Neighbor, NeighborList, + NeighborListLink, Notification, NotificationList, NotificationListLink, Offset, + OperationalModeStatusType, PEVInfo, PowerConfiguration, PowerFactor, PowerFactorWithExcitation, + PowerStatus, PowerStatusLink, Prepayment, PrepaymentLink, PrepaymentList, PrepaymentListLink, + PrepayOperationStatus, PrepayOperationStatusLink, PriceResponse, PriceResponseCfg, + PriceResponseCfgList, PriceResponseCfgListLink, ProjectionReading, ProjectionReadingList, + ProjectionReadingListLink, RandomizableEvent, RateComponent, RateComponentLink, + RateComponentList, RateComponentListLink, ReactivePower, ReactiveSusceptance, Reading, + ReadingBase, ReadingLink, ReadingList, ReadingListLink, ReadingSet, ReadingSetBase, + ReadingSetList, ReadingSetListLink, ReadingType, ReadingTypeLink, RealEnergy, Registration, + RegistrationLink, RequestStatus, Resource, RespondableIdentifiedObject, RespondableResource, + RespondableSubscribableIdentifiedObject, Response, ResponseList, ResponseListLink, ResponseSet, + ResponseSetList, ResponseSetListLink, RPLInstance, RPLInstanceList, RPLInstanceListLink, + RPLSourceRoutes, RPLSourceRoutesList, RPLSourceRoutesListLink, SelfDevice, SelfDeviceLink, + ServiceChange, ServiceSupplier, ServiceSupplierLink, ServiceSupplierList, SetPoint, + SignedRealEnergy, StateOfChargeStatusType, StorageModeStatusType, SubscribableIdentifiedObject, + SubscribableList, SubscribableResource, Subscription, SubscriptionBase, SubscriptionList, + SubscriptionListLink, SupplyInterruptionOverride, SupplyInterruptionOverrideList, + SupplyInterruptionOverrideListLink, SupportedLocale, SupportedLocaleList, + SupportedLocaleListLink, TargetReading, TargetReadingList, TargetReadingListLink, + TargetReduction, TariffProfile, TariffProfileLink, TariffProfileList, TariffProfileListLink, + Temperature, TextMessage, TextMessageList, TextMessageListLink, TextResponse, Time, + TimeConfiguration, TimeLink, TimeTariffInterval, TimeTariffIntervalList, + TimeTariffIntervalListLink, UnitValueType, UnsignedFixedPointType, UsagePoint, UsagePointBase, + UsagePointLink, UsagePointList, UsagePointListLink, VoltageRMS, WattHour, loWPAN) + +__all__ = [ + 'ForecastNumericType', + 'ForecastParameter', + 'ForecastParameterSet', + 'ForecastParameterSetList', + 'AbstractDevice', + 'AccountBalance', + 'AccountBalanceLink', + 'AccountingUnit', + 'ActiveBillingPeriodListLink', + 'ActiveCreditRegisterListLink', + 'ActiveDERControlListLink', + 'ActiveEndDeviceControlListLink', + 'ActiveFlowReservationListLink', + 'ActivePower', + 'ActiveProjectionReadingListLink', + 'ActiveSupplyInterruptionOverrideListLink', + 'ActiveTargetReadingListLink', + 'ActiveTextMessageListLink', + 'ActiveTimeTariffIntervalListLink', + 'AmpereHour', + 'ApparentPower', + 'ApplianceLoadReduction', + 'AppliedTargetReduction', + 'AssociatedDERProgramListLink', + 'AssociatedUsagePointLink', + 'BillingMeterReadingBase', + 'BillingPeriod', + 'BillingPeriodList', + 'BillingPeriodListLink', + 'BillingReading', + 'BillingReadingList', + 'BillingReadingListLink', + 'BillingReadingSet', + 'BillingReadingSetList', + 'BillingReadingSetListLink', + 'Charge', + 'Condition', + 'Configuration', + 'ConfigurationLink', + 'ConnectStatusType', + 'ConsumptionTariffInterval', + 'ConsumptionTariffIntervalList', + 'ConsumptionTariffIntervalListLink', + 'CreditRegister', + 'CreditRegisterList', + 'CreditRegisterListLink', + 'CreditTypeChange', + 'CurrentDERProgramLink', + 'CurrentRMS', + 'CurveData', + 'CurveType', + 'CustomerAccount', + 'CustomerAccountLink', + 'CustomerAccountList', + 'CustomerAccountListLink', + 'CustomerAgreement', + 'CustomerAgreementList', + 'CustomerAgreementListLink', + 'DER', + 'DERAvailability', + 'DERAvailabilityLink', + 'DERCapability', + 'DERCapabilityLink', + 'DERControl', + 'DERControlBase', + 'DERControlList', + 'DERControlListLink', + 'DERControlResponse', + 'DERCurve', + 'DERCurveLink', + 'DERCurveList', + 'DERCurveListLink', + 'DERLink', + 'DERList', + 'DERListLink', + 'DERProgram', + 'DERProgramLink', + 'DERProgramList', + 'DERProgramListLink', + 'DERSettings', + 'DERSettingsLink', + 'DERStatus', + 'DERStatusLink', + 'DRLCCapabilities', + 'DateTimeInterval', + 'DefaultDERControl', + 'DefaultDERControlLink', + 'DemandResponseProgram', + 'DemandResponseProgramLink', + 'DemandResponseProgramList', + 'DemandResponseProgramListLink', + 'DeviceCapability', + 'DeviceCapabilityLink', + 'DeviceCategoryType', + 'DeviceInformation', + 'DeviceInformationLink', + 'DeviceStatus', + 'DeviceStatusLink', + 'DrResponse', + 'DutyCycle', + 'EndDevice', + 'EndDeviceControl', + 'EndDeviceControlList', + 'EndDeviceControlListLink', + 'EndDeviceLink', + 'EndDeviceList', + 'EndDeviceListLink', + 'EnvironmentalCost', + 'Error', + 'Event', + 'EventStatus', + 'File', + 'FileLink', + 'FileList', + 'FileListLink', + 'FileStatus', + 'FileStatusLink', + 'FixedPointType', + 'FixedVar', + 'FlowReservationRequest', + 'FlowReservationRequestList', + 'FlowReservationRequestListLink', + 'FlowReservationResponse', + 'FlowReservationResponseList', + 'FlowReservationResponseListLink', + 'FlowReservationResponseResponse', + 'FreqDroopType', + 'FunctionSetAssignments', + 'FunctionSetAssignmentsBase', + 'FunctionSetAssignmentsList', + 'FunctionSetAssignmentsListLink', + 'GPSLocationType', + 'HistoricalReading', + 'HistoricalReadingList', + 'HistoricalReadingListLink', + 'IEEE_802_15_4', + 'IPAddr', + 'IPAddrList', + 'IPAddrListLink', + 'IPInterface', + 'IPInterfaceList', + 'IPInterfaceListLink', + 'IdentifiedObject', + 'InverterStatusType', + 'LLInterface', + 'LLInterfaceList', + 'LLInterfaceListLink', + 'Link', + 'List_type', + 'ListLink', + 'LoadShedAvailability', + 'LoadShedAvailabilityList', + 'LoadShedAvailabilityListLink', + 'LocalControlModeStatusType', + 'LogEvent', + 'LogEventList', + 'LogEventListLink', + 'ManufacturerStatusType', + 'MessagingProgram', + 'MessagingProgramList', + 'MessagingProgramListLink', + 'MeterReading', + 'MeterReadingBase', + 'MeterReadingLink', + 'MeterReadingList', + 'MeterReadingListLink', + 'MirrorMeterReading', + 'MirrorMeterReadingList', + 'MirrorReadingSet', + 'MirrorUsagePoint', + 'MirrorUsagePointList', + 'MirrorUsagePointListLink', + 'Neighbor', + 'NeighborList', + 'NeighborListLink', + 'Notification', + 'NotificationList', + 'NotificationListLink', + 'Offset', + 'OperationalModeStatusType', + 'PEVInfo', + 'PowerConfiguration', + 'PowerFactor', + 'PowerFactorWithExcitation', + 'PowerStatus', + 'PowerStatusLink', + 'PrepayOperationStatus', + 'PrepayOperationStatusLink', + 'Prepayment', + 'PrepaymentLink', + 'PrepaymentList', + 'PrepaymentListLink', + 'PriceResponse', + 'PriceResponseCfg', + 'PriceResponseCfgList', + 'PriceResponseCfgListLink', + 'ProjectionReading', + 'ProjectionReadingList', + 'ProjectionReadingListLink', + 'RPLInstance', + 'RPLInstanceList', + 'RPLInstanceListLink', + 'RPLSourceRoutes', + 'RPLSourceRoutesList', + 'RPLSourceRoutesListLink', + 'RandomizableEvent', + 'RateComponent', + 'RateComponentLink', + 'RateComponentList', + 'RateComponentListLink', + 'ReactivePower', + 'ReactiveSusceptance', + 'Reading', + 'ReadingBase', + 'ReadingLink', + 'ReadingList', + 'ReadingListLink', + 'ReadingSet', + 'ReadingSetBase', + 'ReadingSetList', + 'ReadingSetListLink', + 'ReadingType', + 'ReadingTypeLink', + 'RealEnergy', + 'Registration', + 'RegistrationLink', + 'RequestStatus', + 'Resource', + 'RespondableIdentifiedObject', + 'RespondableResource', + 'RespondableSubscribableIdentifiedObject', + 'Response', + 'ResponseList', + 'ResponseListLink', + 'ResponseSet', + 'ResponseSetList', + 'ResponseSetListLink', + 'SelfDevice', + 'SelfDeviceLink', + 'ServiceChange', + 'ServiceSupplier', + 'ServiceSupplierLink', + 'ServiceSupplierList', + 'SetPoint', + 'SignedRealEnergy', + 'StateOfChargeStatusType', + 'StorageModeStatusType', + 'SubscribableIdentifiedObject', + 'SubscribableList', + 'SubscribableResource', + 'Subscription', + 'SubscriptionBase', + 'SubscriptionList', + 'SubscriptionListLink', + 'SupplyInterruptionOverride', + 'SupplyInterruptionOverrideList', + 'SupplyInterruptionOverrideListLink', + 'SupportedLocale', + 'SupportedLocaleList', + 'SupportedLocaleListLink', + 'TargetReading', + 'TargetReadingList', + 'TargetReadingListLink', + 'TargetReduction', + 'TariffProfile', + 'TariffProfileLink', + 'TariffProfileList', + 'TariffProfileListLink', + 'Temperature', + 'TextMessage', + 'TextMessageList', + 'TextMessageListLink', + 'TextResponse', + 'Time', + 'TimeConfiguration', + 'TimeLink', + 'TimeTariffInterval', + 'TimeTariffIntervalList', + 'TimeTariffIntervalListLink', + 'UnitValueType', + 'UnsignedFixedPointType', + 'UsagePoint', + 'UsagePointBase', + 'UsagePointLink', + 'UsagePointList', + 'UsagePointListLink', + 'VoltageRMS', + 'WattHour', + 'loWPAN', +] diff --git a/services/core/IEEE_2030_5/ieee_2030_5/models/constants.py b/services/core/IEEE_2030_5/ieee_2030_5/models/constants.py new file mode 100644 index 0000000000..b8b525e229 --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/models/constants.py @@ -0,0 +1,221 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +import enum + + +class RtgNormalCategoryType(enum.IntEnum): + not_specified = 0 + category_a = 1 + category_b = 2 + + +class RtgAbnormalCategoryType(enum.IntEnum): + not_specified = 0 + category_I = 1 + category_II = 2 + category_III = 3 + + +class DataQualifierType(enum.IntEnum): + Not_applicable = 0 + Average = 2 + Maximum = 8 + Minimum = 9 + Normal = 12 + Standard_deviation_of_population = 29 + Standard_deviation_of_sample = 30 + + +class CommodityType(enum.IntEnum): + Not_applicable = 0 + Electricity_secondary_metered = 1 + Electricity_primary_metered = 2 + Air = 4 + NaturalGas = 7 + Propane = 8 + PotableWater = 9 + Steam = 10 + WasteWater = 11 + HeatingFluid = 12 + CoolingFluid = 13 + + +class FlowDirectionType(enum.IntEnum): + Not_applicable = 0 + Forward = 1 + Reverse = 19 + + +class UomType(enum.IntEnum): + Not_applicable = 0 + Amperes = 5 + Kelvin = 6 + Degrees_celsius = 23 + Voltage = 29 + Joule = 31 + Hz = 33 + W = 38 + M_cubed = 42 + VA = 61 + VAr = 63 + CosTheta = 65 + V_squared = 67 + A_squared = 69 + VAh = 71 + Wh = 72 + VArh = 73 + Ah = 106 + Ft_cubed = 119 + Ft_cubed_per_hour = 122 + M_cubed_per_hour = 125 + US_gallons = 128 + UG_gallons_per_hour = 129 + Imperial_gallons = 130 + Imperial_gallons_per_hour = 131 + BTU = 132 + BTU_per_hour = 133 + Liter = 134 + Liter_per_hour = 137 + PA_gauge = 140 + PA_absolute = 155 + Therm = 169 + + +class RoleFlagsType(enum.Flag): + IsMirror = 0 + IsPremiseAggregationPoint = 1 + IsPEV = 2 + IsDER = 4 + IsRevenueQuality = 8 + IsDC = 16 + IsSubmeter = 32 + + +class AccumlationBehaviourType(enum.IntEnum): + Not_applicable = 0 + Cumulative = 3 + DeltaData = 4 + Indicating = 6 + Summation = 9 + Instantaneous = 12 + + +class ServiceKind(enum.IntEnum): + Electricity = 0 + Gas = 1 + Water = 2 + Time = 3 + Pressure = 4 + Heat = 5 + Cooling = 6 + + +class QualityFlagsType(enum.Flag): + Valid = 0 + Manually_edited = 1 + estimated_using_reference_day = 2 + estimated_using_linear_interpolation = 4 + questionable = 8 + derived = 16 + projected = 32 + + +# p163 +class ConsumptionBlockType(enum.IntEnum): + Not_applicable = 0 + Block_1 = 1 + Block_2 = 2 + Block_3 = 3 + Block_4 = 4 + Block_5 = 5 + Block_6 = 6 + Block_7 = 7 + Block_8 = 8 + Block_9 = 9 + Block_10 = 10 + Block_11 = 11 + Block_12 = 12 + Block_13 = 13 + Block_14 = 14 + Block_15 = 15 + Block_16 = 16 + + +# p170 +class TOUType(enum.IntEnum): + Not_applicable = 0 + TOU_A = 1 + TOU_B = 2 + TOU_C = 3 + TOU_D = 4 + TOU_E = 5 + TOU_F = 6 + TOU_G = 7 + TOU_H = 8 + TOU_I = 9 + TOU_J = 10 + TOU_K = 11 + TOU_L = 12 + TOU_M = 13 + TOU_N = 14 + TOU_O = 15 + + +class KindType(enum.IntEnum): + Not_applicable = 0 + Currency = 3 + Demand = 8 + Energy = 12 + Power = 37 + + +class PhaseCode(enum.IntEnum): + Not_applicable = 0 + Phase_C = 32 # and S2 + Phase_CN = 33 # and S2N + Phase_CA = 40 + Phase_B = 64 + Phase_BN = 65 + Phase_BC = 66 + Phase_A = 128 # and S1 + Phase_AN = 129 # and S1N + Phase_AB = 132 + Phase_ABC = 224 + + +""" Subscription/Notification +""" + + +class ResponseRequiredType(enum.Flag): + enddevice_shall_indicate_that_message_was_received = 0 + enddevice_shall_indicate_specific_response = 1 + enduser_customer_response_is_required = 2 + + +class SubscribableType(enum.IntEnum): + resource_does_not_support_subscriptions = 0 + resource_supports_non_conditional_subscriptions = 1 + resource_supports_conditional_subscriptions = 2 + resource_supports_both_conditional_and_non_conditional_subscriptions = 3 diff --git a/services/core/IEEE_2030_5/ieee_2030_5/models/enums.py b/services/core/IEEE_2030_5/ieee_2030_5/models/enums.py new file mode 100644 index 0000000000..645b7dadf3 --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/models/enums.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +from enum import IntEnum + + +class PrimacyType(IntEnum): + # Values possible for indication of "Primary" provider: + # 0: In home energy management system + # 1: Contracted premises service provider + # 2: Non-contractual service provider + # 3 - 64: Reserved + # 65 - 191: User-defined + #192 - 255: Reserved + InHomeManagementSystem = 0 + ContractedPremisesServiceProvider = 1 + NonContractualServiceProvider = 2 + + +class DERUnitRefType(IntEnum): + # 0 - N/A + # 1 - %setMaxW + # 2 - %setMaxVar + # 3 - %statVarAvail + # 4 - %setEffectiveV + # 5 - %setMaxChargeRateW + # 6 - %setMaxDischargeRateW + # 7 - %statWAvail + NA = 0 + setMaxW = 1 + setMaxVar = 2 + statVarAvail = 3 + setEffectiveV = 4 + setMaxChargeRateW = 5 + setMaxDischargeRateW = 6 + statWAvail = 7 + +class CurveType(IntEnum): + # 0 - opModFreqWatt (Frequency-Watt Curve Mode) + # 1 - opModHFRTMayTrip (High Frequency Ride Through, May Trip Mode) + # 2 - opModHFRTMustTrip (High Frequency Ride Through, Must Trip Mode) + # 3 - opModHVRTMayTrip (High Voltage Ride Through, May Trip Mode) + # 4 - opModHVRTMomentaryCessation (High Voltage Ride Through, Momentary Cessation + # Mode) + # 5 - opModHVRTMustTrip (High Voltage Ride Through, Must Trip Mode) + # 6 - opModLFRTMayTrip (Low Frequency Ride Through, May Trip Mode) + # 7 - opModLFRTMustTrip (Low Frequency Ride Through, Must Trip Mode) + # 8 - opModLVRTMayTrip (Low Voltage Ride Through, May Trip Mode) + # 9 - opModLVRTMomentaryCessation (Low Voltage Ride Through, Momentary Cessation + # Mode) + # 10 - opModLVRTMustTrip (Low Voltage Ride Through, Must Trip Mode) + # 11 - opModVoltVar (Volt-Var Mode) + # 12 - opModVoltWatt (Volt-Watt Mode) + # 13 - opModWattPF (Watt-PowerFactor Mode) + # 14 - opModWattVar (Watt-Var Mode) + opModFreqWatt = 0 + opModHFRTMayTrip = 1 + opModHFRTMustTrip = 2 + opModHVRTMayTrip = 3 + opModHVRTMomentaryCessation = 4 + opModHVRTMustTrip = 5 + opModLFRTMayTrip = 6 + opModLFRTMustTrip = 7 + opModLVRTMayTrip = 8 + opModLVRTMomentaryCessation = 9 + opModLVRTMustTrip = 10 + opModVoltVar = 11 + opModVoltWatt = 12 + opModWattPF = 13 + opModWattVar = 14 + + +class DeviceCategoryType(IntEnum): + """ + DeviceCategoryType defined from 20305-2018_IIEStandardforSmartEnergyProfileApplicationsProtocol.pdf Appendix + B.2.3.4 Types package + """ + # The Device category types defined. + # Bit positions SHALL be defined as follows: + PROGRAMMABLE_COMMUNICATING_THERMOSTAT = 0 + STRIP_HEATERS = 1 + BASEBOARD_HEATERS = 2 + WATER_HEATER = 3 + POOL_PUMP = 4 + SAUNA = 5 + HOT_TUB = 6 + SMART_APPLIANCE = 7 + IRRIGATION_PUMP = 8 + MANAGED_COMMERCIAL_AND_INDUSTRIAL_LOADS = 9 + SIMPLE_RESIDENTIAL_LOADS = 10 # On/Off loads + EXTERIOR_LIGHTING = 11 + INTERIOR_LIGHTING = 12 + LOAD_CONTROL_SWITCH = 13 + ENERGY_MANAGEMENT_SYSTEM = 14 + SMART_ENERGY_MODULE = 15 + ELECTRIC_VEHICLE = 16 + ELECTRIC_VEHICLE_SUPPLY_EQUIPMENT = 17 + VIRTUAL_OR_MIXED_DER = 18 + RECIPROCATING_ENGINE = 19 # Synchronous Machine + FUEL_CELL = 20 # Battery + PHOTOVOLTAIC_SYSTEM = 21 # Solar + COMBINED_HEAT_AND_POWER = 22 + COMBINED_PV_AND_STORAGE = 23 + OTHER_GENERATION_SYSTEMS = 24 + OTHER_STORAGE_SYSTEMS = 25 + + # Additional here for Aggregator + AGGREGATOR = 99 + OTHER_CLIENT = 100 + + +# 0 - Programmable Communicating Thermostat +# 1 - Strip Heaters +# 2 - Baseboard Heaters +# 3 - Water Heater +# 4 - Pool Pump +# 5 - Sauna +# 6 - Hot tub +# 7 - Smart Appliance +# 8 - Irrigation Pump +# 9 - Managed Commercial and Industrial Loads +# 10 - Simple Residential Loads +# 11 - Exterior Lighting +# 12 - Interior Lighting +# 13 - Electric Vehicle +# 14 - Generation Systems +# 15 - Load Control Switch +# 16 - Smart Inverter +# 17 - EVSE +# 18 - Residential Energy Storage Unit +# 19 - Energy Management System +# 20 - Smart Energy Module diff --git a/services/core/IEEE_2030_5/ieee_2030_5/models/sep.py b/services/core/IEEE_2030_5/ieee_2030_5/models/sep.py new file mode 100644 index 0000000000..a4d1df4758 --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/models/sep.py @@ -0,0 +1,8115 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List, Optional + +__NAMESPACE__ = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActivePower: + """The active (real) power P (in W) is the product of root-mean-square + (RMS) voltage, RMS current, and cos(theta) where theta is the phase angle + of current relative to voltage. + + It is the primary measure of the rate of flow of energy. + + :ivar multiplier: Specifies exponent for uom. + :ivar value: Value in watts (uom 38) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class AmpereHour: + """ + Available electric charge. + + :ivar multiplier: Specifies exponent of uom. + :ivar value: Value in ampere-hours (uom 106) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class ApparentPower: + """ + The apparent power S (in VA) is the product of root mean square (RMS) + voltage and RMS current. + + :ivar multiplier: Specifies exponent of uom. + :ivar value: Value in volt-amperes (uom 61) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class ApplianceLoadReduction: + """The ApplianceLoadReduction object is used by a Demand Response service + provider to provide signals for ENERGY STAR compliant appliances. + + See the definition of ApplianceLoadReductionType for more + information. + + :ivar type: Indicates the type of appliance load reduction + requested. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + type: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class AppliedTargetReduction: + """ + Specifies the value of the TargetReduction applied by the device. + + :ivar type: Enumerated field representing the type of reduction + requested. + :ivar value: Indicates the requested amount of the relevant + commodity to be reduced. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + type: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class Charge: + """Charges contain charges on a customer bill. + + These could be items like taxes, levies, surcharges, rebates, or + others. This is meant to allow the HAN device to retrieve enough + information to be able to reconstruct an estimate of what the total + bill would look like. Providers can provide line item billing, + including multiple charge kinds (e.g. taxes, surcharges) at whatever + granularity desired, using as many Charges as desired during a + billing period. There can also be any number of Charges associated + with different ReadingTypes to distinguish between TOU tiers, + consumption blocks, or demand charges. + + :ivar description: A description of the charge. + :ivar kind: The type (kind) of charge. + :ivar value: A monetary charge. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + description: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 20, + }) + kind: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class Condition: + """ + Indicates a condition that must be satisfied for the Notification to be + triggered. + + :ivar attributeIdentifier: 0 = Reading value 1-255 = Reserved + :ivar lowerThreshold: The value of the lower threshold + :ivar upperThreshold: The value of the upper threshold + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + attributeIdentifier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + lowerThreshold: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'min_inclusive': -140737488355328, + 'max_inclusive': 140737488355328, + }) + upperThreshold: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'min_inclusive': -140737488355328, + 'max_inclusive': 140737488355328, + }) + + +@dataclass +class ConnectStatusType: + """DER ConnectStatus value (bitmap): + + 0 - Connected + 1 - Available + 2 - Operating + 3 - Test + 4 - Fault / Error + All other values reserved. + + :ivar dateTime: The date and time at which the state applied. + :ivar value: The value indicating the state. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 1, + 'format': 'base16', + }) + + +@dataclass +class CreditTypeChange: + """ + Specifies a change to the credit type. + + :ivar newType: The new credit type, to take effect at the time + specified by startTime + :ivar startTime: The date/time when the change is to take effect. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + newType: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + startTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class CurrentRMS: + """ + Average flow of charge through a conductor. + + :ivar multiplier: Specifies exponent of value. + :ivar value: Value in amperes RMS (uom 5) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class CurveData: + """ + Data point values for defining a curve or schedule. + + :ivar excitation: If yvalue is Power Factor, then this field SHALL + be present. If yvalue is not Power Factor, then this field SHALL + NOT be present. True when DER is absorbing reactive power + (under-excited), false when DER is injecting reactive power + (over-excited). + :ivar xvalue: The data value of the X-axis (independent) variable, + depending on the curve type. See definitions in DERControlBase + for further information. + :ivar yvalue: The data value of the Y-axis (dependent) variable, + depending on the curve type. See definitions in DERControlBase + for further information. If yvalue is Power Factor, the + excitation field SHALL be present and yvalue SHALL be a positive + value. If yvalue is not Power Factor, the excitation field SHALL + NOT be present. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + excitation: Optional[bool] = field(default=None, metadata={ + 'type': 'Element', + }) + xvalue: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + yvalue: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class DateTimeInterval: + """ + Interval of date and time. + + :ivar duration: Duration of the interval, in seconds. + :ivar start: Date and time of the start of the interval. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + duration: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + start: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class DutyCycle: + """Duty cycle control is a device specific issue and is managed by the + device. + + The duty cycle of the device under control should span the shortest + practical time period in accordance with the nature of the device + under control and the intent of the request for demand reduction. + The default factory setting SHOULD be three minutes for each 10% of + duty cycle. This indicates that the default time period over which + a duty cycle is applied is 30 minutes, meaning a 10% duty cycle + would cause a device to be ON for 3 minutes. The “off state” SHALL + precede the “on state”. + + :ivar normalValue: Contains the maximum On state duty cycle applied + by the end device, as a percentage of time. The field not + present indicates that this field has not been used by the end + device. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + normalValue: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class EnvironmentalCost: + """Provides alternative or secondary price information for the relevant + RateComponent. + + Supports jurisdictions that seek to convey the environmental price + per unit of the specified commodity not expressed in currency. + Implementers and consumers can use this attribute to prioritize + operations of their HAN devices (e.g., PEV charging during times of + high availability of renewable electricity resources). + + :ivar amount: The estimated or actual environmental or other cost, + per commodity unit defined by the ReadingType, for this + RateComponent (e.g., grams of carbon dioxide emissions each per + kWh). + :ivar costKind: The kind of cost referred to in the amount. + :ivar costLevel: The relative level of the amount attribute. In + conjunction with numCostLevels, this attribute informs a device + of the relative scarcity of the amount attribute (e.g., a high + or low availability of renewable generation). numCostLevels and + costLevel values SHALL ascend in order of scarcity, where "0" + signals the lowest relative cost and higher values signal + increasing cost. For example, if numCostLevels is equal to “3,” + then if the lowest relative costLevel were equal to “0,” devices + would assume this is the lowest relative period to operate. + Likewise, if the costLevel in the next TimeTariffInterval + instance is equal to “1,” then the device would assume it is + relatively more expensive, in environmental terms, to operate + during this TimeTariffInterval instance than the previous one. + There is no limit to the number of relative price levels other + than that indicated in the attribute type, but for practicality, + service providers should strive for simplicity and recognize the + diminishing returns derived from increasing the numCostLevel + value greater than four. + :ivar numCostLevels: The number of all relative cost levels. In + conjunction with costLevel, numCostLevels signals the relative + scarcity of the commodity for the duration of the + TimeTariffInterval instance (e.g., a relative indication of + cost). This is useful in providing context for nominal cost + signals to consumers or devices that might see a range of amount + values from different service providres or from the same service + provider. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + amount: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + costKind: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + costLevel: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + numCostLevels: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class Error: + """ + Contains information about the nature of an error if a request could not be + completed successfully. + + :ivar maxRetryDuration: Contains the number of seconds the client + SHOULD wait before retrying the request. + :ivar reasonCode: Code indicating the reason for failure. 0 - + Invalid request format 1 - Invalid request values (e.g. invalid + threshold values) 2 - Resource limit reached 3 - Conditional + subscription field not supported 4 - Maximum request frequency + exceeded All other values reserved + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + maxRetryDuration: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + reasonCode: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class EventStatus: + """Current status information relevant to a specific object. + + The Status object is used to indicate the current status of an + Event. Devices can read the containing resource (e.g. TextMessage) + to get the most up to date status of the event. Devices can also + subscribe to a specific resource instance to get updates when any of + its attributes change, including the Status object. + + :ivar currentStatus: Field representing the current status type. 0 = + Scheduled This status indicates that the event has been + scheduled and the event has not yet started. The server SHALL + set the event to this status when the event is first scheduled + and persist until the event has become active or has been + cancelled. For events with a start time less than or equal to + the current time, this status SHALL never be indicated, the + event SHALL start with a status of “Active”. 1 = Active This + status indicates that the event is currently active. The server + SHALL set the event to this status when the event reaches its + earliest Effective Start Time. 2 = Cancelled When events are + cancelled, the Status.dateTime attribute SHALL be set to the + time the cancellation occurred, which cannot be in the future. + The server is responsible for maintaining the cancelled event in + its collection for the duration of the original event, or until + the server has run out of space and needs to store a new event. + Client devices SHALL be aware of Cancelled events, determine if + the Cancelled event applies to them, and cancel the event + immediately if applicable. 3 = Cancelled with Randomization The + server is responsible for maintaining the cancelled event in its + collection for the duration of the Effective Scheduled Period. + Client devices SHALL be aware of Cancelled with Randomization + events, determine if the Cancelled event applies to them, and + cancel the event immediately, using the larger of (absolute + value of randomizeStart) and (absolute value of + randomizeDuration) as the end randomization, in seconds. This + Status.type SHALL NOT be used with "regular" Events, only with + specializations of RandomizableEvent. 4 = Superseded Events + marked as Superseded by servers are events that may have been + replaced by new events from the same program that target the + exact same set of deviceCategory's (if applicable) AND + DERControl controls (e.g., opModTargetW) (if applicable) and + overlap for a given period of time. Servers SHALL mark an event + as Superseded at the earliest Effective Start Time of the + overlapping event. Servers are responsible for maintaining the + Superseded event in their collection for the duration of the + Effective Scheduled Period. Client devices encountering a + Superseded event SHALL terminate execution of the event + immediately and commence execution of the new event immediately, + unless the current time is within the start randomization window + of the superseded event, in which case the client SHALL obey the + start randomization of the new event. This Status.type SHALL NOT + be used with TextMessage, since multiple text messages can be + active. All other values reserved. + :ivar dateTime: The dateTime attribute will provide a timestamp of + when the current status was defined. dateTime MUST be set to the + time at which the status change occurred, not a time in the + future or past. + :ivar potentiallySuperseded: Set to true by a server of this event + if there are events that overlap this event in time and also + overlap in some, but not all, deviceCategory's (if applicable) + AND DERControl controls (e.g., opModTargetW) (if applicable) in + the same function set instance. + :ivar potentiallySupersededTime: Indicates the time that the + potentiallySuperseded flag was set. + :ivar reason: The Reason attribute allows a Service provider to + provide a textual explanation of the status. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + currentStatus: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + potentiallySuperseded: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + potentiallySupersededTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + reason: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 192, + }) + + +@dataclass +class FixedPointType: + """ + Abstract type for specifying a fixed-point value without a given unit of + measure. + + :ivar multiplier: Specifies exponent of uom. + :ivar value: Dimensionless value + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class FixedVar: + """ + Specifies a signed setpoint for reactive power. + + :ivar refType: Indicates whether to interpret 'value' as %setMaxVar + or %statVarAvail. + :ivar value: Specify a signed setpoint for reactive power in % (see + 'refType' for context). + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + refType: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class FreqDroopType: + """ + Type for Frequency-Droop (Frequency-Watt) operation. + + :ivar dBOF: Frequency droop dead band for over-frequency conditions. + In thousandths of Hz. + :ivar dBUF: Frequency droop dead band for under-frequency + conditions. In thousandths of Hz. + :ivar kOF: Frequency droop per-unit frequency change for over- + frequency conditions corresponding to 1 per-unit power output + change. In thousandths, unitless. + :ivar kUF: Frequency droop per-unit frequency change for under- + frequency conditions corresponding to 1 per-unit power output + change. In thousandths, unitless. + :ivar openLoopTms: Open loop response time, the duration from a step + change in control signal input until the output changes by 90% + of its final change before any overshoot, in hundredths of a + second. Resolution is 1/100 sec. A value of 0 is used to mean no + limit. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dBOF: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + dBUF: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + kOF: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + kUF: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + openLoopTms: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class GPSLocationType: + """ + Specifies a GPS location, expressed in WGS 84 coordinates. + + :ivar lat: Specifies the latitude from equator. -90 (south) to +90 + (north) in decimal degrees. + :ivar lon: Specifies the longitude from Greenwich Meridian. -180 + (west) to +180 (east) in decimal degrees. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + lat: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + lon: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + + +@dataclass +class InverterStatusType: + """DER InverterStatus value: + + 0 - N/A + 1 - off + 2 - sleeping (auto-shutdown) or DER is at low output power/voltage + 3 - starting up or ON but not producing power + 4 - tracking MPPT power point + 5 - forced power reduction/derating + 6 - shutting down + 7 - one or more faults exist + 8 - standby (service on unit) - DER may be at high output voltage/power + 9 - test mode + 10 - as defined in manufacturer status + All other values reserved. + + :ivar dateTime: The date and time at which the state applied. + :ivar value: The value indicating the state. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class Link: + """ + Links provide a reference, via URI, to another resource. + + :ivar href: A URI reference. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + href: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class LocalControlModeStatusType: + """DER LocalControlModeStatus/value: + + 0 – local control 1 – remote control All other values reserved. + + :ivar dateTime: The date and time at which the state applied. + :ivar value: The value indicating the state. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class ManufacturerStatusType: + """ + DER ManufacturerStatus/value: String data type. + + :ivar dateTime: The date and time at which the state applied. + :ivar value: The value indicating the state. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 6, + }) + + +@dataclass +class Offset: + """If a temperature offset is sent that causes the heating or cooling + temperature set point to exceed the limit boundaries that are programmed + into the device, the device SHALL respond by setting the temperature at the + limit. + + If an EDC is being targeted at multiple devices or to a device that + controls multiple devices (e.g., EMS), it can provide multiple + Offset types within one EDC. For events with multiple Offset types, + a client SHALL select the Offset that best fits their operating + function. Alternatively, an event with a single Offset type can be + targeted at an EMS in order to request a percentage load reduction + on the average energy usage of the entire premise. An EMS SHOULD use + the Metering function set to determine the initial load in the + premise, reduce energy consumption by controlling devices at its + disposal, and at the conclusion of the event, once again use the + Metering function set to determine if the desired load reduction was + achieved. + + :ivar coolingOffset: The value change requested for the cooling + offset, in degree C / 10. The value should be added to the + normal set point for cooling, or if loadShiftForward is true, + then the value should be subtracted from the normal set point. + :ivar heatingOffset: The value change requested for the heating + offset, in degree C / 10. The value should be subtracted for + heating, or if loadShiftForward is true, then the value should + be added to the normal set point. + :ivar loadAdjustmentPercentageOffset: The value change requested for + the load adjustment percentage. The value should be subtracted + from the normal setting, or if loadShiftForward is true, then + the value should be added to the normal setting. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + coolingOffset: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + heatingOffset: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + loadAdjustmentPercentageOffset: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class OperationalModeStatusType: + """DER OperationalModeStatus value: + + 0 - Not applicable / Unknown + 1 - Off + 2 - Operational mode + 3 - Test mode + All other values reserved. + + :ivar dateTime: The date and time at which the state applied. + :ivar value: The value indicating the state. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class PowerConfiguration: + """ + Contains configuration related to the device's power sources. + + :ivar batteryInstallTime: Time/Date at which battery was installed, + :ivar lowChargeThreshold: In context of the PowerStatus resource, + this is the value of EstimatedTimeRemaining below which + BatteryStatus "low" is indicated and the PS_LOW_BATTERY is + raised. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + batteryInstallTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + lowChargeThreshold: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class PowerFactor: + """ + Specifies a setpoint for Displacement Power Factor, the ratio between + apparent and active powers at the fundamental frequency (e.g. 60 Hz). + + :ivar displacement: Significand of an unsigned value of cos(theta) + between 0 and 1.0. E.g. a value of 0.95 may be specified as a + displacement of 950 and a multiplier of -3. + :ivar multiplier: Specifies exponent of 'displacement'. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + displacement: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class PowerFactorWithExcitation: + """ + Specifies a setpoint for Displacement Power Factor, the ratio between + apparent and active powers at the fundamental frequency (e.g. 60 Hz) and + includes an excitation flag. + + :ivar displacement: Significand of an unsigned value of cos(theta) + between 0 and 1.0. E.g. a value of 0.95 may be specified as a + displacement of 950 and a multiplier of -3. + :ivar excitation: True when DER is absorbing reactive power (under- + excited), false when DER is injecting reactive power (over- + excited). + :ivar multiplier: Specifies exponent of 'displacement'. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + displacement: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + excitation: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class ReactivePower: + """ + The reactive power Q (in var) is the product of root mean square (RMS) + voltage, RMS current, and sin(theta) where theta is the phase angle of + current relative to voltage. + + :ivar multiplier: Specifies exponent of uom. + :ivar value: Value in volt-amperes reactive (var) (uom 63) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class ReactiveSusceptance: + """ + Reactive susceptance. + + :ivar multiplier: Specifies exponent of uom. + :ivar value: Value in siemens (uom 53) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class RealEnergy: + """ + Real electrical energy. + + :ivar multiplier: Multiplier for 'unit'. + :ivar value: Value of the energy in Watt-hours. (uom 72) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_inclusive': 281474976710655, + }) + + +@dataclass +class RequestStatus: + """ + The RequestStatus object is used to indicate the current status of a Flow + Reservation Request. + + :ivar dateTime: The dateTime attribute will provide a timestamp of + when the request status was set. dateTime MUST be set to the + time at which the status change occurred, not a time in the + future or past. + :ivar requestStatus: Field representing the request status type. 0 = + Requested 1 = Cancelled All other values reserved. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + requestStatus: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class Resource: + """ + A resource is an addressable unit of information, either a collection + (List) or instance of an object (identifiedObject, or simply, Resource) + + :ivar href: A reference to the resource address (URI). Required in a + response to a GET, ignored otherwise. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + href: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class ServiceChange: + """ + Specifies a change to the service status. + + :ivar newStatus: The new service status, to take effect at the time + specified by startTime + :ivar startTime: The date/time when the change is to take effect. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + newStatus: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + startTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class SetPoint: + """The SetPoint object is used to apply specific temperature set points to + a temperature control device. + + The values of the heatingSetpoint and coolingSetpoint attributes SHALL be calculated as follows: + Cooling/Heating Temperature Set Point / 100 = temperature in degrees Celsius where -273.15°C &lt;= temperature &lt;= 327.67°C, corresponding to a Cooling and/or Heating Temperature Set Point. The maximum resolution this format allows is 0.01°C. + The field not present in a Response indicates that this field has not been used by the end device. + If a temperature is sent that exceeds the temperature limit boundaries that are programmed into the device, the device SHALL respond by setting the temperature at the limit. + + :ivar coolingSetpoint: This attribute represents the cooling + temperature set point in degrees Celsius / 100. (Hundredths of a + degree C) + :ivar heatingSetpoint: This attribute represents the heating + temperature set point in degrees Celsius / 100. (Hundredths of a + degree C) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + coolingSetpoint: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + heatingSetpoint: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class SignedRealEnergy: + """ + Real electrical energy, signed. + + :ivar multiplier: Multiplier for 'unit'. + :ivar value: Value of the energy in Watt-hours. (uom 72) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'min_inclusive': -140737488355328, + 'max_inclusive': 140737488355328, + }) + + +@dataclass +class StateOfChargeStatusType: + """ + DER StateOfChargeStatus value: Percent data type. + + :ivar dateTime: The date and time at which the state applied. + :ivar value: The value indicating the state. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class StorageModeStatusType: + """DER StorageModeStatus value: + + 0 – storage charging 1 – storage discharging 2 – storage holding All + other values reserved. + + :ivar dateTime: The date and time at which the state applied. + :ivar value: The value indicating the state. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class TargetReduction: + """The TargetReduction object is used by a Demand Response service provider + to provide a RECOMMENDED threshold that a device/premises should maintain + its consumption below. + + For example, a service provider can provide a RECOMMENDED threshold + of some kWh for a 3-hour event. This means that the device/premises + would maintain its consumption below the specified limit for the + specified period. + + :ivar type: Indicates the type of reduction requested. + :ivar value: Indicates the requested amount of the relevant + commodity to be reduced. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + type: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class Temperature: + """ + Specification of a temperature. + + :ivar multiplier: Multiplier for 'unit'. + :ivar subject: The subject of the temperature measurement 0 - + Enclosure 1 - Transformer 2 - HeatSink + :ivar value: Value in Degrees Celsius (uom 23). + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + subject: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class TimeConfiguration: + """ + Contains attributes related to the configuration of the time service. + + :ivar dstEndRule: Rule to calculate end of daylight savings time in + the current year. Result of dstEndRule must be greater than + result of dstStartRule. + :ivar dstOffset: Daylight savings time offset from local standard + time. + :ivar dstStartRule: Rule to calculate start of daylight savings time + in the current year. Result of dstEndRule must be greater than + result of dstStartRule. + :ivar tzOffset: Local time zone offset from UTCTime. Does not + include any daylight savings time offsets. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dstEndRule: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 4, + 'format': 'base16', + }) + dstOffset: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + dstStartRule: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 4, + 'format': 'base16', + }) + tzOffset: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class UnitValueType: + """ + Type for specification of a specific value, with units and power of ten + multiplier. + + :ivar multiplier: Multiplier for 'unit'. + :ivar unit: Unit in symbol + :ivar value: Value in units specified + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + unit: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class UnsignedFixedPointType: + """ + Abstract type for specifying an unsigned fixed-point value without a given + unit of measure. + + :ivar multiplier: Specifies exponent of uom. + :ivar value: Dimensionless value + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class VoltageRMS: + """ + Average electric potential difference between two points. + + :ivar multiplier: Specifies exponent of uom. + :ivar value: Value in volts RMS (uom 29) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class WattHour: + """ + Active (real) energy. + + :ivar multiplier: Specifies exponent of uom. + :ivar value: Value in watt-hours (uom 72) + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class loWPAN: + """ + Contains information specific to 6LoWPAN. + + :ivar octetsRx: Number of Bytes received + :ivar octetsTx: Number of Bytes transmitted + :ivar packetsRx: Number of packets received + :ivar packetsTx: Number of packets transmitted + :ivar rxFragError: Number of errors receiving fragments + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + octetsRx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + octetsTx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + packetsRx: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + packetsTx: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + rxFragError: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class AccountBalanceLink(Link): + """ + SHALL contain a Link to an instance of AccountBalance. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class AccountingUnit: + """ + Unit for accounting; use either 'energyUnit' or 'currencyUnit' to specify + the unit for 'value'. + + :ivar energyUnit: Unit of service. + :ivar monetaryUnit: Unit of currency. + :ivar multiplier: Multiplier for the 'energyUnit' or 'monetaryUnit'. + :ivar value: Value of the monetary aspect + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + energyUnit: Optional[RealEnergy] = field(default=None, metadata={ + 'type': 'Element', + }) + monetaryUnit: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + multiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + value: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class AssociatedUsagePointLink(Link): + """SHALL contain a Link to an instance of UsagePoint. + + If present, this is the submeter that monitors the DER output. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class BillingPeriod(Resource): + """A Billing Period relates to the period of time on which a customer is + billed. + + As an example the billing period interval for a particular customer + might be 31 days starting on July 1, 2011. The start date and + interval can change on each billing period. There may also be + multiple billing periods related to a customer agreement to support + different tariff structures. + + :ivar billLastPeriod: The amount of the bill for the previous + billing period. + :ivar billToDate: The bill amount related to the billing period as + of the statusTimeStamp. + :ivar interval: The time interval for this billing period. + :ivar statusTimeStamp: The date / time of the last update of this + resource. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + billLastPeriod: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'min_inclusive': -140737488355328, + 'max_inclusive': 140737488355328, + }) + billToDate: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'min_inclusive': -140737488355328, + 'max_inclusive': 140737488355328, + }) + interval: Optional[DateTimeInterval] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + statusTimeStamp: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class ConfigurationLink(Link): + """ + SHALL contain a Link to an instance of Configuration. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ConsumptionTariffInterval(Resource): + """One of a sequence of thresholds defined in terms of consumption quantity + of a service such as electricity, water, gas, etc. + + It defines the steps or blocks in a step tariff structure, where + startValue simultaneously defines the entry value of this step and + the closing value of the previous step. Where consumption is greater + than startValue, it falls within this block and where consumption is + less than or equal to startValue, it falls within one of the + previous blocks. + + :ivar consumptionBlock: Indicates the consumption block related to + the reading. If not specified, is assumed to be "0 - N/A". + :ivar EnvironmentalCost: + :ivar price: The charge for this rate component, per unit of measure + defined by the associated ReadingType, in currency specified in + TariffProfile. The Pricing service provider determines the + appropriate price attribute value based on its applicable + regulatory rules. For example, price could be net or inclusive + of applicable taxes, fees, or levies. The Billing function set + provides the ability to represent billing information in a more + detailed manner. + :ivar startValue: The lowest level of consumption that defines the + starting point of this consumption step or block. Thresholds + start at zero for each billing period. If specified, the first + ConsumptionTariffInterval.startValue for a TimeTariffInteral + instance SHALL begin at "0." Subsequent + ConsumptionTariffInterval.startValue elements SHALL be greater + than the previous one. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + consumptionBlock: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + EnvironmentalCost: List[EnvironmentalCost] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + price: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + startValue: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_inclusive': 281474976710655, + }) + + +@dataclass +class CurrentDERProgramLink(Link): + """SHALL contain a Link to an instance of DERProgram. + + If present, this is the DERProgram containing the currently active + DERControl. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class CustomerAccountLink(Link): + """ + SHALL contain a Link to an instance of CustomerAccount. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERAvailabilityLink(Link): + """ + SHALL contain a Link to an instance of DERAvailability. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERCapability(Resource): + """ + Distributed energy resource type and nameplate ratings. + + :ivar modesSupported: Bitmap indicating the DER Controls implemented + by the device. See DERControlType for values. + :ivar rtgAbnormalCategory: Abnormal operating performance category + as defined by IEEE 1547-2018. One of: 0 - not specified 1 - + Category I 2 - Category II 3 - Category III All other values + reserved. + :ivar rtgMaxA: Maximum continuous AC current capability of the DER, + in Amperes (RMS). + :ivar rtgMaxAh: Usable energy storage capacity of the DER, in + AmpHours. + :ivar rtgMaxChargeRateVA: Maximum apparent power charge rating in + Volt-Amperes. May differ from the maximum apparent power rating. + :ivar rtgMaxChargeRateW: Maximum rate of energy transfer received by + the storage DER, in Watts. + :ivar rtgMaxDischargeRateVA: Maximum apparent power discharge rating + in Volt-Amperes. May differ from the maximum apparent power + rating. + :ivar rtgMaxDischargeRateW: Maximum rate of energy transfer + delivered by the storage DER, in Watts. Required for combined + generation/storage DERs (e.g. DERType == 83). + :ivar rtgMaxV: AC voltage maximum rating. + :ivar rtgMaxVA: Maximum continuous apparent power output capability + of the DER, in VA. + :ivar rtgMaxVar: Maximum continuous reactive power delivered by the + DER, in var. + :ivar rtgMaxVarNeg: Maximum continuous reactive power received by + the DER, in var. If absent, defaults to negative rtgMaxVar. + :ivar rtgMaxW: Maximum continuous active power output capability of + the DER, in watts. Represents combined generation plus storage + output if DERType == 83. + :ivar rtgMaxWh: Maximum energy storage capacity of the DER, in + WattHours. + :ivar rtgMinPFOverExcited: Minimum Power Factor displacement + capability of the DER when injecting reactive power (over- + excited); SHALL be a positive value between 0.0 (typically + &gt; 0.7) and 1.0. If absent, defaults to unity. + :ivar rtgMinPFUnderExcited: Minimum Power Factor displacement + capability of the DER when absorbing reactive power (under- + excited); SHALL be a positive value between 0.0 (typically + &gt; 0.7) and 0.9999. If absent, defaults to + rtgMinPFOverExcited. + :ivar rtgMinV: AC voltage minimum rating. + :ivar rtgNormalCategory: Normal operating performance category as + defined by IEEE 1547-2018. One of: 0 - not specified 1 - + Category A 2 - Category B All other values reserved. + :ivar rtgOverExcitedPF: Specified over-excited power factor. + :ivar rtgOverExcitedW: Active power rating in Watts at specified + over-excited power factor (rtgOverExcitedPF). If present, + rtgOverExcitedPF SHALL be present. + :ivar rtgReactiveSusceptance: Reactive susceptance that remains + connected to the Area EPS in the cease to energize and trip + state. + :ivar rtgUnderExcitedPF: Specified under-excited power factor. + :ivar rtgUnderExcitedW: Active power rating in Watts at specified + under-excited power factor (rtgUnderExcitedPF). If present, + rtgUnderExcitedPF SHALL be present. + :ivar rtgVNom: AC voltage nominal rating. + :ivar type: Type of DER; see DERType object + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + modesSupported: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 4, + 'format': 'base16', + }) + rtgAbnormalCategory: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMaxA: Optional[CurrentRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMaxAh: Optional[AmpereHour] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMaxChargeRateVA: Optional[ApparentPower] = field(default=None, + metadata={ + 'type': 'Element', + }) + rtgMaxChargeRateW: Optional[ActivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMaxDischargeRateVA: Optional[ApparentPower] = field(default=None, + metadata={ + 'type': 'Element', + }) + rtgMaxDischargeRateW: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + }) + rtgMaxV: Optional[VoltageRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMaxVA: Optional[ApparentPower] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMaxVar: Optional[ReactivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMaxVarNeg: Optional[ReactivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMaxW: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + rtgMaxWh: Optional[WattHour] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgMinPFOverExcited: Optional[PowerFactor] = field(default=None, + metadata={ + 'type': 'Element', + }) + rtgMinPFUnderExcited: Optional[PowerFactor] = field(default=None, + metadata={ + 'type': 'Element', + }) + rtgMinV: Optional[VoltageRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgNormalCategory: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgOverExcitedPF: Optional[PowerFactor] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgOverExcitedW: Optional[ActivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgReactiveSusceptance: Optional[ReactiveSusceptance] = field(default=None, + metadata={ + 'type': 'Element', + }) + rtgUnderExcitedPF: Optional[PowerFactor] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgUnderExcitedW: Optional[ActivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + rtgVNom: Optional[VoltageRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + type: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class DERCapabilityLink(Link): + """ + SHALL contain a Link to an instance of DERCapability. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERCurveLink(Link): + """ + SHALL contain a Link to an instance of DERCurve. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERLink(Link): + """ + SHALL contain a Link to an instance of DER. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERProgramLink(Link): + """ + SHALL contain a Link to an instance of DERProgram. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERSettingsLink(Link): + """ + SHALL contain a Link to an instance of DERSettings. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERStatusLink(Link): + """ + SHALL contain a Link to an instance of DERStatus. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DRLCCapabilities: + """ + Contains information about the static capabilities of the device, to allow + service providers to know what types of functions are supported, what the + normal operating ranges and limits are, and other similar information, in + order to provide better suggestions of applicable programs to receive the + maximum benefit. + + :ivar averageEnergy: The average hourly energy usage when in normal + operating mode. + :ivar maxDemand: The maximum demand rating of this end device. + :ivar optionsImplemented: Bitmap indicating the DRLC options + implemented by the device. 0 - Target reduction (kWh) 1 - Target + reduction (kW) 2 - Target reduction (Watts) 3 - Target reduction + (Cubic Meters) 4 - Target reduction (Cubic Feet) 5 - Target + reduction (US Gallons) 6 - Target reduction (Imperial Gallons) 7 + - Target reduction (BTUs) 8 - Target reduction (Liters) 9 - + Target reduction (kPA (gauge)) 10 - Target reduction (kPA + (absolute)) 11 - Target reduction (Mega Joule) 12 - Target + reduction (Unitless) 13-15 - Reserved 16 - Temperature set point + 17 - Temperature offset 18 - Duty cycle 19 - Load adjustment + percentage 20 - Appliance load reduction 21-31 - Reserved + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + averageEnergy: Optional[RealEnergy] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + maxDemand: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + optionsImplemented: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 4, + 'format': 'base16', + }) + + +@dataclass +class DefaultDERControlLink(Link): + """SHALL contain a Link to an instance of DefaultDERControl. + + This is the default mode of the DER which MAY be overridden by + DERControl events. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DemandResponseProgramLink(Link): + """ + SHALL contain a Link to an instance of DemandResponseProgram. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DeviceCapabilityLink(Link): + """ + SHALL contain a Link to an instance of DeviceCapability. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DeviceInformationLink(Link): + """ + SHALL contain a Link to an instance of DeviceInformation. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DeviceStatusLink(Link): + """ + SHALL contain a Link to an instance of DeviceStatus. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class EndDeviceLink(Link): + """ + SHALL contain a Link to an instance of EndDevice. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class File(Resource): + """This resource contains various meta-data describing a file's + characteristics. + + The meta-data provides general file information and also is used to + support filtered queries of file lists + + :ivar activateTime: This element MUST be set to the date/time at + which this file is activated. If the activation time is less + than or equal to current time, the LD MUST immediately place the + file into the activated state (in the case of a firmware file, + the file is now the running image). If the activation time is + greater than the current time, the LD MUST wait until the + specified activation time is reached, then MUST place the file + into the activated state. Omission of this element means that + the LD MUST NOT take any action to activate the file until a + subsequent GET to this File resource provides an activateTime. + :ivar fileURI: This element MUST be set to the URI location of the + file binary artifact. This is the BLOB (binary large object) + that is actually loaded by the LD + :ivar lFDI: This element MUST be set to the LFDI of the device for + which this file in targeted. + :ivar mfHwVer: This element MUST be set to the hardware version for + which this file is targeted. + :ivar mfID: This element MUST be set to the manufacturer's Private + Enterprise Number (assigned by IANA). + :ivar mfModel: This element MUST be set to the manufacturer model + number for which this file is targeted. The syntax and semantics + are left to the manufacturer. + :ivar mfSerNum: This element MUST be set to the manufacturer serial + number for which this file is targeted. The syntax and semantics + are left to the manufacturer. + :ivar mfVer: This element MUST be set to the software version + information for this file. The syntax and semantics are left to + the manufacturer. + :ivar size: This element MUST be set to the total size (in bytes) of + the file referenced by fileURI. + :ivar type: A value indicating the type of the file. MUST be one of + the following values: 00 = Software Image 01 = Security + Credential 02 = Configuration 03 = Log 04–7FFF = reserved + 8000-FFFF = Manufacturer defined + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + activateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + fileURI: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + lFDI: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 20, + 'format': 'base16', + }) + mfHwVer: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 32, + }) + mfID: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + mfModel: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + mfSerNum: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 32, + }) + mfVer: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + }) + size: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + type: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 2, + 'format': 'base16', + }) + + +@dataclass +class FileLink(Link): + """This element MUST be set to the URI of the most recent File being + loaded/activated by the LD. + + In the case of file status 0, this element MUST be omitted. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class FileStatusLink(Link): + """ + SHALL contain a Link to an instance of FileStatus. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class IdentifiedObject(Resource): + """ + This is a root class to provide common naming attributes for all classes + needing naming attributes. + + :ivar mRID: The global identifier of the object. + :ivar description: The description is a human readable text + describing or naming the object. + :ivar version: Contains the version number of the object. See the + type definition for details. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + mRID: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + description: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 32, + }) + version: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class List_type(Resource): + """Container to hold a collection of object instances or references. + + See Design Pattern section for additional details. + + :ivar all: The number specifying "all" of the items in the list. + Required on a response to a GET, ignored otherwise. + :ivar results: Indicates the number of items in this page of + results. + """ + + class Meta: + name = 'List' + namespace = 'urn:ieee:std:2030.5:ns' + + all: Optional[int] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + results: Optional[int] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class ListLink(Link): + """ + ListLinks provide a reference, via URI, to a List. + + :ivar all: Indicates the total number of items in the referenced + list. This attribute SHALL be present if the href is a local or + relative URI. This attribute SHOULD NOT be present if the href + is a remote or absolute URI, as the server may be unaware of + changes to the value. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + all: Optional[int] = field(default=None, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class LogEvent(Resource): + """ + A time stamped instance of a significant event detected by the device. + + :ivar createdDateTime: The date and time that the event occurred. + :ivar details: Human readable text that MAY be used to transmit + additional details about the event. A host MAY remove this field + when received. + :ivar extendedData: May be used to transmit additional details about + the event. + :ivar functionSet: If the profileID indicates this is IEEE 2030.5, + the functionSet is defined by IEEE 2030.5 and SHALL be one of + the values from the table below (IEEE 2030.5 function set + identifiers). If the profileID is anything else, the functionSet + is defined by the identified profile. 0 General (not + specific to a function set) 1 Publish and Subscribe 2 + End Device 3 Function Set Assignment 4 Response 5 + Demand Response and Load Control 6 Metering 7 + Pricing 8 Messaging 9 Billing 10 Prepayment 11 + Distributed Energy Resources 12 Time 13 Software + Download 14 Device Information 15 Power Status 16 + Network Status 17 Log Event List 18 Configuration 19 + Security All other values are reserved. + :ivar logEventCode: An 8 bit unsigned integer. logEventCodes are + scoped to a profile and a function set. If the profile is IEEE + 2030.5, the logEventCode is defined by IEEE 2030.5 within one of + the function sets of IEEE 2030.5. If the profile is anything + else, the logEventCode is defined by the specified profile. + :ivar logEventID: This 16-bit value, combined with createdDateTime, + profileID, and logEventPEN, should provide a reasonable level of + uniqueness. + :ivar logEventPEN: The Private Enterprise Number(PEN) of the entity + that defined the profileID, functionSet, and logEventCode of the + logEvent. IEEE 2030.5-assigned logEventCodes SHALL use the IEEE + 2030.5 PEN. Combinations of profileID, functionSet, and + logEventCode SHALL have unique meaning within a logEventPEN and + are defined by the owner of the PEN. + :ivar profileID: The profileID identifies which profile (HA, BA, SE, + etc) defines the following event information. 0 Not + profile specific. 1 Vendor Defined 2 IEEE 2030.5 3 + Home Automation 4 Building Automation All other values are + reserved. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + createdDateTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + details: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 32, + }) + extendedData: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + functionSet: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + logEventCode: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + logEventID: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + logEventPEN: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + profileID: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class MeterReadingLink(Link): + """ + SHALL contain a Link to an instance of MeterReading. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class Neighbor(Resource): + """ + Contains 802.15.4 link layer specific attributes. + + :ivar isChild: True if the neighbor is a child. + :ivar linkQuality: The quality of the link, as defined by 802.15.4 + :ivar shortAddress: As defined by IEEE 802.15.4 + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + isChild: Optional[bool] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + linkQuality: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + shortAddress: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class PEVInfo: + """ + Contains attributes that can be exposed by PEVs and other devices that have + charging requirements. + + :ivar chargingPowerNow: This is the actual power flow in or out of + the charger or inverter. This is calculated by the vehicle based + on actual measurements. This number is positive for charging. + :ivar energyRequestNow: This is the amount of energy that must be + transferred from the grid to EVSE and PEV to achieve the target + state of charge allowing for charger efficiency and any vehicle + and EVSE parasitic loads. This is calculated by the vehicle and + changes throughout the connection as forward or reverse power + flow change the battery state of charge. This number is + positive for charging. + :ivar maxForwardPower: This is maximum power transfer capability + that could be used for charging the PEV to perform the requested + energy transfer. It is the lower of the vehicle or EVSE + physical power limitations. It is not based on economic + considerations. The vehicle may draw less power than this value + based on its charging cycle. The vehicle defines this parameter. + This number is positive for charging power flow. + :ivar minimumChargingDuration: This is computed by the PEV based on + the charging profile to complete the energy transfer if the + maximum power is authorized. The value will never be smaller + than the ratio of the energy request to the power request + because the charging profile may not allow the maximum power to + be used throughout the transfer. This is a critical parameter + for determining whether any slack time exists in the charging + cycle between the current time and the TCIN. + :ivar targetStateOfCharge: This is the target state of charge that + is to be achieved during charging before the time of departure + (TCIN). The default value is 100%. The value cannot be set to a + value less than the actual state of charge. + :ivar timeChargeIsNeeded: Time Charge is Needed (TCIN) is the time + that the PEV is expected to depart. The value is manually + entered using controls and displays in the vehicle or on the + EVSE or using a mobile device. It is authenticated and saved by + the PEV. This value may be updated during a charging session. + :ivar timeChargingStatusPEV: This is the time that the parameters + are updated, except for changes to TCIN. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + chargingPowerNow: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + energyRequestNow: Optional[RealEnergy] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + maxForwardPower: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + minimumChargingDuration: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + targetStateOfCharge: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + timeChargeIsNeeded: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + timeChargingStatusPEV: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class PowerStatusLink(Link): + """ + SHALL contain a Link to an instance of PowerStatus. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class PrepayOperationStatus(Resource): + """ + PrepayOperationStatus describes the status of the service or commodity + being conditionally controlled by the Prepayment function set. + + :ivar creditTypeChange: CreditTypeChange is used to define a pending + change of creditTypeInUse, which will activate at a specified + time. + :ivar creditTypeInUse: CreditTypeInUse identifies whether the + present mode of operation is consuming regular credit or + emergency credit. + :ivar serviceChange: ServiceChange is used to define a pending + change of serviceStatus, which will activate at a specified + time. + :ivar serviceStatus: ServiceStatus identifies whether the service is + connected or disconnected, or armed for connection or + disconnection. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + creditTypeChange: Optional[CreditTypeChange] = field(default=None, + metadata={ + 'type': 'Element', + }) + creditTypeInUse: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + serviceChange: Optional[ServiceChange] = field(default=None, metadata={ + 'type': 'Element', + }) + serviceStatus: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class PrepayOperationStatusLink(Link): + """ + SHALL contain a Link to an instance of PrepayOperationStatus. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class PrepaymentLink(Link): + """ + SHALL contain a Link to an instance of Prepayment. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class RPLSourceRoutes(Resource): + """ + A RPL source routes object. + + :ivar DestAddress: See [RFC 6554]. + :ivar SourceRoute: See [RFC 6554]. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DestAddress: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + SourceRoute: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + + +@dataclass +class RateComponentLink(Link): + """ + SHALL contain a Link to an instance of RateComponent. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ReadingBase(Resource): + """Specific value measured by a meter or other asset. + + ReadingBase is abstract, used to define the elements common to + Reading and IntervalReading. + + :ivar consumptionBlock: Indicates the consumption block related to + the reading. REQUIRED if ReadingType numberOfConsumptionBlocks + is non-zero. If not specified, is assumed to be "0 - N/A". + :ivar qualityFlags: List of codes indicating the quality of the + reading, using specification: Bit 0 - valid: data that has gone + through all required validation checks and either passed them + all or has been verified Bit 1 - manually edited: Replaced or + approved by a human Bit 2 - estimated using reference day: data + value was replaced by a machine computed value based on analysis + of historical data using the same type of measurement. Bit 3 - + estimated using linear interpolation: data value was computed + using linear interpolation based on the readings before and + after it Bit 4 - questionable: data that has failed one or more + checks Bit 5 - derived: data that has been calculated (using + logic or mathematical operations), not necessarily measured + directly Bit 6 - projected (forecast): data that has been + calculated as a projection or forecast of future readings + :ivar timePeriod: The time interval associated with the reading. If + not specified, then defaults to the intervalLength specified in + the associated ReadingType. + :ivar touTier: Indicates the time of use tier related to the + reading. REQUIRED if ReadingType numberOfTouTiers is non-zero. + If not specified, is assumed to be "0 - N/A". + :ivar value: Value in units specified by ReadingType + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + consumptionBlock: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + qualityFlags: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 2, + 'format': 'base16', + }) + timePeriod: Optional[DateTimeInterval] = field(default=None, metadata={ + 'type': 'Element', + }) + touTier: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + value: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'min_inclusive': -140737488355328, + 'max_inclusive': 140737488355328, + }) + + +@dataclass +class ReadingLink(Link): + """ + A Link to a Reading. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ReadingType(Resource): + """Type of data conveyed by a specific Reading. + + See IEC 61968 Part 9 Annex C for full definitions of these values. + + :ivar accumulationBehaviour: The “accumulation behaviour” indicates + how the value is represented to accumulate over time. + :ivar calorificValue: The amount of heat generated when a given mass + of fuel is completely burned. The CalorificValue is used to + convert the measured volume or mass of gas into kWh. The + CalorificValue attribute represents the current active value. + :ivar commodity: Indicates the commodity applicable to this + ReadingType. + :ivar conversionFactor: Accounts for changes in the volume of gas + based on temperature and pressure. The ConversionFactor + attribute represents the current active value. The + ConversionFactor is dimensionless. The default value for the + ConversionFactor is 1, which means no conversion is applied. A + price server can advertise a new/different value at any time. + :ivar dataQualifier: The data type can be used to describe a salient + attribute of the data. Possible values are average, absolute, + and etc. + :ivar flowDirection: Anything involving current might have a flow + direction. Possible values include forward and reverse. + :ivar intervalLength: Default interval length specified in seconds. + :ivar kind: Compound class that contains kindCategory and kindIndex + :ivar maxNumberOfIntervals: To be populated for mirrors of interval + data to set the expected number of intervals per ReadingSet. + Servers may discard intervals received that exceed this number. + :ivar numberOfConsumptionBlocks: Number of consumption blocks. 0 + means not applicable, and is the default if not specified. The + value needs to be at least 1 if any actual prices are provided. + :ivar numberOfTouTiers: The number of TOU tiers that can be used by + any resource configured by this ReadingType. Servers SHALL + populate this value with the largest touTier value that will + <i>ever</i> be used while this ReadingType is in + effect. Servers SHALL set numberOfTouTiers equal to the number + of standard TOU tiers plus the number of CPP tiers that may be + used while this ReadingType is in effect. Servers SHALL specify + a value between 0 and 255 (inclusive) for numberOfTouTiers + (servers providing flat rate pricing SHOULD set numberOfTouTiers + to 0, as in practice there is no difference between having no + tiers and having one tier). + :ivar phase: Contains phase information associated with the type. + :ivar powerOfTenMultiplier: Indicates the power of ten multiplier + applicable to the unit of measure of this ReadingType. + :ivar subIntervalLength: Default sub-interval length specified in + seconds for Readings of ReadingType. Some demand calculations + are done over a number of smaller intervals. For example, in a + rolling demand calculation, the demand value is defined as the + rolling sum of smaller intervals over the intervalLength. The + subintervalLength is the length of the smaller interval in this + calculation. It SHALL be an integral division of the + intervalLength. The number of sub-intervals can be calculated by + dividing the intervalLength by the subintervalLength. + :ivar supplyLimit: Reflects the supply limit set in the meter. This + value can be compared to the Reading value to understand if + limits are being approached or exceeded. Units follow the same + definition as in this ReadingType. + :ivar tieredConsumptionBlocks: Specifies whether or not the + consumption blocks are differentiated by TOUTier or not. Default + is false, if not specified. true = consumption accumulated over + individual tiers false = consumption accumulated over all tiers + :ivar uom: Indicates the measurement type for the units of measure + for the readings of this type. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + accumulationBehaviour: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + calorificValue: Optional[UnitValueType] = field(default=None, metadata={ + 'type': 'Element', + }) + commodity: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + conversionFactor: Optional[UnitValueType] = field(default=None, metadata={ + 'type': 'Element', + }) + dataQualifier: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + flowDirection: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + intervalLength: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + kind: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + maxNumberOfIntervals: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + numberOfConsumptionBlocks: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + numberOfTouTiers: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + phase: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + powerOfTenMultiplier: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + subIntervalLength: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + supplyLimit: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'max_inclusive': 281474976710655, + }) + tieredConsumptionBlocks: Optional[bool] = field(default=None, metadata={ + 'type': 'Element', + }) + uom: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class ReadingTypeLink(Link): + """ + SHALL contain a Link to an instance of ReadingType. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class Registration(Resource): + """ + Registration represents an authorization to access the resources on a host. + + :ivar dateTimeRegistered: Contains the time at which this + registration was created, by which clients MAY prioritize + information providers with the most recent registrations, when + no additional direction from the consumer is available. + :ivar pIN: Contains the registration PIN number associated with the + device, including the checksum digit. + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + dateTimeRegistered: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + pIN: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class RegistrationLink(Link): + """ + SHALL contain a Link to an instance of Registration. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class RespondableResource(Resource): + """ + A Resource to which a Response can be requested. + + :ivar replyTo: A reference to the response resource address (URI). + Required on a response to a GET if responseRequired is "true". + :ivar responseRequired: Indicates whether or not a response is + required upon receipt, creation or update of this resource. + Responses shall be posted to the collection specified in + "replyTo". If the resource has a deviceCategory field, devices + that match one or more of the device types indicated in + deviceCategory SHALL respond according to the rules listed + below. If the category does not match, the device SHALL NOT + respond. If the resource does not have a deviceCategory field, a + device receiving the resource SHALL respond according to the + rules listed below. Value encoded as hex according to the + following bit assignments, any combination is possible. See + Table 27 for the list of appropriate Response status codes to be + sent for these purposes. 0 - End device shall indicate that + message was received 1 - End device shall indicate specific + response. 2 - End user / customer response is required. All + other values reserved. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + replyTo: Optional[str] = field(default=None, metadata={ + 'type': 'Attribute', + }) + responseRequired: bytes = field(default=b'\x00', + metadata={ + 'type': 'Attribute', + 'max_length': 1, + 'format': 'base16', + }) + + +@dataclass +class Response(Resource): + """ + The Response object is the generic response data repository which is + extended for specific function sets. + + :ivar createdDateTime: The createdDateTime field contains the date + and time when the acknowledgement/status occurred in the client. + The client will provide the timestamp to ensure the proper time + is captured in case the response is delayed in reaching the + server (server receipt time would not be the same as the actual + confirmation time). The time reported from the client should be + relative to the time server indicated by the + FunctionSetAssignment that also indicated the event resource; if + no FunctionSetAssignment exists, the time of the server where + the event resource was hosted. + :ivar endDeviceLFDI: Contains the LFDI of the device providing the + response. + :ivar status: The status field contains the acknowledgement or + status. Each event type (DRLC, DER, Price, or Text) can return + different status information (e.g. an Acknowledge will be + returned for a Price event where a DRLC event can return Event + Received, Event Started, and Event Completed). The Status field + value definitions are defined in Table 27: Response Types by + Function Set. + :ivar subject: The subject field provides a method to match the + response with the originating event. It is populated with the + mRID of the original object. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + createdDateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + endDeviceLFDI: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 20, + 'format': 'base16', + }) + status: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + subject: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + + +@dataclass +class SelfDeviceLink(Link): + """ + SHALL contain a Link to an instance of SelfDevice. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ServiceSupplierLink(Link): + """ + SHALL contain a Link to an instance of ServiceSupplier. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class SubscribableResource(Resource): + """ + A Resource to which a Subscription can be requested. + + :ivar subscribable: Indicates whether or not subscriptions are + supported for this resource, and whether or not conditional + (thresholds) are supported. If not specified, is "not + subscribable" (0). + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + subscribable: int = field(default=0, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class SubscriptionBase(Resource): + """Holds the information related to a client subscription to receive + updates to a resource automatically. + + The actual resources may be passed in the Notification by specifying + a specific xsi:type for the Resource and passing the full + representation. + + :ivar subscribedResource: The resource for which the subscription + applies. Query string parameters SHALL NOT be specified when + subscribing to list resources. Should a query string parameter + be specified, servers SHALL ignore them. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + subscribedResource: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class SupplyInterruptionOverride(Resource): + """SupplyInterruptionOverride: There may be periods of time when social, regulatory or other concerns mean that service should not be interrupted, even when available credit has been exhausted. Each Prepayment instance links to a List of SupplyInterruptionOverride instances. Each SupplyInterruptionOverride defines a contiguous period of time during which supply SHALL NOT be interrupted. + + :ivar description: The description is a human readable text + describing or naming the object. + :ivar interval: Interval defines the period of time during which + supply should not be interrupted. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + description: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 32, + }) + interval: Optional[DateTimeInterval] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class SupportedLocale(Resource): + """ + Specifies a locale that is supported. + + :ivar locale: The code for a locale that is supported + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + locale: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 42, + }) + + +@dataclass +class TariffProfileLink(Link): + """ + SHALL contain a Link to an instance of TariffProfile. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class Time(Resource): + """ + Contains the representation of time, constantly updated. + + :ivar currentTime: The current time, in the format defined by + TimeType. + :ivar dstEndTime: Time at which daylight savings ends (dstOffset no + longer applied). Result of dstEndRule calculation. + :ivar dstOffset: Daylight savings time offset from local standard + time. A typical practice is advancing clocks one hour when + daylight savings time is in effect, which would result in a + positive dstOffset. + :ivar dstStartTime: Time at which daylight savings begins (apply + dstOffset). Result of dstStartRule calculation. + :ivar localTime: Local time: localTime = currentTime + tzOffset (+ + dstOffset when in effect). + :ivar quality: Metric indicating the quality of the time source from + which the service acquired time. Lower (smaller) quality + enumeration values are assumed to be more accurate. 3 - time + obtained from external authoritative source such as NTP 4 - time + obtained from level 3 source 5 - time manually set or obtained + from level 4 source 6 - time obtained from level 5 source 7 - + time intentionally uncoordinated All other values are reserved + for future use. + :ivar tzOffset: Local time zone offset from currentTime. Does not + include any daylight savings time offsets. For American time + zones, a negative tzOffset SHALL be used (eg, EST = GMT-5 which + is -18000). + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + currentTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + dstEndTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + dstOffset: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + dstStartTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + localTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + quality: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + tzOffset: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class TimeLink(Link): + """ + SHALL contain a Link to an instance of Time. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class UsagePointLink(Link): + """ + SHALL contain a Link to an instance of UsagePoint. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class AccountBalance(Resource): + """AccountBalance contains the regular credit and emergency credit balance + for this given service or commodity prepay instance. + + It may also contain status information concerning the balance data. + + :ivar availableCredit: AvailableCredit shows the balance of the sum + of credits minus the sum of charges. In a Central Wallet mode + this value may be passed down to the Prepayment server via an + out-of-band mechanism. In Local or ESI modes, this value may be + calculated based upon summation of CreditRegister transactions + minus consumption charges calculated using Metering (and + possibly Pricing) function set data. This value may be negative; + for instance, if disconnection is prevented due to a Supply + Interruption Override. + :ivar creditStatus: CreditStatus identifies whether the present + value of availableCredit is considered OK, low, exhausted, or + negative. + :ivar emergencyCredit: EmergencyCredit is the amount of credit still + available for the given service or commodity prepayment + instance. If both availableCredit and emergyCredit are + exhausted, then service will typically be disconnected. + :ivar emergencyCreditStatus: EmergencyCreditStatus identifies + whether the present value of emergencyCredit is considered OK, + low, exhausted, or negative. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + availableCredit: Optional[AccountingUnit] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + creditStatus: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + emergencyCredit: Optional[AccountingUnit] = field(default=None, metadata={ + 'type': 'Element', + }) + emergencyCreditStatus: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class ActiveBillingPeriodListLink(ListLink): + """ + SHALL contain a Link to a List of active BillingPeriod instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveCreditRegisterListLink(ListLink): + """ + SHALL contain a Link to a List of active CreditRegister instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveDERControlListLink(ListLink): + """ + SHALL contain a Link to a List of active DERControl instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveEndDeviceControlListLink(ListLink): + """ + SHALL contain a Link to a List of active EndDeviceControl instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveFlowReservationListLink(ListLink): + """ + SHALL contain a Link to a List of active FlowReservation instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveProjectionReadingListLink(ListLink): + """ + SHALL contain a Link to a List of active ProjectionReading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveSupplyInterruptionOverrideListLink(ListLink): + """ + SHALL contain a Link to a List of active SupplyInterruptionOverride + instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveTargetReadingListLink(ListLink): + """ + SHALL contain a Link to a List of active TargetReading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveTextMessageListLink(ListLink): + """ + SHALL contain a Link to a List of active TextMessage instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ActiveTimeTariffIntervalListLink(ListLink): + """ + SHALL contain a Link to a List of active TimeTariffInterval instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class AssociatedDERProgramListLink(ListLink): + """ + SHALL contain a Link to a List of DERPrograms having the DERControl(s) for + this DER. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class BillingPeriodListLink(ListLink): + """ + SHALL contain a Link to a List of BillingPeriod instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class BillingReading(ReadingBase): + """Data captured at regular intervals of time. + + Interval data could be captured as incremental data, absolute data, + or relative data. The source for the data is usually a tariff + quantity or an engineering quantity. Data is typically captured in + time-tagged, uniform, fixed-length intervals of 5 min, 10 min, 15 + min, 30 min, or 60 min. However, consumption aggregations can also + be represented with this class. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Charge: List[Charge] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class BillingReadingListLink(ListLink): + """ + SHALL contain a Link to a List of BillingReading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class BillingReadingSetListLink(ListLink): + """ + SHALL contain a Link to a List of BillingReadingSet instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ConsumptionTariffIntervalList(List_type): + """ + A List element to hold ConsumptionTariffInterval objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ConsumptionTariffInterval: List[ConsumptionTariffInterval] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class ConsumptionTariffIntervalListLink(ListLink): + """ + SHALL contain a Link to a List of ConsumptionTariffInterval instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class CreditRegister(IdentifiedObject): + """CreditRegister instances define a credit-modifying transaction. + + Typically this would be a credit-adding transaction, but may be a + subtracting transaction (perhaps in response to an out-of-band debt + signal). + + :ivar creditAmount: CreditAmount is the amount of credit being added + by a particular CreditRegister transaction. Negative values + indicate that credit is being subtracted. + :ivar creditType: CreditType indicates whether the credit + transaction applies to regular or emergency credit. + :ivar effectiveTime: EffectiveTime identifies the time at which the + credit transaction goes into effect. For credit addition + transactions, this is typically the moment at which the + transaction takes place. For credit subtraction transactions, + (e.g., non-fuel debt recovery transactions initiated from a + back-haul or ESI) this may be a future time at which credit is + deducted. + :ivar token: Token is security data that authenticates the + legitimacy of the transaction. The details of this token are not + defined by IEEE 2030.5. How a Prepayment server handles this + field is left as vendor specific implementation or will be + defined by one or more other standards. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + creditAmount: Optional[AccountingUnit] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + creditType: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + effectiveTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + token: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + + +@dataclass +class CreditRegisterListLink(ListLink): + """ + SHALL contain a Link to a List of CreditRegister instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class CustomerAccountListLink(ListLink): + """ + SHALL contain a Link to a List of CustomerAccount instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class CustomerAgreementListLink(ListLink): + """ + SHALL contain a Link to a List of CustomerAgreement instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERAvailability(SubscribableResource): + """ + Indicates current reserve generation status. + + :ivar availabilityDuration: Indicates number of seconds the DER will + be able to deliver active power at the reservePercent level. + :ivar maxChargeDuration: Indicates number of seconds the DER will be + able to receive active power at the reserveChargePercent level. + :ivar readingTime: The timestamp when the DER availability was last + updated. + :ivar reserveChargePercent: Percent of continuous received active + power (%setMaxChargeRateW) that is estimated to be available in + reserve. + :ivar reservePercent: Percent of continuous delivered active power + (%setMaxW) that is estimated to be available in reserve. + :ivar statVarAvail: Estimated reserve reactive power, in var. + Represents the lesser of received or delivered reactive power. + :ivar statWAvail: Estimated reserve active power, in watts. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + availabilityDuration: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + maxChargeDuration: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + readingTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + reserveChargePercent: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + reservePercent: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + statVarAvail: Optional[ReactivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + statWAvail: Optional[ActivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class DERControlBase: + """ + Distributed Energy Resource (DER) control values. + + :ivar opModConnect: Set DER as connected (true) or disconnected + (false). Used in conjunction with ramp rate when re-connecting. + Implies galvanic isolation. + :ivar opModEnergize: Set DER as energized (true) or de-energized + (false). Used in conjunction with ramp rate when re-energizing. + :ivar opModFixedPFAbsorbW: The opModFixedPFAbsorbW function + specifies a requested fixed Power Factor (PF) setting for when + active power is being absorbed. The actual displacement SHALL be + within the limits established by setMinPFOverExcited and + setMinPFUnderExcited. If issued simultaneously with other + reactive power controls (e.g. opModFixedVar) the control + resulting in least var magnitude SHOULD take precedence. + :ivar opModFixedPFInjectW: The opModFixedPFInjectW function + specifies a requested fixed Power Factor (PF) setting for when + active power is being injected. The actual displacement SHALL be + within the limits established by setMinPFOverExcited and + setMinPFUnderExcited. If issued simultaneously with other + reactive power controls (e.g. opModFixedVar) the control + resulting in least var magnitude SHOULD take precedence. + :ivar opModFixedVar: The opModFixedVar function specifies the + delivered or received reactive power setpoint. The context for + the setpoint value is determined by refType and SHALL be one of + %setMaxW, %setMaxVar, or %statVarAvail. If issued + simultaneously with other reactive power controls (e.g. + opModFixedPFInjectW) the control resulting in least var + magnitude SHOULD take precedence. + :ivar opModFixedW: The opModFixedW function specifies a requested + charge or discharge mode setpoint, in %setMaxChargeRateW if + negative value or %setMaxW or %setMaxDischargeRateW if positive + value (in hundredths). + :ivar opModFreqDroop: Specifies a frequency-watt operation. This + operation limits active power generation or consumption when the + line frequency deviates from nominal by a specified amount. + :ivar opModFreqWatt: Specify DERCurveLink for curveType == 0. The + Frequency-Watt function limits active power generation or + consumption when the line frequency deviates from nominal by a + specified amount. The Frequency-Watt curve is specified as an + array of Frequency-Watt pairs that are interpolated into a + piecewise linear function with hysteresis. The x value of each + pair specifies a frequency in Hz. The y value specifies a + corresponding active power output in %setMaxW. + :ivar opModHFRTMayTrip: Specify DERCurveLink for curveType == 1. The + High Frequency Ride-Through (HFRT) function is specified by one + or two duration-frequency curves that define the operating + region under high frequency conditions. Each HFRT curve is + specified by an array of duration-frequency pairs that will be + interpolated into a piecewise linear function that defines an + operating region. The x value of each pair specifies a duration + (time at a given frequency in seconds). The y value of each pair + specifies a frequency, in Hz. This control specifies the "may + trip" region. + :ivar opModHFRTMustTrip: Specify DERCurveLink for curveType == 2. + The High Frequency Ride-Through (HFRT) function is specified by + a duration-frequency curve that defines the operating region + under high frequency conditions. Each HFRT curve is specified + by an array of duration-frequency pairs that will be + interpolated into a piecewise linear function that defines an + operating region. The x value of each pair specifies a duration + (time at a given frequency in seconds). The y value of each pair + specifies a frequency, in Hz. This control specifies the "must + trip" region. + :ivar opModHVRTMayTrip: Specify DERCurveLink for curveType == 3. The + High Voltage Ride-Through (HVRT) function is specified by one, + two, or three duration-volt curves that define the operating + region under high voltage conditions. Each HVRT curve is + specified by an array of duration-volt pairs that will be + interpolated into a piecewise linear function that defines an + operating region. The x value of each pair specifies a duration + (time at a given voltage in seconds). The y value of each pair + specifies an effective percentage voltage, defined as ((locally + measured voltage - setVRefOfs / setVRef). This control specifies + the "may trip" region. + :ivar opModHVRTMomentaryCessation: Specify DERCurveLink for + curveType == 4. The High Voltage Ride-Through (HVRT) function + is specified by duration-volt curves that define the operating + region under high voltage conditions. Each HVRT curve is + specified by an array of duration-volt pairs that will be + interpolated into a piecewise linear function that defines an + operating region. The x value of each pair specifies a duration + (time at a given voltage in seconds). The y value of each pair + specifies an effective percent voltage, defined as ((locally + measured voltage - setVRefOfs) / setVRef). This control + specifies the "momentary cessation" region. + :ivar opModHVRTMustTrip: Specify DERCurveLink for curveType == 5. + The High Voltage Ride-Through (HVRT) function is specified by + duration-volt curves that define the operating region under high + voltage conditions. Each HVRT curve is specified by an array of + duration-volt pairs that will be interpolated into a piecewise + linear function that defines an operating region. The x value + of each pair specifies a duration (time at a given voltage in + seconds). The y value of each pair specifies an effective + percent voltage, defined as ((locally measured voltage - + setVRefOfs) / setVRef). This control specifies the "must trip" + region. + :ivar opModLFRTMayTrip: Specify DERCurveLink for curveType == 6. The + Low Frequency Ride-Through (LFRT) function is specified by one + or two duration-frequency curves that define the operating + region under low frequency conditions. Each LFRT curve is + specified by an array of duration-frequency pairs that will be + interpolated into a piecewise linear function that defines an + operating region. The x value of each pair specifies a duration + (time at a given frequency in seconds). The y value of each pair + specifies a frequency, in Hz. This control specifies the "may + trip" region. + :ivar opModLFRTMustTrip: Specify DERCurveLink for curveType == 7. + The Low Frequency Ride-Through (LFRT) function is specified by a + duration-frequency curve that defines the operating region under + low frequency conditions. Each LFRT curve is specified by an + array of duration-frequency pairs that will be interpolated into + a piecewise linear function that defines an operating region. + The x value of each pair specifies a duration (time at a given + frequency in seconds). The y value of each pair specifies a + frequency, in Hz. This control specifies the "must trip" region. + :ivar opModLVRTMayTrip: Specify DERCurveLink for curveType == 8. The + Low Voltage Ride-Through (LVRT) function is specified by one, + two, or three duration-volt curves that define the operating + region under low voltage conditions. Each LVRT curve is + specified by an array of duration-volt pairs that will be + interpolated into a piecewise linear function that defines an + operating region. The x value of each pair specifies a duration + (time at a given voltage in seconds). The y value of each pair + specifies an effective percent voltage, defined as ((locally + measured voltage - setVRefOfs) / setVRef). This control + specifies the "may trip" region. + :ivar opModLVRTMomentaryCessation: Specify DERCurveLink for + curveType == 9. The Low Voltage Ride-Through (LVRT) function is + specified by duration-volt curves that define the operating + region under low voltage conditions. Each LVRT curve is + specified by an array of duration-volt pairs that will be + interpolated into a piecewise linear function that defines an + operating region. The x value of each pair specifies a duration + (time at a given voltage in seconds). The y value of each pair + specifies an effective percent voltage, defined as ((locally + measured voltage - setVRefOfs) / setVRef). This control + specifies the "momentary cessation" region. + :ivar opModLVRTMustTrip: Specify DERCurveLink for curveType == 10. + The Low Voltage Ride-Through (LVRT) function is specified by + duration-volt curves that define the operating region under low + voltage conditions. Each LVRT curve is specified by an array of + duration-volt pairs that will be interpolated into a piecewise + linear function that defines an operating region. The x value + of each pair specifies a duration (time at a given voltage in + seconds). The y value of each pair specifies an effective + percent voltage, defined as ((locally measured voltage - + setVRefOfs) / setVRef). This control specifies the "must trip" + region. + :ivar opModMaxLimW: The opModMaxLimW function sets the maximum + active power generation level at the electrical coupling point + as a percentage of set capacity (%setMaxW, in hundredths). This + limitation may be met e.g. by reducing PV output or by using + excess PV output to charge associated storage. + :ivar opModTargetVar: Target reactive power, in var. This control is + likely to be more useful for aggregators, as individual DERs may + not be able to maintain a target setting. + :ivar opModTargetW: Target output power, in Watts. This control is + likely to be more useful for aggregators, as individual DERs may + not be able to maintain a target setting. + :ivar opModVoltVar: Specify DERCurveLink for curveType == 11. The + static volt-var function provides over- or under-excited var + compensation as a function of measured voltage. The volt-var + curve is specified as an array of volt-var pairs that are + interpolated into a piecewise linear function with hysteresis. + The x value of each pair specifies an effective percent voltage, + defined as ((locally measured voltage - setVRefOfs) / setVRef) + and SHOULD support a domain of at least 0 - 135. If VRef is + present in DERCurve, then the x value of each pair is + additionally multiplied by (VRef / 10000). The y value specifies + a target var output interpreted as a signed percentage (-100 to + 100). The meaning of the y value is determined by yRefType and + must be one of %setMaxW, %setMaxVar, or %statVarAvail. + :ivar opModVoltWatt: Specify DERCurveLink for curveType == 12. The + Volt-Watt reduces active power output as a function of measured + voltage. The Volt-Watt curve is specified as an array of Volt- + Watt pairs that are interpolated into a piecewise linear + function with hysteresis. The x value of each pair specifies an + effective percent voltage, defined as ((locally measured voltage + - setVRefOfs) / setVRef) and SHOULD support a domain of at least + 0 - 135. The y value specifies an active power output + interpreted as a percentage (0 - 100). The meaning of the y + value is determined by yRefType and must be one of %setMaxW or + %statWAvail. + :ivar opModWattPF: Specify DERCurveLink for curveType == 13. The + Watt-PF function varies Power Factor (PF) as a function of + delivered active power. The Watt-PF curve is specified as an + array of Watt-PF coordinates that are interpolated into a + piecewise linear function with hysteresis. The x value of each + pair specifies a watt setting in %setMaxW, (0 - 100). The PF + output setting is a signed displacement in y value (PF sign + SHALL be interpreted according to the EEI convention, where + unity PF is considered unsigned). These settings are not + expected to be updated very often during the life of the + installation, therefore only a single curve is required. If + issued simultaneously with other reactive power controls (e.g. + opModFixedPFInjectW) the control resulting in least var + magnitude SHOULD take precedence. + :ivar opModWattVar: Specify DERCurveLink for curveType == 14. The + Watt-Var function varies vars as a function of delivered active + power. The Watt-Var curve is specified as an array of Watt-Var + pairs that are interpolated into a piecewise linear function + with hysteresis. The x value of each pair specifies a watt + setting in %setMaxW, (0-100). The y value specifies a target var + output interpreted as a signed percentage (-100 to 100). The + meaning of the y value is determined by yRefType and must be one + of %setMaxW, %setMaxVar, or %statVarAvail. + :ivar rampTms: Requested ramp time, in hundredths of a second, for + the device to transition from the current DERControl mode + setting(s) to the new mode setting(s). If absent, use default + ramp rate (setGradW). Resolution is 1/100 sec. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + opModConnect: Optional[bool] = field(default=None, metadata={ + 'type': 'Element', + }) + opModEnergize: Optional[bool] = field(default=None, metadata={ + 'type': 'Element', + }) + opModFixedPFAbsorbW: Optional[PowerFactorWithExcitation] = field(default=None, + metadata={ + 'type': 'Element', + }) + opModFixedPFInjectW: Optional[PowerFactorWithExcitation] = field(default=None, + metadata={ + 'type': 'Element', + }) + opModFixedVar: Optional[FixedVar] = field(default=None, metadata={ + 'type': 'Element', + }) + opModFixedW: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + opModFreqDroop: Optional[FreqDroopType] = field(default=None, metadata={ + 'type': 'Element', + }) + opModFreqWatt: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModHFRTMayTrip: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModHFRTMustTrip: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModHVRTMayTrip: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModHVRTMomentaryCessation: Optional[DERCurveLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + opModHVRTMustTrip: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModLFRTMayTrip: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModLFRTMustTrip: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModLVRTMayTrip: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModLVRTMomentaryCessation: Optional[DERCurveLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + opModLVRTMustTrip: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModMaxLimW: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + opModTargetVar: Optional[ReactivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + opModTargetW: Optional[ActivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + opModVoltVar: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModVoltWatt: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModWattPF: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + opModWattVar: Optional[DERCurveLink] = field(default=None, metadata={ + 'type': 'Element', + }) + rampTms: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class DERControlListLink(ListLink): + """ + SHALL contain a Link to a List of DERControl instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERControlResponse(Response): + """ + A response to a DERControl. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERCurve(IdentifiedObject): + """DER related curves such as Volt-Var mode curves. + + Relationship between an independent variable (X-axis) and a + dependent variable (Y-axis). + + :ivar autonomousVRefEnable: If the curveType is opModVoltVar, then + this field MAY be present. If the curveType is not opModVoltVar, + then this field SHALL NOT be present. Enable/disable autonomous + vRef adjustment. When enabled, the Volt-Var curve characteristic + SHALL be adjusted autonomously as vRef changes and + autonomousVRefTimeConstant SHALL be present. If a DER is able to + support Volt-Var mode but is unable to support autonomous vRef + adjustment, then the DER SHALL execute the curve without + autonomous vRef adjustment. If not specified, then the value is + false. + :ivar autonomousVRefTimeConstant: If the curveType is opModVoltVar, + then this field MAY be present. If the curveType is not + opModVoltVar, then this field SHALL NOT be present. Adjustment + range for vRef time constant, in hundredths of a second. + :ivar creationTime: The time at which the object was created. + :ivar CurveData: + :ivar curveType: Specifies the associated curve-based control mode. + :ivar openLoopTms: Open loop response time, the time to ramp up to + 90% of the new target in response to the change in voltage, in + hundredths of a second. Resolution is 1/100 sec. A value of 0 is + used to mean no limit. When not present, the device SHOULD + follow its default behavior. + :ivar rampDecTms: Decreasing ramp rate, interpreted as a percentage + change in output capability limit per second (e.g. %setMaxW / + sec). Resolution is in hundredths of a percent/second. A value + of 0 means there is no limit. If absent, ramp rate defaults to + setGradW. + :ivar rampIncTms: Increasing ramp rate, interpreted as a percentage + change in output capability limit per second (e.g. %setMaxW / + sec). Resolution is in hundredths of a percent/second. A value + of 0 means there is no limit. If absent, ramp rate defaults to + rampDecTms. + :ivar rampPT1Tms: The configuration parameter for a low-pass filter, + PT1 is a time, in hundredths of a second, in which the filter + will settle to 95% of a step change in the input value. + Resolution is 1/100 sec. + :ivar vRef: If the curveType is opModVoltVar, then this field MAY be + present. If the curveType is not opModVoltVar, then this field + SHALL NOT be present. The nominal AC voltage (RMS) adjustment to + the voltage curve points for Volt-Var curves. + :ivar xMultiplier: Exponent for X-axis value. + :ivar yMultiplier: Exponent for Y-axis value. + :ivar yRefType: The Y-axis units context. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + autonomousVRefEnable: Optional[bool] = field(default=None, metadata={ + 'type': 'Element', + }) + autonomousVRefTimeConstant: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + creationTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + CurveData: List[CurveData] = field(default_factory=list, + metadata={ + 'type': 'Element', + 'min_occurs': 1, + 'max_occurs': 10, + }) + curveType: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + openLoopTms: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + rampDecTms: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + rampIncTms: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + rampPT1Tms: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + vRef: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + xMultiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + yMultiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + yRefType: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class DERCurveListLink(ListLink): + """ + SHALL contain a Link to a List of DERCurve instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERListLink(ListLink): + """ + SHALL contain a Link to a List of DER instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERProgramListLink(ListLink): + """ + SHALL contain a Link to a List of DERProgram instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DERSettings(SubscribableResource): + """ + Distributed energy resource settings. + + :ivar modesEnabled: Bitmap indicating the DER Controls enabled on + the device. See DERControlType for values. If a control is + supported (see DERCapability::modesSupported), but not enabled, + the control will not be executed if encountered. + :ivar setESDelay: Enter service delay, in hundredths of a second. + :ivar setESHighFreq: Enter service frequency high. Specified in + hundredths of Hz. + :ivar setESHighVolt: Enter service voltage high. Specified as an + effective percent voltage, defined as (100% * (locally measured + voltage - setVRefOfs) / setVRef), in hundredths of a percent. + :ivar setESLowFreq: Enter service frequency low. Specified in + hundredths of Hz. + :ivar setESLowVolt: Enter service voltage low. Specified as an + effective percent voltage, defined as (100% * (locally measured + voltage - setVRefOfs) / setVRef), in hundredths of a percent. + :ivar setESRampTms: Enter service ramp time, in hundredths of a + second. + :ivar setESRandomDelay: Enter service randomized delay, in + hundredths of a second. + :ivar setGradW: Set default rate of change (ramp rate) of active + power output due to command or internal action, defined in + %setWMax / second. Resolution is in hundredths of a + percent/second. A value of 0 means there is no limit. + Interpreted as a percentage change in output capability limit + per second when used as a default ramp rate. + :ivar setMaxA: AC current maximum. Maximum AC current in RMS + Amperes. + :ivar setMaxAh: Maximum usable energy storage capacity of the DER, + in AmpHours. Note: this may be different from physical + capability. + :ivar setMaxChargeRateVA: Apparent power charge maximum. Maximum + apparent power the DER can absorb from the grid in Volt-Amperes. + May differ from the apparent power maximum (setMaxVA). + :ivar setMaxChargeRateW: Maximum rate of energy transfer received by + the storage device, in Watts. Defaults to rtgMaxChargeRateW. + :ivar setMaxDischargeRateVA: Apparent power discharge maximum. + Maximum apparent power the DER can deliver to the grid in Volt- + Amperes. May differ from the apparent power maximum (setMaxVA). + :ivar setMaxDischargeRateW: Maximum rate of energy transfer + delivered by the storage device, in Watts. Defaults to + rtgMaxDischargeRateW. + :ivar setMaxV: AC voltage maximum setting. + :ivar setMaxVA: Set limit for maximum apparent power capability of + the DER (in VA). Defaults to rtgMaxVA. + :ivar setMaxVar: Set limit for maximum reactive power delivered by + the DER (in var). SHALL be a positive value &lt;= rtgMaxVar + (default). + :ivar setMaxVarNeg: Set limit for maximum reactive power received by + the DER (in var). If present, SHALL be a negative value + &gt;= rtgMaxVarNeg (default). If absent, defaults to + negative setMaxVar. + :ivar setMaxW: Set limit for maximum active power capability of the + DER (in W). Defaults to rtgMaxW. + :ivar setMaxWh: Maximum energy storage capacity of the DER, in + WattHours. Note: this may be different from physical capability. + :ivar setMinPFOverExcited: Set minimum Power Factor displacement + limit of the DER when injecting reactive power (over-excited); + SHALL be a positive value between 0.0 (typically &gt; 0.7) + and 1.0. SHALL be &gt;= rtgMinPFOverExcited (default). + :ivar setMinPFUnderExcited: Set minimum Power Factor displacement + limit of the DER when absorbing reactive power (under-excited); + SHALL be a positive value between 0.0 (typically &gt; 0.7) + and 0.9999. If present, SHALL be &gt;= rtgMinPFUnderExcited + (default). If absent, defaults to setMinPFOverExcited. + :ivar setMinV: AC voltage minimum setting. + :ivar setSoftGradW: Set soft-start rate of change (soft-start ramp + rate) of active power output due to command or internal action, + defined in %setWMax / second. Resolution is in hundredths of a + percent/second. A value of 0 means there is no limit. + Interpreted as a percentage change in output capability limit + per second when used as a ramp rate. + :ivar setVNom: AC voltage nominal setting. + :ivar setVRef: The nominal AC voltage (RMS) at the utility's point + of common coupling. + :ivar setVRefOfs: The nominal AC voltage (RMS) offset between the + DER's electrical connection point and the utility's point of + common coupling. + :ivar updatedTime: Specifies the time at which the DER information + was last updated. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + modesEnabled: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 4, + 'format': 'base16', + }) + setESDelay: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESHighFreq: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESHighVolt: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESLowFreq: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESLowVolt: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESRampTms: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESRandomDelay: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setGradW: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + setMaxA: Optional[CurrentRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + setMaxAh: Optional[AmpereHour] = field(default=None, metadata={ + 'type': 'Element', + }) + setMaxChargeRateVA: Optional[ApparentPower] = field(default=None, + metadata={ + 'type': 'Element', + }) + setMaxChargeRateW: Optional[ActivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + setMaxDischargeRateVA: Optional[ApparentPower] = field(default=None, + metadata={ + 'type': 'Element', + }) + setMaxDischargeRateW: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + }) + setMaxV: Optional[VoltageRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + setMaxVA: Optional[ApparentPower] = field(default=None, metadata={ + 'type': 'Element', + }) + setMaxVar: Optional[ReactivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + setMaxVarNeg: Optional[ReactivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + setMaxW: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + setMaxWh: Optional[WattHour] = field(default=None, metadata={ + 'type': 'Element', + }) + setMinPFOverExcited: Optional[PowerFactor] = field(default=None, + metadata={ + 'type': 'Element', + }) + setMinPFUnderExcited: Optional[PowerFactor] = field(default=None, + metadata={ + 'type': 'Element', + }) + setMinV: Optional[VoltageRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + setSoftGradW: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setVNom: Optional[VoltageRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + setVRef: Optional[VoltageRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + setVRefOfs: Optional[VoltageRMS] = field(default=None, metadata={ + 'type': 'Element', + }) + updatedTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class DERStatus(SubscribableResource): + """ + DER status information. + + :ivar alarmStatus: Bitmap indicating the status of DER alarms (see + DER LogEvents for more details). 0 - DER_FAULT_OVER_CURRENT 1 - + DER_FAULT_OVER_VOLTAGE 2 - DER_FAULT_UNDER_VOLTAGE 3 - + DER_FAULT_OVER_FREQUENCY 4 - DER_FAULT_UNDER_FREQUENCY 5 - + DER_FAULT_VOLTAGE_IMBALANCE 6 - DER_FAULT_CURRENT_IMBALANCE 7 - + DER_FAULT_EMERGENCY_LOCAL 8 - DER_FAULT_EMERGENCY_REMOTE 9 - + DER_FAULT_LOW_POWER_INPUT 10 - DER_FAULT_PHASE_ROTATION 11-31 - + Reserved + :ivar genConnectStatus: Connect/status value for generator DER. See + ConnectStatusType for values. + :ivar inverterStatus: DER InverterStatus/value. See + InverterStatusType for values. + :ivar localControlModeStatus: The local control mode status. See + LocalControlModeStatusType for values. + :ivar manufacturerStatus: Manufacturer status code. + :ivar operationalModeStatus: Operational mode currently in use. See + OperationalModeStatusType for values. + :ivar readingTime: The timestamp when the current status was last + updated. + :ivar stateOfChargeStatus: State of charge status. See + StateOfChargeStatusType for values. + :ivar storageModeStatus: Storage mode status. See + StorageModeStatusType for values. + :ivar storConnectStatus: Connect/status value for storage DER. See + ConnectStatusType for values. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + alarmStatus: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 4, + 'format': 'base16', + }) + genConnectStatus: Optional[ConnectStatusType] = field(default=None, + metadata={ + 'type': 'Element', + }) + inverterStatus: Optional[InverterStatusType] = field(default=None, + metadata={ + 'type': 'Element', + }) + localControlModeStatus: Optional[LocalControlModeStatusType] = field(default=None, + metadata={ + 'type': 'Element', + }) + manufacturerStatus: Optional[ManufacturerStatusType] = field(default=None, + metadata={ + 'type': 'Element', + }) + operationalModeStatus: Optional[OperationalModeStatusType] = field(default=None, + metadata={ + 'type': 'Element', + }) + readingTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + stateOfChargeStatus: Optional[StateOfChargeStatusType] = field(default=None, + metadata={ + 'type': 'Element', + }) + storageModeStatus: Optional[StorageModeStatusType] = field(default=None, + metadata={ + 'type': 'Element', + }) + storConnectStatus: Optional[ConnectStatusType] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class DemandResponseProgramListLink(ListLink): + """ + SHALL contain a Link to a List of DemandResponseProgram instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class DeviceStatus(Resource): + """ + Status of device. + + :ivar changedTime: The time at which the reported values were + recorded. + :ivar onCount: The number of times that the device has been turned + on: Count of "device on" times, since the last time the counter + was reset + :ivar opState: Device operational state: 0 - Not applicable / + Unknown 1 - Not operating 2 - Operating 3 - Starting up 4 - + Shutting down 5 - At disconnect level 6 - kW ramping 7 - kVar + ramping + :ivar opTime: Total time device has operated: re-settable: + Accumulated time in seconds since the last time the counter was + reset. + :ivar Temperature: + :ivar TimeLink: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + changedTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + onCount: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + opState: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + opTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + Temperature: List[Temperature] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + TimeLink: Optional[TimeLink] = field(default=None, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class DrResponse(Response): + """ + A response to a Demand Response Load Control (EndDeviceControl) message. + + :ivar ApplianceLoadReduction: + :ivar AppliedTargetReduction: + :ivar DutyCycle: + :ivar Offset: + :ivar overrideDuration: Indicates the amount of time, in seconds, + that the client partially opts-out during the demand response + event. When overriding within the allowed override duration, the + client SHALL send a partial opt-out (Response status code 8) for + partial opt-out upon completion, with the total time the event + was overridden (this attribute) populated. The client SHALL send + a no participation status response (status type 10) if the user + partially opts-out for longer than + EndDeviceControl.overrideDuration. + :ivar SetPoint: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ApplianceLoadReduction: Optional[ApplianceLoadReduction] = field(default=None, + metadata={ + 'type': 'Element', + }) + AppliedTargetReduction: Optional[AppliedTargetReduction] = field(default=None, + metadata={ + 'type': 'Element', + }) + DutyCycle: Optional[DutyCycle] = field(default=None, metadata={ + 'type': 'Element', + }) + Offset: Optional[Offset] = field(default=None, metadata={ + 'type': 'Element', + }) + overrideDuration: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + SetPoint: Optional[SetPoint] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class EndDeviceControlListLink(ListLink): + """ + SHALL contain a Link to a List of EndDeviceControl instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class EndDeviceListLink(ListLink): + """ + SHALL contain a Link to a List of EndDevice instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class FileList(List_type): + """ + A List element to hold File objects. + + :ivar File: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + File: List[File] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class FileListLink(ListLink): + """ + SHALL contain a Link to a List of File instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class FileStatus(Resource): + """ + This object provides status of device file load and activation operations. + + :ivar activateTime: Date/time at which this File, referred to by + FileLink, will be activated. Omission of or presence and value + of this element MUST exactly match omission or presence and + value of the activateTime element from the File resource. + :ivar FileLink: + :ivar loadPercent: This element MUST be set to the percentage of the + file, indicated by FileLink, that was loaded during the latest + load attempt. This value MUST be reset to 0 each time a load + attempt is started for the File indicated by FileLink. This + value MUST be increased when an LD receives HTTP response + containing file content. This value MUST be set to 100 when the + full content of the file has been received by the LD + :ivar nextRequestAttempt: This element MUST be set to the time at + which the LD will issue its next GET request for file content + from the File indicated by FileLink + :ivar request503Count: This value MUST be reset to 0 when FileLink + is first pointed at a new File. This value MUST be incremented + each time an LD receives a 503 error from the FS. + :ivar requestFailCount: This value MUST be reset to 0 when FileLink + is first pointed at a new File. This value MUST be incremented + each time a GET request for file content failed. 503 errors MUST + be excluded from this counter. + :ivar status: Current loading status of the file indicated by + FileLink. This element MUST be set to one of the following + values: 0 - No load operation in progress 1 - File load in + progress (first request for file content has been issued by LD) + 2 - File load failed 3 - File loaded successfully (full content + of file has been received by the LD), signature verification in + progress 4 - File signature verification failed 5 - File + signature verified, waiting to activate file. 6 - File + activation failed 7 - File activation in progress 8 - File + activated successfully (this state may not be reached/persisted + through an image activation) 9-255 - Reserved for future use. + :ivar statusTime: This element MUST be set to the time at which file + status transitioned to the value indicated in the status + element. + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + activateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + FileLink: Optional[FileLink] = field(default=None, metadata={ + 'type': 'Element', + }) + loadPercent: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + nextRequestAttempt: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + request503Count: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + requestFailCount: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + status: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + statusTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class FlowReservationRequest(IdentifiedObject): + """Used to request flow transactions. + + Client EndDevices submit a request for charging or discharging from + the server. The server creates an associated FlowReservationResponse + containing the charging parameters and interval to provide a lower + aggregated demand at the premises, or within a larger part of the + distribution system. + + :ivar creationTime: The time at which the request was created. + :ivar durationRequested: A value that is calculated by the storage + device that defines the minimum duration, in seconds, that it + will take to complete the actual flow transaction, including any + ramp times and conditioning times, if applicable. + :ivar energyRequested: Indicates the total amount of energy, in + Watt-Hours, requested to be transferred between the storage + device and the electric power system. Positive values indicate + charging and negative values indicate discharging. This sign + convention is different than for the DER function where + discharging is positive. Note that the energyRequestNow + attribute in the PowerStatus Object must always represent a + charging solution and it is not allowed to have a negative + value. + :ivar intervalRequested: The time window during which the flow + reservation is needed. For example, if an electric vehicle is + set with a 7:00 AM time charge is needed, and price drops to the + lowest tier at 11:00 PM, then this window would likely be from + 11:00 PM until 7:00 AM. + :ivar powerRequested: Indicates the sustained level of power, in + Watts, that is requested. For charging this is calculated by the + storage device and it represents the charging system capability + (which for an electric vehicle must also account for any power + limitations due to the EVSE control pilot). For discharging, a + lower value than the inverter capability can be used as a + target. + :ivar RequestStatus: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + creationTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + durationRequested: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + energyRequested: Optional[SignedRealEnergy] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + intervalRequested: Optional[DateTimeInterval] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + powerRequested: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + RequestStatus: Optional[RequestStatus] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class FlowReservationRequestListLink(ListLink): + """ + SHALL contain a Link to a List of FlowReservationRequest instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class FlowReservationResponseListLink(ListLink): + """ + SHALL contain a Link to a List of FlowReservationResponse instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class FlowReservationResponseResponse(Response): + """ + A response to a FlowReservationResponse. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class FunctionSetAssignmentsListLink(ListLink): + """ + SHALL contain a Link to a List of FunctionSetAssignments instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class HistoricalReadingListLink(ListLink): + """ + SHALL contain a Link to a List of HistoricalReading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class IPAddrListLink(ListLink): + """ + SHALL contain a Link to a List of IPAddr instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class IPInterfaceListLink(ListLink): + """ + SHALL contain a Link to a List of IPInterface instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class LLInterfaceListLink(ListLink): + """ + SHALL contain a Link to a List of LLInterface instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class LoadShedAvailability(Resource): + """ + Indicates current consumption status and ability to shed load. + + :ivar availabilityDuration: Indicates for how many seconds the + consuming device will be able to reduce consumption at the + maximum response level. + :ivar DemandResponseProgramLink: + :ivar sheddablePercent: Maximum percent of current operating load + that is estimated to be sheddable. + :ivar sheddablePower: Maximum amount of current operating load that + is estimated to be sheddable, in Watts. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + availabilityDuration: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + DemandResponseProgramLink: Optional[DemandResponseProgramLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + sheddablePercent: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + sheddablePower: Optional[ActivePower] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class LoadShedAvailabilityListLink(ListLink): + """ + SHALL contain a Link to a List of LoadShedAvailability instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class LogEventListLink(ListLink): + """ + SHALL contain a Link to a List of LogEvent instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class MessagingProgramListLink(ListLink): + """ + SHALL contain a Link to a List of MessagingProgram instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class MeterReadingBase(IdentifiedObject): + """ + A container for associating ReadingType, Readings and ReadingSets. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class MeterReadingListLink(ListLink): + """ + SHALL contain a Link to a List of MeterReading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class MirrorUsagePointListLink(ListLink): + """ + SHALL contain a Link to a List of MirrorUsagePoint instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class NeighborList(List_type): + """ + List of 15.4 neighbors. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Neighbor: List[Neighbor] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class NeighborListLink(ListLink): + """ + SHALL contain a Link to a List of Neighbor instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class Notification(SubscriptionBase): + """Holds the information related to a client subscription to receive + updates to a resource automatically. + + The actual resources may be passed in the Notification by specifying + a specific xsi:type for the Resource and passing the full + representation. + + :ivar newResourceURI: The new location of the resource, if moved. + This attribute SHALL be a fully-qualified absolute URI, not a + relative reference. + :ivar Resource: + :ivar status: 0 = Default Status 1 = Subscription canceled, no + additional information 2 = Subscription canceled, resource moved + 3 = Subscription canceled, resource definition changed (e.g., a + new version of IEEE 2030.5) 4 = Subscription canceled, resource + deleted All other values reserved. + :ivar subscriptionURI: The subscription from which this notification + was triggered. This attribute SHALL be a fully-qualified + absolute URI, not a relative reference. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + newResourceURI: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + }) + Resource: Optional[Resource] = field(default=None, metadata={ + 'type': 'Element', + }) + status: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + subscriptionURI: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class NotificationListLink(ListLink): + """ + SHALL contain a Link to a List of Notification instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class PowerStatus(Resource): + """ + Contains the status of the device's power sources. + + :ivar batteryStatus: Battery system status 0 = unknown 1 = normal + (more than LowChargeThreshold remaining) 2 = low (less than + LowChargeThreshold remaining) 3 = depleted (0% charge remaining) + 4 = not applicable (mains powered only) + :ivar changedTime: The time at which the reported values were + recorded. + :ivar currentPowerSource: This value will be fixed for devices + powered by a single source. This value may change for devices + able to transition between multiple power sources (mains to + battery backup, etc.). + :ivar estimatedChargeRemaining: Estimate of remaining battery charge + as a percent of full charge. + :ivar estimatedTimeRemaining: Estimated time (in seconds) to total + battery charge depletion (under current load) + :ivar PEVInfo: + :ivar sessionTimeOnBattery: If the device has a battery, this is the + time since the device last switched to battery power, or the + time since the device was restarted, whichever is less, in + seconds. + :ivar totalTimeOnBattery: If the device has a battery, this is the + total time the device has been on battery power, in seconds. It + may be reset when the battery is replaced. + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + batteryStatus: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + changedTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + currentPowerSource: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + estimatedChargeRemaining: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + estimatedTimeRemaining: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + PEVInfo: Optional[PEVInfo] = field(default=None, metadata={ + 'type': 'Element', + }) + sessionTimeOnBattery: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + totalTimeOnBattery: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class PrepaymentListLink(ListLink): + """ + SHALL contain a Link to a List of Prepayment instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class PriceResponse(Response): + """ + A response related to a price message. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class PriceResponseCfg(Resource): + """ + Configuration data that specifies how price responsive devices SHOULD + respond to price changes while acting upon a given RateComponent. + + :ivar consumeThreshold: Price responsive clients acting upon the + associated RateComponent SHOULD consume the associated commodity + while the price is less than this threshold. + :ivar maxReductionThreshold: Price responsive clients acting upon + the associated RateComponent SHOULD reduce consumption to the + maximum extent possible while the price is greater than this + threshold. + :ivar RateComponentLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + consumeThreshold: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + maxReductionThreshold: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + RateComponentLink: Optional[RateComponentLink] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class PriceResponseCfgListLink(ListLink): + """ + SHALL contain a Link to a List of PriceResponseCfg instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ProjectionReadingListLink(ListLink): + """ + SHALL contain a Link to a List of ProjectionReading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class RPLInstanceListLink(ListLink): + """ + SHALL contain a Link to a List of RPLInterface instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class RPLSourceRoutesList(List_type): + """ + List or RPL source routes if the hosting device is the DODAGroot. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + RPLSourceRoutes: List[RPLSourceRoutes] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class RPLSourceRoutesListLink(ListLink): + """ + SHALL contain a Link to a List of RPLSourceRoutes instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class RateComponentListLink(ListLink): + """ + SHALL contain a Link to a List of RateComponent instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class Reading(ReadingBase): + """ + Specific value measured by a meter or other asset. + + :ivar localID: The local identifier for this reading within the + reading set. localIDs are assigned in order of creation time. + For interval data, this value SHALL increase with each interval + time, and for block/tier readings, localID SHALL not be + specified. + :ivar subscribable: Indicates whether or not subscriptions are + supported for this resource, and whether or not conditional + (thresholds) are supported. If not specified, is "not + subscribable" (0). + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + localID: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 2, + 'format': 'base16', + }) + subscribable: int = field(default=0, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class ReadingListLink(ListLink): + """ + SHALL contain a Link to a List of Reading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ReadingSetBase(IdentifiedObject): + """A set of Readings of the ReadingType indicated by the parent + MeterReading. + + ReadingBase is abstract, used to define the elements common to + ReadingSet and IntervalBlock. + + :ivar timePeriod: Specifies the time range during which the + contained readings were taken. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + timePeriod: Optional[DateTimeInterval] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class ReadingSetListLink(ListLink): + """ + SHALL contain a Link to a List of ReadingSet instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class RespondableIdentifiedObject(RespondableResource): + """ + An IdentifiedObject to which a Response can be requested. + + :ivar mRID: The global identifier of the object. + :ivar description: The description is a human readable text + describing or naming the object. + :ivar version: Contains the version number of the object. See the + type definition for details. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + mRID: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + description: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 32, + }) + version: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class RespondableSubscribableIdentifiedObject(RespondableResource): + """ + An IdentifiedObject to which a Response can be requested. + + :ivar mRID: The global identifier of the object. + :ivar description: The description is a human readable text + describing or naming the object. + :ivar version: Contains the version number of the object. See the + type definition for details. + :ivar subscribable: Indicates whether or not subscriptions are + supported for this resource, and whether or not conditional + (thresholds) are supported. If not specified, is "not + subscribable" (0). + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + mRID: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + description: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 32, + }) + version: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + subscribable: int = field(default=0, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class ResponseList(List_type): + """ + A List element to hold Response objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Response: List[Response] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class ResponseListLink(ListLink): + """ + SHALL contain a Link to a List of Response instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ResponseSetListLink(ListLink): + """ + SHALL contain a Link to a List of ResponseSet instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class ServiceSupplier(IdentifiedObject): + """ + Organisation that provides services to Customers. + + :ivar email: E-mail address for this service supplier. + :ivar phone: Human-readable phone number for this service supplier. + :ivar providerID: Contains the IANA PEN for the commodity provider. + :ivar web: Website URI address for this service supplier. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + email: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 32, + }) + phone: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 20, + }) + providerID: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + web: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 42, + }) + + +@dataclass +class SubscribableIdentifiedObject(SubscribableResource): + """ + An IdentifiedObject to which a Subscription can be requested. + + :ivar mRID: The global identifier of the object. + :ivar description: The description is a human readable text + describing or naming the object. + :ivar version: Contains the version number of the object. See the + type definition for details. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + mRID: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + description: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 32, + }) + version: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class SubscribableList(SubscribableResource): + """ + A List to which a Subscription can be requested. + + :ivar all: The number specifying "all" of the items in the list. + Required on GET, ignored otherwise. + :ivar results: Indicates the number of items in this page of + results. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + all: Optional[int] = field(default=None, metadata={ + 'type': 'Attribute', + 'required': True, + }) + results: Optional[int] = field(default=None, + metadata={ + 'type': 'Attribute', + 'required': True, + }) + + +@dataclass +class Subscription(SubscriptionBase): + """ + Holds the information related to a client subscription to receive updates + to a resource automatically. + + :ivar Condition: + :ivar encoding: 0 - application/sep+xml 1 - application/sep-exi + 2-255 - reserved + :ivar level: Contains the preferred schema and extensibility level + indication such as "+S1" + :ivar limit: This element is used to indicate the maximum number of + list items that should be included in a notification when the + subscribed resource changes. This limit is meant to be + functionally equivalent to the ‘limit’ query string parameter, + but applies to both list resources as well as other resources. + For list resources, if a limit of ‘0’ is specified, then + notifications SHALL contain a list resource with results=’0’ + (equivalent to a simple change notification). For list + resources, if a limit greater than ‘0’ is specified, then + notifications SHALL contain a list resource with results equal + to the limit specified (or less, should the list contain fewer + items than the limit specified or should the server be unable to + provide the requested number of items for any reason) and follow + the same rules for list resources (e.g., ordering). For non- + list resources, if a limit of ‘0’ is specified, then + notifications SHALL NOT contain a resource representation + (equivalent to a simple change notification). For non-list + resources, if a limit greater than ‘0’ is specified, then + notifications SHALL contain the representation of the changed + resource. + :ivar notificationURI: The resource to which to post the + notifications about the requested subscribed resource. Because + this URI will exist on a server other than the one being POSTed + to, this attribute SHALL be a fully-qualified absolute URI, not + a relative reference. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Condition: Optional[Condition] = field(default=None, metadata={ + 'type': 'Element', + }) + encoding: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + level: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + }) + limit: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + notificationURI: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class SubscriptionListLink(ListLink): + """ + SHALL contain a Link to a List of Subscription instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class SupplyInterruptionOverrideList(List_type): + """ + A List element to hold SupplyInterruptionOverride objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + SupplyInterruptionOverride: List[SupplyInterruptionOverride] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class SupplyInterruptionOverrideListLink(ListLink): + """ + SHALL contain a Link to a List of SupplyInterruptionOverride instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class SupportedLocaleList(List_type): + """ + A List element to hold SupportedLocale objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + SupportedLocale: List[SupportedLocale] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class SupportedLocaleListLink(ListLink): + """ + SHALL contain a Link to a List of SupportedLocale instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class TargetReadingListLink(ListLink): + """ + SHALL contain a Link to a List of TargetReading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class TariffProfileListLink(ListLink): + """ + SHALL contain a Link to a List of TariffProfile instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class TextMessageListLink(ListLink): + """ + SHALL contain a Link to a List of TextMessage instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class TextResponse(Response): + """ + A response to a text message. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class TimeTariffIntervalListLink(ListLink): + """ + SHALL contain a Link to a List of TimeTariffInterval instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class UsagePointBase(IdentifiedObject): + """Logical point on a network at which consumption or production is either + physically measured (e.g. metered) or estimated (e.g. unmetered street + lights). + + A container for associating ReadingType, Readings and ReadingSets. + + :ivar roleFlags: Specifies the roles that apply to the usage point. + :ivar serviceCategoryKind: The kind of service provided by this + usage point. + :ivar status: Specifies the current status of the service at this + usage point. 0 = off 1 = on + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + roleFlags: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 2, + 'format': 'base16', + }) + serviceCategoryKind: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + status: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class UsagePointListLink(ListLink): + """ + SHALL contain a Link to a List of UsagePoint instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class AbstractDevice(SubscribableResource): + """ + The EndDevice providing the resources available within the + DeviceCapabilities. + + :ivar ConfigurationLink: + :ivar DERListLink: + :ivar deviceCategory: This field is for use in devices that can + adjust energy usage (e.g., demand response, distributed energy + resources). For devices that do not respond to + EndDeviceControls or DERControls (for instance, an ESI), this + field should not have any bits set. + :ivar DeviceInformationLink: + :ivar DeviceStatusLink: + :ivar FileStatusLink: + :ivar IPInterfaceListLink: + :ivar lFDI: Long form of device identifier. See the Security section + for additional details. + :ivar LoadShedAvailabilityListLink: + :ivar LogEventListLink: + :ivar PowerStatusLink: + :ivar sFDI: Short form of device identifier, WITH the checksum + digit. See the Security section for additional details. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ConfigurationLink: Optional[ConfigurationLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DERListLink: Optional[DERListLink] = field(default=None, metadata={ + 'type': 'Element', + }) + deviceCategory: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 4, + 'format': 'base16', + }) + DeviceInformationLink: Optional[DeviceInformationLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DeviceStatusLink: Optional[DeviceStatusLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + FileStatusLink: Optional[FileStatusLink] = field(default=None, metadata={ + 'type': 'Element', + }) + IPInterfaceListLink: Optional[IPInterfaceListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + lFDI: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 20, + 'format': 'base16', + }) + LoadShedAvailabilityListLink: Optional[LoadShedAvailabilityListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + LogEventListLink: Optional[LogEventListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + PowerStatusLink: Optional[PowerStatusLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + sFDI: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_inclusive': 281474976710655, + }) + + +@dataclass +class BillingMeterReadingBase(MeterReadingBase): + """ + Contains historical, target, and projection readings of various types, + possibly associated with charges. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + BillingReadingSetListLink: Optional[BillingReadingSetListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + ReadingTypeLink: Optional[ReadingTypeLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class BillingPeriodList(SubscribableList): + """ + A List element to hold BillingPeriod objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + BillingPeriod: List[BillingPeriod] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class BillingReadingList(List_type): + """ + A List element to hold BillingReading objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + BillingReading: List[BillingReading] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class BillingReadingSet(ReadingSetBase): + """ + Time sequence of readings of the same reading type. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + BillingReadingListLink: Optional[BillingReadingListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class Configuration(SubscribableResource): + """ + This resource contains various settings to control the operation of the + device. + + :ivar currentLocale: [RFC 4646] identifier of the language-region + currently in use. + :ivar PowerConfiguration: + :ivar PriceResponseCfgListLink: + :ivar TimeConfiguration: + :ivar userDeviceName: User assigned, convenience name used for + network browsing displays, etc. Example "My Thermostat" + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + currentLocale: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 42, + }) + PowerConfiguration: Optional[PowerConfiguration] = field(default=None, + metadata={ + 'type': 'Element', + }) + PriceResponseCfgListLink: Optional[PriceResponseCfgListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + TimeConfiguration: Optional[TimeConfiguration] = field(default=None, + metadata={ + 'type': 'Element', + }) + userDeviceName: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class CreditRegisterList(List_type): + """ + A List element to hold CreditRegister objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + CreditRegister: List[CreditRegister] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class CustomerAccount(IdentifiedObject): + """Assignment of a group of products and services purchased by the Customer + through a CustomerAgreement, used as a mechanism for customer billing and + payment. + + It contains common information from the various types of + CustomerAgreements to create billings (invoices) for a Customer and + receive payment. + + :ivar currency: The ISO 4217 code indicating the currency applicable + to the bill amounts in the summary. See list at + http://www.unece.org/cefact/recommendations/rec09/rec09_ecetrd203.pdf + :ivar customerAccount: The account number for the customer (if + applicable). + :ivar CustomerAgreementListLink: + :ivar customerName: The name of the customer. + :ivar pricePowerOfTenMultiplier: Indicates the power of ten + multiplier for the prices in this function set. + :ivar ServiceSupplierLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + currency: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + customerAccount: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 42, + }) + CustomerAgreementListLink: Optional[CustomerAgreementListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + customerName: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 42, + }) + pricePowerOfTenMultiplier: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + ServiceSupplierLink: Optional[ServiceSupplierLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class CustomerAgreement(IdentifiedObject): + """Agreement between the customer and the service supplier to pay for + service at a specific service location. + + It records certain billing information about the type of service + provided at the service location and is used during charge creation + to determine the type of service. + + :ivar ActiveBillingPeriodListLink: + :ivar ActiveProjectionReadingListLink: + :ivar ActiveTargetReadingListLink: + :ivar BillingPeriodListLink: + :ivar HistoricalReadingListLink: + :ivar PrepaymentLink: + :ivar ProjectionReadingListLink: + :ivar serviceAccount: The account number of the service account (if + applicable). + :ivar serviceLocation: The address or textual description of the + service location. + :ivar TargetReadingListLink: + :ivar TariffProfileLink: + :ivar UsagePointLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ActiveBillingPeriodListLink: Optional[ActiveBillingPeriodListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + ActiveProjectionReadingListLink: Optional[ActiveProjectionReadingListLink] = field( + default=None, metadata={ + 'type': 'Element', + }) + ActiveTargetReadingListLink: Optional[ActiveTargetReadingListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + BillingPeriodListLink: Optional[BillingPeriodListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + HistoricalReadingListLink: Optional[HistoricalReadingListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + PrepaymentLink: Optional[PrepaymentLink] = field(default=None, metadata={ + 'type': 'Element', + }) + ProjectionReadingListLink: Optional[ProjectionReadingListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + serviceAccount: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 42, + }) + serviceLocation: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 42, + }) + TargetReadingListLink: Optional[TargetReadingListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + TariffProfileLink: Optional[TariffProfileLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + UsagePointLink: Optional[UsagePointLink] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class DER(SubscribableResource): + """ + Contains links to DER resources. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + AssociatedDERProgramListLink: Optional[AssociatedDERProgramListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + AssociatedUsagePointLink: Optional[AssociatedUsagePointLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + CurrentDERProgramLink: Optional[CurrentDERProgramLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DERAvailabilityLink: Optional[DERAvailabilityLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DERCapabilityLink: Optional[DERCapabilityLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DERSettingsLink: Optional[DERSettingsLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DERStatusLink: Optional[DERStatusLink] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class DERCurveList(List_type): + """ + A List element to hold DERCurve objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DERCurve: List[DERCurve] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class DERProgram(SubscribableIdentifiedObject): + """ + Distributed Energy Resource program. + + :ivar ActiveDERControlListLink: + :ivar DefaultDERControlLink: + :ivar DERControlListLink: + :ivar DERCurveListLink: + :ivar primacy: Indicates the relative primacy of the provider of + this Program. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ActiveDERControlListLink: Optional[ActiveDERControlListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DefaultDERControlLink: Optional[DefaultDERControlLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DERControlListLink: Optional[DERControlListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DERCurveListLink: Optional[DERCurveListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + primacy: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class DefaultDERControl(SubscribableIdentifiedObject): + """ + Contains control mode information to be used if no active DERControl is + found. + + :ivar DERControlBase: + :ivar setESDelay: Enter service delay, in hundredths of a second. + When present, this value SHALL update the value of the + corresponding setting (DERSettings::setESDelay). + :ivar setESHighFreq: Enter service frequency high. Specified in + hundredths of Hz. When present, this value SHALL update the + value of the corresponding setting (DERSettings::setESHighFreq). + :ivar setESHighVolt: Enter service voltage high. Specified as an + effective percent voltage, defined as (100% * (locally measured + voltage - setVRefOfs) / setVRef), in hundredths of a percent. + When present, this value SHALL update the value of the + corresponding setting (DERSettings::setESHighVolt). + :ivar setESLowFreq: Enter service frequency low. Specified in + hundredths of Hz. When present, this value SHALL update the + value of the corresponding setting (DERSettings::setESLowFreq). + :ivar setESLowVolt: Enter service voltage low. Specified as an + effective percent voltage, defined as (100% * (locally measured + voltage - setVRefOfs) / setVRef), in hundredths of a percent. + When present, this value SHALL update the value of the + corresponding setting (DERSettings::setESLowVolt). + :ivar setESRampTms: Enter service ramp time, in hundredths of a + second. When present, this value SHALL update the value of the + corresponding setting (DERSettings::setESRampTms). + :ivar setESRandomDelay: Enter service randomized delay, in + hundredths of a second. When present, this value SHALL update + the value of the corresponding setting + (DERSettings::setESRandomDelay). + :ivar setGradW: Set default rate of change (ramp rate) of active + power output due to command or internal action, defined in + %setWMax / second. Resolution is in hundredths of a + percent/second. A value of 0 means there is no limit. + Interpreted as a percentage change in output capability limit + per second when used as a default ramp rate. When present, this + value SHALL update the value of the corresponding setting + (DERSettings::setGradW). + :ivar setSoftGradW: Set soft-start rate of change (soft-start ramp + rate) of active power output due to command or internal action, + defined in %setWMax / second. Resolution is in hundredths of a + percent/second. A value of 0 means there is no limit. + Interpreted as a percentage change in output capability limit + per second when used as a ramp rate. When present, this value + SHALL update the value of the corresponding setting + (DERSettings::setSoftGradW). + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DERControlBase: Optional[DERControlBase] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + setESDelay: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESHighFreq: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESHighVolt: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESLowFreq: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESLowVolt: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESRampTms: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setESRandomDelay: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setGradW: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + setSoftGradW: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class DemandResponseProgram(IdentifiedObject): + """ + Demand response program. + + :ivar ActiveEndDeviceControlListLink: + :ivar availabilityUpdatePercentChangeThreshold: This attribute + allows program providers to specify the requested granularity of + updates to LoadShedAvailability sheddablePercent. If not + present, or set to 0, then updates to LoadShedAvailability SHALL + NOT be provided. If present and greater than zero, then clients + SHALL provide their LoadShedAvailability if it has not + previously been provided, and thereafter if the difference + between the previously provided value and the current value of + LoadShedAvailability sheddablePercent is greater than + availabilityUpdatePercentChangeThreshold. + :ivar availabilityUpdatePowerChangeThreshold: This attribute allows + program providers to specify the requested granularity of + updates to LoadShedAvailability sheddablePower. If not present, + or set to 0, then updates to LoadShedAvailability SHALL NOT be + provided. If present and greater than zero, then clients SHALL + provide their LoadShedAvailability if it has not previously been + provided, and thereafter if the difference between the + previously provided value and the current value of + LoadShedAvailability sheddablePower is greater than + availabilityUpdatePowerChangeThreshold. + :ivar EndDeviceControlListLink: + :ivar primacy: Indicates the relative primacy of the provider of + this program. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ActiveEndDeviceControlListLink: Optional[ActiveEndDeviceControlListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + availabilityUpdatePercentChangeThreshold: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + }) + availabilityUpdatePowerChangeThreshold: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + }) + EndDeviceControlListLink: Optional[EndDeviceControlListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + primacy: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class DeviceInformation(Resource): + """ + Contains identification and other information about the device that changes + very infrequently, typically only when updates are applied, if ever. + + :ivar DRLCCapabilities: + :ivar functionsImplemented: Bitmap indicating the function sets used + by the device as a client. 0 - Device Capability 1 - Self Device + Resource 2 - End Device Resource 3 - Function Set Assignments 4 + - Subscription/Notification Mechanism 5 - Response 6 - Time 7 - + Device Information 8 - Power Status 9 - Network Status 10 - Log + Event 11 - Configuration Resource 12 - Software Download 13 - + DRLC 14 - Metering 15 - Pricing 16 - Messaging 17 - Billing 18 - + Prepayment 19 - Flow Reservation 20 - DER Control + :ivar gpsLocation: GPS location of this device. + :ivar lFDI: Long form device identifier. See the Security section + for full details. + :ivar mfDate: Date/time of manufacture + :ivar mfHwVer: Manufacturer hardware version + :ivar mfID: The manufacturer's IANA Enterprise Number. + :ivar mfInfo: Manufacturer dependent information related to the + manufacture of this device + :ivar mfModel: Manufacturer's model number + :ivar mfSerNum: Manufacturer assigned serial number + :ivar primaryPower: Primary source of power. + :ivar secondaryPower: Secondary source of power + :ivar SupportedLocaleListLink: + :ivar swActTime: Activation date/time of currently running software + :ivar swVer: Currently running software version + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DRLCCapabilities: Optional[DRLCCapabilities] = field(default=None, + metadata={ + 'type': 'Element', + }) + functionsImplemented: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 8, + 'format': 'base16', + }) + gpsLocation: Optional[GPSLocationType] = field(default=None, metadata={ + 'type': 'Element', + }) + lFDI: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 20, + 'format': 'base16', + }) + mfDate: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + mfHwVer: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + mfID: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + mfInfo: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 32, + }) + mfModel: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + mfSerNum: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + primaryPower: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + secondaryPower: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + SupportedLocaleListLink: Optional[SupportedLocaleListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + swActTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + swVer: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 32, + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class Event(RespondableSubscribableIdentifiedObject): + """An Event indicates information that applies to a particular period of + time. + + Events SHALL be executed relative to the time of the server, as + described in the Time function set section 11.1. + + :ivar creationTime: The time at which the Event was created. + :ivar EventStatus: + :ivar interval: The period during which the Event applies. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + creationTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + EventStatus: Optional[EventStatus] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + interval: Optional[DateTimeInterval] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class FlowReservationRequestList(List_type): + """ + A List element to hold FlowReservationRequest objects. + + :ivar FlowReservationRequest: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + FlowReservationRequest: List[FlowReservationRequest] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class FunctionSetAssignmentsBase(Resource): + """ + Defines a collection of function set instances that are to be used by one + or more devices as indicated by the EndDevice object(s) of the server. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + CustomerAccountListLink: Optional[CustomerAccountListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + DemandResponseProgramListLink: Optional[DemandResponseProgramListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + DERProgramListLink: Optional[DERProgramListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + FileListLink: Optional[FileListLink] = field(default=None, metadata={ + 'type': 'Element', + }) + MessagingProgramListLink: Optional[MessagingProgramListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + PrepaymentListLink: Optional[PrepaymentListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + ResponseSetListLink: Optional[ResponseSetListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + TariffProfileListLink: Optional[TariffProfileListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + TimeLink: Optional[TimeLink] = field(default=None, metadata={ + 'type': 'Element', + }) + UsagePointListLink: Optional[UsagePointListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class IEEE_802_15_4: + """ + Contains 802.15.4 link layer specific attributes. + + :ivar capabilityInfo: As defined by IEEE 802.15.4 + :ivar NeighborListLink: + :ivar shortAddress: As defined by IEEE 802.15.4 + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + capabilityInfo: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 1, + 'format': 'base16', + }) + NeighborListLink: Optional[NeighborListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + shortAddress: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class IPAddr(Resource): + """ + An Internet Protocol address object. + + :ivar address: An IP address value. + :ivar RPLInstanceListLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + address: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + RPLInstanceListLink: Optional[RPLInstanceListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class IPInterface(Resource): + """Specific IPInterface resource. + + This resource may be thought of as network status information for a + specific network (IP) layer interface. + + :ivar ifDescr: Use rules from [RFC 2863]. + :ivar ifHighSpeed: Use rules from [RFC 2863]. + :ivar ifInBroadcastPkts: Use rules from [RFC 2863]. + :ivar ifIndex: Use rules from [RFC 2863]. + :ivar ifInDiscards: Use rules from [RFC 2863]. Can be thought of as + Input Datagrams Discarded. + :ivar ifInErrors: Use rules from [RFC 2863]. + :ivar ifInMulticastPkts: Use rules from [RFC 2863]. Can be thought + of as Multicast Datagrams Received. + :ivar ifInOctets: Use rules from [RFC 2863]. Can be thought of as + Bytes Received. + :ivar ifInUcastPkts: Use rules from [RFC 2863]. Can be thought of as + Datagrams Received. + :ivar ifInUnknownProtos: Use rules from [RFC 2863]. Can be thought + of as Datagrams with Unknown Protocol Received. + :ivar ifMtu: Use rules from [RFC 2863]. + :ivar ifName: Use rules from [RFC 2863]. + :ivar ifOperStatus: Use rules and assignments from [RFC 2863]. + :ivar ifOutBroadcastPkts: Use rules from [RFC 2863]. Can be thought + of as Broadcast Datagrams Sent. + :ivar ifOutDiscards: Use rules from [RFC 2863]. Can be thought of as + Output Datagrams Discarded. + :ivar ifOutErrors: Use rules from [RFC 2863]. + :ivar ifOutMulticastPkts: Use rules from [RFC 2863]. Can be thought + of as Multicast Datagrams Sent. + :ivar ifOutOctets: Use rules from [RFC 2863]. Can be thought of as + Bytes Sent. + :ivar ifOutUcastPkts: Use rules from [RFC 2863]. Can be thought of + as Datagrams Sent. + :ivar ifPromiscuousMode: Use rules from [RFC 2863]. + :ivar ifSpeed: Use rules from [RFC 2863]. + :ivar ifType: Use rules and assignments from [RFC 2863]. + :ivar IPAddrListLink: + :ivar lastResetTime: Similar to ifLastChange in [RFC 2863]. + :ivar lastUpdatedTime: The date/time of the reported status. + :ivar LLInterfaceListLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ifDescr: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 192, + }) + ifHighSpeed: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifInBroadcastPkts: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifIndex: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifInDiscards: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifInErrors: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifInMulticastPkts: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifInOctets: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifInUcastPkts: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifInUnknownProtos: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifMtu: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifName: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 16, + }) + ifOperStatus: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifOutBroadcastPkts: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifOutDiscards: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifOutErrors: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifOutMulticastPkts: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifOutOctets: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifOutUcastPkts: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifPromiscuousMode: Optional[bool] = field(default=None, metadata={ + 'type': 'Element', + }) + ifSpeed: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + ifType: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + IPAddrListLink: Optional[IPAddrListLink] = field(default=None, metadata={ + 'type': 'Element', + }) + lastResetTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + lastUpdatedTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLInterfaceListLink: Optional[LLInterfaceListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class LoadShedAvailabilityList(List_type): + """ + A List element to hold LoadShedAvailability objects. + + :ivar LoadShedAvailability: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + LoadShedAvailability: List[LoadShedAvailability] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class LogEventList(SubscribableList): + """ + A List element to hold LogEvent objects. + + :ivar LogEvent: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + LogEvent: List[LogEvent] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class MessagingProgram(SubscribableIdentifiedObject): + """ + Provides a container for collections of text messages. + + :ivar ActiveTextMessageListLink: + :ivar locale: Indicates the language and region of the messages in + this collection. + :ivar primacy: Indicates the relative primacy of the provider of + this program. + :ivar TextMessageListLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ActiveTextMessageListLink: Optional[ActiveTextMessageListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + locale: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 42, + }) + primacy: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + TextMessageListLink: Optional[TextMessageListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class MeterReading(MeterReadingBase): + """ + Set of values obtained from the meter. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + RateComponentListLink: Optional[RateComponentListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + ReadingLink: Optional[ReadingLink] = field(default=None, metadata={ + 'type': 'Element', + }) + ReadingSetListLink: Optional[ReadingSetListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + ReadingTypeLink: Optional[ReadingTypeLink] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class MirrorReadingSet(ReadingSetBase): + """ + A set of Readings of the ReadingType indicated by the parent MeterReading. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Reading: List[Reading] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class NotificationList(List_type): + """ + A List element to hold Notification objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Notification: List[Notification] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class PriceResponseCfgList(List_type): + """ + A List element to hold PriceResponseCfg objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + PriceResponseCfg: List[PriceResponseCfg] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class RPLInstance(Resource): + """Specific RPLInstance resource. + + This resource may be thought of as network status information for a + specific RPL instance associated with IPInterface. + + :ivar DODAGid: See [RFC 6550]. + :ivar DODAGroot: See [RFC 6550]. + :ivar flags: See [RFC 6550]. + :ivar groundedFlag: See [RFC 6550]. + :ivar MOP: See [RFC 6550]. + :ivar PRF: See [RFC 6550]. + :ivar rank: See [RFC 6550]. + :ivar RPLInstanceID: See [RFC 6550]. + :ivar RPLSourceRoutesListLink: + :ivar versionNumber: See [RFC 6550]. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DODAGid: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + DODAGroot: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + flags: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + groundedFlag: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + MOP: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + PRF: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + rank: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + RPLInstanceID: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + RPLSourceRoutesListLink: Optional[RPLSourceRoutesListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + versionNumber: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class RateComponent(IdentifiedObject): + """ + Specifies the applicable charges for a single component of the rate, which + could be generation price or consumption price, for example. + + :ivar ActiveTimeTariffIntervalListLink: + :ivar flowRateEndLimit: Specifies the maximum flow rate (e.g. kW for + electricity) for which this RateComponent applies, for the usage + point and given rate / tariff. In combination with + flowRateStartLimit, allows a service provider to define the + demand or output characteristics for the particular tariff + design. If a server includes the flowRateEndLimit attribute, + then it SHALL also include flowRateStartLimit attribute. For + example, a service provider’s tariff limits customers to 20 kWs + of demand for the given rate structure. Above this threshold + (from 20-50 kWs), there are different demand charges per unit of + consumption. The service provider can use flowRateStartLimit + and flowRateEndLimit to describe the demand characteristics of + the different rates. Similarly, these attributes can be used to + describe limits on premises DERs that might be producing a + commodity and sending it back into the distribution network. + Note: At the time of writing, service provider tariffs with + demand-based components were not originally identified as being + in scope, and service provider tariffs vary widely in their use + of demand components and the method for computing charges. It + is expected that industry groups (e.g., OpenSG) will document + requirements in the future that the IEEE 2030.5 community can + then use as source material for the next version of IEEE 2030.5. + :ivar flowRateStartLimit: Specifies the minimum flow rate (e.g., kW + for electricity) for which this RateComponent applies, for the + usage point and given rate / tariff. In combination with + flowRateEndLimit, allows a service provider to define the demand + or output characteristics for the particular tariff design. If + a server includes the flowRateStartLimit attribute, then it + SHALL also include flowRateEndLimit attribute. + :ivar ReadingTypeLink: Provides indication of the ReadingType with + which this price is associated. + :ivar roleFlags: Specifies the roles that this usage point has been + assigned. + :ivar TimeTariffIntervalListLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ActiveTimeTariffIntervalListLink: Optional[ActiveTimeTariffIntervalListLink] = field( + default=None, metadata={ + 'type': 'Element', + }) + flowRateEndLimit: Optional[UnitValueType] = field(default=None, metadata={ + 'type': 'Element', + }) + flowRateStartLimit: Optional[UnitValueType] = field(default=None, + metadata={ + 'type': 'Element', + }) + ReadingTypeLink: Optional[ReadingTypeLink] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + roleFlags: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 2, + 'format': 'base16', + }) + TimeTariffIntervalListLink: Optional[TimeTariffIntervalListLink] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class ReadingList(SubscribableList): + """ + A List element to hold Reading objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Reading: List[Reading] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class ReadingSet(ReadingSetBase): + """ + A set of Readings of the ReadingType indicated by the parent MeterReading. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ReadingListLink: Optional[ReadingListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class ResponseSet(IdentifiedObject): + """ + A container for a ResponseList. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ResponseListLink: Optional[ResponseListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class ServiceSupplierList(List_type): + """ + A List element to hold ServiceSupplier objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ServiceSupplier: List[ServiceSupplier] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class SubscriptionList(List_type): + """ + A List element to hold Subscription objects. + + :ivar Subscription: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Subscription: List[Subscription] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class TariffProfile(IdentifiedObject): + """ + A schedule of charges; structure that allows the definition of tariff + structures such as step (block) and time of use (tier) when used in + conjunction with TimeTariffInterval and ConsumptionTariffInterval. + + :ivar currency: The currency code indicating the currency for this + TariffProfile. + :ivar pricePowerOfTenMultiplier: Indicates the power of ten + multiplier for the price attribute. + :ivar primacy: Indicates the relative primacy of the provider of + this program. + :ivar rateCode: The rate code for this tariff profile. Provided by + the Pricing service provider per its internal business needs and + practices and provides a method to identify the specific rate + code for the TariffProfile instance. This would typically not + be communicated to the user except to facilitate troubleshooting + due to its service provider-specific technical nature. + :ivar RateComponentListLink: + :ivar serviceCategoryKind: The kind of service provided by this + usage point. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + currency: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + pricePowerOfTenMultiplier: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + primacy: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + rateCode: Optional[str] = field(default=None, metadata={ + 'type': 'Element', + 'max_length': 20, + }) + RateComponentListLink: Optional[RateComponentListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + serviceCategoryKind: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class UsagePoint(UsagePointBase): + """ + Logical point on a network at which consumption or production is either + physically measured (e.g. metered) or estimated (e.g. unmetered street + lights). + + :ivar deviceLFDI: The LFDI of the source device. This attribute + SHALL be present when mirroring. + :ivar MeterReadingListLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + deviceLFDI: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 20, + 'format': 'base16', + }) + MeterReadingListLink: Optional[MeterReadingListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class BillingReadingSetList(SubscribableList): + """ + A List element to hold BillingReadingSet objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + BillingReadingSet: List[BillingReadingSet] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class CustomerAccountList(SubscribableList): + """ + A List element to hold CustomerAccount objects. + + :ivar CustomerAccount: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + CustomerAccount: List[CustomerAccount] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class CustomerAgreementList(SubscribableList): + """ + A List element to hold CustomerAgreement objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + CustomerAgreement: List[CustomerAgreement] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class DERList(List_type): + """ + A List element to hold DER objects. + + :ivar DER: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DER: List[DER] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class DERProgramList(SubscribableList): + """ + A List element to hold DERProgram objects. + + :ivar DERProgram: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DERProgram: List[DERProgram] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class DemandResponseProgramList(SubscribableList): + """ + A List element to hold DemandResponseProgram objects. + + :ivar DemandResponseProgram: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DemandResponseProgram: List[DemandResponseProgram] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class DeviceCapability(FunctionSetAssignmentsBase): + """ + Returned by the URI provided by DNS-SD, to allow clients to find the URIs + to the resources in which they are interested. + + :ivar EndDeviceListLink: + :ivar MirrorUsagePointListLink: + :ivar SelfDeviceLink: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + EndDeviceListLink: Optional[EndDeviceListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + MirrorUsagePointListLink: Optional[MirrorUsagePointListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + SelfDeviceLink: Optional[SelfDeviceLink] = field(default=None, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class EndDevice(AbstractDevice): + """Asset container that performs one or more end device functions. + + Contains information about individual devices in the network. + + :ivar changedTime: The time at which this resource was last modified + or created. + :ivar enabled: This attribute indicates whether or not an EndDevice + is enabled, or registered, on the server. If a server sets this + attribute to false, the device is no longer registered. It + should be noted that servers can delete EndDevice instances, but + using this attribute for some time is more convenient for + clients. + :ivar FlowReservationRequestListLink: + :ivar FlowReservationResponseListLink: + :ivar FunctionSetAssignmentsListLink: + :ivar postRate: POST rate, or how often EndDevice and subordinate + resources should be POSTed, in seconds. A client MAY indicate a + preferred postRate when POSTing EndDevice. A server MAY add or + modify postRate to indicate its preferred posting rate. + :ivar RegistrationLink: + :ivar SubscriptionListLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + changedTime: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + enabled: Optional[bool] = field(default=None, metadata={ + 'type': 'Element', + }) + FlowReservationRequestListLink: Optional[FlowReservationRequestListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + FlowReservationResponseListLink: Optional[FlowReservationResponseListLink] = field( + default=None, metadata={ + 'type': 'Element', + }) + FunctionSetAssignmentsListLink: Optional[FunctionSetAssignmentsListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + postRate: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + RegistrationLink: Optional[RegistrationLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + SubscriptionListLink: Optional[SubscriptionListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class FlowReservationResponse(Event): + """ + The server may modify the charging or discharging parameters and interval + to provide a lower aggregated demand at the premises, or within a larger + part of the distribution system. + + :ivar energyAvailable: Indicates the amount of energy available. + :ivar powerAvailable: Indicates the amount of power available. + :ivar subject: The subject field provides a method to match the + response with the originating event. It is populated with the + mRID of the corresponding FlowReservationRequest object. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + energyAvailable: Optional[SignedRealEnergy] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + powerAvailable: Optional[ActivePower] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + subject: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + + +@dataclass +class FunctionSetAssignments(FunctionSetAssignmentsBase): + """ + Provides an identifiable, subscribable collection of resources for a + particular device to consume. + + :ivar mRID: The global identifier of the object. + :ivar description: The description is a human readable text + describing or naming the object. + :ivar version: Contains the version number of the object. See the + type definition for details. + :ivar subscribable: Indicates whether or not subscriptions are + supported for this resource, and whether or not conditional + (thresholds) are supported. If not specified, is "not + subscribable" (0). + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + mRID: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 16, + 'format': 'base16', + }) + description: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 32, + }) + version: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + subscribable: int = field(default=0, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class HistoricalReading(BillingMeterReadingBase): + """To be used to present readings that have been processed and possibly + corrected (as allowed, due to missing or incorrect data) by backend + systems. + + This includes quality codes valid, verified, estimated, and derived + / corrected. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class IPAddrList(List_type): + """ + List of IPAddr instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + IPAddr: List[IPAddr] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class IPInterfaceList(List_type): + """ + List of IPInterface instances. + + :ivar IPInterface: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + IPInterface: List[IPInterface] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class LLInterface(Resource): + """ + A link-layer interface object. + + :ivar CRCerrors: Contains the number of CRC errors since reset. + :ivar EUI64: Contains the EUI-64 of the link layer interface. 48 bit + MAC addresses SHALL be changed into an EUI-64 using the method + defined in [RFC 4291], Appendix A. (The method is to insert + "0xFFFE" as described in the reference.) + :ivar IEEE_802_15_4: + :ivar linkLayerType: Specifies the type of link layer interface + associated with the IPInterface. Values are below. 0 = + Unspecified 1 = IEEE 802.3 (Ethernet) 2 = IEEE 802.11 (WLAN) 3 = + IEEE 802.15 (PAN) 4 = IEEE 1901 (PLC) All other values reserved. + :ivar LLAckNotRx: Number of times an ACK was not received for a + frame transmitted (when ACK was requested). + :ivar LLCSMAFail: Number of times CSMA failed. + :ivar LLFramesDropRx: Number of dropped receive frames. + :ivar LLFramesDropTx: Number of dropped transmit frames. + :ivar LLFramesRx: Number of link layer frames received. + :ivar LLFramesTx: Number of link layer frames transmitted. + :ivar LLMediaAccessFail: Number of times access to media failed. + :ivar LLOctetsRx: Number of Bytes received. + :ivar LLOctetsTx: Number of Bytes transmitted. + :ivar LLRetryCount: Number of MAC transmit retries. + :ivar LLSecurityErrorRx: Number of receive security errors. + :ivar loWPAN: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + CRCerrors: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + EUI64: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 8, + 'format': 'base16', + }) + IEEE_802_15_4: Optional[IEEE_802_15_4] = field(default=None, metadata={ + 'type': 'Element', + }) + linkLayerType: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + LLAckNotRx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLCSMAFail: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLFramesDropRx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLFramesDropTx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLFramesRx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLFramesTx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLMediaAccessFail: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLOctetsRx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLOctetsTx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLRetryCount: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + LLSecurityErrorRx: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + loWPAN: Optional[loWPAN] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class MessagingProgramList(SubscribableList): + """ + A List element to hold MessagingProgram objects. + + :ivar MessagingProgram: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + MessagingProgram: List[MessagingProgram] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class MeterReadingList(SubscribableList): + """ + A List element to hold MeterReading objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + MeterReading: List[MeterReading] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class MirrorMeterReading(MeterReadingBase): + """ + Mimic of MeterReading used for managing mirrors. + + :ivar lastUpdateTime: The date and time of the last update. + :ivar MirrorReadingSet: + :ivar nextUpdateTime: The date and time of the next planned update. + :ivar Reading: + :ivar ReadingType: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + lastUpdateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + MirrorReadingSet: List[MirrorReadingSet] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + nextUpdateTime: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + Reading: Optional[Reading] = field(default=None, metadata={ + 'type': 'Element', + }) + ReadingType: Optional[ReadingType] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class Prepayment(IdentifiedObject): + """ + Prepayment (inherited from CIM SDPAccountingFunction) + + :ivar AccountBalanceLink: + :ivar ActiveCreditRegisterListLink: + :ivar ActiveSupplyInterruptionOverrideListLink: + :ivar creditExpiryLevel: CreditExpiryLevel is the set point for + availableCredit at which the service level may be changed. The + typical value for this attribute is 0, regardless of whether the + account balance is measured in a monetary or commodity basis. + The units for this attribute SHALL match the units used for + availableCredit. + :ivar CreditRegisterListLink: + :ivar lowCreditWarningLevel: LowCreditWarningLevel is the set point + for availableCredit at which the creditStatus attribute in the + AccountBalance resource SHALL indicate that available credit is + low. The units for this attribute SHALL match the units used for + availableCredit. Typically, this value is set by the service + provider. + :ivar lowEmergencyCreditWarningLevel: LowEmergencyCreditWarningLevel + is the set point for emergencyCredit at which the creditStatus + attribute in the AccountBalance resource SHALL indicate that + emergencycredit is low. The units for this attribute SHALL match + the units used for availableCredit. Typically, this value is set + by the service provider. + :ivar prepayMode: PrepayMode specifies whether the given Prepayment + instance is operating in Credit, Central Wallet, ESI, or Local + prepayment mode. The Credit mode indicates that prepayment is + not presently in effect. The other modes are described in the + Overview Section above. + :ivar PrepayOperationStatusLink: + :ivar SupplyInterruptionOverrideListLink: + :ivar UsagePoint: + :ivar UsagePointLink: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + AccountBalanceLink: Optional[AccountBalanceLink] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + ActiveCreditRegisterListLink: Optional[ActiveCreditRegisterListLink] = field(default=None, + metadata={ + 'type': + 'Element', + }) + ActiveSupplyInterruptionOverrideListLink: Optional[ + ActiveSupplyInterruptionOverrideListLink] = field(default=None, + metadata={ + 'type': 'Element', + }) + creditExpiryLevel: Optional[AccountingUnit] = field(default=None, + metadata={ + 'type': 'Element', + }) + CreditRegisterListLink: Optional[CreditRegisterListLink] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + lowCreditWarningLevel: Optional[AccountingUnit] = field(default=None, + metadata={ + 'type': 'Element', + }) + lowEmergencyCreditWarningLevel: Optional[AccountingUnit] = field(default=None, + metadata={ + 'type': 'Element', + }) + prepayMode: Optional[int] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + PrepayOperationStatusLink: Optional[PrepayOperationStatusLink] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + SupplyInterruptionOverrideListLink: Optional[SupplyInterruptionOverrideListLink] = field( + default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + UsagePoint: List[UsagePoint] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + UsagePointLink: Optional[UsagePointLink] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class ProjectionReading(BillingMeterReadingBase): + """ + Contains values that forecast a future reading for the time or interval + specified. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class RPLInstanceList(List_type): + """ + List of RPLInstances associated with the IPinterface. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + RPLInstance: List[RPLInstance] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class RandomizableEvent(Event): + """ + An Event that can indicate time ranges over which the start time and + duration SHALL be randomized. + + :ivar randomizeDuration: Number of seconds boundary inside which a + random value must be selected to be applied to the associated + interval duration, to avoid sudden synchronized demand changes. + If related to price level changes, sign may be ignored. Valid + range is -3600 to 3600. If not specified, 0 is the default. + :ivar randomizeStart: Number of seconds boundary inside which a + random value must be selected to be applied to the associated + interval start time, to avoid sudden synchronized demand + changes. If related to price level changes, sign may be ignored. + Valid range is -3600 to 3600. If not specified, 0 is the + default. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + randomizeDuration: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + randomizeStart: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class RateComponentList(List_type): + """ + A List element to hold RateComponent objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + RateComponent: List[RateComponent] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class ReadingSetList(SubscribableList): + """ + A List element to hold ReadingSet objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ReadingSet: List[ReadingSet] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class ResponseSetList(List_type): + """ + A List element to hold ResponseSet objects. + + :ivar ResponseSet: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ResponseSet: List[ResponseSet] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class SelfDevice(AbstractDevice): + """ + The EndDevice providing the resources available within the + DeviceCapabilities. + + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class TargetReading(BillingMeterReadingBase): + """ + Contains readings that specify a target or goal, such as a consumption + target, to which billing incentives or other contractual ramifications may + be associated. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + +@dataclass +class TariffProfileList(SubscribableList): + """ + A List element to hold TariffProfile objects. + + :ivar TariffProfile: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + TariffProfile: List[TariffProfile] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class TextMessage(Event): + """ + Text message such as a notification. + + :ivar originator: Indicates the human-readable name of the publisher + of the message + :ivar priority: The priority is used to inform the client of the + priority of the particular message. Devices with constrained or + limited resources for displaying Messages should use this + attribute to determine how to handle displaying currently active + Messages (e.g. if a device uses a scrolling method with a single + Message viewable at a time it MAY want to push a low priority + Message to the background and bring a newly received higher + priority Message to the foreground). + :ivar textMessage: The textMessage attribute contains the actual + UTF-8 encoded text to be displayed in conjunction with the + messageLength attribute which contains the overall length of the + textMessage attribute. Clients and servers SHALL support a + reception of a Message of 100 bytes in length. Messages that + exceed the clients display size will be left to the client to + choose what method to handle the message (truncation, scrolling, + etc.). + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + originator: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 20, + }) + priority: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + textMessage: Optional[str] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class UsagePointList(SubscribableList): + """ + A List element to hold UsagePoint objects. + + :ivar UsagePoint: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + UsagePoint: List[UsagePoint] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class DERControl(RandomizableEvent): + """ + Distributed Energy Resource (DER) time/event-based control. + + :ivar DERControlBase: + :ivar deviceCategory: Specifies the bitmap indicating the + categories of devices that SHOULD respond. Devices SHOULD ignore + events that do not indicate their device category. If not + present, all devices SHOULD respond. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DERControlBase: Optional[DERControlBase] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + deviceCategory: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'max_length': 4, + 'format': 'base16', + }) + + +@dataclass +class EndDeviceControl(RandomizableEvent): + """ + Instructs an EndDevice to perform a specified action. + + :ivar ApplianceLoadReduction: + :ivar deviceCategory: Specifies the bitmap indicating the + categories of devices that SHOULD respond. Devices SHOULD ignore + events that do not indicate their device category. + :ivar drProgramMandatory: A flag to indicate if the EndDeviceControl + is considered a mandatory event as defined by the service + provider issuing the EndDeviceControl. The drProgramMandatory + flag alerts the client/user that they will be subject to penalty + or ineligibility based on the service provider’s program rules + for that deviceCategory. + :ivar DutyCycle: + :ivar loadShiftForward: Indicates that the event intends to increase + consumption. A value of true indicates the intention to increase + usage value, and a value of false indicates the intention to + decrease usage. + :ivar Offset: + :ivar overrideDuration: The overrideDuration attribute provides a + duration, in seconds, for which a client device is allowed to + override this EndDeviceControl and still meet the contractual + agreement with a service provider without opting out. If + overrideDuration is not specified, then it SHALL default to 0. + :ivar SetPoint: + :ivar TargetReduction: + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ApplianceLoadReduction: Optional[ApplianceLoadReduction] = field(default=None, + metadata={ + 'type': 'Element', + }) + deviceCategory: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 4, + 'format': 'base16', + }) + drProgramMandatory: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + DutyCycle: Optional[DutyCycle] = field(default=None, metadata={ + 'type': 'Element', + }) + loadShiftForward: Optional[bool] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + }) + Offset: Optional[Offset] = field(default=None, metadata={ + 'type': 'Element', + }) + overrideDuration: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + SetPoint: Optional[SetPoint] = field(default=None, metadata={ + 'type': 'Element', + }) + TargetReduction: Optional[TargetReduction] = field(default=None, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class EndDeviceList(SubscribableList): + """ + A List element to hold EndDevice objects. + + :ivar EndDevice: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + EndDevice: List[EndDevice] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class FlowReservationResponseList(SubscribableList): + """ + A List element to hold FlowReservationResponse objects. + + :ivar FlowReservationResponse: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + FlowReservationResponse: List[FlowReservationResponse] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class FunctionSetAssignmentsList(SubscribableList): + """ + A List element to hold FunctionSetAssignments objects. + + :ivar FunctionSetAssignments: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + FunctionSetAssignments: List[FunctionSetAssignments] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class HistoricalReadingList(List_type): + """ + A List element to hold HistoricalReading objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + HistoricalReading: List[HistoricalReading] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class LLInterfaceList(List_type): + """ + List of LLInterface instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + LLInterface: List[LLInterface] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class MirrorMeterReadingList(List_type): + """ + A List of MirrorMeterReading instances. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + MirrorMeterReading: List[MirrorMeterReading] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class MirrorUsagePoint(UsagePointBase): + """ + A parallel to UsagePoint to support mirroring. + + :ivar deviceLFDI: The LFDI of the device being mirrored. + :ivar MirrorMeterReading: + :ivar postRate: POST rate, or how often mirrored data should be + POSTed, in seconds. A client MAY indicate a preferred postRate + when POSTing MirrorUsagePoint. A server MAY add or modify + postRate to indicate its preferred posting rate. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + deviceLFDI: Optional[bytes] = field(default=None, + metadata={ + 'type': 'Element', + 'required': True, + 'max_length': 20, + 'format': 'base16', + }) + MirrorMeterReading: List[MirrorMeterReading] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + postRate: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + }) + + +@dataclass +class PrepaymentList(SubscribableList): + """ + A List element to hold Prepayment objects. + + :ivar Prepayment: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + Prepayment: List[Prepayment] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class ProjectionReadingList(List_type): + """ + A List element to hold ProjectionReading objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ProjectionReading: List[ProjectionReading] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class TargetReadingList(List_type): + """ + A List element to hold TargetReading objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + TargetReading: List[TargetReading] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class TextMessageList(SubscribableList): + """ + A List element to hold TextMessage objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + TextMessage: List[TextMessage] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class TimeTariffInterval(RandomizableEvent): + """ + Describes the time-differentiated portion of the RateComponent, if + applicable, and provides the ability to specify multiple time intervals, + each with its own consumption-based components and other attributes. + + :ivar ConsumptionTariffIntervalListLink: + :ivar touTier: Indicates the time of use tier related to the + reading. If not specified, is assumed to be "0 - N/A". + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + ConsumptionTariffIntervalListLink: Optional[ConsumptionTariffIntervalListLink] = field( + default=None, metadata={ + 'type': 'Element', + }) + touTier: Optional[int] = field(default=None, metadata={ + 'type': 'Element', + 'required': True, + }) + + +@dataclass +class DERControlList(SubscribableList): + """ + A List element to hold DERControl objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + DERControl: List[DERControl] = field(default_factory=list, metadata={ + 'type': 'Element', + }) + + +@dataclass +class EndDeviceControlList(SubscribableList): + """ + A List element to hold EndDeviceControl objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + EndDeviceControl: List[EndDeviceControl] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + + +@dataclass +class MirrorUsagePointList(List_type): + """ + A List of MirrorUsagePoint instances. + + :ivar MirrorUsagePoint: + :ivar pollRate: The default polling rate for this function set (this + resource and all resources below), in seconds. If not specified, + a default of 900 seconds (15 minutes) is used. It is RECOMMENDED + a client poll the resources of this function set every pollRate + seconds. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + MirrorUsagePoint: List[MirrorUsagePoint] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) + pollRate: int = field(default=900, metadata={ + 'type': 'Attribute', + }) + + +@dataclass +class TimeTariffIntervalList(SubscribableList): + """ + A List element to hold TimeTariffInterval objects. + """ + + class Meta: + namespace = 'urn:ieee:std:2030.5:ns' + + TimeTariffInterval: List[TimeTariffInterval] = field(default_factory=list, + metadata={ + 'type': 'Element', + }) diff --git a/services/core/IEEE_2030_5/ieee_2030_5/utils.py b/services/core/IEEE_2030_5/ieee_2030_5/utils.py new file mode 100644 index 0000000000..4fd1a9dfb2 --- /dev/null +++ b/services/core/IEEE_2030_5/ieee_2030_5/utils.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +def is_binary(binary: str) -> bool: + return all([c in '01' for c in str(binary)]) + + +def is_hex(hex: str) -> bool: + return all([c in '0123456789ABCDEFabcdef' for c in hex]) + + +def binary_to_binary_hex(binary: str) -> str: + return hex(int(binary, 2))[2:] + + +def decimal_to_binary_hex(decimal: int) -> str: + return hex(int(decimal))[2:] diff --git a/services/core/IEEE_2030_5/inverter_sample.csv b/services/core/IEEE_2030_5/inverter_sample.csv new file mode 100644 index 0000000000..cf98438b52 --- /dev/null +++ b/services/core/IEEE_2030_5/inverter_sample.csv @@ -0,0 +1,66 @@ +Point Name,Description,Multiplier,MRID,Offset,Parameter Type,Notes +,,,,,DERCapability::rtgMaxW,DERCapabilities are not generally writable but the corresponding setting is. +,,,,,DERCapability::rtgOverExcitedW, +,,,,,DERCapability::rtgOverExcitedPF, +,,,,,DERCapability::rtgUnderExcitedW, +,,,,,DERCapability::rtgUnderExcitedPF, +,,,,,DERCapability::rtgMaxVA, +,,,,,DERCapability::rtgNormalCategory, +,,,,,DERCapability::rtgAbnormalCategory, +,,,,,DERCapability::rtgMaxVar, +,,,,,DERCapability::rtgMaxVarNeg, +,,,,,DERCapability::rtgMaxChargeRateW, +,,,,,DERCapability::rtgMaxChargeRateVA, +,,,,,DERCapability::rtgVNom, +,,,,,DERCapability::rtgMaxV, +,,,,,DERCapability::rtgMinV, +,,,,,DERCapability::modesSupported, +,,,,,DERCapability::rtgReactiveSusceptance, +,,,,,DERStatus::alarmStatus,"Bitmap Position (0 = over current, 1 over voltage, 2 under voltage, 3 over frequency, 4 under frequency, 5 voltage imbalance, 6 current imbalance, 7 emergency local, 8 emergency remote, 9 low power input, 10 phase rotation)" +,,,,,DERStatus::genConnectStatus,"DER Generator Status (0 = Connected, 1 = Available, 2 = Operating, 3 = Test, 4 = Fault/Error)" +,,,,,DERStatus::inverterStatus,"DER Inverter Status (0 = Connected, 1 = Available, 2 = Operating, 3 = Test, 4 = Fault/Error)" +,,,,,DERStatus::localControlModeStatus,0 = local control 1 = remote control +,,,,,DERStatus::manufacturerStatus,A manufacturer status code string +,,,,,DERStatus::operationalModeStatus,"DER OperationalModeStatus (0 = Not applicable, 1 = Off, 2 = Operational, 3 = Test)" +BAT_SOC,,,,,DERStatus::stateOfChargeStatus,DER StateOfChargeStatus % of charge +,,,,,DERStatus::storageModeStatus,"DER StorageModeStatus (0 = Charging, 1 = Discharging, 2 = Holding)" +,,,,,DERStatus::storConnectStatus,"DER Storage Status (0 = Connected, 1 = Available, 2 = Operating, 3 = Test, 4 = Fault/Error)" +,,,,,DERSettings::setESHighVolt, +,,,,,DERSettings::setESLowVolt, +,,,,,DERSettings::setESHighFreq, +,,,,,DERSettings::setESLowFreq, +,,,,,DERSettings::setESDelay, +,,,,,DERSettings::setESRandomDelay, +,,,,,DERSettings::setESRampTms, +ctrl_es_delay,,,,,DefaultDERControl::setESDelay, +ctrl_freq_max,,,,,DefaultDERControl::setESHighFreq, +ctrl_volt_max,,,,,DefaultDERControl::setESHighVolt, +ctrl_freq_min,,,,,DefaultDERControl::setESLowFreq, +ctrl_volt_min,,,,,DefaultDERControl::setESLowVolt, +ctrl_ramp_tms,,,,,DefaultDERControl::setESRampTms, +ctrl_rand_delay,,,,,DefaultDERControl::setESRandomDelay, +ctrl_grad_w,,,,,DefaultDERControl::setGradW, +ctrl_soft_grad_w,,,,,DefaultDERControl::setSoftGradW, +ctrl_connected,,,,,DERControlBase::opModConnect,"True/False Connected = True, Disconnected = False" +ctrl_energized,,,,,DERControlBase::opModEnergize,"True/False Energized = True, De-Energized = False" +ctrl_fixed_pf_absorb_w,,,,,DERControlBase::opModFixedPFAbsorbW, +ctrl_fixed_pf_ingect_w,,,,,DERControlBase::opModFixedPFInjectW, +ctrl_fixed_var,,,,,DERControlBase::opModFixedVar, +ctrl_fixed_w,,,,,DERControlBase::opModFixedW, +ctrl_freq_droop,,,,,DERControlBase::opModFreqDroop, +ctrl_freq_w,,,,,DERControlBase::opModFreqWatt, +,,,,,DERControlBase::opModHFRTMayTrip, +,,,,,DERControlBase::opModHFRTMustTrip, +,,,,,DERControlBase::opModHVRTMomentaryCessation, +,,,,,DERControlBase::opModHVRTMustTrip, +,,,,,DERControlBase::opModLFRTMayTrip, +,,,,,DERControlBase::opModLVRTMomentaryCessation, +,,,,,DERControlBase::opModLVRTMustTrip, +ctrl_max_w,,,,,DERControlBase::opModMaxLimW, +ctrl_target_var,,,,,DERControlBase::opModTargetVar, +ctrl_target_w,Target Real Power,,,,DERControlBase::opModTargetW, +,,,,,DERControlBase::opModVoltVar, +,,,,,DERControlBase:opModVoltWatt, +,,,,,DERControlBase::opModWattPF, +,,,,,DERControlBase::opModWattVar, +,,,,,DERControlBase::rampTms, diff --git a/services/core/IEEE_2030_5/requirements.txt b/services/core/IEEE_2030_5/requirements.txt new file mode 100644 index 0000000000..22e8585248 --- /dev/null +++ b/services/core/IEEE_2030_5/requirements.txt @@ -0,0 +1,2 @@ +xsdata>=23.8 +blinker diff --git a/services/core/IEEE_2030_5/requirements_demo.txt b/services/core/IEEE_2030_5/requirements_demo.txt new file mode 100644 index 0000000000..cf84bba01d --- /dev/null +++ b/services/core/IEEE_2030_5/requirements_demo.txt @@ -0,0 +1,4 @@ +nicegui +requests +xsdata>=23.8 +blinker diff --git a/services/core/IEEE_2030_5/setup.py b/services/core/IEEE_2030_5/setup.py new file mode 100644 index 0000000000..d038299030 --- /dev/null +++ b/services/core/IEEE_2030_5/setup.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} + +from os import path + +from setuptools import find_packages, setup + +MAIN_MODULE = 'agent' + +# Find the agent package that contains the main module +packages = find_packages('.') +agent_package = '' +for package in find_packages(): + # Because there could be other packages such as tests + if path.isfile(package + '/' + MAIN_MODULE + '.py') is True: + agent_package = package +if not agent_package: + raise RuntimeError('None of the packages under {dir} contain the file ' + '{main_module}'.format(main_module=MAIN_MODULE + '.py', + dir=path.abspath('.'))) + +# Find the version number from the main module +agent_module = agent_package + '.' + MAIN_MODULE +_temp = __import__(agent_module, globals(), locals(), ['__version__'], 0) +__version__ = _temp.__version__ + +# Setup +setup(name=agent_package + 'agent', + version=__version__, + install_requires=['volttron'], + packages=packages, + entry_points={'setuptools.installation': [ + 'eggsecutable = ' + agent_module + ':main', + ]}) diff --git a/services/core/IEEE_2030_5/tests/fixtures/test_config.yml b/services/core/IEEE_2030_5/tests/fixtures/test_config.yml new file mode 100644 index 0000000000..cb6f5c4689 --- /dev/null +++ b/services/core/IEEE_2030_5/tests/fixtures/test_config.yml @@ -0,0 +1,84 @@ +# required parameters +cacertfile: ~/tls/certs/ca.crt +keyfile: ~/tls/private/dev1.pem +certfile: ~/tls/certs/dev1.crt +server_hostname: 127.0.0.1 +# the pin number is used to verify the server is the correct server +pin: 111115 + +# Log the request and responses from the server. +log_req_resp: true + +# SSL defaults to 443 +server_ssl_port: 8443 +# http port defaults to none +#server_http_port: 8080 + +MirrorUsagePointList: + # MirrorMeterReading based on Table E.2 IEEE Std 2030.5-18 + # note the mRID in the MirrorMeterReading is the same that is in the + # MirrorUsagePoint. + - subscription_point: p_ac + mRID: 5509D69F8B3535950000000000009182 + description: DER Inverter Real Power + roleFlags: 49 + serviceCategoryKind: 0 + status: 0 + MirrorMeterReading: + mRID: 5509D69F8B3535950000000000009182 + description: Real Power(W) Set + ReadingType: + accumulationBehavior: 12 + commodity: 1 + dataQualifier: 2 + intervalLength: 300 + powerOfTenMultiplier: 0 + uom: 38 + - subscription_point: q_ac + mRID: 5509D69F8B3535950000000000009184 + description: DER Inverter Reactive Power + roleFlags: 49 + serviceCategoryKind: 0 + status: 0 + MirrorMeterReading: + mRID: 5509D69F8B3535950000000000009184 + description: Reactive Power(VAr) Set + ReadingType: + accumulationBehavior: 12 + commodity: 1 + dataQualifier: 2 + intervalLength: 300 + powerOfTenMultiplier: 0 + uom: 38 + +# publishes on the following subscriptions will +# be available to create and POST readings to the +# 2030.5 server. +subscriptions: + - devices/inverter1/all + +# Nameplate ratings for this der client will be put to the +# server during startup of the system. +DERCapability: + # modesSupported is a HexBinary31 representation of DERControlType + # See Figure B.34 DER info types for information + # conversion in python is as follows + # "{0:08b}".format(int("500040", 16)) + # '10100000000000001000000' # This is a bitmask + # to generate HexBinary + # hex(int('10100000000000001000000', 2)) + # 0x500040 + modesSupported: 500040 + rtgMaxW: + multiplier: 0 + value: 0 + type: 0 + +DERSettings: + modesEnabled: 100000 + setGradW: 0 + setMaxW: + multiplier: 0 + value: 0 + +point_map: config:///inverter_sample.csv \ No newline at end of file diff --git a/services/core/IEEE_2030_5/tests/fixtures/test_inverter.csv b/services/core/IEEE_2030_5/tests/fixtures/test_inverter.csv new file mode 100644 index 0000000000..34ce513301 --- /dev/null +++ b/services/core/IEEE_2030_5/tests/fixtures/test_inverter.csv @@ -0,0 +1,8 @@ +Point Name,Description,Multiplier,MRID,Writeable,Parameter Type,Notes +INV_REAL_PWR,Inverter Real Power,,,,ActivePower,2030.5 is in Watts +INV_REAC_PWR,Inverter Reactive Power,,,,ReactivePower,2030.5 is in vars +BESS_SETOP_REQ,Energy Storage Set Point,,,True,, +INV_OPER_STATE,Inverter Operating State,,,True,DERControlBase::opModFixedW, +INV_REAL_PWR_REQ,Power Request Topic,,,,ActivePower, +BAT_SOC,,,,True,DERStatus::stateOfChargeStatus, +target_p,Target Real Power,,,True,DERControlBase::opModTargetW, diff --git a/services/core/IEEE_2030_5/tests/get_dcap.py b/services/core/IEEE_2030_5/tests/get_dcap.py new file mode 100644 index 0000000000..d9ebdd8dd8 --- /dev/null +++ b/services/core/IEEE_2030_5/tests/get_dcap.py @@ -0,0 +1,202 @@ +from datetime import datetime +import sys +import os +import time +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from dataclasses import asdict +from pprint import pprint +import urllib3 +from request_session import get_as_admin, get_as_device, post_as_admin, post_as_device +import ieee_2030_5.models as m +from ieee_2030_5 import dataclass_to_xml, xml_to_dataclass +urllib3.disable_warnings() + +def print_it(thing: str, obj: object): + print(f"{'='*20} {thing} {'='*20}") + try: + pprint(asdict(obj), indent=4) + except TypeError: + print(f'Type: {type(obj)} was passed and cannot be printed!') + +dcap: m.DeviceCapability = get_as_device('dcap') +print_it('DeviceCapability', dcap) + +tm: m.Time = get_as_device(dcap.TimeLink.href) +print_it('Time', tm) + +edevl: m.EndDeviceList = get_as_device('edev') +print_it('EndDeviceList', edevl) +edev = edevl.EndDevice[0] +print(edev.LogEventListLink.href) + +derl = get_as_device(edev.DERListLink.href) +print_it('DERList', derl) + +der: m.DER = derl.DER[0] +current_program = get_as_device(der.CurrentDERProgramLink.href) +print_it('CurrentDERProgram', current_program) + +config: m.Configuration = get_as_device(edev.ConfigurationLink.href) +print_it('Configuration', config) + +info: m.DeviceInformation = get_as_device(edev.DeviceInformationLink.href) +print_it('DeviceInformation', info) + +status: m.DeviceStatus = get_as_device(edev.DeviceStatusLink.href) +print_it('DeviceStatus', status) + +fsal: m.FunctionSetAssignmentsList = get_as_device(edev.FunctionSetAssignmentsListLink.href) +print_it('FunctionSetAssignmentsList', fsal) +derpl: m.DERProgramList = get_as_device(fsal.FunctionSetAssignments[0].DERProgramListLink.href) +print_it('DERProgramList', derpl) + +derp: m.DERProgram = derpl.DERProgram[0] +derca = get_as_device(derp.ActiveDERControlListLink.href) +print_it('ActiveDERControlList', derca) + + +dderc: m.DefaultDERControl = get_as_device(derp.DefaultDERControlLink.href) +print_it('DefaultDERControl', dderc) + + +dercl: m.DERControlList = get_as_device(derp.DERControlListLink.href) +print_it('DERControlList', dercl) + +# No curves yet +#curvel = get_as_device(derp.DERCurveListLink.href) +#print_it("DERCurveList", curvel) + +mup = m.MirrorUsagePoint() +mup.description = 'Test Mirror Usage Point' +mup.deviceLFDI = edev.lFDI +mup.mRID = '5509D69F8B3535950000000000009182' +mup.serviceCategoryKind = 0 +mup.roleFlags = 49 + +mmr = m.MirrorMeterReading() +mmr.description = 'Real Power(W) Set' +mmr.mRID = '5509D69F8B3535950000000000009182' + +mrt = m.ReadingType() +mrt.accumulationBehaviour = 12 +mrt.commodity = 1 +mrt.intervalLength = 300 +mrt.powerOfTenMultiplier = 0 +mrt.uom = 38 +mmr.ReadingType = mrt +mup.MirrorMeterReading.append(mmr) + +# Expect +resp = post_as_device('mup', data=dataclass_to_xml(mup)) + +new_mup = get_as_device(resp.headers['Location']) + +print_it('New Mirror Usage Point', new_mup) +print('\n\n') +input('Press Enter to continue...') +#while True: +current_time = int(time.mktime(datetime.utcnow().timetuple())) +print(f'Time is: {current_time}') +new_ctrl = m.DERControl(mRID='b234245afff', DERControlBase=dderc.DERControlBase, description='A new control is going here') +new_ctrl.interval = m.DateTimeInterval(start=current_time + 5, duration=10) +response = post_as_admin(dercl.href, data=dataclass_to_xml(new_ctrl)) + +ctrl_evnt = get_as_device(response.headers['Location']) +print_it('DERControl', ctrl_evnt) + +ctrll = get_as_device(derp.DERControlListLink.href) +print_it('DERControl List', ctrll) + +activel = get_as_device(derp.ActiveDERControlListLink.href) +print_it('ActiveDERControl', activel) + +print('Waiting for activation of control on server...') +print(print(f"{'='*20} Sleeping 6 s {'='*20}")) +time.sleep(6) + +activel = get_as_device(derp.ActiveDERControlListLink.href) +print_it('ActiveDERControl', activel) + +print('Waiting for deactivation of control on server...') +print(print(f"{'='*20} Sleeping 20 s {'='*20}")) +time.sleep(20) + +activel = get_as_device(derp.ActiveDERControlListLink.href) +print_it('ActiveDERControl', activel) + +# ctrl_str = """ +# +# Control 1 +# {'opModConnect': True, 'opModMaxLimW': 9500} +# +# +# Control 2 +# {'opModConnect': True, 'opModFixedW': 80} +# +# +# 94E46E50F4964762B94E6C24AA350CA2 +# +# 60 +# 1696592892 +# +# +# true +# 9500 +# +# +# """ + + + + +# def _change_power_factor(new_pf): +# global inverter_pf + +# current_time = int(time.mktime(datetime.utcnow().timetuple())) + +# ctrl_base = m.DERControlBase(opModConnect=True, opModMaxLimW=9500) +# ctrl = m.DERControl(mRID="ctrl1mrdi", description="A control for the control list") +# ctrl.DERControlBase = ctrl_base +# ctrl.interval = m.DateTimeInterval(start=current_time + 10, duration=20) +# ctrl.randomizeDuration = 180 +# ctrl.randomizeStart = 180 +# ctrl.DERControlBase.opModFixedW = 500 +# ctrl.DERControlBase.opModFixedPFInjectW = m.PowerFactorWithExcitation( +# displacement=int(pf.value)) + +# posted = dataclass_to_xml(ctrl) +# _log.debug(f"POST\n{posted}") +# resp = session.post(get_url("derp/0/derc"), data=posted) +# # Post will have a response with the location of the DERControl +# der_control_uri = resp.headers.get('Location') +# _log.debug(f"GET\n{der_control_uri}") +# resp = session.get(der_control_uri, not_admin=True) +# _log.debug(f"{resp.text}") +# # pfingect: m.DERControl = resp.text) +# # inverter_pf = pfingect.DERControlBase.opModFixedPFInjectW.displacement +# # status.content = updated_markdown() + + +# def get_control_event_default(): +# derbase = m.DERControlBase(opModConnect=True, opModEnergize=False, opModFixedPFInjectW=80) + +# time_plus_10 = int(time.mktime((datetime.utcnow() + timedelta(seconds=60)).timetuple())) + +# derc = m.DERControl(mRID=str(uuid.uuid4()), +# description="New DER Control Event", +# DERControlBase=derbase, +# interval=m.DateTimeInterval(duration=10, start=time_plus_10)) + +# return dataclass_to_xml(derc) + + +# def _setup_event(element): +# derbase = m.DERControlBase(opModConnect=True, opModEnergize=False, opModFixedPFInjectW=80) + +# time_plus_60 = int(time.mktime((datetime.utcnow() + timedelta(seconds=60)).timetuple())) + +# derc = m.DERControl(mRID=str(uuid.uuid4()), +# description="New DER Control Event", +# DERControlBase=derbase, +# interval=m.DateTimeInterval(duration=10, start=time_plus_60)) +# element.value = dataclass_to_xml(derc) diff --git a/services/core/IEEE_2030_5/tests/new_event.py b/services/core/IEEE_2030_5/tests/new_event.py new file mode 100644 index 0000000000..2b9c35f16c --- /dev/null +++ b/services/core/IEEE_2030_5/tests/new_event.py @@ -0,0 +1,66 @@ +from datetime import datetime +import sys +import os +import time +import uuid +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from dataclasses import asdict +from pprint import pprint +import urllib3 +from request_session import get_as_admin, get_as_device, post_as_admin, post_as_device +import ieee_2030_5.models as m +from ieee_2030_5 import dataclass_to_xml, xml_to_dataclass +urllib3.disable_warnings() + +def print_it(thing: str, obj: object): + print(f"{'='*20} {thing} {'='*20}") + try: + pprint(asdict(obj), indent=4) + except TypeError: + print(f"Type: {type(obj)} was passed and cannot be printed!") + +dcap: m.DeviceCapability = get_as_device("dcap") +print_it("DeviceCapability", dcap) + +edevl: m.EndDeviceList = get_as_device("edev") +print_it("EndDeviceList", edevl) + +edev = edevl.EndDevice[0] +derl = get_as_device(edev.DERListLink.href) +print_it("DERList", derl) + +der: m.DER = derl.DER[0] +current_program: m.DERProgram = get_as_device(der.CurrentDERProgramLink.href) +print_it("CurrentDERProgram", current_program) + +dderc: m.DefaultDERControl = get_as_device(current_program.DefaultDERControlLink.href) +print_it("DefaultDERControl", dderc) + +dercl: m.DERControlList = get_as_device(current_program.DERControlListLink.href) +print_it("DERControlList", dercl) + +current_time = int(time.mktime(datetime.utcnow().timetuple())) +print(f"Time is: {current_time}") +mrid = str(uuid.uuid4()).replace('-', '') +new_ctrl = m.DERControl(mRID=mrid, DERControlBase=dderc.DERControlBase, description="A new control is going here") +new_ctrl.interval = m.DateTimeInterval(start=current_time + 5, duration=30) +new_ctrl.DERControlBase.opModTargetW = m.ActivePower(3, 2000) +print_it("New Control is", new_ctrl) +print(f"{dataclass_to_xml(new_ctrl)}") +response = post_as_admin(dercl.href, data=dataclass_to_xml(new_ctrl)) + +print("Right before controls start") +dercl: m.DERControlList = get_as_device(current_program.DERControlListLink.href) +print_it("DERControlList", dercl) +activectl: m.DERControlList = get_as_device(current_program.ActiveDERControlListLink.href) +print("Should not have an active control.") +print_it("ActiveDERControlList", activectl) +print("Sleeping 10 seconds until control has started") +time.sleep(10) +activectl: m.DERControlList = get_as_device(current_program.ActiveDERControlListLink.href) +print("Active control should have started!") +print_it("ActiveDERControlList", activectl) +time.sleep(35) +activectl: m.DERControlList = get_as_device(current_program.ActiveDERControlListLink.href) +print("Event should be over now") +print_it("ActiveDERControlList", activectl) \ No newline at end of file diff --git a/services/core/IEEE_2030_5/tests/request_session.py b/services/core/IEEE_2030_5/tests/request_session.py new file mode 100644 index 0000000000..67b29b8f2c --- /dev/null +++ b/services/core/IEEE_2030_5/tests/request_session.py @@ -0,0 +1,56 @@ +from pathlib import Path +from requests import Session +import yaml + +from ieee_2030_5 import xml_to_dataclass + +__test_config_file__ = Path(__file__).parent.joinpath("fixtures/test_config.yml") +__test_config_file_data__ = yaml.safe_load(__test_config_file__.open("rt").read()) + +__request_admin_session__ = Session() +__request_base_uri__ = f"https://{__test_config_file_data__['server_hostname']}:{__test_config_file_data__['server_ssl_port']}" +__tls_path__ = Path(__test_config_file_data__["certfile"]).expanduser().parent.parent +__request_admin_session__.cert = (__tls_path__.joinpath("certs/admin.crt"), __tls_path__.joinpath("private/admin.pem")) +__request_admin_session__.verify = Path(__test_config_file_data__["cacertfile"]).expanduser().as_posix() + +__request_device_session__ = Session() +__request_device_session__.cert = (__tls_path__.joinpath("certs/dev1.crt"), __tls_path__.joinpath("private/dev1.pem")) +__request_device_session__.verify = Path(__test_config_file_data__["cacertfile"]).expanduser().as_posix() + +def __admin_uri__(path: str): + path = path.replace("_", "/") + if path.startswith("/"): + path = path[1:] + return f"{__request_base_uri__}/admin/{path}" + +def __uri__(path: str): + if path.startswith("/"): + path = path[1:] + return f"{__request_base_uri__}/{path}" + +def post_as_admin(path, data): + print(f"POST: {__admin_uri__(path)}") + return __request_admin_session__.post(__admin_uri__(path), data=data) + +def post_as_device(path, data): + print(f"POST: {__uri__(path)}") + return __request_device_session__.post(__uri__(path), data=data) + + +def get_as_admin(path) -> str: + print(f"GET: {__uri__(path)}") + resp = __request_device_session__.get(__admin_uri__(path)) + + if resp.text: + return xml_to_dataclass(resp.text) + else: + resp + +def get_as_device(path) -> str: + print(f"GET: {__uri__(path)}") + resp = __request_device_session__.get(__uri__(path)) + + if resp.text: + return xml_to_dataclass(resp.text) + else: + resp \ No newline at end of file diff --git a/services/core/MQTTHistorian/Tests/test_mqtt_historian.py b/services/core/MQTTHistorian/Tests/test_mqtt_historian.py index b814254d24..7d1156f8c1 100644 --- a/services/core/MQTTHistorian/Tests/test_mqtt_historian.py +++ b/services/core/MQTTHistorian/Tests/test_mqtt_historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from ast import Import diff --git a/services/core/MQTTHistorian/mqtt_historian/agent.py b/services/core/MQTTHistorian/mqtt_historian/agent.py index 6ee394486b..c4e2f97953 100644 --- a/services/core/MQTTHistorian/mqtt_historian/agent.py +++ b/services/core/MQTTHistorian/mqtt_historian/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/MQTTHistorian/setup.py b/services/core/MQTTHistorian/setup.py index cc64769bff..5284d29efb 100644 --- a/services/core/MQTTHistorian/setup.py +++ b/services/core/MQTTHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/MongodbTaggingService/README.md b/services/core/MongodbTaggingService/README.md index 449dbe7488..0136e3551c 100644 --- a/services/core/MongodbTaggingService/README.md +++ b/services/core/MongodbTaggingService/README.md @@ -21,11 +21,16 @@ keyword AND and OR, and use the keyword NOT to negate a conditions. ## Requirements -This historian requires a mongodb connector installed in your activated -volttron environment to talk to mongodb. Please execute the following -from an activated shell in order to install it. +This historian requires: - pip install pymongo +1. Mongodb server: Version tested - 7.0.1 + This agent requires mongodb server installed and running on the system. In addition create a database user and + database that can be used by this agent. +2. mongodb connector: Tested version - 4.5.0 + This agent requires a python mongo connected to be installed in your activated volttron environment to talk to + mongodb. Please execute the following from an activated shell in order to install it. + + pip install pymongo==4.5.0 ## Dependencies and Limitations diff --git a/services/core/MongodbTaggingService/mongotagging/tagging.py b/services/core/MongodbTaggingService/mongotagging/tagging.py index ed0c787098..d30d7f5805 100644 --- a/services/core/MongodbTaggingService/mongotagging/tagging.py +++ b/services/core/MongodbTaggingService/mongotagging/tagging.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import collections @@ -44,7 +30,7 @@ import pymongo import re -from pkg_resources import resource_string, resource_exists +from pymongo import InsertOne, UpdateOne from pymongo.errors import BulkWriteError from volttron.platform.agent import utils from volttron.platform.agent.base_tagging import BaseTaggingService @@ -90,13 +76,13 @@ def tagging_service(config_path, **kwargs): class MongodbTaggingService(BaseTaggingService): """This is a tagging service agent that writes data to a Mongo database. - For instance with large amount of tags and frequent tag queries, a NOSQL - database such as Mongodb would provide better efficiency than SQLite. + For instance with large amount of tags and frequent tag queries, a NOSQL + database such as Mongodb would provide better efficiency than SQLite. """ def __init__(self, connection, table_prefix=None, **kwargs): """Initialise the tagging service. - :param connection: dictionary object containing the database + :param connection: dictionary object containing the database connection details :param table_prefix: optional prefix to be used for all tag tables :param kwargs: additional keyword arguments. (optional identity and @@ -133,9 +119,9 @@ def setup(self): collections = [] db = None try: - db = self._client.get_default_database() - collections = db.collection_names(include_system_collections=False) - _log.debug(collections) + db = self._client.get_database() + collections = db.list_collection_names() + _log.debug(f"GOT collections as {collections}") except Exception as e: err_message = "Unable to query list of existing tables from the " \ "database. Exception in init of tagging service: {}. " \ @@ -181,6 +167,8 @@ def setup(self): # _log.debug("status:{}".format(status)) self.vip.health.send_alert(TAGGING_SERVICE_SETUP_FAILED, status) self.core.stop() + else: + _log.info("Initialization complete") @doc_inherit def load_valid_tags(self): @@ -210,12 +198,11 @@ def _init_tags(self, db): # csv.DictReader uses first line in file for column headings # by default dr = csv.DictReader(csv_str.splitlines()) - bulk_tags = db[self.tags_collection].initialize_ordered_bulk_op() + inserts = [] for i in dr: - bulk_tags.insert({"_id":i['name'], - "kind":i['kind'], - "description":i['description']}) - bulk_tags.execute() + inserts.append(InsertOne( + {"_id": i['name'], "kind": i['kind'], "description": i['description']})) + db[self.tags_collection].bulk_write(inserts) else: raise ValueError( "Unable to load list of reference tags and its parent. No " @@ -231,18 +218,15 @@ def _init_tag_refs(self, db): # csv.DictReader uses first line in file for column headings # by default dr = csv.DictReader(csv_str.splitlines()) - bulk_tags = db[ - self.tag_refs_collection].initialize_ordered_bulk_op() + inserts = [] for i in dr: - bulk_tags.insert({"_id":i['tag'], - "parent":i['parent_tag']}) - bulk_tags.execute() + inserts.append(InsertOne({"_id": i['tag'], "parent": i['parent_tag']})) + db[self.tag_refs_collection].bulk_write(inserts) else: raise ValueError( "Unable to load list of reference tags and its parent. No " "such file: {}".format(file_path)) - def _init_categories(self, db): file_path = self.resource_sub_dir + '/categories.csv' _log.debug("Loading file :" + file_path) @@ -250,12 +234,10 @@ def _init_categories(self, db): csv_str = content_file.read() if csv_str: dr = csv.DictReader(csv_str.splitlines()) - bulk = db[ - self.categories_collection].initialize_ordered_bulk_op() + inserts = [] for i in dr: - bulk.insert({"_id": i['name'], - "description": i['description']}) - bulk.execute() + inserts.append(InsertOne({"_id": i['name'], "description": i['description']})) + db[self.categories_collection].bulk_write(inserts) else: _log.warning("No categories to initialize. No such file " + file_path) @@ -265,7 +247,7 @@ def _init_category_tags(self, db): with open(file_path, 'r') as content_file: txt_str = content_file.read() - bulk_tags = db[self.tags_collection].initialize_ordered_bulk_op() + updates = [] if txt_str: current_category = "" tags = set() @@ -283,15 +265,14 @@ def _init_category_tags(self, db): else: temp= line.split(":") # ignore description tags.update(re.split(" +", temp[0])) - if len(tags)>0: + if len(tags) > 0: for tag in tags: mapping[tag].add(current_category) for tag in mapping.keys(): - bulk_tags.find({"_id": tag}).update( - {'$set': {"categories": list(mapping[tag])}}) + updates.append(UpdateOne({"_id": tag}, {'$set': {"categories": list(mapping[tag])}})) - bulk_tags.execute() + db[self.tags_collection].bulk_write(updates) db[self.tags_collection].create_index( [('categories', pymongo.ASCENDING)], background=True) @@ -370,7 +351,7 @@ def query_tags_by_category(self, category, include_kind=False, @doc_inherit def insert_topic_tags(self, tags, update_version=False): db = self._client.get_default_database() - bulk = db[self.topic_tags_collection].initialize_unordered_bulk_op() + updates = [] result = dict() result['info'] = dict() result['error'] = dict() @@ -400,9 +381,9 @@ def insert_topic_tags(self, tags, update_version=False): temp['_id'] = prefix temp['id'] = prefix execute = True - bulk.find({'_id': prefix}).upsert().update_one( - {'$set': temp}) + updates.append(UpdateOne({'_id': prefix}, {'$set': temp}, upsert=True)) result['info'][topic_pattern].append(prefix) + if len(result['info'][topic_pattern]) == 1 and \ topic_pattern == result['info'][topic_pattern][0]: # means value sent was actually some pattern so add @@ -413,7 +394,7 @@ def insert_topic_tags(self, tags, update_version=False): result['info'].pop(topic_pattern) if execute: try: - bulk.execute() + db[self.topic_tags_collection].bulk_write(updates) except BulkWriteError as bwe: errors = bwe.details['writeErrors'] _log.error("bwe error count {}".format(len(errors))) diff --git a/services/core/MongodbTaggingService/requirements.txt b/services/core/MongodbTaggingService/requirements.txt index 891fc9d356..78cf745f08 100644 --- a/services/core/MongodbTaggingService/requirements.txt +++ b/services/core/MongodbTaggingService/requirements.txt @@ -1 +1 @@ -pymongo==3.7.2 +pymongo==4.5.0 diff --git a/services/core/MongodbTaggingService/scripts/insert_test_data.py b/services/core/MongodbTaggingService/scripts/insert_test_data.py index 2c468a9b23..ce3f7d9875 100644 --- a/services/core/MongodbTaggingService/scripts/insert_test_data.py +++ b/services/core/MongodbTaggingService/scripts/insert_test_data.py @@ -145,7 +145,7 @@ def mongo_insert(tags, execute_now=False): try: result = mongo_bulk.execute() if result['nInserted'] != mongo_batch_size: - print ("bulk execute result {}".format(result)) + print("bulk execute result {}".format(result)) errors = True except BulkWriteError as ex: print(str(ex.details)) @@ -205,7 +205,7 @@ def test_mongo_tags(): "equip_tag 7": {"$gt": 2}}, {"topic_prefix": 1}) topics = [record['_id'] for record in tags_cursor] print("example query result: {}".format(topics)) - print ("Time taken by mongo for result: {}".format( + print("Time taken by mongo for result: {}".format( datetime.datetime.now() - start)) @@ -230,8 +230,8 @@ def test_sqlite_tags(): ' INTERSECT ' 'select topic_prefix from test_tags where tag = "equip_tag 7" and ' 'value > 2') - print ("topics :{}".format(tags_cursor.fetchall())) - print ("Time taken by sqlite for result: {}".format( + print("topics :{}".format(tags_cursor.fetchall())) + print("Time taken by sqlite for result: {}".format( datetime.datetime.now() - start)) diff --git a/services/core/MongodbTaggingService/setup.py b/services/core/MongodbTaggingService/setup.py index 38d236e876..ef95843d97 100644 --- a/services/core/MongodbTaggingService/setup.py +++ b/services/core/MongodbTaggingService/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/OpenADRVenAgent/IDENTITY b/services/core/OpenADRVenAgent/IDENTITY new file mode 100644 index 0000000000..186296b23b --- /dev/null +++ b/services/core/OpenADRVenAgent/IDENTITY @@ -0,0 +1 @@ +platform.openadr.ven \ No newline at end of file diff --git a/services/core/OpenADRVenAgent/config_example1.json b/services/core/OpenADRVenAgent/config_example1.json index 6e4f1b14ee..2d5bd36bf5 100644 --- a/services/core/OpenADRVenAgent/config_example1.json +++ b/services/core/OpenADRVenAgent/config_example1.json @@ -1,9 +1,8 @@ { "ven_name": "PNNLVEN", "vtn_url": "https://eiss2demo.ipkeys.com/oadr2/OpenADR2/Simple/2.0b", - "cert_path": "~/.ssh/secret/path_to_cert.pem", - "key_path": "~/.ssh/secret/path_to_privkey.pem", "debug": true, "disable_signature": true, - "openadr_client_type": "IPKeysClient" + "cert_path": "~/.ssh/secret/TEST_RSA_VEN_221206215541_cert.pem", + "key_path": "~/.ssh/secret/TEST_RSA_VEN_221206215541_privkey.pem" } diff --git a/services/core/OpenADRVenAgent/conftest.py b/services/core/OpenADRVenAgent/conftest.py index 8559470457..68e5e611b1 100644 --- a/services/core/OpenADRVenAgent/conftest.py +++ b/services/core/OpenADRVenAgent/conftest.py @@ -3,4 +3,4 @@ from volttrontesting.fixtures.volttron_platform_fixtures import * # Add system path of the agent's directory -sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) \ No newline at end of file +sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) diff --git a/services/core/OpenADRVenAgent/openadr_ven/agent.py b/services/core/OpenADRVenAgent/openadr_ven/agent.py index eff9aed6fa..79213a0f10 100644 --- a/services/core/OpenADRVenAgent/openadr_ven/agent.py +++ b/services/core/OpenADRVenAgent/openadr_ven/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging import asyncio @@ -42,14 +28,8 @@ from pathlib import Path from pprint import pformat -from datetime import timedelta, datetime, date, time, timezone -from typing import Callable, Dict, Any -from openleadr.enums import OPT, REPORT_NAME, MEASUREMENTS -from openleadr.client import OpenADRClient -from openleadr.objects import Event - -from volttron.platform import jsonapi +from typing import Callable, Dict from volttron.platform.agent.utils import ( get_aware_utc_now, setup_logging, @@ -59,6 +39,14 @@ ) from volttron.platform.messaging import topics, headers from volttron.platform.vip.agent import Agent, RPC +from .volttron_openadr_client import ( + VolttronOpenADRClient, + OpenADRClientInterface, + OpenADREvent, + OpenADRReportName, + OpenADRMeasurements, + OpenADROpt, +) from .constants import ( REQUIRED_KEYS, @@ -73,10 +61,9 @@ CA_FILE, VEN_ID, DISABLE_SIGNATURE, - OPENADR_CLIENT_TYPE, - IDENTITY, ) -from .volttron_openadr_client import openadr_clients + +from openleadr.objects import Event setup_logging() _log = logging.getLogger(__name__) @@ -96,10 +83,10 @@ class OpenADRVenAgent(Agent): def __init__(self, config_path: str, **kwargs) -> None: # adding 'fake_ven_client' to support dependency injection and preventing call to super class for unit testing - if kwargs.get('fake_ven_client'): - self.ven_client = kwargs['fake_ven_client'] + self.ven_client: OpenADRClientInterface + if kwargs.get("fake_ven_client"): + self.ven_client = kwargs["fake_ven_client"] else: - self.ven_client: OpenADRClient super(OpenADRVenAgent, self).__init__(enable_web=True, **kwargs) self.default_config = self._parse_config(config_path) @@ -115,7 +102,7 @@ def __init__(self, config_path: str, **kwargs) -> None: def _configure_ven_client( self, config_name: str, action: str, contents: Dict ) -> None: - """Initializes the agent's configuration and creates an OpenADR Client using OpenLeadr. + """Initializes the agent's configuration, creates and starts VolttronOpenADRClient. :param config_name: :param action: the action @@ -125,80 +112,53 @@ def _configure_ven_client( config.update(contents) _log.info(f"config_name: {config_name}, action: {action}") - _log.info(f"Configuring agent with: \n {pformat(config)} ") - - # instantiate VEN client - client_type = config.get(OPENADR_CLIENT_TYPE) - openADRClient = openadr_clients().get(client_type) - if openADRClient is None: - msg = f"Invalid client type: {client_type}. Please use valid client types: {list(openadr_clients().keys())}" - _log.debug(msg) - raise KeyError(msg) - - _log.info(f"Creating OpenADRClient type: {client_type}...") - self.ven_client = openADRClient( - config.get(VEN_NAME), - config.get(VTN_URL), - debug=config.get(DEBUG), - cert=config.get(CERT), - key=config.get(KEY), - passphrase=config.get(PASSPHRASE), - vtn_fingerprint=config.get(VTN_FINGERPRINT), - show_fingerprint=config.get(SHOW_FINGERPRINT), - ca_file=config.get(CA_FILE), - ven_id=config.get(VEN_ID), - disable_signature=config.get(DISABLE_SIGNATURE), - ) - _log.info(f"{client_type} successfully created.") + _log.info(f"Configuring VEN client with: \n {pformat(config)} ") + + self.ven_client = VolttronOpenADRClient.build_client(config) - _log.info( - f"Adding capabilities (e.g. handlers, reports) to {client_type}..." - ) # Add event handling capability to the client # if you want to add more handlers on a specific event, you must create a coroutine in this class # and then add it as the second input for 'self.ven_client.add_handler(, )' self.ven_client.add_handler("on_event", self.handle_event) - _log.info("Capabilities successfully added.") + _log.info("Starting OpenADRVen agent...") gevent.spawn_later(3, self._start_asyncio_loop) def _start_asyncio_loop(self) -> None: - """ Start event loop - """ - _log.info("Starting agent...") loop = asyncio.get_event_loop() loop.create_task(self.ven_client.run()) loop.run_forever() # ***************** Methods for Servicing VTN Requests ******************** - async def handle_event(self, event: Event) -> OPT: + async def handle_event(self, event: Event) -> OpenADROpt: """Publish event to the Volttron message bus. This coroutine will be called when there is an event to be handled. :param event: The event sent from a VTN :return: Message to VTN to opt in to the event. """ + openadr_event = OpenADREvent(event) try: - _log.debug("Received event. Processing event now...") - signal = event.get("event_signals")[0] - _log.info(f"Event signal:\n {pformat(signal)}") + _log.info( + f"Received event. Processing event now...\n Event signal:\n {pformat(openadr_event.get_event_signals())}" + ) except IndexError as e: _log.debug( - f"Event signals is empty. {e} \n Showing whole event: {pformat(event)}" + f"Event signals is empty. {e} \n Showing whole event: {pformat(openadr_event)}" ) pass - self.publish_event(event) + self.publish_event(openadr_event) - return OPT.OPT_IN + return OpenADROpt.OPT_IN @RPC.export def add_report_capability( self, callback: Callable, - report_name: REPORT_NAME, + report_name: OpenADRReportName, resource_id: str, - measurement: MEASUREMENTS, + measurement: OpenADRMeasurements, ) -> tuple: """Add a new reporting capability to the client. @@ -223,14 +183,14 @@ def add_report_capability( return report_specifier_id, r_id # ***************** VOLTTRON Pub/Sub Requests ******************** - def publish_event(self, event: Event) -> None: + def publish_event(self, event: OpenADREvent) -> None: """Publish an event to the Volttron message bus. When an event is created/updated, it is published to the VOLTTRON bus with a topic that includes 'openadr/event_update'. :param event: The Event received from the VTN """ # OADR rule 6: If testEvent is present and != "false", handle the event as a test event. try: - if event["event_descriptor"]["test_event"]: + if event.isTestEvent(): _log.debug("Suppressing publication of test event") return except KeyError as e: @@ -240,42 +200,14 @@ def publish_event(self, event: Event) -> None: _log.debug(f"Publishing real/non-test event \n {pformat(event)}") self.vip.pubsub.publish( peer="pubsub", - topic=f"{topics.OPENADR_EVENT}/{self.ven_client.ven_name}", + topic=f"{topics.OPENADR_EVENT}/{self.ven_client.get_ven_name()}", headers={headers.TIMESTAMP: format_timestamp(get_aware_utc_now())}, - message=self._parse_event(event), + message=event.parse_event(), ) return # ***************** Helper methods ******************** - def _parse_event(self, obj: Event) -> Any: - """Parse event so that it properly displays on message bus. - - :param obj: The event received from a VTN - :return: A deserialized Event that is converted into a python object - """ - - # function that gets called for objects that can’t otherwise be serialized. - def _default_serialzer(x): - if isinstance(x, timedelta): - return int(x.total_seconds()) - elif isinstance(x, datetime): - return format_timestamp(x) - elif isinstance(x, date): - return x.isoformat() - elif isinstance(x, time): - return x.isoformat() - elif isinstance(x, timezone): - return int(x.utcoffset().total_seconds()) - else: - return None - - obj_string = jsonapi.dumps( - obj, - default=_default_serialzer - ) - return jsonapi.loads(obj_string) - def _parse_config(self, config_path: str) -> Dict: """Parses the OpenADR agent's configuration file. @@ -300,26 +232,24 @@ def _parse_config(self, config_path: str) -> Dict: self._check_required_key(required_key, key_actual) req_keys_actual[required_key] = key_actual - # optional configurations - debug = config.get(DEBUG) - - # keypair paths + # optional configurations cert = config.get(CERT) if cert: cert = str(Path(cert).expanduser().resolve(strict=True)) key = config.get(KEY) if key: key = str(Path(key).expanduser().resolve(strict=True)) - + ca_file = config.get(CA_FILE) + if ca_file: + ca_file = str(Path(ca_file).expanduser().resolve(strict=True)) + debug = config.get(DEBUG) ven_name = config.get(VEN_NAME) vtn_url = config.get(VTN_URL) passphrase = config.get(PASSPHRASE) vtn_fingerprint = config.get(VTN_FINGERPRINT) - show_fingerprint = bool(config.get(SHOW_FINGERPRINT)) - ca_file = config.get(CA_FILE) + show_fingerprint = bool(config.get(SHOW_FINGERPRINT, True)) ven_id = config.get(VEN_ID) disable_signature = bool(config.get(DISABLE_SIGNATURE)) - openadr_client_type = config.get(OPENADR_CLIENT_TYPE) return { VEN_NAME: ven_name, @@ -333,7 +263,6 @@ def _parse_config(self, config_path: str) -> Dict: CA_FILE: ca_file, VEN_ID: ven_id, DISABLE_SIGNATURE: disable_signature, - OPENADR_CLIENT_TYPE: openadr_client_type, } def _check_required_key(self, required_key: str, key_actual: str) -> None: @@ -349,16 +278,12 @@ def _check_required_key(self, required_key: str, key_actual: str) -> None: raise KeyError( f"{VTN_URL} is required. Ensure {VTN_URL} is given a URL to the VTN." ) - elif required_key == OPENADR_CLIENT_TYPE and not key_actual: - raise KeyError( - f"{OPENADR_CLIENT_TYPE} is required. Specify one of the following valid client types: {list(openadr_clients().keys())}" - ) return def main(): """Main method called to start the agent.""" - vip_main(OpenADRVenAgent, IDENTITY) + vip_main(OpenADRVenAgent) if __name__ == "__main__": diff --git a/services/core/OpenADRVenAgent/openadr_ven/constants.py b/services/core/OpenADRVenAgent/openadr_ven/constants.py index b33ec22871..186aba7f25 100644 --- a/services/core/OpenADRVenAgent/openadr_ven/constants.py +++ b/services/core/OpenADRVenAgent/openadr_ven/constants.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} # key names for processing config file for OpenADR VEN agent @@ -48,7 +34,4 @@ CA_FILE = "ca_file" VEN_ID = "ven_id" DISABLE_SIGNATURE = "disable_signature" -OPENADR_CLIENT_TYPE = "openadr_client_type" -REQUIRED_KEYS = [VEN_NAME, VTN_URL, OPENADR_CLIENT_TYPE] - -IDENTITY = "openadr_ven" +REQUIRED_KEYS = [VEN_NAME, VTN_URL] diff --git a/services/core/OpenADRVenAgent/openadr_ven/volttron_openadr_client.py b/services/core/OpenADRVenAgent/openadr_ven/volttron_openadr_client.py index d6b7c6c9e5..32ee0141ba 100644 --- a/services/core/OpenADRVenAgent/openadr_ven/volttron_openadr_client.py +++ b/services/core/OpenADRVenAgent/openadr_ven/volttron_openadr_client.py @@ -1,274 +1,159 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} -import logging -import asyncio - -from abc import ABC -from functools import partial -from lxml import etree from openleadr.client import OpenADRClient -from openleadr.preflight import preflight_message -from openleadr.messaging import TEMPLATES, SIGNER, _create_replay_protect -from openleadr import utils, enums +from openleadr.objects import Event +from volttron.platform import jsonapi +import abc -from volttron.platform.agent.utils import setup_logging +from .constants import ( + VEN_NAME, + VTN_URL, + DEBUG, + CERT, + KEY, + PASSPHRASE, + VTN_FINGERPRINT, + SHOW_FINGERPRINT, + CA_FILE, + VEN_ID, + DISABLE_SIGNATURE, +) +from openleadr.enums import OPT, REPORT_NAME, MEASUREMENTS +from datetime import timedelta, datetime, date, time, timezone +from typing import Callable +from volttron.platform.agent.utils import format_timestamp -setup_logging() -logger = logging.getLogger(__name__) +class OpenADRReportName(REPORT_NAME): + def __init__(self): + super.__init__() -class OpenADRClientBase(OpenADRClient, ABC): - """ - The Volttron OpenADR VEN agent uses the python library OpenLEADR https://github.com/openleadr/openleadr-python to create - an OpenADR VEN client. OpenADRClientBase is extended from OpenLEADR's OpenADRClient, giving us the flexibility - to connect to any implementation of an OpenADR VTN. For example, to connect to an IPKeys VTN that was implemented - on an old OpenADR protocol, the IPKeysClient subclass was created so that it can successfully connect to an IPKeys VTN. - If you have a specific VTN that you want to connect to and require further customization of the OpenADRVEN client, create your - own OpenADRClient by extending the base class OpenADRClientBase, updating your client with your business logic, and putting that subclass in this module. - """ +class OpenADRMeasurements(MEASUREMENTS): + def __init__(self): + super.__init__() - def __init__(self, ven_name, vtn_url, disable_signature=False, **kwargs): - """ - Initializes a new OpenADR Client (Virtual End Node) - :param str ven_name: The name for this VEN - :param str vtn_url: The URL of the VTN (Server) to connect to - :param bool: The boolean flag to disable signatures on messages - """ - super().__init__(ven_name, vtn_url, **kwargs) - self.disable_signature = disable_signature +class OpenADROpt(OPT): + def __init__(self): + super.__init__() -class IPKeysClient(OpenADRClientBase, ABC): - def __init__(self, ven_name, vtn_url, disable_signature, **kwargs): - """ - Initializes a new OpenADR Client (Virtual End Node) +class OpenADREvent: + def __init__(self, event: Event): + self.event = event - :param str ven_name: The name for this VEN - :param str vtn_url: The URL of the VTN (Server) to connect to - :param bool: The boolean flag to disable signatures on messages - """ - super().__init__(ven_name, vtn_url, disable_signature, **kwargs) + def get_event_signals(self): + return self.event.get("event_signals")[0] - self._create_message = partial( - self.create_message_ipkeys, - cert=self.cert_path, - key=self.key_path, - passphrase=self.passphrase, - disable_signature=self.disable_signature, - ) + def isTestEvent(self): + return self.event["event_descriptor"]["test_event"] - async def _on_event(self, message): - """ - :param message dict: dictionary containing event information - """ - logger.debug("The VEN received an event") - events = message["events"] - try: - results = [] + def parse_event(self) -> Event: + """Parse event so that it properly displays on message bus. - for event in message["events"]: - event_id = event["event_descriptor"]["event_id"] - event_status = event["event_descriptor"]["event_status"] - modification_number = event["event_descriptor"][ - "modification_number" - ] - received_event = utils.find_by( - self.received_events, "event_descriptor.event_id", event_id - ) + :param obj: The event received from a VTN + :return: A deserialized Event that is converted into a python object + """ - if received_event: - if ( - received_event["event_descriptor"][ - "modification_number" - ] - == modification_number - ): - # Re-submit the same opt type as we already had previously - result = self.responded_events[event_id] - else: - # Replace the event with the fresh copy - utils.pop_by( - self.received_events, - "event_descriptor.event_id", - event_id, - ) - self.received_events.append(event) - # Wait for the result of the on_update_event handler - result = await utils.await_if_required( - self.on_update_event(event) - ) - else: - # Wait for the result of the on_event - self.received_events.append(event) - result = self.on_event(event) - if asyncio.iscoroutine(result): - result = await result - results.append(result) - if ( - event_status - in ( - enums.EVENT_STATUS.COMPLETED, - enums.EVENT_STATUS.CANCELLED, - ) - and event_id in self.responded_events - ): - self.responded_events.pop(event_id) - else: - self.responded_events[event_id] = result - for i, result in enumerate(results): - if ( - result not in ("optIn", "optOut") - and events[i]["response_required"] == "always" - ): - logger.error( - "Your on_event or on_update_event handler must return 'optIn' or 'optOut'; " - f"you supplied {result}. Please fix your on_event handler." - ) - results[i] = "optOut" - except Exception as err: - logger.error( - "Your on_event handler encountered an error. Will Opt Out of the event. " - f"The error was {err.__class__.__name__}: {str(err)}" - ) - results = ["optOut"] * len(events) + # function that gets called for objects that can’t otherwise be serialized. + def _default_serialzer(x): + if isinstance(x, timedelta): + return int(x.total_seconds()) + elif isinstance(x, datetime): + return format_timestamp(x) + elif isinstance(x, date): + return x.isoformat() + elif isinstance(x, time): + return x.isoformat() + elif isinstance(x, timezone): + return int(x.utcoffset().total_seconds()) + else: + return None + + obj_string = jsonapi.dumps(self.event, default=_default_serialzer) + return jsonapi.loads(obj_string) + + +class OpenADRClientInterface(metaclass=abc.ABCMeta): + @abc.abstractmethod + async def run(self): + pass + + @abc.abstractmethod + def get_ven_name(self): + pass + + @abc.abstractmethod + def add_handler(self, event: OpenADREvent, function): + pass + + @abc.abstractmethod + def add_report( + self, + callback: Callable, + report_name: OpenADRReportName, + resource_id: str, + measurement: OpenADRMeasurements, + ): + pass - event_responses = [ - { - "response_code": 200, - "response_description": "OK", - "opt_type": results[i], - "request_id": message["request_id"], - "modification_number": events[i]["event_descriptor"][ - "modification_number" - ], - "event_id": events[i]["event_descriptor"]["event_id"], - } - for i, event in enumerate(events) - if event["response_required"] == "always" - and not utils.determine_event_status(event["active_period"]) - == "completed" - ] - if len(event_responses) > 0: - response = { - "response_code": 200, - "response_description": "OK", - "request_id": message["request_id"], - } - message = self._create_message( - "oadrCreatedEvent", - response=response, - event_responses=event_responses, - ven_id=self.ven_id, - ) - service = "EiEvent" - response_type, response_payload = await self._perform_request( - service, message - ) - logger.info(response_type, response_payload) - else: - logger.info( - "Not sending any event responses, because a response was not required/allowed by the VTN." - ) +class VolttronOpenADRClient(OpenADRClientInterface): + def __init__(self, openadr_client: OpenADRClient) -> None: + self._openadr_client = openadr_client @staticmethod - def create_message_ipkeys( - message_type, - cert=None, - key=None, - passphrase=None, - disable_signature=False, - **message_payload, - ): - """ - Create and optionally sign an OpenADR message. Returns an XML string. - - :param message_type string: The type of message you are sending - :param str cert: The path to a PEM-formatted Certificate file to use - for signing messages. - :param str key: The path to a PEM-formatted Private Key file to use - for signing messages. - :param str passphrase: The passphrase for the Private Key - :param bool: The boolean flag to disable signatures on messages - """ - message_payload = preflight_message(message_type, message_payload) - template = TEMPLATES.get_template(f"{message_type}.xml") - signed_object = utils.flatten_xml(template.render(**message_payload)) - envelope = TEMPLATES.get_template("oadrPayload.xml") - if cert and key and not disable_signature: - tree = etree.fromstring(signed_object) - signature_tree = SIGNER.sign( - tree, - key=key, - cert=cert, - passphrase=utils.ensure_bytes(passphrase), - reference_uri="#oadrSignedObject", - signature_properties=_create_replay_protect(), + def build_client(config): + # Creates a VEN client using openleadr library + return VolttronOpenADRClient( + OpenADRClient( + config.get(VEN_NAME), + config.get(VTN_URL), + debug=config.get(DEBUG), + cert=config.get(CERT), + key=config.get(KEY), + passphrase=config.get(PASSPHRASE), + vtn_fingerprint=config.get(VTN_FINGERPRINT), + show_fingerprint=config.get(SHOW_FINGERPRINT, True), + ca_file=config.get(CA_FILE), + ven_id=config.get(VEN_ID), + disable_signature=config.get(DISABLE_SIGNATURE), ) - signature = etree.tostring(signature_tree).decode("utf-8") - else: - signature = None - msg = envelope.render( - template=f"{message_type}", - signature=signature, - signed_object=signed_object, ) - return msg + ##### Abstract methods implemented##### + async def run(self): + await self._openadr_client.run() + + def get_ven_name(self): + self._openadr_client.ven_name -def openadr_clients(): - """ - Returns a dictionary in which the keys are the class names of OpenADRClientBase subclasses and the values are the subclass objects. - For example: + def add_handler(self, event, function): + self._openadr_client.add_handler(event, function) - { "IPKeysClient": IPKeysClient } - """ - clients = {} - children = [OpenADRClient] - while children: - parent = children.pop() - for child in parent.__subclasses__(): - child_name = child.__name__ - if child_name not in clients: - clients[child_name] = child - children.append(child) - return clients + def add_report(self, callback, report_name, resource_id, measurement): + self._openadr_client.add_report(callback, report_name, resource_id, measurement) diff --git a/services/core/OpenADRVenAgent/requirements.txt b/services/core/OpenADRVenAgent/requirements.txt index 1dce359f4a..070898a182 100644 --- a/services/core/OpenADRVenAgent/requirements.txt +++ b/services/core/OpenADRVenAgent/requirements.txt @@ -1,2 +1,2 @@ -openleadr==0.5.24 -lxml==4.6.4 +openleadr==0.5.30 +cryptography==37.0.4 diff --git a/services/core/OpenADRVenAgent/setup.py b/services/core/OpenADRVenAgent/setup.py index c9f1bccf8c..286478069a 100644 --- a/services/core/OpenADRVenAgent/setup.py +++ b/services/core/OpenADRVenAgent/setup.py @@ -3,41 +3,41 @@ from os import path from setuptools import setup, find_packages -MAIN_MODULE = 'agent' +MAIN_MODULE = "agent" # Find the agent package that contains the main module -packages = find_packages('.') -agent_package = '' +packages = find_packages(".") +agent_package = "" for package in find_packages(): # Because there could be other packages such as tests - if path.isfile(package + '/' + MAIN_MODULE + '.py'): + if path.isfile(package + "/" + MAIN_MODULE + ".py"): agent_package = package break if not agent_package: - raise RuntimeError(f"None of the packages under {path.abspath('.')} contain the file {MAIN_MODULE}.py") + raise RuntimeError( + f"None of the packages under {path.abspath('.')} contain the file {MAIN_MODULE}.py" + ) # Find the version number from the main module agent_module = f"{agent_package}.{MAIN_MODULE}" -_temp = __import__(agent_module, globals(), locals(), ['__version__'], 0) +_temp = __import__(agent_module, globals(), locals(), ["__version__"], 0) __version__ = _temp.__version__ setup( name=f"{agent_package}agent", version=__version__, - install_requires=['volttron'], + install_requires=["volttron"], packages=packages, - entry_points={ - "setuptools.installation": [ - f"eggsecutable = {agent_module}:main" - ] - }, - classifiers=["Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "Topic :: Home Automation", - "Topic :: Software Development :: Embedded Systems", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9"] + entry_points={"setuptools.installation": [f"eggsecutable = {agent_module}:main"]}, + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Topic :: Home Automation", + "Topic :: Software Development :: Embedded Systems", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + ], ) diff --git a/services/core/OpenADRVenAgent/tests/config_test.json b/services/core/OpenADRVenAgent/tests/config_test.json index 47e8086616..21419d7b6c 100644 --- a/services/core/OpenADRVenAgent/tests/config_test.json +++ b/services/core/OpenADRVenAgent/tests/config_test.json @@ -1,5 +1,4 @@ { "ven_name": "PNNLVEN", - "vtn_url": "https://eiss2demo.ipkeys.com/oadr2/OpenADR2/Simple/2.0b", - "openadr_client_type": "OpenADRClientBase" + "vtn_url": "https://eiss2demo.ipkeys.com/oadr2/OpenADR2/Simple/2.0b" } diff --git a/services/core/OpenADRVenAgent/tests/test_openadr_ven_agent.py b/services/core/OpenADRVenAgent/tests/test_openadr_ven_agent.py index 5b18a26daf..7a5f7dd588 100644 --- a/services/core/OpenADRVenAgent/tests/test_openadr_ven_agent.py +++ b/services/core/OpenADRVenAgent/tests/test_openadr_ven_agent.py @@ -1,9 +1,14 @@ import pytest +from openadr_ven.volttron_openadr_client import OpenADRClientInterface + try: import openleadr except ModuleNotFoundError as e: - pytest.skip(f"openleadr not found! \nPlease install openleadr to run \ - tests: pip install openleadr.\n Original error message: {e}", allow_module_level=True) + pytest.skip( + f"openleadr not found! \nPlease install openleadr to run \ + tests: pip install openleadr.\n Original error message: {e}", + allow_module_level=True, + ) from pathlib import Path from mock import MagicMock @@ -23,19 +28,43 @@ async def test_handle_event_should_return_optIn(mock_openadr_ven): vipmock.pubsub.publish = pubsub_publishmock mock_openadr_ven.vip = vipmock - expected = await mock_openadr_ven.handle_event({"event_signals": [42]}) + expected = await mock_openadr_ven.handle_event( + {"event_descriptor": {"test_event": True}, "event_signals": [42]} + ) - assert expected == 'optIn' + assert expected == "optIn" @pytest.fixture def mock_openadr_ven(): - config_path = str(Path('config_test.json').absolute()) - OpenADRVenAgent.__bases__ = (AgentMock.imitate(Agent, OpenADRVenAgent(config_path)),) + config_path = f"{Path(__file__).parent.absolute()}/config_test.json" + OpenADRVenAgent.__bases__ = ( + AgentMock.imitate(Agent, OpenADRVenAgent(config_path)), + ) yield OpenADRVenAgent(config_path, fake_ven_client=FakeOpenADRClient()) -class FakeOpenADRClient: +class FakeOpenADRClient(OpenADRClientInterface): def __init__(self): - self.ven_name = 'fake_ven_name' + self.ven_name = "fake_ven_name" + + async def run(self): + pass + + + def get_ven_name(self): + pass + + + def add_handler(self, event, function): + pass + + def add_report( + self, + callback, + report_name, + resource_id, + measurement, + ): + pass diff --git a/services/core/PlatformDriverAgent/platform_driver/agent.py b/services/core/PlatformDriverAgent/platform_driver/agent.py index 7a08f93298..967e2c81f1 100644 --- a/services/core/PlatformDriverAgent/platform_driver/agent.py +++ b/services/core/PlatformDriverAgent/platform_driver/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -75,7 +61,7 @@ def get_config(name, default=None): # Increase open files resource limit to max or 8192 if unlimited system_socket_limit = None - + try: soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) except OSError: @@ -99,7 +85,7 @@ def get_config(name, default=None): max_concurrent_publishes = get_config('max_concurrent_publishes', 10000) driver_config_list = get_config('driver_config_list') - + scalability_test = get_config('scalability_test', False) scalability_test_iterations = get_config('scalability_test_iterations', 3) @@ -193,7 +179,7 @@ def __init__(self, driver_config_list, scalability_test = False, self.vip.config.subscribe(self.configure_main, actions=["NEW", "UPDATE"], pattern="config") self.vip.config.subscribe(self.update_driver, actions=["NEW", "UPDATE"], pattern="devices/*") self.vip.config.subscribe(self.remove_driver, actions="DELETE", pattern="devices/*") - + def configure_main(self, config_name, action, contents): config = self.default_config.copy() config.update(contents) @@ -391,16 +377,16 @@ def remove_driver(self, config_name, action, contents): # _log.debug("Driver hooked up for "+topic) # topic = topic.strip('/') # self.instances[topic] = driver - + def scrape_starting(self, topic): if not self.scalability_test: return - + if not self.waiting_to_finish: # Start a new measurement self.current_test_start = datetime.now() self.waiting_to_finish = set(self.instances.keys()) - + if topic not in self.waiting_to_finish: _log.warning( f"{topic} started twice before test finished, increase the length of scrape interval and rerun test") @@ -408,7 +394,7 @@ def scrape_starting(self, topic): def scrape_ending(self, topic): if not self.scalability_test: return - + try: self.waiting_to_finish.remove(topic) except KeyError: @@ -420,15 +406,15 @@ def scrape_ending(self, topic): delta = end - self.current_test_start delta = delta.total_seconds() self.test_results.append(delta) - + self.test_iterations += 1 - + _log.info("publish {} took {} seconds".format(self.test_iterations, delta)) - + if self.test_iterations >= self.scalability_test_iterations: # Test is now over. Button it up and shutdown. - mean = math_utils.mean(self.test_results) - stdev = math_utils.stdev(self.test_results) + mean = math_utils.mean(self.test_results) + stdev = math_utils.stdev(self.test_results) _log.info("Mean total publish time: "+str(mean)) _log.info("Std dev publish time: "+str(stdev)) sys.exit(0) @@ -492,7 +478,7 @@ def set_multiple_points(self, path, point_names_values, **kwargs): "Cannot set point on device {} since global override is set".format(path)) else: return self.instances[path].set_multiple_points(point_names_values, **kwargs) - + @RPC.export def heart_beat(self): """RPC method @@ -502,7 +488,7 @@ def heart_beat(self): _log.debug("sending heartbeat") for device in self.instances.values(): device.heart_beat() - + @RPC.export def revert_point(self, path, point_name, **kwargs): """RPC method diff --git a/services/core/PlatformDriverAgent/platform_driver/driver.py b/services/core/PlatformDriverAgent/platform_driver/driver.py index 6f9c479a90..b86688f465 100644 --- a/services/core/PlatformDriverAgent/platform_driver/driver.py +++ b/services/core/PlatformDriverAgent/platform_driver/driver.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from volttron.platform.vip.agent import BasicAgent, Core @@ -188,7 +174,7 @@ def setup_device(self): for point in self.interface.get_register_names(): register = self.interface.get_register_by_name(point) - if register.register_type == 'bit': + if register.register_type == 'bit' or register.python_type is bool: ts_type = 'boolean' else: if register.python_type is int: @@ -197,6 +183,8 @@ def setup_device(self): ts_type = 'float' elif register.python_type is str: ts_type = 'string' + else: + ts_type = register.python_type.__name__ self.meta_data[point] = {'units': register.get_units(), 'type': ts_type, diff --git a/services/core/PlatformDriverAgent/platform_driver/driver_exceptions.py b/services/core/PlatformDriverAgent/platform_driver/driver_exceptions.py index 5a20709dd5..5f32fb4525 100644 --- a/services/core/PlatformDriverAgent/platform_driver/driver_exceptions.py +++ b/services/core/PlatformDriverAgent/platform_driver/driver_exceptions.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} class DriverError(Exception): diff --git a/services/core/PlatformDriverAgent/platform_driver/driver_locks.py b/services/core/PlatformDriverAgent/platform_driver/driver_locks.py index 5ef6340171..2b0c0d9774 100644 --- a/services/core/PlatformDriverAgent/platform_driver/driver_locks.py +++ b/services/core/PlatformDriverAgent/platform_driver/driver_locks.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from gevent.lock import BoundedSemaphore, DummySemaphore @@ -50,17 +36,17 @@ def configure_socket_lock(max_connections=0): else: _socket_lock = BoundedSemaphore(max_connections) -@contextmanager +@contextmanager def socket_lock(): global _socket_lock if _socket_lock is None: raise RuntimeError("socket_lock not configured!") _socket_lock.acquire() - try: - yield + try: + yield finally: _socket_lock.release() - + _publish_lock = None def configure_publish_lock(max_connections=0): @@ -72,13 +58,13 @@ def configure_publish_lock(max_connections=0): else: _publish_lock = BoundedSemaphore(max_connections) -@contextmanager +@contextmanager def publish_lock(): global _publish_lock if _publish_lock is None: raise RuntimeError("socket_lock not configured!") _publish_lock.acquire() - try: - yield + try: + yield finally: _publish_lock.release() diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/__init__.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/__init__.py index 86e37efefe..128bc617d1 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/__init__.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/__init__.py @@ -1,41 +1,26 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} - """ ================== Driver Development @@ -167,9 +152,9 @@ """ - import abc import logging +from typing import List _log = logging.getLogger(__name__) @@ -203,35 +188,36 @@ class BaseRegister: publishing. When instantiating register instances be sure to provide a useful string for the units argument. """ - def __init__(self, register_type, read_only, pointName, units, description = ''): + + def __init__(self, register_type, read_only, pointName, units, description=''): self.read_only = read_only self.register_type = register_type self.point_name = pointName self.units = units self.description = description self.python_type = int - + def get_register_python_type(self): """ :return: The python type of the register. :rtype: type """ return self.python_type - + def get_register_type(self): """ :return: (register_type, read_only) :rtype: tuple """ return self.register_type, self.read_only - + def get_units(self): """ :return: Register units :rtype: str """ return self.units - + def get_description(self): """ :return: Register description @@ -250,23 +236,26 @@ class BaseInterface(object, metaclass=abc.ABCMeta): :param core: A reference to the parent driver agent's core subsystem. """ + def __init__(self, vip=None, core=None, **kwargs): # Object does not take any arguments to the init. super(BaseInterface, self).__init__() self.vip = vip self.core = core - + self.point_map = {} - + self.build_register_map() - + def build_register_map(self): - self.registers = {('byte',True):[], - ('byte',False):[], - ('bit',True):[], - ('bit',False):[]} - - @abc.abstractmethod + self.registers = { + ('byte', True): [], + ('byte', False): [], + ('bit', True): [], + ('bit', False): [] + } + + @abc.abstractmethod def configure(self, config_dict, registry_config_str): """ Configures the :py:class:`Interface` for the specific instance of a device. @@ -282,7 +271,7 @@ def configure(self, config_dict, registry_config_str): to the Interface with :py:meth:`BaseInterface.insert_register`. """ pass - + def get_register_by_name(self, name): """ Get a register by it's point name. @@ -295,8 +284,8 @@ def get_register_by_name(self, name): try: return self.point_map[name] except KeyError: - raise DriverInterfaceError("Point not configured on device: "+name) - + raise DriverInterfaceError("Point not configured on device: " + name) + def get_register_names(self): """ Get a list of register names. @@ -312,8 +301,8 @@ def get_register_names_view(self): :rtype: dictview """ return self.point_map.keys() - - def get_registers_by_type(self, reg_type, read_only): + + def get_registers_by_type(self, reg_type, read_only) -> List[BaseRegister]: """ Get a list of registers by type. Useful for an :py:class:`Interface` that needs to categorize registers by type when doing a scrape. @@ -325,8 +314,8 @@ def get_registers_by_type(self, reg_type, read_only): :return: An list of BaseRegister instances. :rtype: list """ - return self.registers[reg_type,read_only] - + return self.registers[reg_type, read_only] + def insert_register(self, register): """ Inserts a register into the :py:class:`Interface`. @@ -336,12 +325,12 @@ def insert_register(self, register): """ register_point = register.point_name self.point_map[register_point] = register - + register_type = register.get_register_type() - self.registers[register_type].append(register) - + self.registers[register_type].append(register) + @abc.abstractmethod - def get_point(self, point_name, **kwargs): + def get_point(self, point_name, **kwargs): """ Get the current value for the point name given. @@ -350,7 +339,7 @@ def get_point(self, point_name, **kwargs): :type point_name: str :return: Point value """ - + @abc.abstractmethod def set_point(self, point_name, value, **kwargs): """ @@ -369,8 +358,8 @@ def set_point(self, point_name, value, **kwargs): :type point_name: str :return: Actual point value set. """ - - @abc.abstractmethod + + @abc.abstractmethod def scrape_all(self): """ Method the Platform Driver Agent calls to get the current state @@ -379,16 +368,16 @@ def scrape_all(self): :return: Point names to values for device. :rtype: dict """ - - @abc.abstractmethod + + @abc.abstractmethod def revert_all(self, **kwargs): """ Revert entire device to it's default state :param kwargs: Any interface specific parameters. """ - - @abc.abstractmethod + + @abc.abstractmethod def revert_point(self, point_name, **kwargs): """ Revert point to it's default state. @@ -452,11 +441,12 @@ class RevertTracker: """ A helper class for tracking the state of writable points on a device. """ + def __init__(self): self.defaults = {} self.clean_values = {} self.dirty_points = set() - + def update_clean_values(self, points): """ Update all state of all the clean point values for a device. @@ -471,7 +461,7 @@ def update_clean_values(self, points): if k not in self.dirty_points and k not in self.defaults: clean_values[k] = v self.clean_values.update(clean_values) - + def set_default(self, point, value): """ Set the value to revert a point to. Overrides any clean value detected. @@ -481,7 +471,7 @@ def set_default(self, point, value): :type point: str """ self.defaults[point] = value - + def get_revert_value(self, point): """ Returns the clean value for a point if no default is set, otherwise returns @@ -498,9 +488,9 @@ def get_revert_value(self, point): return self.defaults[point] if point not in self.clean_values: raise DriverInterfaceError("Nothing to revert to for {}".format(point)) - + return self.clean_values[point] - + def clear_dirty_point(self, point): """ Clears the dirty flag on a point. @@ -509,7 +499,7 @@ def clear_dirty_point(self, point): :type point: str """ self.dirty_points.discard(point) - + def mark_dirty_point(self, point): """ Sets the dirty flag on a point. @@ -521,7 +511,7 @@ def mark_dirty_point(self, point): """ if point not in self.defaults: self.dirty_points.add(point) - + def get_all_revert_values(self): """ Returns a dict of points to revert values. @@ -543,7 +533,7 @@ def get_all_revert_values(self): results[point] = self.get_revert_value(point) except DriverInterfaceError: results[point] = DriverInterfaceError() - + return results @@ -573,13 +563,14 @@ class BasicRevert(object, metaclass=abc.ABCMeta): should be set in the :py:meth:`BaseInterface.configure` call. """ + def __init__(self, **kwargs): super(BasicRevert, self).__init__(**kwargs) self._tracker = RevertTracker() - + def _update_clean_values(self, points): self._tracker.update_clean_values(points) - + def set_default(self, point, value): """ Set the value to revert a point to. @@ -596,20 +587,20 @@ def set_point(self, point_name, value): Passes arguments through to :py:meth:`BasicRevert._set_point` """ - result = self._set_point(point_name, value) + result = self._set_point(point_name, value) self._tracker.mark_dirty_point(point_name) return result - + def scrape_all(self): """ Implementation of :py:meth:`BaseInterface.scrape_all` """ - result = self._scrape_all() + result = self._scrape_all() self._update_clean_values(result) return result - - @abc.abstractmethod + + @abc.abstractmethod def _set_point(self, point_name, value): """ Set the current value for the point name given. @@ -631,8 +622,8 @@ def _set_point(self, point_name, value): :type point_name: str :return: Actual point value set. """ - - @abc.abstractmethod + + @abc.abstractmethod def _scrape_all(self): """ Method the Platform Driver Agent calls to get the current state @@ -645,8 +636,7 @@ def _scrape_all(self): :return: Point names to values for device. :rtype: dict """ - - + def revert_all(self, **kwargs): """ Implementation of :py:meth:`BaseInterface.revert_all` @@ -685,8 +675,8 @@ def revert_point(self, point_name, **kwargs): value = self._tracker.get_revert_value(point_name) except DriverInterfaceError: return - + _log.debug("Reverting {} to {}".format(point_name, value)) - - self._set_point(point_name, value) + + self._set_point(point_name, value) self._tracker.clear_dirty_point(point_name) diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/bacnet.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/bacnet.py index 4009152d7a..b2fc973e10 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/bacnet.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/bacnet.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/__init__.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/__init__.py index d9a90e0482..0f8d26e5bb 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/__init__.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/async_service.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/async_service.py index 670c190aa5..ca98c8a753 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/async_service.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/async_service.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/service.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/service.py index 916333a9ed..da845c676e 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/service.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/service.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import suds.client diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/tests/TestAgent/tester/agent.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/tests/TestAgent/tester/agent.py index f9322e88fd..6e0fcbdb54 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/tests/TestAgent/tester/agent.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/tests/TestAgent/tester/agent.py @@ -1,39 +1,25 @@ ## -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/tests/test_chargepoint_driver.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/tests/test_chargepoint_driver.py index 7851d675e4..b698ef248b 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/tests/test_chargepoint_driver.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/chargepoint/tests/test_chargepoint_driver.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -157,7 +143,7 @@ def agent(request, volttron_instance): md_agent = volttron_instance.build_agent() # Clean out platform driver configurations. md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', 'platform.driver').get(timeout=10) driver1_config = DRIVER1_CONFIG_STRING % os.environ.get('CHARGEPOINT_PASSWORD', 'Must set a password') @@ -166,21 +152,21 @@ def agent(request, volttron_instance): # Add test configurations. md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', 'platform.driver', 'devices/chargepoint1', driver1_config, 'json').get(timeout=10) md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', 'platform.driver', 'devices/chargepoint2', driver2_config, 'json').get(timeout=10) md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', 'platform.driver', 'chargepoint.csv', REGISTRY_CONFIG_STRING, diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/__init__.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/__init__.py new file mode 100644 index 0000000000..91b2cd5813 --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/__init__.py @@ -0,0 +1 @@ +from .dnp3 import * diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/dnp3-driver.md b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/dnp3-driver.md new file mode 100644 index 0000000000..3771c0c5b6 --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/dnp3-driver.md @@ -0,0 +1,469 @@ +# DNP3 Driver + +Distributed Network Protocol (DNP +or [DNP3](https://en.wikipedia.org/wiki/DNP3)) +has achieved a large-scale acceptance since its introduction in 1993. This +protocol is an immediately deployable solution for monitoring remote sites because it was developed for communication of +critical infrastructure status, allowing for reliable remote control. + +DNP3 is typically used between centrally located masters and distributed remotes. The master provides the interface +between the human network manager and the monitoring system. The remote (RTUs and intelligent electronic devices) +provides the interface between the master and the physical device(s) being monitored and/or controlled. +The DNP3-Driver is a wrapper on the DNP3 master following +the [VOLTTRON driver framework](https://volttron.readthedocs.io/en/develop/agent-framework/driver-framework/drivers-overview.html#driver-framework). + +Note that the DNP3-Driver requires a DNP3 outstation instance to properly function. e.g., polling data, setting point +values, etc. The [dnp3-python](https://github.com/VOLTTRON/dnp3-python) can provide the essential outstation +functionality, and as part of the DNP3-Driver dependency, it is immediately available after the DNP3-Driver is +installed. + +### Requirements + +The DNP3 driver requires the [dnp3-python](https://github.com/VOLTTRON/dnp3-python) package, a wrapper on Pydnp3 +package. +This package can be installed in an activated environment with: + + pip install dnp3-python==0.2.3b3 + +### Quick Start + +The following recipe walks through the steps to install and configure a DNP3 Driver. Note that it uses default setup to +work out-of-the-box. Please feel free to refer to related documentations for details. + +1. Install volttron and start the platform. + + Refer + to [VOLTTRON Quick Start](https://volttron.readthedocs.io/en/main/tutorials/quick-start.html#volttron-quick-start) to + install the platform. + Then start the platform with the following command. (Please see `volttron --help` for more details.) + + ```shell + # Start platform with output going to volttron.log + volttron -vv -l volttron.log & + ``` + +1. Install the volttron platform driver: + + Install the required dependency for driver using `python bootstrap.py --drivers`. (Please + see `python bootstrap.py --help` for more details.) + + Note: for reproducibility, this demo will install platform driver with `vip-identity==platform_driver_for_dnp3`. + Free feel to specify any agent vip-identity as desired. + + ```shell + vctl install services/core/PlatformDriverAgent/ \ + --vip-identity platform_driver_for_dnp3 \ + --agent-config services/core/PlatformDriverAgent/platform-driver.agent \ + --tag platform_driver_for_dnp3 \ + -f \ + --start + ``` + +
+ Verify with `vctl status`. + + ```shell + (env) kefei@ubuntu-22:~/sandbox/dnp3-driver-sandbox$ vctl status + + UUID AGENT IDENTITY TAG PRIORITY STATUS HEALTH + + 5 platform_driveragent-4.0 platform_driver_for_dnp3 running [23217] GOOD + ``` + +### Configure the DNP3 driver + +1. Install a DNP3 Driver onto the Platform Driver. + + Installing a DNP3 driver in the Platform Driver Agent requires adding copies of the device configuration and registry + configuration files to the Platform Driver’s configuration store. For demo purpose, we will use default configure + files. + + Prepare the default config files: + + ```shell + # Create config file place holders + mkdir config + touch config/dnp3-config.json + touch config/dnp3.csv + ``` + + An example config file is available at " + services/core/PlatformDriverAgent/platform_driver/interfaces/udd_dnp3/examples/dnp3.config" + + ```json + { + "driver_config": { + "master_ip": "0.0.0.0", + "outstation_ip": "127.0.0.1", + "master_id": 2, + "outstation_id": 1, + "port": 20000 + }, + "registry_config": "config://dnp3.csv", + "driver_type": "dnp3", + "interval": 5, + "timezone": "UTC", + "publish_depth_first_all": true, + "heart_beat_point": "random_bool" + } + ``` + + Another example config file is available at " + services/core/PlatformDriverAgent/platform_driver/interfaces/udd_dnp3/examples/dnp3.csv" + + ```csv + Point Name,Volttron Point Name,Group,Variation,Index,Scaling,Units,Writable,Notes + AnalogInput_index0,AnalogInput_index0,30,6,0,1,NA,FALSE,Double Analogue input without status + AnalogInput_index1,AnalogInput_index1,30,6,1,1,NA,FALSE,Double Analogue input without status + AnalogInput_index2,AnalogInput_index2,30,6,2,1,NA,FALSE,Double Analogue input without status + AnalogInput_index3,AnalogInput_index3,30,6,3,1,NA,FALSE,Double Analogue input without status + BinaryInput_index0,BinaryInput_index0,1,2,0,1,NA,FALSE,Single bit binary input with status + BinaryInput_index1,BinaryInput_index1,1,2,1,1,NA,FALSE,Single bit binary input with status + BinaryInput_index2,BinaryInput_index2,1,2,2,1,NA,FALSE,Single bit binary input with status + BinaryInput_index3,BinaryInput_index3,1,2,3,1,NA,FALSE,Single bit binary input with status + AnalogOutput_index0,AnalogOutput_index0,40,4,0,1,NA,TRUE,Double-precision floating point with flags + AnalogOutput_index1,AnalogOutput_index1,40,4,1,1,NA,TRUE,Double-precision floating point with flags + AnalogOutput_index2,AnalogOutput_index2,40,4,2,1,NA,TRUE,Double-precision floating point with flags + AnalogOutput_index3,AnalogOutput_index3,40,4,3,1,NA,TRUE,Double-precision floating point with flags + BinaryOutput_index0,BinaryOutput_index0,10,2,0,1,NA,TRUE,Binary Output with flags + BinaryOutput_index1,BinaryOutput_index1,10,2,1,1,NA,TRUE,Binary Output with flags + BinaryOutput_index2,BinaryOutput_index2,10,2,2,1,NA,TRUE,Binary Output with flags + BinaryOutput_index3,BinaryOutput_index3,10,2,3,1,NA,TRUE,Binary Output with flags + + ``` + + Add config to the configuration store: + + ``` + vctl config store platform_driver_for_dnp3 devices/campus/building/dnp3 services/core/PlatformDriverAgent/platform_driver/interfaces/udd_dnp3/examples/dnp3.config + vctl config store platform_driver_for_dnp3 dnp3.csv services/core/PlatformDriverAgent/platform_driver/interfaces/udd_dnp3/examples/dnp3.csv --csv + ``` + +
+ Verify with `vctl config list` and `vctl config get` command. + (Please refer to the `vctl config` documentation for more details.) + + ```shell + (env) kefei@ubuntu-22:~/sandbox/dnp3-driver-sandbox$ vctl config get platform_driver_for_dnp3 devices/campus/building/dnp3 + { + "driver_config": { + "master_ip": "0.0.0.0", + "outstation_ip": "127.0.0.1", + "master_id": 2, + "outstation_id": 1, + "port": 20000 + }, + "registry_config": "config://dnp3.csv", + "driver_type": "dnp3", + "interval": 5, + "timezone": "UTC", + "publish_depth_first_all": true, + "heart_beat_point": "random_bool" + } + + (env) kefei@ubuntu-22:~/sandbox/dnp3-driver-sandbox$ vctl config get platform_driver_for_dnp3 dnp3.csv + [ + { + "Point Name": "AnalogInput_index0", + "Volttron Point Name": "AnalogInput_index0", + "Group": "30", + "Variation": "6", + "Index": "0", + ... + ] + ``` + +
+ +1. Verify with logging data + + When the DNP3-Driver is properly installed and configured, we can verify with logging data in "volttron.log". + + ``` + tail -f /volttron.log + ``` + +
+ Expected logging example + + ```shell + ... + 2023-03-13 23:26:56,611 (volttron-platform-driver-0.2.0rc1 23666) volttron.driver.base.driver(334) DEBUG: finish publishing: devices/campus/building/dnp3/all + 2023-03-13 23:26:57,897 () volttron.services.auth.auth_service(235) DEBUG: after getting peerlist to send auth updates + 2023-03-13 23:26:57,897 () volttron.services.auth.auth_service(239) DEBUG: Sending auth update to peers platform.control + 2023-03-13 23:26:57,897 () volttron.services.auth.auth_service(239) DEBUG: Sending auth update to peers platform_driver_for_dnp3 + 2023-03-13 23:26:57,898 () volttron.services.auth.auth_service(239) DEBUG: Sending auth update to peers platform.health + 2023-03-13 23:26:57,898 () volttron.services.auth.auth_service(239) DEBUG: Sending auth update to peers platform.config_store + 2023-03-13 23:26:57,898 () volttron.services.auth.auth_service(193) INFO: auth file /home/kefei/.volttron/auth.json loaded + 2023-03-13 23:26:57,898 () volttron.services.auth.auth_service(172) INFO: loading auth file /home/kefei/.volttron/auth.json + 2023-03-13 23:26:57,898 () volttron.services.auth.auth_service(185) DEBUG: Sending auth updates to peers + 2023-03-13 23:26:58,241 (volttron-platform-driver-0.2.0rc1 23666) (0) INFO: ['ms(1678768018241) INFO tcpclient - Connecting to: 127.0.0.1'] + 2023-03-13 23:26:58,241 (volttron-platform-driver-0.2.0rc1 23666) (0) INFO: ['ms(1678768018241) WARN tcpclient - Error Connecting: Connection refused'] + 2023-03-13 23:26:59,905 () volttron.services.auth.auth_service(235) DEBUG: after getting peerlist to send auth updates + 2023-03-13 23:26:59,905 () volttron.services.auth.auth_service(239) DEBUG: Sending auth update to peers platform.control + 2023-03-13 23:26:59,905 () volttron.services.auth.auth_service(239) DEBUG: Sending auth update to peers platform_driver_for_dnp3... + ] + ``` +
+ +1. (Optional) Verify with published data polled from outstation + + To see data being polled from an outstation and published to the bus, we need to + + * Set up an outstation, and + * install a [Listener Agent](https://pypi.org/project/volttron-listener/): + + **Set up an outstation**: The [dnp3-python](https://github.com/VOLTTRON/dnp3-python) is part of the dnp3-driver + dependency, and it is immediately available after the DNP3-Driver is installed. + + **Open another terminal**, and run `dnp3demo outstation`. For demo purpose, we assign arbitrary values to the + point. ( + More details about the "dnp3demo" module, please + see [dnp3demo-Module.md](https://github.com/VOLTTRON/dnp3-python/blob/main/docs/dnp3demo-Module.md)) + + ```shell + ==== Outstation Operation MENU ================================== + - update analog-input point value (for local reading) + - update analog-output point value (for local control) + - update binary-input point value (for local reading) + - update binary-output point value (for local control) +
- display database + - display configuration + ================================================================= + + ======== Your Input Here: ==(outstation)====== + ai + You chose - update analog-input point value (for local reading) + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + + + ======== Your Input Here: ==(outstation)====== + 0.1212 0 + {'Analog': {0: 0.1212, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}} + You chose - update analog-input point value (for local reading) + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + + + ======== Your Input Here: ==(outstation)====== + 1.2323 1 + {'Analog': {0: 0.1212, 1: 1.2323, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}} + You chose - update analog-input point value (for local reading) + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + ``` +
+ Example of interaction with the `dnp3demo outstation` sub-command + + ```shell + (env) kefei@ubuntu-22:~/sandbox/dnp3-driver-sandbox$ dnp3demo outstation + dnp3demo.run_outstation {'command': 'outstation', 'outstation_ip=': '0.0.0.0', 'port=': 20000, 'master_id=': 2, 'outstation_id=': 1} + ms(1678770551216) INFO manager - Starting thread (0) + 2023-03-14 00:09:11,216 control_workflow_demo INFO Connection Config + 2023-03-14 00:09:11,216 control_workflow_demo INFO Connection Config + 2023-03-14 00:09:11,216 control_workflow_demo INFO Connection Config + ms(1678770551216) INFO server - Listening on: 0.0.0.0:20000 + 2023-03-14 00:09:11,216 control_workflow_demo DEBUG Initialization complete. Outstation in command loop. + 2023-03-14 00:09:11,216 control_workflow_demo DEBUG Initialization complete. Outstation in command loop. + 2023-03-14 00:09:11,216 control_workflow_demo DEBUG Initialization complete. Outstation in command loop. + Connection error. + Connection Config {'outstation_ip_str': '0.0.0.0', 'port': 20000, 'masterstation_id_int': 2, 'outstation_id_int': 1} + Start retry... + Connection error. + Connection Config {'outstation_ip_str': '0.0.0.0', 'port': 20000, 'masterstation_id_int': 2, 'outstation_id_int': 1} + ms(1678770565247) INFO server - Accepted connection from: 127.0.0.1 + ==== Outstation Operation MENU ================================== + - update analog-input point value (for local reading) + - update analog-output point value (for local control) + - update binary-input point value (for local reading) + - update binary-output point value (for local control) +
- display database + - display configuration + ================================================================= + + + ======== Your Input Here: ==(outstation)====== + ai + You chose - update analog-input point value (for local reading) + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + + + ======== Your Input Here: ==(outstation)====== + 0.1212 0 + {'Analog': {0: 0.1212, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}} + You chose - update analog-input point value (for local reading) + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + + + ======== Your Input Here: ==(outstation)====== + 1.2323 1 + {'Analog': {0: 0.1212, 1: 1.2323, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}} + You chose - update analog-input point value (for local reading) + Type in and . Separate with space, then hit ENTER. + Type 'q', 'quit', 'exit' to main menu. + + + ======== Your Input Here: ==(outstation)====== + ``` +
+ + **Install the [Listener Agent](https://pypi.org/project/volttron-listener/)**: + Run `vctl install volttron-listener --start`. Once installed, you should see the data being published by viewing the + Volttron logs file. (i.e., `tail -f /volttron.log`) + > **Note**: + > it is recommended to restart the Platform Driver after a specific driver is installed and configured. i.e., + > using the `vctl restart ` command.) The expected logging will be similar as follows: + + ```shell + 2023-03-14 00:11:55,000 (volttron-platform-driver-0.2.0rc0 24737) volttron.driver.base.driver(277) DEBUG: scraping device: campus/building/dnp3 + 2023-03-14 00:11:55,805 (volttron-platform-driver-0.2.0rc0 24737) volttron.driver.base.driver(330) DEBUG: publishing: devices/campus/building/dnp3/all + 2023-03-14 00:11:55,810 (volttron-listener-0.2.0rc0 24424) listener.agent(104) INFO: Peer: pubsub, Sender: platform_driver_for_dnp3:, Bus: , Topic: devices/campus/building/dnp3/all, Headers: {'Date': '2023-03-14T05:11:55.805245+00:00', 'TimeStamp': '2023-03-14T05:11:55.805245+00:00', 'SynchronizedTimeStamp': '2023-03-14T05:11:55.000000+00:00', 'min_compatible_version': '3.0', 'max_compatible_version': ''}, Message: + [{'AnalogInput_index0': 0.1212, + 'AnalogInput_index1': 1.2323, + 'AnalogInput_index2': 0.0, + 'AnalogInput_index3': 0.0, + 'AnalogOutput_index0': 0.0, + 'AnalogOutput_index1': 0.0, + 'AnalogOutput_index2': 0.0, + 'AnalogOutput_index3': 0.0, + 'BinaryInput_index0': False, + 'BinaryInput_index1': False, + 'BinaryInput_index2': False, + 'BinaryInput_index3': False, + 'BinaryOutput_index0': False, + 'BinaryOutput_index1': False, + 'BinaryOutput_index2': False, + 'BinaryOutput_index3': False}, + {'AnalogInput_index0': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'AnalogInput_index1': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'AnalogInput_index2': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'AnalogInput_index3': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'AnalogOutput_index0': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'AnalogOutput_index1': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'AnalogOutput_index2': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'AnalogOutput_index3': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'BinaryInput_index0': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'BinaryInput_index1': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'BinaryInput_index2': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'BinaryInput_index3': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'BinaryOutput_index0': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'BinaryOutput_index1': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'BinaryOutput_index2': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}, + 'BinaryOutput_index3': {'type': 'integer', 'tz': 'UTC', 'units': 'NA'}}] + 2023-03-14 00:11:55,810 (volttron-platform-driver-0.2.0rc0 24737) volttron.driver.base.driver(334) DEBUG: finish publishing: devices/campus/building/dnp3/all + 2023-03-14 00:11:56,825 (volttron-listener-0.2.0rc0 24424) listener.agent(104) INFO: Peer: pubsub, Sender: volttron-listener-0.2.0rc0_2:, Bus: , Topic: heartbeat/volttron-listener-0.2.0rc0_2, Headers: {'TimeStamp': '2023-03-14T05:11:56.820827+00:00', 'min_compatible_version': '3.0', 'max_compatible_version': ''}, Message: + + ``` + +1. Shutdown the platform + + ```shell + ./stop-volttron + ``` + +### DNP3 Registry Configuration File + +The driver's registry configuration file, a [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) file, +specifies which DNP3 points the driver will read and/or write. Each row configures a single DNP3 point. + +The following columns are required for each row: + +- **Volttron Point Name** - The name used by the VOLTTRON platform and agents to refer to the point. +- **Group** - The point's DNP3 group number. +- **Variation** - THe permit negotiated exchange of data formatted, i.e., data type. +- **Index** - The point's index number within its DNP3 data type (which is derived from its DNP3 group number). +- **Scaling** - A factor by which to multiply point values. +- **Units** - Point value units. +- **Writable** - TRUE or FALSE, indicating whether the point can be written by the driver (FALSE = read-only). + +Consult the **DNP3 data dictionary** for a point's Group and Index values. Point +definitions in the data dictionary are by agreement between the DNP3 Outstation and Master. +The VOLTTRON DNP3Agent loads the data dictionary of point definitions from the JSON file +at "point_definitions_path" in the DNP3Agent's config file. + +### Testing + +1. (If not satisfied,) install the dependencies for testing. + + ```shell + python bootstrap.py --testing + ``` + +1. Run pytest + + ```shell + pytest ./services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/. + ``` + + Note: the tests run on port=20000 by default. Make sure there is no other dnp3 instances running on port 20000 when + running the tests. + +
+ Example output + + ```shell + ===================================================================================================== test session starts ===================================================================================================== + platform linux -- Python 3.10.6, pytest-7.1.2, pluggy-1.0.0 -- /home/kefei/project/volttron/env/bin/python + cachedir: .pytest_cache + rootdir: /home/kefei/project/volttron, configfile: pytest.ini + plugins: rerunfailures-10.2, asyncio-0.19.0, timeout-2.1.0 + asyncio: mode=auto + timeout: 300.0s + timeout method: signal + timeout func_only: False + collected 27 items + + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDummy::test_dummy PASSED [ 3%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestStation::test_station_init PASSED [ 7%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestStation::test_station_get_val_analog_input_float PASSED [ 11%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestStation::test_station_set_val_analog_input_float PASSED [ 14%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNPRegister::test_init PASSED [ 18%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNPRegister::test_get_register_value_analog_float PASSED [ 22%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNPRegister::test_get_register_value_analog_int PASSED [ 25%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNPRegister::test_get_register_value_binary PASSED [ 29%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNP3RegisterControlWorkflow::test_set_register_value_analog_float PASSED [ 33%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNP3RegisterControlWorkflow::test_set_register_value_analog_int PASSED [ 37%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNP3RegisterControlWorkflow::test_set_register_value_binary PASSED [ 40%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNP3InterfaceNaive::test_init PASSED [ 44%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNP3InterfaceNaive::test_get_reg_point PASSED [ 48%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py::TestDNP3InterfaceNaive::test_set_reg_point PASSED [ 51%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDummy::test_dummy PASSED [ 55%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDummyAgentFixture::test_agent_dummy[volttron_instance0] SKIPPED (only for debugging purpose) [ 59%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_interface_get_point[volttron_instance0] PASSED [ 62%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_interface_set_point[volttron_instance0] PASSED [ 66%]ms(1684117269227) INFO manager - Exiting thread (0) + + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDummyAgentFixture::test_agent_dummy[volttron_instance1] SKIPPED (RabbitMQ is not setup and/or...) [ 70%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_interface_get_point[volttron_instance1] SKIPPED (RabbitMQ is not setup an...) [ 74%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_interface_set_point[volttron_instance1] SKIPPED (RabbitMQ is not setup an...) [ 77%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDummyAgentFixture::test_agent_dummy[volttron_instance2] SKIPPED (only for debugging purpose) [ 81%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_interface_get_point[volttron_instance2] PASSED [ 85%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_interface_set_point[volttron_instance2] PASSED [ 88%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_scrape_all SKIPPED (TODO) [ 92%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_revert_all SKIPPED (TODO) [ 96%] + services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py::TestDnp3DriverRPC::test_revert_point SKIPPED (TODO) [100%] + + ====================================================================================================== warnings summary ======================================================================================================= + env/lib/python3.10/site-packages/wheel/paths.py:7 + /home/kefei/project/volttron/env/lib/python3.10/site-packages/wheel/paths.py:7: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives + import distutils.command.install as install + + ../../../../usr/lib/python3.10/distutils/command/install.py:13 + /usr/lib/python3.10/distutils/command/install.py:13: DeprecationWarning: The distutils.sysconfig module is deprecated, use sysconfig instead + from distutils.sysconfig import get_config_vars, is_virtual_environment + + -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html + =================================================================================================== short test summary info =================================================================================================== + SKIPPED [2] services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py: only for debugging purpose + SKIPPED [1] services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py: RabbitMQ is not setup and/or SSL does not work in CI + SKIPPED [1] services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py:65: RabbitMQ is not setup and/or SSL does not work in CI + SKIPPED [1] services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py:85: RabbitMQ is not setup and/or SSL does not work in CI + SKIPPED [1] services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py:104: TODO + SKIPPED [1] services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py:117: TODO + SKIPPED [1] services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py:129: TODO + ==================================================================================== 19 passed, 8 skipped, 2 warnings in 227.38s (0:03:47) ==================================================================================== + ``` + +
diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/dnp3.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/dnp3.py new file mode 100644 index 0000000000..c64fd775ee --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/dnp3.py @@ -0,0 +1,211 @@ +from .driver_wrapper import WrapperInterface, WrapperRegister +from .driver_wrapper import ImplementedRegister, RegisterValue +from typing import List, Optional, Dict + +from dnp3_python.dnp3station.master_new import MyMasterNew + +# TODO-developer: Your code here +# Add dependency as needed, and update in requirements + +import logging +import sys + + +stdout_stream = logging.StreamHandler(sys.stdout) +stdout_stream.setFormatter(logging.Formatter('%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s')) + +_log = logging.getLogger(__name__) +_log.addHandler(stdout_stream) +_log.setLevel(logging.DEBUG) +_log.setLevel(logging.WARNING) +_log.setLevel(logging.ERROR) + + +# TODO-developer: Your code here +# Change the classname "UserDevelopRegister" as needed +class UserDevelopRegisterDnp3(WrapperRegister): + # TODO-developer: Your code here + def __init__(self, master_application, reg_def, *args, **kwargs): + super().__init__(*args, **kwargs) + # self.master_application = kwargs['master_application'] + # self.reg_def = kwargs['reg_def'] + self.master_application = master_application + self.reg_def = reg_def + + def get_register_value(self) -> RegisterValue: + # TODO-developer: Your code here + # Implement get-register-value logic here + # Note: Keep the method name as it is including the signatures. + # Use a helper method if needed. + + # EXAMPLE: + # def get_register_value(self) -> RegisterValue: + # return _get_register_value_helper(url=self.driver_config.get("url")) + # def _get_register_value_helper(self, url: str): + # ... + + # print("silly implementation") + # the url will be in the config file + + try: + reg_def = self.reg_def + group = int(reg_def.get("Group")) + variation = int(reg_def.get("Variation")) + index = int(reg_def.get("Index")) + val = self._get_outstation_pt(self.master_application, group, variation, index) + # val = str(val) + + if val is not None: + return val + else: + _log.warning("dnp3 driver (master) couldn't collect data from the outstation.") + raise ValueError(f"Returned invalid dnp3 data point {val}") # do not publish invalid values + except Exception as e: + # print(f"!!!!!!!!!!!!!!!!!!!!{e}") + _log.error(e) + + raise Exception(e) + + @staticmethod + def _get_outstation_pt(master_application, group, variation, index) -> RegisterValue: + """ + Core logic to retrieve register value by polling a dnp3 outstation + Note: using def get_db_by_group_variation_index + Returns + ------- + + """ + return_point_value = master_application.get_val_by_group_variation_index(group=group, + variation=variation, + index=index) + return return_point_value + + def set_register_value(self, value, **kwargs) -> Optional[RegisterValue]: + """ + TODO: docstring + """ + try: + reg_def = self.reg_def + group = int(reg_def.get("Group")) + variation = int(reg_def.get("Variation")) + index = int(reg_def.get("Index")) + + val: Optional[RegisterValue] + self._set_outstation_pt(self.master_application, group, variation, index, set_value=value) + val = None + + return val + except Exception as e: + _log.error(e) + _log.warning("dnp3 driver (master) couldn't set value for the outstation.") + + @staticmethod + def _set_outstation_pt(master_application, group, variation, index, set_value) -> None: + """ + Core logic to send point operate command to outstation + Note: using def send_direct_point_command + Returns None + ------- + + """ + master_application.send_direct_point_command(group=group, variation=variation, index=index, + val_to_set=set_value) + + +class Interface(WrapperInterface): + # TODO-developer: Your code here + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.master_application = None + + # TODO-developer: Your code here + # Register type configuration + @staticmethod + def pass_register_types(csv_config: dict, driver_config_in_json_config: List[dict], + register_type_list: List[ImplementedRegister] = None): + """ + Note: based on the config.csv file. + By default, assuming register points are dnp3-register type + (optional) heartbeat register + """ + return [UserDevelopRegisterDnp3] * len(csv_config) + + @staticmethod + def _create_master_station(driver_config: dict): + """ + init a master station and later pass to registers + + Note: rely on XX.config json file convention, e.g., + "driver_config": + {"master_ip": "0.0.0.0", + "outstation_ip": "127.0.0.1", + "master_id": 2, + "outstation_id": 1, + "port": 20000}, + + Returns + ------- + + """ + + master_application = MyMasterNew( + masterstation_ip_str=driver_config.get("master_ip"), + outstation_ip_str=driver_config.get("outstation_ip"), + port=driver_config.get("port"), + masterstation_id_int=driver_config.get("master_id"), + outstation_id_int=driver_config.get("outstation_id"), + ) + # master_application.start() + return master_application + + def create_register(self, driver_config, + point_name, + data_type, + units, + read_only, + default_value, + description, + csv_config, + reg_def, + register_type, *args, **kwargs): + def get_master_station(): + # Note: this a closure, since parameter driver_config is required. + # (at current state) only create_register workflow should use it. + if self.master_application: + return self.master_application + else: + self.master_application = self._create_master_station(driver_config) + return self.master_application + + master = get_master_station() + master.start() + + register = UserDevelopRegisterDnp3( + driver_config=driver_config, + point_name=point_name, + data_type=data_type, # TODO: make it more clear in documentation + units=units, + read_only=read_only, + default_value=default_value, + description=description, + csv_config=csv_config, + reg_def=reg_def, + master_application=master + ) + return register + + @staticmethod + def get_reg_point(register: ImplementedRegister): + """ + Core logic for get_point + Note: Can be used for vip-agent-mock testing + """ + return register.get_register_value() + + @staticmethod + def set_reg_point(register: ImplementedRegister, value_to_set: RegisterValue): + """ + Core logic for set_point, i.e., _set_point without verification + Note: Can be used for vip-agent-mock testing + """ + set_pt_response = register.set_register_value(value=value_to_set) + return set_pt_response diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/driver_wrapper.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/driver_wrapper.py new file mode 100644 index 0000000000..6a87b39d21 --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/driver_wrapper.py @@ -0,0 +1,822 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +import abc + +from platform_driver.interfaces import BaseInterface, BaseRegister, BasicRevert +# from ...platform_driver.interfaces import BaseInterface, BaseRegister, BasicRevert +from csv import DictReader +from io import StringIO +import logging +import sys + +import requests + +from typing import List, Type, Dict, Union, Optional, TypeVar +from time import sleep + +stdout_stream = logging.StreamHandler(sys.stdout) +stdout_stream.setFormatter(logging.Formatter('%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s')) + +_log = logging.getLogger(__name__) +# _log = logging.getLogger("data_retrieval_demo") +_log.addHandler(stdout_stream) +_log.setLevel(logging.DEBUG) +_log.setLevel(logging.WARNING) + +# TODO: parse to python_type based on literal. i.e., locate("int")("1") -> int(1) +# Design the data type validation logic (recommend but not enforce?) +type_mapping = {"string": str, + "int": int, + "integer": int, + "float": float, + "bool": bool, + "boolean": bool} + +# Type alias +RegisterValue = Union[int, str, float, bool] +Register = TypeVar("Register", bound=BaseRegister) + + +class WrapperRegister(BaseRegister): + """ + Template Register, host boilerplate code + """ + + # TODO: do we need to separate read-only and writable register? How a writable register looks like? + # TODO: e.g., How the set-value pass to the register class? + # TODO: (Mimic what happen to get_register_value method, we might need a controller method. + def __init__(self, driver_config: dict, point_name: str, data_type: RegisterValue, units: str, read_only: bool, + default_value=None, description='', csv_config={}, *args, **kwargs): + """ + Parameters # TODO: clean this up, + ---------- + config_dict: associated with `driver_config` in driver-config.config (json-like file) + user inputs are put here, e.g., IP address, url, etc. + + read_only: associated with `Writable` in driver-config.csv + point_name: associated with `Volttron Point Name` in driver-config.csv + units: associated with `Units` in driver-config.csv + reg_type: ?? # TODO: clean this up, + default_value: ?? # TODO: clean this up, + description: ?? # TODO: clean this up, + + Associated with Point Name,Volttron Point Name,Units,Units Details,Writable,Starting Value,Type,Notes + read_only = regDef['Writable'].lower() != 'true' + point_name = regDef['Volttron Point Name'] + description = regDef.get('Notes', '') + units = regDef['Units'] + default_value = regDef.get("Starting Value", 'sin').strip() + """ + super().__init__("byte", read_only, point_name, units, description='') + self._value: str = "" + self.driver_config: dict = driver_config + + self.point_name: str = point_name + self.data_type_str: str = data_type # "byte" or "bit" + self.units: Optional[str] = units + self.read_only: bool = read_only + self.default_value: Optional[RegisterValue] = default_value + self.description: str = description + self.csv_config: list = csv_config + + @property + def value(self): + self._value = self.get_register_value() # pre-requite methods + return self._value + + @value.setter + def value(self, x: RegisterValue): + if self.read_only: + raise RuntimeError( # TODO: Is RuntimeError necessary + "Trying to write to a point configured read only: " + self.point_name) # TODO: clean up + self._value = x + + @abc.abstractmethod + def get_register_value(self, **kwargs) -> RegisterValue: + """ + Override this to get register value + Examples 1 retrieve: + def get_register_value(): + some_url: str = self.config_dict.get("url") + return self.get_restAPI_value(url=some_url) + def get_restAPI_value(url=some_url) + ... + Returns + ------- + + """ + + @abc.abstractmethod + def set_register_value(self, value, **kwargs) -> Optional[RegisterValue]: # TODO: need an example/redesign for this + pass + # """ + # Override this to set register value. (Only for writable==True/read_only==False) + # Examples: + # def set_register_value(): + # some_temperature: int = get_comfortable_temperature(...) + # self.value(some_temperature) + # def get_comfortable_temperature(**kwargs) -> int: + # ... + # Returns + # ------- + # + # """ + + +# alias +ImplementedRegister = Union[WrapperRegister, Type[WrapperRegister]] + + +class DriverConfig: + """ + For validate driver configuration, e.g., driver-config.csv + """ + + def __init__(self, csv_config: List[dict]): + self.csv_config: List[dict] = csv_config + """ + + Parameters + ---------- + csv_config + + Returns + ------- + Examples: + [{'Point Name': 'Heartbeat', 'Volttron Point Name': 'Heartbeat', 'Units': 'On/Off', + 'Units Details': 'On/Off', 'Writable': 'TRUE', 'Starting Value': '0', 'Type': 'boolean', + 'Notes': 'Point for heartbeat toggle'}, + {'Point Name': 'Catfact', 'Volttron Point Name': 'Catfact', 'Units': 'No cat fact', + 'Units Details': 'No cat fact', 'Writable': 'TRUE', 'Starting Value': 'No cat fact', 'Type': 'str', + 'Notes': 'Cat fact extract from REST API'}] + """ + + @staticmethod + def _validate_header(point_config: dict): + """ + Require the header include the following keys + "PointName", "DataType", "Units", "ReadOnly", "DefaultValue", "Description" + (or allow parsing with minimal effort) + "PointName" <- "Point Name", "point name", "point-name", but not "point names" or "the point name" + Parameters + ---------- + point_config + + Returns + ------- + + """ + + def _to_alpha_lower(key: str): + return ''.join([x.lower() for x in key if x.isalpha()]) + + new_dict = {_to_alpha_lower(k): v for k, v in point_config.items()} + new_keys = new_dict.keys() + + standardized_valid_names = ["Volttron Point Name", "Data Type", "Units", "Writable", "Default Value", "Notes"] + for valid_name in standardized_valid_names: + if valid_name.lower() not in new_keys: + raise ValueError(f"`{valid_name}` is not in the config") + return new_dict + + def key_validate(self) -> List[dict]: + """ + + Returns + EXAMPLE: + {'pointname': 'Heartbeat', + 'datatype': 'boolean', + 'units': 'On/Off', + 'readonly': 'TRUE', + 'defaultvalue': '0', + 'description': 'Point for heartbeat toggle', + 'volttronpointname': 'Heartbeat', + 'unitsdetails': 'On/Off'} + ------- + + """ + key_validate_csv = [self._validate_header(point_config) for point_config in self.csv_config] + return key_validate_csv + + +class WrapperInterface(BasicRevert, BaseInterface): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + self.point_map: Dict[str, ImplementedRegister] = {} # {register.point_name: register} + self.register_types: List[ + ImplementedRegister] = [] # TODO: add sanity check for restister_types, e.g., count == register counts + + self.csv_config = None # TODO: try to get this value, potentially from def configure. get inspiration from modbus_tk testing + self.driver_config_in_json_config = None # TODO: try to get this value, potentially from def configure + + # TODO: clean up this public interface + # from *.csv configure file "driver_config": {...} + # self.driver_config: dict = {} + + def configure(self, driver_config_in_json_config: dict, csv_config: List[ + dict]): # TODO: ask driver.py, BaseInterface.configure to update signature when evoking + """ + Used by driver.py + def get_interface(self, driver_type, config_dict, config_string): + interface.configure(config_dict, config_string) + + Parameters # TODO: follow BaseInterface.configure signatures. But the names are wrong. + ---------- + driver_config_in_json_config: associated with `driver_config` in driver-config.config (json-like file) + user inputs are put here, e.g., IP address, url, etc. + csv_config: associated with the whole driver-config.csv file + Examples: + [{'Point Name': 'Heartbeat', 'Volttron Point Name': 'Heartbeat', 'Units': 'On/Off', + 'Units Details': 'On/Off', 'Writable': 'TRUE', 'Starting Value': '0', 'Type': 'boolean', + 'Notes': 'Point for heartbeat toggle'}, + {'Point Name': 'Catfact', 'Volttron Point Name': 'Catfact', 'Units': 'No cat fact', + 'Units Details': 'No cat fact', 'Writable': 'TRUE', 'Starting Value': 'No cat fact', 'Type': 'str', + 'Notes': 'Cat fact extract from REST API'}] + + """ + # print("========================================== csv_config, ", csv_config) + # print("========================================== driver_config_in_json_config, ", driver_config_in_json_config) + self.csv_config = csv_config + self.driver_config_in_json_config = driver_config_in_json_config + + # TODO configuration validation, i.e., self.config_check(...) + # self.config_check + self.parse_config(csv_config, driver_config_in_json_config) + + @staticmethod + @abc.abstractmethod + def pass_register_types(csv_config: dict, driver_config_in_json_config: List[dict], + register_type_list: List[ImplementedRegister] = None) -> List[ImplementedRegister]: + """ + For ingesting the register types list + Will be used by concrete Interface class inherit this template + + Parameters + ---------- + driver_config_in_json_config: associated with `driver_config` in driver-config.config (json-like file) + user inputs are put here, e.g., IP address, url, etc. + csv_config: associated with the whole driver-config.csv file + Examples: + [{'Point Name': 'Heartbeat', 'Volttron Point Name': 'Heartbeat', 'Units': 'On/Off', + 'Units Details': 'On/Off', 'Writable': 'TRUE', 'Starting Value': '0', 'Type': 'boolean', + 'Notes': 'Point for heartbeat toggle'}, + {'Point Name': 'Catfact', 'Volttron Point Name': 'Catfact', 'Units': 'No cat fact', + 'Units Details': 'No cat fact', 'Writable': 'TRUE', 'Starting Value': 'No cat fact', 'Type': 'str', + 'Notes': 'Cat fact extract from REST API'}] + register_type_list: + Example: + [RestAPIRegister, RestAPIRegister, RestAPIRegister, RandomBoolRegister] + """ + pass + return register_type_list + + def parse_config(self, csv_config, driver_config_in_json_config): # TODO: this configDict is from *.csv not .config + # print("========================================== csv_config, ", csv_config) + # print("========================================== driver_config_in_json_config, ", driver_config_in_json_config) + + # driver_config: DriverConfig = DriverConfig(csv_config) + # valid_csv_config = DriverConfig(csv_config).key_validate() + # print("========================================== valid_csv_config, ", valid_csv_config) + + if csv_config is None: # TODO: leave it now. Later for central data check + return + + register_types: List[ImplementedRegister] = self.pass_register_types(csv_config, driver_config_in_json_config) + valid_csv_config = csv_config # TODO: Design the config check (No config check for now.) + for reg_def, register_type_iter in zip(valid_csv_config, register_types): + # Skip lines that have no address yet. # TODO: understand why + if not reg_def['Point Name']: + continue + + point_name = reg_def['Volttron Point Name'] + type_name = reg_def.get("Data Type", 'string') + reg_type = type_mapping.get(type_name, str) + units = reg_def['Units'] + read_only = reg_def['Writable'].lower() != 'true' # TODO: watch out for this is opposite logic + + description = reg_def.get('Notes', '') + + # default_value = reg_def.get("defaultvalue", 'sin').strip() + default_value = reg_def.get( + "Default Value") # TODO: redesign default value logic, e.g., beable to map to real python type + if not default_value: + default_value = None + + # register_type = FakeRegister if not point_name.startswith('Cat') else CatfactRegister # TODO: change this + register_type = register_type_iter # TODO: Inconventional, document this. + + # print("========================================== point_name, ", point_name) + # print("========================================== reg_type, ", reg_type) + # print("========================================== units, ", units) + # print("========================================== read_only, ", read_only) + # print("========================================== default_value, ", default_value) + # print("========================================== description, ", description) + # print("========================================== reg_def, ", reg_def) + # Note: the following is to init a register_type object, e.g., WrapperRegister + try: + # register: WrapperRegister = register_type(driver_config=driver_config_in_json_config, + # point_name=point_name, + # data_type=reg_type, # TODO: make it more clear in documentation + # units=units, + # read_only=read_only, + # default_value=default_value, + # description=description, + # csv_config=csv_config, + # reg_def=reg_def) + + register: WrapperRegister = self.create_register(driver_config=driver_config_in_json_config, + point_name=point_name, + data_type=reg_type, + # TODO: make it more clear in documentation + units=units, + read_only=read_only, + default_value=default_value, + description=description, + csv_config=csv_config, + reg_def=reg_def, + register_type=register_type) + if default_value is not None: + self.set_default(point_name, register.value) + + self.insert_register(register) + except Exception as e: + print(e) + + + + def create_register(self, driver_config, + point_name, + data_type, + units, + read_only, + default_value, + description, + csv_config, + reg_def, + register_type, *args, **kwargs) -> ImplementedRegister: + pass + """ + Factory method to init (WrapperRegister) register object + + :param register_type: the class name of the to-be-created register, e.g., WrapperRegister + :param driver_config_in_json_config: json config file, + :param csv_config: csv config file, Dict[str, str] + + """ + register: WrapperRegister = register_type(driver_config=driver_config, + point_name=point_name, + data_type=data_type, # TODO: make it more clear in documentation + units=units, + read_only=read_only, + default_value=default_value, + description=description, + csv_config=csv_config, + reg_def=reg_def) + return register + + def insert_register(self, register: WrapperRegister): + """ + Inserts a register into the :py:class:`Interface`. + + :param register: Register to add to the interface. + :type register: :py:class:`BaseRegister` + """ + register_point: str = register.point_name + self.point_map[register_point] = register + + register_type = register.get_register_type() + self.registers[register_type].append(register) + + def get_point(self, point_name, **kwargs) -> RegisterValue: + """ + Override BasicInvert method + Note: this method should be evoked by vip agent + EXAMPLE: + rs = a.vip.rpc.call("platform.driver", "get_point", + "campus-vm/building-vm/Dnp3", + "AnalogInput_index0").get() + """ + register: WrapperRegister = self.get_register_by_name(point_name) + val = self.get_reg_point(register) + return val + + # def _set_point(self, point_name: str, + # value_to_set: RegisterValue): # TODO: this method has some problem. Understand the logic: overall + example + + def set_point(self, point_name, value): + """ + Override/Restate BasicInvert method for convenience + Note: this method should be evoked by vip agent + EXAMPLE: + rs = a.vip.rpc.call("platform.driver", "set_point", + "campus-vm/building-vm/Dnp3", + "AnalogInput_index0", 0.543).get() + """ + # result = self._set_point(point_name, value) + # self._tracker.mark_dirty_point(point_name) + return super().set_point(point_name, value) + + def _set_point(self, point_name, value, **kwargs): + """ + Parameters + ---------- + point_name + value + + Returns + ------- + + """ + # value_to_set = value + register: ImplementedRegister = self.get_register_by_name(point_name) + + # response = self.set_reg_point_w_verification(value_to_set=value, register=register) + response = self.set_reg_point_async_w_verification(value_to_set=value, register=register) + return response + + @staticmethod + def get_reg_point(register: ImplementedRegister): + """ + Core logic for get_point + """ + return register.value + + @staticmethod + def set_reg_point(register: ImplementedRegister, value_to_set: RegisterValue): + """ + Core logic for set_point, i.e., _set_point without verification + Note: Can be used for vip-agent-mock testing + """ + set_pt_response = register.set_register_value(value=value_to_set) + return set_pt_response + + @classmethod + def set_reg_point_w_verification(cls, value_to_set: RegisterValue, register: ImplementedRegister, + relax_verification=True): + """ + Core logic for set_point, i.e., _set_point with verification + Note: Can be used for vip-agent-mock testing + """ + # Note: leave register method to verify, e.g., check writability. + + # set point workflow + set_pt_response = cls.set_reg_point(register=register, value_to_set=value_to_set) + + # verify with get_point + get_pt_response = cls.get_reg_point(register) + + success_flag_strict = (get_pt_response == value_to_set) + success_flag_relax = (str(get_pt_response) == str(value_to_set)) + if relax_verification: + success_flag = success_flag_relax + else: + success_flag = success_flag_strict + + response = {"success_flag": success_flag, + "value_to_set": value_to_set, + "set_pt_response": set_pt_response, + "get_pt_response": get_pt_response} + if not success_flag: + _log.warning(f"Set value failed, {response}") + return response + + @classmethod + def set_reg_point_async_w_verification(cls, value_to_set: RegisterValue, register: ImplementedRegister, + relax_verification=True): + """ + Counterpart of set_reg_point_w_verification for asynchronous workflow with delay and retry. + """ + + # set point workflow + set_pt_response = cls.set_reg_point(register=register, value_to_set=value_to_set) + + # verify with get_point + get_pt_response = cls.get_reg_point(register) + + def check_success_flag(): + _success_flag_strict = (get_pt_response == value_to_set) + _success_flag_relax = (str(get_pt_response) == str(value_to_set)) + if relax_verification: + _success_flag = _success_flag_relax + else: + _success_flag = _success_flag_strict + return _success_flag + + # note: only delay and retry the read/get logic NOT the send/set logic + # note: hard-coded delay time and number of retry. Use small delay, large retry number strategy. + # For local instances, 2 sec should be sufficient. + retry_delay = 0.2 + retry_max = 20 + retry_count = 0 + success_flag = check_success_flag() + while not success_flag and retry_count < retry_max: + sleep(retry_delay) + retry_count += 1 + + get_pt_response = cls.get_reg_point(register) + + success_flag = check_success_flag() + + response = {"success_flag": success_flag, + "value_to_set": value_to_set, + "set_pt_response": set_pt_response, + "get_pt_response": get_pt_response} + if not success_flag: + _log.warning(f"Set value failed, {response}") + return response + + def _scrape_all(self) -> Dict[str, any]: + result: Dict[str, RegisterValue] = {} # Dict[register.point_name, register.value] + read_registers = self.get_registers_by_type(reg_type="byte", + read_only=True) # TODO: Parameterize the "byte" hard-code here + write_registers = self.get_registers_by_type(reg_type="byte", read_only=False) + all_registers: List[ImplementedRegister] = read_registers + write_registers + for register in all_registers: + result[register.point_name] = register.value + return result + + def get_register_by_name(self, name: str) -> WrapperRegister: + """ + Get a register by it's point name. + + :param name: Point name of register. + :type name: str + :return: An instance of BaseRegister + :rtype: :py:class:`BaseRegister` + """ + try: + return self.point_map[name] + except KeyError: + raise DriverInterfaceError("Point not configured on device: " + name) + + +class WrapperInterfaceNew: + """ + Use composition instead of inheritance + """ + + def __init__(self, *args, **kwargs): + # self.basic_revert = BasicRevert(**kwargs) + # self.basic_interface = BaseInterface(**kwargs) + self.basic_revert = BasicRevert() + self.basic_interface = BaseInterface() + self._tracker = self.basic_revert._tracker + + self.point_map: Dict[str, ImplementedRegister] = {} # {register.point_name: register} + self.register_types: List[ + ImplementedRegister] = [] # TODO: add sanity check for restister_types, e.g., count == register counts + + self.csv_config = None # TODO: try to get this value, potentially from def configure. get inspiration from modbus_tk testing + self.driver_config_in_json_config = None # TODO: try to get this value, potentially from def configure + + def configure(self, driver_config_in_json_config: dict, csv_config: List[ + dict]): # TODO: ask driver.py, BaseInterface.configure to update signature when evoking + """ + Used by driver.py + def get_interface(self, driver_type, config_dict, config_string): + interface.configure(config_dict, config_string) + + Parameters # TODO: follow BaseInterface.configure signatures. But the names are wrong. + ---------- + driver_config_in_json_config: associated with `driver_config` in driver-config.config (json-like file) + user inputs are put here, e.g., IP address, url, etc. + csv_config: associated with the whole driver-config.csv file + Examples: + [{'Point Name': 'Heartbeat', 'Volttron Point Name': 'Heartbeat', 'Units': 'On/Off', + 'Units Details': 'On/Off', 'Writable': 'TRUE', 'Starting Value': '0', 'Type': 'boolean', + 'Notes': 'Point for heartbeat toggle'}, + {'Point Name': 'Catfact', 'Volttron Point Name': 'Catfact', 'Units': 'No cat fact', + 'Units Details': 'No cat fact', 'Writable': 'TRUE', 'Starting Value': 'No cat fact', 'Type': 'str', + 'Notes': 'Cat fact extract from REST API'}] + + """ + # print("========================================== csv_config, ", csv_config) + # print("========================================== driver_config_in_json_config, ", driver_config_in_json_config) + self.csv_config = csv_config + self.driver_config_in_json_config = driver_config_in_json_config + + # TODO configuration validation, i.e., self.config_check(...) + # self.config_check + self.parse_config(csv_config, driver_config_in_json_config) + + def parse_config(self, csv_config, driver_config_in_json_config, + register_type_list): # TODO: this configDict is from *.csv not .config + # print("========================================== csv_config, ", csv_config) + # print("========================================== driver_config_in_json_config, ", driver_config_in_json_config) + + # driver_config: DriverConfig = DriverConfig(csv_config) + # valid_csv_config = DriverConfig(csv_config).key_validate() + # print("========================================== valid_csv_config, ", valid_csv_config) + + if csv_config is None: # TODO: leave it now. Later for central data check + return + + # register_types: List[ImplementedRegister] = register_type_list + register_types: List[ImplementedRegister] = self.pass_register_types(csv_config, driver_config_in_json_config) + valid_csv_config = csv_config # TODO: Design the config check (No config check for now.) + for reg_def, register_type_iter in zip(valid_csv_config, register_types): + # Skip lines that have no address yet. # TODO: understand why + if not reg_def['Point Name']: + continue + + point_name = reg_def['Volttron Point Name'] + type_name = reg_def.get("Data Type", 'string') + reg_type = type_mapping.get(type_name, str) + units = reg_def['Units'] + read_only = reg_def['Writable'].lower() != 'true' # TODO: watch out for this is opposite logic + + description = reg_def.get('Notes', '') + + # default_value = reg_def.get("defaultvalue", 'sin').strip() + default_value = reg_def.get( + "Default Value") # TODO: redesign default value logic, e.g., beable to map to real python type + if not default_value: + default_value = None + + # register_type = FakeRegister if not point_name.startswith('Cat') else CatfactRegister # TODO: change this + register_type = register_type_iter # TODO: Inconventional, document this. + + # print("========================================== point_name, ", point_name) + # print("========================================== reg_type, ", reg_type) + # print("========================================== units, ", units) + # print("========================================== read_only, ", read_only) + # print("========================================== default_value, ", default_value) + # print("========================================== description, ", description) + # print("========================================== reg_def, ", reg_def) + # Note: the following is to init a register_type object, e.g., WrapperRegister + try: + register: WrapperRegister = self.create_register(driver_config=driver_config_in_json_config, + point_name=point_name, + data_type=reg_type, + # TODO: make it more clear in documentation + units=units, + read_only=read_only, + default_value=default_value, + description=description, + csv_config=csv_config, + reg_def=reg_def, + register_type=register_type) + + if default_value: + self.basic_revert.set_default(point_name, register.value) + + self.insert_register(register) + + except Exception as e: + print(e) + + @staticmethod + @abc.abstractmethod + def pass_register_types(csv_config: dict, driver_config_in_json_config: List[dict], + register_type_list: List[ImplementedRegister] = None) -> List[ImplementedRegister]: + """ + For ingesting the register types list + Will be used by concrete Interface class inherit this template + + Parameters + ---------- + driver_config_in_json_config: associated with `driver_config` in driver-config.config (json-like file) + user inputs are put here, e.g., IP address, url, etc. + csv_config: associated with the whole driver-config.csv file + Examples: + [{'Point Name': 'Heartbeat', 'Volttron Point Name': 'Heartbeat', 'Units': 'On/Off', + 'Units Details': 'On/Off', 'Writable': 'TRUE', 'Starting Value': '0', 'Type': 'boolean', + 'Notes': 'Point for heartbeat toggle'}, + {'Point Name': 'Catfact', 'Volttron Point Name': 'Catfact', 'Units': 'No cat fact', + 'Units Details': 'No cat fact', 'Writable': 'TRUE', 'Starting Value': 'No cat fact', 'Type': 'str', + 'Notes': 'Cat fact extract from REST API'}] + register_type_list: + Example: + [RestAPIRegister, RestAPIRegister, RestAPIRegister, RandomBoolRegister] + """ + pass + return register_type_list + + def create_register(self, driver_config, + point_name, + data_type, + units, + read_only, + default_value, + description, + csv_config, + reg_def, + register_type, *args, **kwargs) -> ImplementedRegister: + pass + """ + Factory method to init (WrapperRegister) register object + + :param register_type: the class name of the to-be-created register, e.g., WrapperRegister + :param driver_config_in_json_config: json config file, + :param csv_config: csv config file, Dict[str, str] + + """ + register: WrapperRegister = register_type(driver_config=driver_config, + point_name=point_name, + data_type=data_type, # TODO: make it more clear in documentation + units=units, + read_only=read_only, + default_value=default_value, + description=description, + csv_config=csv_config, + reg_def=reg_def) + return register + + def insert_register(self, register: WrapperRegister): + """ + Inserts a register into the :py:class:`Interface`. + + :param register: Register to add to the interface. + :type register: :py:class:`BaseRegister` + """ + register_point: str = register.point_name + self.point_map[register_point] = register + + register_type = register.get_register_type() + self.basic_interface.registers[register_type].append(register) + + def get_point(self, point_name, **kwargs) -> RegisterValue: + register: WrapperRegister = self.get_register_by_name(point_name) + # val: RegisterValue = register.get_register_value() + + # return "testing_value" + return register.value + + def get_register_by_name(self, name: str) -> Register: + return self.basic_interface.get_register_by_name(name) + + def set_point(self, point_name, value): + """ + Implementation of :py:meth:`BaseInterface.set_point` + + Passes arguments through to :py:meth:`BasicRevert._set_point` + """ + # return self.basic_revert.set_point(point_name, value) + result = self._set_point(point_name, value) + self._tracker.mark_dirty_point(point_name) + return result + + def _set_point(self, point_name, value, **kwargs): + """ + Parameters + ---------- + point_name + value + + Returns + ------- + + """ + value_to_set = value + register: ImplementedRegister = self.get_register_by_name(point_name) + # Note: leave register method to verify, e.g., check writability. + # register.value(value_to_set) + # value_response: RegisterValue = register.value + + set_pt_response = register.set_register_value(value=value_to_set) + # verify with get_point + get_pt_response = self.get_point(point_name=point_name) + + success_flag_strict = (get_pt_response == value_to_set) + success_flag_relax = (str(get_pt_response) == str(value_to_set)) + success_flag = success_flag_relax + + response = {"success_flag": success_flag, + "value_to_set": value_to_set, + "set_pt_response": set_pt_response, + "get_pt_response": get_pt_response} + if not success_flag: + _log.warning(f"Set value failed, {response}") + return response + + def scrape_all(self): + """ + Implementation of :py:meth:`BaseInterface.scrape_all` + """ + return self.basic_revert.scrape_all() + + +class DriverInterfaceError(Exception): + pass diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/examples/dnp3.config b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/examples/dnp3.config new file mode 100644 index 0000000000..fea35bc607 --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/examples/dnp3.config @@ -0,0 +1,11 @@ +{ + "driver_config": {"master_ip": "0.0.0.0", "outstation_ip": "127.0.0.1", + "master_id": 2, "outstation_id": 1, + "port": 20000}, + "registry_config":"config://dnp3.csv", + "driver_type": "dnp3", + "interval": 5, + "timezone": "UTC", + "publish_depth_first_all": true, + "heart_beat_point": "random_bool" +} diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/examples/dnp3.csv b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/examples/dnp3.csv new file mode 100644 index 0000000000..e71b832b3d --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/examples/dnp3.csv @@ -0,0 +1,17 @@ +Point Name,Volttron Point Name,Group,Variation,Index,Scaling,Units,Writable,Notes +AnalogInput_index0,AnalogInput_index0,30,6,0,1,NA,FALSE,Double Analogue input without status +AnalogInput_index1,AnalogInput_index1,30,6,1,1,NA,FALSE,Double Analogue input without status +AnalogInput_index2,AnalogInput_index2,30,6,2,1,NA,FALSE,Double Analogue input without status +AnalogInput_index3,AnalogInput_index3,30,6,3,1,NA,FALSE,Double Analogue input without status +BinaryInput_index0,BinaryInput_index0,1,2,0,1,NA,FALSE,Single bit binary input with status +BinaryInput_index1,BinaryInput_index1,1,2,1,1,NA,FALSE,Single bit binary input with status +BinaryInput_index2,BinaryInput_index2,1,2,2,1,NA,FALSE,Single bit binary input with status +BinaryInput_index3,BinaryInput_index3,1,2,3,1,NA,FALSE,Single bit binary input with status +AnalogOutput_index0,AnalogOutput_index0,40,4,0,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index1,AnalogOutput_index1,40,4,1,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index2,AnalogOutput_index2,40,4,2,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index3,AnalogOutput_index3,40,4,3,1,NA,TRUE,Double-precision floating point with flags +BinaryOutput_index0,BinaryOutput_index0,10,2,0,1,NA,TRUE,Binary Output with flags +BinaryOutput_index1,BinaryOutput_index1,10,2,1,1,NA,TRUE,Binary Output with flags +BinaryOutput_index2,BinaryOutput_index2,10,2,2,1,NA,TRUE,Binary Output with flags +BinaryOutput_index3,BinaryOutput_index3,10,2,3,1,NA,TRUE,Binary Output with flags diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py new file mode 100644 index 0000000000..73eaf8ad9e --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver.py @@ -0,0 +1,504 @@ +import pytest +import gevent +import logging +import time +import csv +import json +from pathlib import Path +import random + +from services.core.PlatformDriverAgent.platform_driver.interfaces. \ + dnp3 import UserDevelopRegisterDnp3 +from pydnp3 import opendnp3 +from services.core.PlatformDriverAgent.platform_driver.interfaces. \ + dnp3.dnp3 import Interface as DNP3Interface + +from dnp3_python.dnp3station.master_new import MyMasterNew +from dnp3_python.dnp3station.outstation_new import MyOutStationNew + +import os + +TEST_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class TestDummy: + """ + Dummy test to check pytest setup + """ + + def test_dummy(self): + print("I am a silly dummy test.") + + +@pytest.fixture( + scope="module" +) +def outstation_app(request): + """ + outstation using default configuration (including default database) + Note: since outstation cannot shut down gracefully, + outstation_app fixture need to in "module" scope to prevent interrupting pytest during outstation shut-down + """ + # Note: allow parsing argument to fixture change port number using `request.param` + try: + port = request.param + except AttributeError: + port = 20000 + outstation_appl = MyOutStationNew(port=port) # Note: using default port 20000 + outstation_appl.start() + # time.sleep(3) + yield outstation_appl + # clean-up + outstation_appl.shutdown() + + +@pytest.fixture( + # scope="module" +) +def master_app(request): + """ + master station using default configuration + Note: outstation needs to exist first to make connection. + """ + + # Note: allow parsing argument to fixture change port number using `request.param` + try: + port = request.param + except AttributeError: + port = 20000 + # Note: using default port 20000, + # Note: using small "stale_if_longer_than" to force update + master_appl = MyMasterNew(port=port, stale_if_longer_than=0.1) + master_appl.start() + # Note: add delay to prevent conflict + # (there is a delay when master shutdown. And all master shares the same config) + time.sleep(1) + yield master_appl + # clean-up + master_appl.shutdown() + time.sleep(1) + + +class TestStation: + """ + Testing the underlying pydnp3 package station-related fuctions. + """ + + def test_station_init(self, master_app, outstation_app): + # master_app = MyMasterNew() + # master_app.start() + driver_wrapper_init_arg = {'driver_config': {}, 'point_name': "", 'data_type': "", 'units': "", 'read_only': ""} + UserDevelopRegisterDnp3(master_application=master_app, reg_def={}, + **driver_wrapper_init_arg) + + def test_station_get_val_analog_input_float(self, master_app, outstation_app): + + # outstation update with values + analog_input_val = [1.2454, 33453.23, 45.21] + for i, val_update in enumerate(analog_input_val): + outstation_app.apply_update(opendnp3.Analog(value=val_update, + flags=opendnp3.Flags(24), + time=opendnp3.DNPTime(3094)), + index=i) + # Note: group=30, variation=6 is AnalogInputFloat + for i, val_update in enumerate(analog_input_val): + val_get = master_app.get_val_by_group_variation_index(group=30, variation=6, index=i) + # print(f"===val_update {val_update}, val_get {val_get}") + assert val_get == val_update + + time.sleep(1) # add delay buffer to pass the "stale_if_longer_than" checking statge + + # outstation update with random values + analog_input_val_random = [random.random() for i in range(3)] + for i, val_update in enumerate(analog_input_val_random): + outstation_app.apply_update(opendnp3.Analog(value=val_update), + index=i) + # Note: group=30, variation=6 is AnalogInputFloat + for i, val_update in enumerate(analog_input_val_random): + val_get = master_app.get_val_by_group_variation_index(group=30, variation=6, index=i) + # print(f"===val_update {val_update}, val_get {val_get}") + assert val_get == val_update + + def test_station_set_val_analog_input_float(self, master_app, outstation_app): + + # outstation update with values + analog_output_val = [1.2454, 33453.23, 45.21] + for i, val_to_set in enumerate(analog_output_val): + master_app.send_direct_point_command(group=40, variation=4, index=i, + val_to_set=val_to_set) + # Note: group=40, variation=4 is AnalogOutFloat + for i, val_to_set in enumerate(analog_output_val): + val_get = master_app.get_val_by_group_variation_index(group=40, variation=4, index=i) + # print(f"===val_update {val_update}, val_get {val_get}") + assert val_get == val_to_set + + time.sleep(1) # add delay buffer to pass the "stale_if_longer_than" checking statge + + # outstation update with random values + analog_output_val_random = [random.random() for i in range(3)] + for i, val_to_set in enumerate(analog_output_val_random): + master_app.send_direct_point_command(group=40, variation=4, index=i, + val_to_set=val_to_set) + # Note: group=40, variation=4 is AnalogOutFloat + for i, val_to_set in enumerate(analog_output_val_random): + val_get = master_app.get_val_by_group_variation_index(group=40, variation=4, index=i) + # print(f"===val_update {val_update}, val_get {val_get}") + assert val_get == val_to_set + + +@pytest.fixture +def dnp3_inherit_init_args(csv_config, driver_config_in_json_config): + """ + args required for parent class init (i.e., class WrapperRegister) + """ + args = {'driver_config': driver_config_in_json_config, + 'point_name': "", + 'data_type': "", + 'units': "", + 'read_only': ""} + return args + + +@pytest.fixture +def driver_config_in_json_config(): + """ + associated with `driver_config` in driver-config.config (json-like file) + user inputs are put here, e.g., IP address, url, etc. + """ + json_path = Path("./testing_data/dnp3.config") + json_path = Path(TEST_DIR, json_path) + with open(json_path) as json_f: + driver_config = json.load(json_f) + k = "driver_config" + return {k: driver_config.get(k)} + + +@pytest.fixture +def csv_config(): + """ + associated with the whole driver-config.csv file + """ + csv_path = Path("./testing_data/dnp3.csv") + csv_path = Path(TEST_DIR, csv_path) + with open(csv_path) as f: + reader = csv.DictReader(f, delimiter=',') + csv_config = [row for row in reader] + + return csv_config + + +@pytest.fixture +def reg_def_dummy(): + """ + register definition, row of csv config file + """ + # reg_def = {'Point Name': 'AnalogInput_index0', 'Volttron Point Name': 'AnalogInput_index0', + # 'Group': '30', 'Variation': '6', 'Index': '0', 'Scaling': '1', 'Units': 'NA', + # 'Writable': 'FALSE', 'Notes': 'Double Analogue input without status'} + reg_def = {'Point Name': 'pn', 'Volttron Point Name': 'pn', + 'Group': 'int', 'Variation': 'int', 'Index': 'int', 'Scaling': '1', 'Units': 'NA', + 'Writable': 'NA', 'Notes': ''} + return reg_def + + +class TestDNPRegister: + """ + Tests for UserDevelopRegisterDnp3 class + + init + + get_register_value + analog input float + analog input int + binary input + """ + + def test_init(self, master_app, csv_config, dnp3_inherit_init_args): + for reg_def in csv_config: + UserDevelopRegisterDnp3(master_application=master_app, + reg_def=reg_def, + **dnp3_inherit_init_args + ) + + def test_get_register_value_analog_float(self, outstation_app, master_app, csv_config, + dnp3_inherit_init_args, reg_def_dummy): + + # dummy test variable + analog_input_val = [445.33, 1123.56, 98.456] + [random.random() for i in range(3)] + + # dummy reg_def (csv config row) + # Note: group = 30, variation = 6 is AnalogInputFloat + reg_def = reg_def_dummy + reg_defs = [] + for i in range(len(analog_input_val)): + reg_def["Group"] = "30" + reg_def["Variation"] = "6" + reg_def["Index"] = str(i) + reg_defs.append(reg_def.copy()) # Note: Python gotcha, mutable don't evaluate til the end of the loop. + + # outstation update values + for i, val_update in enumerate(analog_input_val): + outstation_app.apply_update(opendnp3.Analog(value=val_update), index=i) + + # verify: driver read value + for i, (val_update, csv_row) in enumerate(zip(analog_input_val, reg_defs)): + # print(f"====== reg_defs {reg_defs}, analog_input_val {analog_input_val}") + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + val_get = dnp3_register.get_register_value() + # print("===========val_get, val_update", val_get, val_update) + assert val_get == val_update + + def test_get_register_value_analog_int(self, outstation_app, master_app, csv_config, + dnp3_inherit_init_args, reg_def_dummy): + + # dummy test variable + analog_input_val = [345, 1123, 98] + [random.randint(1, 100) for i in range(3)] + + # dummy reg_def (csv config row) + # Note: group = 30, variation = 1 is AnalogInputInt32 + reg_def = reg_def_dummy + reg_defs = [] + for i in range(len(analog_input_val)): + reg_def["Group"] = "30" + reg_def["Variation"] = "1" + reg_def["Index"] = str(i) + reg_defs.append(reg_def.copy()) # Note: Python gotcha, mutable don't evaluate til the end of the loop. + + # outstation update values + for i, val_update in enumerate(analog_input_val): + outstation_app.apply_update(opendnp3.Analog(value=val_update), index=i) + + # verify: driver read value + for i, (val_update, csv_row) in enumerate(zip(analog_input_val, reg_defs)): + # print(f"====== reg_defs {reg_defs}, analog_input_val {analog_input_val}") + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + val_get = dnp3_register.get_register_value() + # print("===========val_get, val_update", val_get, val_update) + assert val_get == val_update + + def test_get_register_value_binary(self, outstation_app, master_app, csv_config, + dnp3_inherit_init_args, reg_def_dummy): + + # dummy test variable + binary_input_val = [True, False, True] + [random.choice([True, False]) for i in range(3)] + + # dummy reg_def (csv config row) + # Note: group = 1, variation = 2 is BinaryInput + reg_def = reg_def_dummy + reg_defs = [] + for i in range(len(binary_input_val)): + reg_def["Group"] = "1" + reg_def["Variation"] = "2" + reg_def["Index"] = str(i) + reg_defs.append(reg_def.copy()) # Note: Python gotcha, mutable don't evaluate til the end of the loop. + + # outstation update values + for i, val_update in enumerate(binary_input_val): + outstation_app.apply_update(opendnp3.Binary(value=val_update), index=i) + + # verify: driver read value + for i, (val_update, csv_row) in enumerate(zip(binary_input_val, reg_defs)): + # print(f"====== reg_defs {reg_defs}, analog_input_val {analog_input_val}") + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + val_get = dnp3_register.get_register_value() + # print(f"=========== i {i}, val_get {val_get}, val_update {val_update}") + assert val_get == val_update + + +class TestDNP3RegisterControlWorkflow: + + def test_set_register_value_analog_float(self, outstation_app, master_app, csv_config, + dnp3_inherit_init_args, reg_def_dummy): + + # dummy test variable + # Note: group=40, variation=4 is AnalogOutputDoubleFloat + output_val = [343.23, 23.1109, 58.2] + [random.random() for i in range(3)] + + # dummy reg_def (csv config row) + # Note: group = 1, variation = 2 is BinaryInput + reg_def = reg_def_dummy + reg_defs = [] + for i in range(len(output_val)): + reg_def["Group"] = "40" + reg_def["Variation"] = "4" + reg_def["Index"] = str(i) + reg_defs.append(reg_def.copy()) # Note: Python gotcha, mutable don't evaluate til the end of the loop. + + # master set values + for i, (val_set, csv_row) in enumerate(zip(output_val, reg_defs)): + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + dnp3_register.set_register_value(value=val_set) + + # verify: driver read value + for i, (val_set, csv_row) in enumerate(zip(output_val, reg_defs)): + # print(f"====== reg_defs {reg_defs}, analog_input_val {analog_input_val}") + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + val_get = dnp3_register.get_register_value() + # print("===========val_get, val_update", val_get, val_update) + assert val_get == val_set + + def test_set_register_value_analog_int(self, outstation_app, master_app, csv_config, + dnp3_inherit_init_args, reg_def_dummy): + + # dummy test variable + # Note: group=40, variation=4 is AnalogOutputDoubleFloat + output_val = [45343, 344, 221] + [random.randint(1, 1000) for i in range(3)] + + # dummy reg_def (csv config row) + # Note: group = 1, variation = 2 is BinaryInput + reg_def = reg_def_dummy + reg_defs = [] + for i in range(len(output_val)): + reg_def["Group"] = "40" + reg_def["Variation"] = "1" + reg_def["Index"] = str(i) + reg_defs.append(reg_def.copy()) # Note: Python gotcha, mutable don't evaluate til the end of the loop. + + # master set values + for i, (val_set, csv_row) in enumerate(zip(output_val, reg_defs)): + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + dnp3_register.set_register_value(value=val_set) + + # verify: driver read value + for i, (val_set, csv_row) in enumerate(zip(output_val, reg_defs)): + # print(f"====== reg_defs {reg_defs}, analog_input_val {analog_input_val}") + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + val_get = dnp3_register.get_register_value() + # print("===========val_get, val_update", val_get, val_update) + assert val_get == val_set + + def test_set_register_value_binary(self, outstation_app, master_app, csv_config, + dnp3_inherit_init_args, reg_def_dummy): + + # dummy test variable + # Note: group=40, variation=4 is AnalogOutputDoubleFloat + output_val = [True, False, True] + [random.choice([True, False]) for i in range(3)] + + # dummy reg_def (csv config row) + # Note: group = 1, variation = 2 is BinaryInput + reg_def = reg_def_dummy + reg_defs = [] + for i in range(len(output_val)): + reg_def["Group"] = "10" + reg_def["Variation"] = "2" + reg_def["Index"] = str(i) + reg_defs.append(reg_def.copy()) # Note: Python gotcha, mutable don't evaluate til the end of the loop. + + # master set values + for i, (val_set, csv_row) in enumerate(zip(output_val, reg_defs)): + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + dnp3_register.set_register_value(value=val_set) + + # verify: driver read value + for i, (val_set, csv_row) in enumerate(zip(output_val, reg_defs)): + # print(f"====== reg_defs {reg_defs}, analog_input_val {analog_input_val}") + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + val_get = dnp3_register.get_register_value() + # print("===========val_get, val_update", val_get, val_update) + assert val_get == val_set + + +class TestDNP3InterfaceNaive: + + def test_init(self): + pass + dnp3_interface = DNP3Interface() + + def test_get_reg_point(self, outstation_app, master_app, csv_config, + dnp3_inherit_init_args, reg_def_dummy): + # dummy test variable + analog_input_val = [445.33, 1123.56, 98.456] + [random.random() for i in range(3)] + + # dummy reg_def (csv config row) + # Note: group = 30, variation = 6 is AnalogInputFloat + reg_def = reg_def_dummy + reg_defs = [] + for i in range(len(analog_input_val)): + reg_def["Group"] = "30" + reg_def["Variation"] = "6" + reg_def["Index"] = str(i) + reg_defs.append(reg_def.copy()) # Note: Python gotcha, mutable don't evaluate til the end of the loop. + + # outstation update values + for i, val_update in enumerate(analog_input_val): + outstation_app.apply_update(opendnp3.Analog(value=val_update), index=i) + + # verify: driver read value + dnp3_interface = DNP3Interface() + for i, (val_update, csv_row) in enumerate(zip(analog_input_val, reg_defs)): + # print(f"====== reg_defs {reg_defs}, analog_input_val {analog_input_val}") + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + + val_get = dnp3_interface.get_reg_point(register=dnp3_register) + # print("======== dnp3_register.value", dnp3_register.value) + # print("===========val_get, val_update", val_get, val_update) + assert val_get == val_update + + def test_set_reg_point(self, outstation_app, master_app, csv_config, + dnp3_inherit_init_args, reg_def_dummy): + # dummy test variable + analog_output_val = [445.33, 1123.56, 98.456] + [random.random() for i in range(3)] + + # dummy reg_def (csv config row) + # Note: group = 30, variation = 6 is AnalogInputFloat + reg_def = reg_def_dummy + reg_defs = [] + for i in range(len(analog_output_val)): + reg_def["Group"] = "40" + reg_def["Variation"] = "4" + reg_def["Index"] = str(i) + reg_defs.append(reg_def.copy()) # Note: Python gotcha, mutable don't evaluate til the end of the loop. + + dnp3_interface = DNP3Interface() + + # dnp3_interface update values + for i, (val_update, csv_row) in enumerate(zip(analog_output_val, reg_defs)): + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + dnp3_interface.set_reg_point(register=dnp3_register, value_to_set=val_update) + + # verify: driver read value + + for i, (val_update, csv_row) in enumerate(zip(analog_output_val, reg_defs)): + # print(f"====== reg_defs {reg_defs}, analog_input_val {analog_input_val}") + dnp3_register = UserDevelopRegisterDnp3(master_application=master_app, + reg_def=csv_row, + **dnp3_inherit_init_args + ) + + val_get = dnp3_interface.get_reg_point(register=dnp3_register) + # print("======== dnp3_register.value", dnp3_register.value) + # print("===========val_get, val_update", val_get, val_update) + assert val_get == val_update diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py new file mode 100644 index 0000000000..9a33d384c4 --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/test_dnp3_driver_integration_volttron.py @@ -0,0 +1,208 @@ +import pytest +import gevent +import logging +import time +import random + +from volttron.platform import get_services_core, jsonapi + +from volttron.platform.agent.known_identities import PLATFORM_DRIVER + +from pydnp3 import opendnp3 + +from dnp3_python.dnp3station.outstation_new import MyOutStationNew +from pathlib import Path + +import os + +TEST_DIR = os.path.dirname(os.path.abspath(__file__)) + + +# TODO: add IP, port pool to avoid conflict +# TODO: make sleep more robust and flexible. (Currently relies on manually setup sleep time.) + + +class TestDummy: + """ + Dummy test to check pytest setup + """ + + def test_dummy(self): + print("I am a silly dummy test.") + + +@pytest.fixture( + scope="class" +) +def outstation_app_p20000(): + """ + outstation using default configuration (including default database) + Note: since outstation cannot shut down gracefully, + outstation_app fixture need to in "module" scope to prevent interrupting pytest during outstation shut-down + """ + port = 20000 + outstation_appl = MyOutStationNew(port=port) # Note: using default port 20000 + outstation_appl.start() + gevent.sleep(10) + yield outstation_appl + + outstation_appl.shutdown() + + +@pytest.mark.skip(reason="only for debugging purpose") +class TestDummyAgentFixture: + """ + Dummy test to check VOLTTRON agent (carry on test VOLTTRON instance) setup + """ + + def test_agent_dummy(self, dnp3_tester_agent): + print("I am a fixture agent dummy test.") + + +class TestDnp3DriverRPC: + + def test_interface_get_point( + self, + dnp3_tester_agent, + outstation_app_p20000, + ): + val_update = 7.124 + random.random() + outstation_app_p20000.apply_update(opendnp3.Analog(value=val_update, + flags=opendnp3.Flags(24), + time=opendnp3.DNPTime(3094)), + index=0) + + time.sleep(2) + + res_val = dnp3_tester_agent.vip.rpc.call("platform.driver", "get_point", + "campus-vm/building-vm/Dnp3-port20000", + "AnalogInput_index0").get(timeout=5) + + print(f"======res_val {res_val}") + assert res_val == val_update + + def test_interface_set_point( + self, + dnp3_tester_agent, + outstation_app_p20000, + ): + val_set = 8.342 + random.random() + + res_val = dnp3_tester_agent.vip.rpc.call("platform.driver", "set_point", + "campus-vm/building-vm/Dnp3-port20000", + "AnalogOutput_index0", val_set).get(timeout=5) + + # print(f"======res_val {res_val}") + # Expected output + # {'success_flag': True, 'value_to_set': 8.342, 'set_pt_response': None, 'get_pt_response': 8.342} + try: + assert res_val.get("success_flag") + except AssertionError: + print(f"======res_val {res_val}") + + @pytest.mark.skip(reason="TODO") + def test_scrape_all(self, ): + """ + Issue a get_point RPC call for the device and return the result. + + @param agent: The test Agent. + @param device_name: The driver name, by default: 'devices/device_name'. + @return: The dictionary mapping point names to their actual values from + the RPC call. + """ + # return agent.vip.rpc.call(PLATFORM_DRIVER, 'scrape_all', device_name) \ + # .get(timeout=10) + + @pytest.mark.skip(reason="TODO") + def test_revert_all(self, ): + """ + Issue a get_point RPC call for the device and return the result. + + @param agent: The test Agent. + @param device_name: The driver name, by default: 'devices/device_name'. + @return: Return value from the RPC call. + """ + # return agent.vip.rpc.call(PLATFORM_DRIVER, 'revert_device', + # device_name).get(timeout=10) + + @pytest.mark.skip(reason="TODO") + def test_revert_point(self, ): + """ + Issue a get_point RPC call for the named point and return the result. + + @param agent: The test Agent. + @param device_name: The driver name, by default: 'devices/device_name'. + @param point_name: The name of the point to query. + @return: Return value from the RPC call. + """ + # return agent.vip.rpc.call(PLATFORM_DRIVER, 'revert_point', + # device_name, point_name).get(timeout=10) + + +@pytest.fixture(scope="module") +# @pytest.fixture +def dnp3_tester_agent(request, volttron_instance): + """ + Build PlatformDriverAgent, add modbus driver & csv configurations + """ + + # Build platform driver agent + tester_agent = volttron_instance.build_agent(identity="test_dnp3_agent") + gevent.sleep(1) + capabilities = {'edit_config_store': {'identity': PLATFORM_DRIVER}} + # Note: commented out the add_capabilities due to complained by volttron_instance fixture, i.e., + # pytest.param(dict(messagebus='rmq', ssl_auth=True), + # marks=rmq_skipif), # complain add_capabilities + # dict(messagebus='zmq', auth_enabled=False), # complain add_capabilities + if volttron_instance.auth_enabled: + volttron_instance.add_capabilities(tester_agent.core.publickey, capabilities) + + # Clean out platform driver configurations + # wait for it to return before adding new config + tester_agent.vip.rpc.call(peer='config.store', + method='manage_delete_store', + identity=PLATFORM_DRIVER).get(timeout=5) + + json_config_path = Path("../examples/dnp3.config") + json_config_path = Path(TEST_DIR, json_config_path) + with open(json_config_path, "r") as f: + json_str_p20000 = f.read() + + csv_config_path = Path("../examples/dnp3.csv") + csv_config_path = Path(TEST_DIR, csv_config_path) + with open(csv_config_path, "r") as f: + csv_str = f.read() + + tester_agent.vip.rpc.call(peer='config.store', + method='manage_store', + identity=PLATFORM_DRIVER, + config_name="dnp3.csv", + raw_contents=csv_str, + config_type='csv' + ).get(timeout=5) + + tester_agent.vip.rpc.call('config.store', + method='manage_store', + identity=PLATFORM_DRIVER, + config_name="devices/campus-vm/building-vm/Dnp3-port20000", + raw_contents=json_str_p20000, + config_type='json' + ).get(timeout=5) + + platform_uuid = volttron_instance.install_agent( + agent_dir=get_services_core("PlatformDriverAgent"), + config_file={}, + start=True) + + gevent.sleep(10) # Note: important, wait for the agent to start and start the devices, otherwise rpc call may fail. + # time.sleep(10) # wait for the agent to start and start the devices + + def stop(): + """ + Stop platform driver agent + """ + volttron_instance.stop_agent(platform_uuid) + tester_agent.core.stop() + + yield tester_agent + request.addfinalizer(stop) diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/testing_data/dnp3.config b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/testing_data/dnp3.config new file mode 100644 index 0000000000..fea35bc607 --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/testing_data/dnp3.config @@ -0,0 +1,11 @@ +{ + "driver_config": {"master_ip": "0.0.0.0", "outstation_ip": "127.0.0.1", + "master_id": 2, "outstation_id": 1, + "port": 20000}, + "registry_config":"config://dnp3.csv", + "driver_type": "dnp3", + "interval": 5, + "timezone": "UTC", + "publish_depth_first_all": true, + "heart_beat_point": "random_bool" +} diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/testing_data/dnp3.csv b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/testing_data/dnp3.csv new file mode 100644 index 0000000000..e71b832b3d --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/dnp3/tests/testing_data/dnp3.csv @@ -0,0 +1,17 @@ +Point Name,Volttron Point Name,Group,Variation,Index,Scaling,Units,Writable,Notes +AnalogInput_index0,AnalogInput_index0,30,6,0,1,NA,FALSE,Double Analogue input without status +AnalogInput_index1,AnalogInput_index1,30,6,1,1,NA,FALSE,Double Analogue input without status +AnalogInput_index2,AnalogInput_index2,30,6,2,1,NA,FALSE,Double Analogue input without status +AnalogInput_index3,AnalogInput_index3,30,6,3,1,NA,FALSE,Double Analogue input without status +BinaryInput_index0,BinaryInput_index0,1,2,0,1,NA,FALSE,Single bit binary input with status +BinaryInput_index1,BinaryInput_index1,1,2,1,1,NA,FALSE,Single bit binary input with status +BinaryInput_index2,BinaryInput_index2,1,2,2,1,NA,FALSE,Single bit binary input with status +BinaryInput_index3,BinaryInput_index3,1,2,3,1,NA,FALSE,Single bit binary input with status +AnalogOutput_index0,AnalogOutput_index0,40,4,0,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index1,AnalogOutput_index1,40,4,1,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index2,AnalogOutput_index2,40,4,2,1,NA,TRUE,Double-precision floating point with flags +AnalogOutput_index3,AnalogOutput_index3,40,4,3,1,NA,TRUE,Double-precision floating point with flags +BinaryOutput_index0,BinaryOutput_index0,10,2,0,1,NA,TRUE,Binary Output with flags +BinaryOutput_index1,BinaryOutput_index1,10,2,1,1,NA,TRUE,Binary Output with flags +BinaryOutput_index2,BinaryOutput_index2,10,2,2,1,NA,TRUE,Binary Output with flags +BinaryOutput_index3,BinaryOutput_index3,10,2,3,1,NA,TRUE,Binary Output with flags diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/ecobee.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/ecobee.py index 6b2ceb6901..9e4c0f5d4c 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/ecobee.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/ecobee.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2017, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime @@ -287,10 +273,10 @@ def get_auth_config_from_store(self): :return: Fetch currently stored auth configuration info from config store, returns empty dict if none is present """ - configs = self.vip.rpc.call(CONFIGURATION_STORE, "manage_list_configs", PLATFORM_DRIVER).get(timeout=3) + configs = self.vip.rpc.call(CONFIGURATION_STORE, "list_configs", PLATFORM_DRIVER).get(timeout=3) if self.auth_config_path in configs: return jsonapi.loads(self.vip.rpc.call( - CONFIGURATION_STORE, "manage_get", PLATFORM_DRIVER, self.auth_config_path).get(timeout=3)) + CONFIGURATION_STORE, "get_config", PLATFORM_DRIVER, self.auth_config_path).get(timeout=3)) else: _log.warning("No Ecobee auth file found in config store") return {} @@ -845,4 +831,3 @@ def make_ecobee_request(request_type, url, **kwargs): if isinstance(content, bytes): content = jsonapi.loads(response.decode("UTF-8")) return content - diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/fakedriver.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/fakedriver.py index f4fd1ca0cc..004773a5f9 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/fakedriver.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/fakedriver.py @@ -1,67 +1,51 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} - import random import datetime import math from math import pi from platform_driver.interfaces import BaseInterface, BaseRegister, BasicRevert -from csv import DictReader -from io import StringIO import logging _log = logging.getLogger(__name__) -type_mapping = {"string": str, - "int": int, - "integer": int, - "float": float, - "bool": bool, - "boolean": bool} +type_mapping = { + "string": str, + "int": int, + "integer": int, + "float": float, + "bool": bool, + "boolean": bool +} class FakeRegister(BaseRegister): - def __init__(self, read_only, pointName, units, reg_type, - default_value=None, description=''): + + def __init__(self, read_only, pointName, units, reg_type, default_value=None, description=''): # register_type, read_only, pointName, units, description = ''): - super(FakeRegister, self).__init__("byte", read_only, pointName, units, - description='') + super(FakeRegister, self).__init__("byte", read_only, pointName, units, description='') self.reg_type = reg_type if default_value is None: @@ -74,14 +58,13 @@ def __init__(self, read_only, pointName, units, reg_type, class EKGregister(BaseRegister): - def __init__(self, read_only, pointName, units, reg_type, - default_value=None, description=''): - super(EKGregister, self).__init__("byte", read_only, pointName, units, - description='') - self._value = 1; - - math_functions = ('acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', - 'atanh', 'sin', 'sinh', 'sqrt', 'tan', 'tanh') + + def __init__(self, read_only, pointName, units, reg_type, default_value=None, description=''): + super(EKGregister, self).__init__("byte", read_only, pointName, units, description='') + self._value = 1 + + math_functions = ('acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'sin', + 'sinh', 'sqrt', 'tan', 'tanh') if default_value in math_functions: self.math_func = getattr(math, default_value) else: @@ -104,6 +87,7 @@ def value(self, x): class Interface(BasicRevert, BaseInterface): + def __init__(self, **kwargs): super(Interface, self).__init__(**kwargs) @@ -118,8 +102,7 @@ def get_point(self, point_name): def _set_point(self, point_name, value): register = self.get_register_by_name(point_name) if register.read_only: - raise RuntimeError( - "Trying to write to a point configured read only: " + point_name) + raise RuntimeError("Trying to write to a point configured read only: " + point_name) register.value = register.reg_type(value) return register.value @@ -130,21 +113,20 @@ def _scrape_all(self): write_registers = self.get_registers_by_type("byte", False) for register in read_registers + write_registers: result[register.point_name] = register.value - return result def parse_config(self, configDict): if configDict is None: return - for regDef in configDict: # Skip lines that have no address yet. if not regDef['Point Name']: continue read_only = regDef['Writable'].lower() != 'true' - point_name = regDef['Volttron Point Name'] + volttron_point_name = regDef['Volttron Point Name'] + point_name = regDef['Point Name'] description = regDef.get('Notes', '') units = regDef['Units'] default_value = regDef.get("Starting Value", 'sin').strip() @@ -155,15 +137,14 @@ def parse_config(self, configDict): register_type = FakeRegister if not point_name.startswith('EKG') else EKGregister - register = register_type( - read_only, - point_name, - units, - reg_type, - default_value=default_value, - description=description) + register = register_type(read_only=read_only, + pointName=volttron_point_name, + reg_type=reg_type, + default_value=default_value, + description=description, + units=units) if default_value is not None: - self.set_default(point_name, register.value) + self.set_default(volttron_point_name, register.value) self.insert_register(register) diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/home_assistant.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/home_assistant.py new file mode 100644 index 0000000000..780b01dab9 --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/home_assistant.py @@ -0,0 +1,407 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} + + +import random +from math import pi +import json +import sys +from platform_driver.interfaces import BaseInterface, BaseRegister, BasicRevert +from volttron.platform.agent import utils +from volttron.platform.vip.agent import Agent +import logging +import requests +from requests import get + +_log = logging.getLogger(__name__) +type_mapping = {"string": str, + "int": int, + "integer": int, + "float": float, + "bool": bool, + "boolean": bool} + + +class HomeAssistantRegister(BaseRegister): + def __init__(self, read_only, pointName, units, reg_type, attributes, entity_id, entity_point, default_value=None, + description=''): + super(HomeAssistantRegister, self).__init__("byte", read_only, pointName, units, description='') + self.reg_type = reg_type + self.attributes = attributes + self.entity_id = entity_id + self.value = None + self.entity_point = entity_point + + +def _post_method(url, headers, data, operation_description): + err = None + try: + response = requests.post(url, headers=headers, json=data) + if response.status_code == 200: + _log.info(f"Success: {operation_description}") + else: + err = f"Failed to {operation_description}. Status code: {response.status_code}. " \ + f"Response: {response.text}" + + except requests.RequestException as e: + err = f"Error when attempting - {operation_description} : {e}" + if err: + _log.error(err) + raise Exception(err) + + +class Interface(BasicRevert, BaseInterface): + def __init__(self, **kwargs): + super(Interface, self).__init__(**kwargs) + self.point_name = None + self.ip_address = None + self.access_token = None + self.port = None + self.units = None + + def configure(self, config_dict, registry_config_str): + self.ip_address = config_dict.get("ip_address", None) + self.access_token = config_dict.get("access_token", None) + self.port = config_dict.get("port", None) + + # Check for None values + if self.ip_address is None: + _log.error("IP address is not set.") + raise ValueError("IP address is required.") + if self.access_token is None: + _log.error("Access token is not set.") + raise ValueError("Access token is required.") + if self.port is None: + _log.error("Port is not set.") + raise ValueError("Port is required.") + + self.parse_config(registry_config_str) + + def get_point(self, point_name): + register = self.get_register_by_name(point_name) + + entity_data = self.get_entity_data(register.entity_id) + if register.point_name == "state": + result = entity_data.get("state", None) + return result + else: + value = entity_data.get("attributes", {}).get(f"{register.point_name}", 0) + return value + + def _set_point(self, point_name, value): + register = self.get_register_by_name(point_name) + if register.read_only: + raise IOError( + "Trying to write to a point configured read only: " + point_name) + register.value = register.reg_type(value) # setting the value + entity_point = register.entity_point + # Changing lights values in home assistant based off of register value. + if "light." in register.entity_id: + if entity_point == "state": + if isinstance(register.value, int) and register.value in [0, 1]: + if register.value == 1: + self.turn_on_lights(register.entity_id) + elif register.value == 0: + self.turn_off_lights(register.entity_id) + else: + error_msg = f"State value for {register.entity_id} should be an integer value of 1 or 0" + _log.info(error_msg) + raise ValueError(error_msg) + + elif entity_point == "brightness": + if isinstance(register.value, int) and 0 <= register.value <= 255: # Make sure its int and within range + self.change_brightness(register.entity_id, register.value) + else: + error_msg = "Brightness value should be an integer between 0 and 255" + _log.error(error_msg) + raise ValueError(error_msg) + else: + error_msg = f"Unexpected point_name {point_name} for register {register.entity_id}" + _log.error(error_msg) + raise ValueError(error_msg) + + elif "input_boolean." in register.entity_id: + if entity_point == "state": + if isinstance(register.value, int) and register.value in [0, 1]: + if register.value == 1: + self.set_input_boolean(register.entity_id, "on") + elif register.value == 0: + self.set_input_boolean(register.entity_id, "off") + else: + error_msg = f"State value for {register.entity_id} should be an integer value of 1 or 0" + _log.info(error_msg) + raise ValueError(error_msg) + else: + _log.info(f"Currently, input_booleans only support state") + + # Changing thermostat values. + elif "climate." in register.entity_id: + if entity_point == "state": + if isinstance(register.value, int) and register.value in [0, 2, 3, 4]: + if register.value == 0: + self.change_thermostat_mode(entity_id=register.entity_id, mode="off") + elif register.value == 2: + self.change_thermostat_mode(entity_id=register.entity_id, mode="heat") + elif register.value == 3: + self.change_thermostat_mode(entity_id=register.entity_id, mode="cool") + elif register.value == 4: + self.change_thermostat_mode(entity_id=register.entity_id, mode="auto") + else: + error_msg = f"Climate state should be an integer value of 0, 2, 3, or 4" + _log.error(error_msg) + raise ValueError(error_msg) + elif entity_point == "temperature": + self.set_thermostat_temperature(entity_id=register.entity_id, temperature=register.value) + + else: + error_msg = f"Currently set_point is supported only for thermostats state and temperature {register.entity_id}" + _log.error(error_msg) + raise ValueError(error_msg) + else: + error_msg = f"Unsupported entity_id: {register.entity_id}. " \ + f"Currently set_point is supported only for thermostats and lights" + _log.error(error_msg) + raise ValueError(error_msg) + return register.value + + def get_entity_data(self, point_name): + headers = { + "Authorization": f"Bearer {self.access_token}", + "Content-Type": "application/json", + } + # the /states grabs current state AND attributes of a specific entity + url = f"http://{self.ip_address}:{self.port}/api/states/{point_name}" + response = requests.get(url, headers=headers) + if response.status_code == 200: + return response.json() # return the json attributes from entity + else: + error_msg = f"Request failed with status code {response.status_code}, Point name: {point_name}, " \ + f"response: {response.text}" + _log.error(error_msg) + raise Exception(error_msg) + + def _scrape_all(self): + result = {} + read_registers = self.get_registers_by_type("byte", True) + write_registers = self.get_registers_by_type("byte", False) + + for register in read_registers + write_registers: + entity_id = register.entity_id + entity_point = register.entity_point + try: + entity_data = self.get_entity_data(entity_id) # Using Entity ID to get data + if "climate." in entity_id: # handling thermostats. + if entity_point == "state": + state = entity_data.get("state", None) + # Giving thermostat states an equivalent number. + if state == "off": + register.value = 0 + result[register.point_name] = 0 + elif state == "heat": + register.value = 2 + result[register.point_name] = 2 + elif state == "cool": + register.value = 3 + result[register.point_name] = 3 + elif state == "auto": + register.value = 4 + result[register.point_name] = 4 + else: + error_msg = f"State {state} from {entity_id} is not yet supported" + _log.error(error_msg) + ValueError(error_msg) + # Assigning attributes + else: + attribute = entity_data.get("attributes", {}).get(f"{entity_point}", 0) + register.value = attribute + result[register.point_name] = attribute + # handling light states + elif "light." or "input_boolean." in entity_id: # Checks for lights or input bools since they have the same states. + if entity_point == "state": + state = entity_data.get("state", None) + # Converting light states to numbers. + if state == "on": + register.value = 1 + result[register.point_name] = 1 + elif state == "off": + register.value = 0 + result[register.point_name] = 0 + else: + attribute = entity_data.get("attributes", {}).get(f"{entity_point}", 0) + register.value = attribute + result[register.point_name] = attribute + else: # handling all devices that are not thermostats or light states + if entity_point == "state": + + state = entity_data.get("state", None) + register.value = state + result[register.point_name] = state + # Assigning attributes + else: + attribute = entity_data.get("attributes", {}).get(f"{entity_point}", 0) + register.value = attribute + result[register.point_name] = attribute + except Exception as e: + _log.error(f"An unexpected error occurred for entity_id: {entity_id}: {e}") + + return result + + def parse_config(self, config_dict): + + if config_dict is None: + return + for regDef in config_dict: + + if not regDef['Entity ID']: + continue + + read_only = str(regDef.get('Writable', '')).lower() != 'true' + entity_id = regDef['Entity ID'] + entity_point = regDef['Entity Point'] + self.point_name = regDef['Volttron Point Name'] + self.units = regDef['Units'] + description = regDef.get('Notes', '') + default_value = ("Starting Value") + type_name = regDef.get("Type", 'string') + reg_type = type_mapping.get(type_name, str) + attributes = regDef.get('Attributes', {}) + register_type = HomeAssistantRegister + + register = register_type( + read_only, + self.point_name, + self.units, + reg_type, + attributes, + entity_id, + entity_point, + default_value=default_value, + description=description) + + if default_value is not None: + self.set_default(self.point_name, register.value) + + self.insert_register(register) + + def turn_off_lights(self, entity_id): + url = f"http://{self.ip_address}:{self.port}/api/services/light/turn_off" + headers = { + "Authorization": f"Bearer {self.access_token}", + "Content-Type": "application/json", + } + payload = { + "entity_id": entity_id, + } + _post_method(url, headers, payload, f"turn off {entity_id}") + + def turn_on_lights(self, entity_id): + url = f"http://{self.ip_address}:{self.port}/api/services/light/turn_on" + headers = { + "Authorization": f"Bearer {self.access_token}", + "Content-Type": "application/json", + } + + payload = { + "entity_id": f"{entity_id}" + } + _post_method(url, headers, payload, f"turn on {entity_id}") + + def change_thermostat_mode(self, entity_id, mode): + # Check if enttiy_id startswith climate. + if not entity_id.startswith("climate."): + _log.error(f"{entity_id} is not a valid thermostat entity ID.") + return + # Build header + url = f"http://{self.ip_address}:{self.port}/api/services/climate/set_hvac_mode" + headers = { + "Authorization": f"Bearer {self.access_token}", + "content-type": "application/json", + } + # Build data + data = { + "entity_id": entity_id, + "hvac_mode": mode, + } + # Post data + _post_method(url, headers, data, f"change mode of {entity_id} to {mode}") + + def set_thermostat_temperature(self, entity_id, temperature): + # Check if the provided entity_id starts with "climate." + if not entity_id.startswith("climate."): + _log.error(f"{entity_id} is not a valid thermostat entity ID.") + return + + url = f"http://{self.ip_address}:{self.port}/api/services/climate/set_temperature" + headers = { + "Authorization": f"Bearer {self.access_token}", + "content-type": "application/json", + } + + if self.units == "C": + converted_temp = round((temperature - 32) * 5/9, 1) + _log.info(f"Converted temperature {converted_temp}") + data = { + "entity_id": entity_id, + "temperature": converted_temp, + } + else: + data = { + "entity_id": entity_id, + "temperature": temperature, + } + _post_method(url, headers, data, f"set temperature of {entity_id} to {temperature}") + + def change_brightness(self, entity_id, value): + url = f"http://{self.ip_address}:{self.port}/api/services/light/turn_on" + headers = { + "Authorization": f"Bearer {self.access_token}", + "Content-Type": "application/json", + } + # ranges from 0 - 255 + payload = { + "entity_id": f"{entity_id}", + "brightness": value, + } + + _post_method(url, headers, payload, f"set brightness of {entity_id} to {value}") + + def set_input_boolean(self, entity_id, state): + service = 'turn_on' if state == 'on' else 'turn_off' + url = f"http://{self.ip_address}:{self.port}/api/services/input_boolean/{service}" + headers = { + "Authorization": f"Bearer {self.access_token}", + "Content-Type": "application/json", + } + + payload = { + "entity_id": entity_id + } + + response = requests.post(url, headers=headers, json=payload) + + # Optionally check for a successful response + if response.status_code == 200: + print(f"Successfully set {entity_id} to {state}") + else: + print(f"Failed to set {entity_id} to {state}: {response.text}") diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus.py index e6f5868c9c..64d4e7a415 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import struct @@ -42,7 +28,7 @@ from gevent import monkey monkey.patch_socket() -from pymodbus.client.sync import ModbusTcpClient as SyncModbusClient +from pymodbus.client.sync import ModbusTcpClient as SyncModbusClient from pymodbus.exceptions import ConnectionException, ModbusIOException, ModbusException from pymodbus.pdu import ExceptionResponse from pymodbus.constants import Defaults @@ -87,26 +73,26 @@ def __init__(self, address, type_string, pointName, units, read_only, mixed_endi slave_id=0): super(ModbusBitRegister, self).__init__(address, "bit", read_only, pointName, units, description=description, slave_id=slave_id) - + self.python_type = bool - + def parse_value(self, starting_address, bit_stream): # find the bytes we care about - index = (self.address - starting_address) + index = (self.address - starting_address) return bit_stream[index] - + def get_register_count(self): return 1 - + def get_state(self, client): response_bits = client.read_discrete_inputs(self.address, unit=self.slave_id) if self.read_only else \ client.read_coils(self.address, unit=self.slave_id) if response_bits is None: raise ModbusInterfaceException("pymodbus returned None") return response_bits.bits[0] - + def set_state(self, client, value): - if not self.read_only: + if not self.read_only: response = client.write_coil(self.address, value, unit=self.slave_id) if response is None: raise ModbusInterfaceException("pymodbus returned None") @@ -120,29 +106,29 @@ def __init__(self, address, type_string, pointName, units, read_only, mixed_endi slave_id=0): super(ModbusByteRegister, self).__init__(address, "byte", read_only, pointName, units, description=description, slave_id=slave_id) - + try: self.parse_struct = struct.Struct(type_string) except struct.error: raise ValueError("Invalid Modbus Register '" + type_string + "' for point " + pointName) - + struct_types = [type(x) for x in self.parse_struct.unpack(b'\x00'*self.parse_struct.size)] - + if len(struct_types) != 1: raise ValueError("Invalid length Modbus Register '" + type_string + "' for point " + pointName) - + self.python_type = struct_types[0] self.mixed_endian = mixed_endian - - def get_register_count(self): + + def get_register_count(self): return self.parse_struct.size // MODBUS_REGISTER_SIZE - + def parse_value(self, starting_address, byte_stream): # find the bytes we care about index = (self.address - starting_address) * 2 width = self.parse_struct.size - + target_bytes = byte_stream[index:index+width] if len(target_bytes) < width: raise ValueError('Not enough data to parse') @@ -157,7 +143,7 @@ def parse_value(self, starting_address, byte_stream): target_bytes = bytes.join(b'', [PYMODBUS_REGISTER_STRUCT.pack(value) for value in register_values]) # for value in register_values: # target_bytes += PYMODBUS_REGISTER_STRUCT.pack(value).decode('utf-8') - + return self.parse_struct.unpack(target_bytes)[0] def get_state(self, client): @@ -165,13 +151,13 @@ def get_state(self, client): response = client.read_input_registers(self.address, count=self.get_register_count(), unit=self.slave_id) else: response = client.read_holding_registers(self.address, count=self.get_register_count(), unit=self.slave_id) - + if response is None: raise ModbusInterfaceException("pymodbus returned None") if self.mixed_endian: response.registers.reverse() - + response_bytes = response.encode() # skip the result count return self.parse_struct.unpack(response_bytes[1:])[0] @@ -187,25 +173,25 @@ def set_state(self, client, value): client.write_registers(self.address, register_values, unit=self.slave_id) return self.get_state(client) return None - - + + class Interface(BasicRevert, BaseInterface): def __init__(self, **kwargs): super(Interface, self).__init__(**kwargs) self.build_ranges_map() - + def configure(self, config_dict, registry_config_str): self.slave_id = config_dict.get("slave_id", 0) self.ip_address = config_dict["device_address"] self.port = config_dict.get("port", Defaults.Port) - self.parse_config(registry_config_str) - + self.parse_config(registry_config_str) + def build_ranges_map(self): self.register_ranges = {('byte', True): [], ('byte', False): [], ('bit', True): [], ('bit', False): []} - + def insert_register(self, register): super(Interface, self).insert_register(register) @@ -249,8 +235,8 @@ def get_point(self, point_name): except (ConnectionException, ModbusIOException, ModbusInterfaceException): result = None return result - - def _set_point(self, point_name, value): + + def _set_point(self, point_name, value): register = self.get_register_by_name(point_name) if register.read_only: raise IOError("Trying to write to a point configured read only: "+point_name) @@ -261,7 +247,7 @@ def _set_point(self, point_name, value): except (ConnectionException, ModbusIOException, ModbusInterfaceException) as ex: raise IOError("Error encountered trying to write to point {}: {}".format(point_name, ex)) return result - + def scrape_byte_registers(self, client, read_only): result_dict = {} register_ranges = self.register_ranges[('byte', read_only)] @@ -289,7 +275,7 @@ def scrape_byte_registers(self, client, read_only): result_dict[point] = value return result_dict - + def scrape_bit_registers(self, client, read_only): result_dict = {} register_ranges = self.register_ranges[('bit', read_only)] @@ -315,52 +301,52 @@ def scrape_bit_registers(self, client, read_only): point = register.point_name value = register.parse_value(start, result) result_dict[point] = value - + return result_dict - + def _scrape_all(self): result_dict = {} with modbus_client(self.ip_address, self.port) as client: try: - + result_dict.update(self.scrape_byte_registers(client, True)) result_dict.update(self.scrape_byte_registers(client, False)) - + result_dict.update(self.scrape_bit_registers(client, True)) result_dict.update(self.scrape_bit_registers(client, False)) except (ConnectionException, ModbusIOException, ModbusInterfaceException) as e: raise DriverInterfaceError("Failed to scrape device at " + self.ip_address + ":" + str(self.port) + " ID: " + str(self.slave_id) + str(e)) - + return result_dict - + def parse_config(self, configDict): if configDict is None: return - + for regDef in configDict: # Skip lines that have no address yet. if not regDef['Volttron Point Name']: continue - + io_type = regDef['Modbus Register'] bit_register = io_type.lower() == 'bool' read_only = regDef['Writable'].lower() != 'true' - point_path = regDef['Volttron Point Name'] - address = int(regDef['Point Address']) + point_path = regDef['Volttron Point Name'] + address = int(regDef['Point Address']) description = regDef.get('Notes', '') - units = regDef['Units'] - + units = regDef['Units'] + default_value = regDef.get("Default Value", '').strip() mixed_endian = regDef.get('Mixed Endian', '').strip().lower() == 'true' - + klass = ModbusBitRegister if bit_register else ModbusByteRegister register = klass(address, io_type, point_path, units, read_only, mixed_endian=mixed_endian, description=description, slave_id=self.slave_id) - + self.insert_register(register) - + if not read_only: if default_value: if isinstance(register, ModbusBitRegister): @@ -376,7 +362,7 @@ def parse_config(self, configDict): except ValueError: _log.warning("Unable to set default value for {}, bad default value in configuration. " "Using default revert method.".format(point_path)) - + else: _log.info("No default value supplied for point {}. Using default revert method.".format(point_path)) diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/__init__.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/__init__.py index 83bcff4ab3..a663498c44 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/__init__.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from gevent import monkey diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/client.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/client.py index b3f90cdd9a..beea69b023 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/client.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/client.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/config_cmd.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/config_cmd.py index ec58de4b96..a9bb75cb32 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/config_cmd.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/config_cmd.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -79,7 +65,7 @@ def set_device_type_maps(self): yaml_file = "{0}/{1}".format(self._directories['map_dir'], file_name) if file_name and os.stat(yaml_file).st_size: with open("{0}/maps.yaml".format(self._directories['map_dir'])) as yaml_file: - device_type_maps = yaml.load(yaml_file) + device_type_maps = yaml.safe_load(yaml_file) return device_type_maps def _sh(self, shell_command): @@ -165,7 +151,7 @@ def get_existed_file(self, file_dir, file_name): if file_dir: while True: if not os.path.exists("{0}/{1}".format(file_dir, file_name)): - print ("'{0}' file '{1}' does not exist in the directory '{2}'".format(file_type, + print("'{0}' file '{1}' does not exist in the directory '{2}'".format(file_type, file_name, file_dir)) if file_name == 'maps.yaml': @@ -268,20 +254,19 @@ def do_edit_directories(self, line): print("No change made to '{0}'".format(dir_key)) else: self._directories[dir_key] = dir + elif line not in self._directories: + print("Directory type '{0}' does not exist".format(line)) + print("Please select another directory type from: {0}".format([k for k in self._directories.keys()])) + print("Enter a directory type. Press if edit all: ", end='') + self.do_edit_directories(input().lower()) else: - if line not in self._directories: - print("Directory type '{0}' does not exist".format(line)) - print("Please select another directory type from: {0}".format([k for k in self._directories.keys()])) - print("Enter a directory type. Press if edit all: ", end='') - self.do_edit_directories(input().lower()) + print("Enter the directory path for {0}. Press if no change needed: ".format(line), end='') + dir_path = input() + dir = self.get_existed_directory(dir_path, line) if dir_path else None + if not dir or dir == self._directories[line]: + print("No change made to {0}".format(line)) else: - print("Enter the directory path for {0}. Press if no change needed: ".format(line), end='') - dir_path = input() - dir = self.get_existed_directory(dir_path, line) if dir_path else None - if not dir or dir == self._directories[line]: - print("No change made to {0}".format(line)) - else: - self._directories[line] = dir + self._directories[line] = dir self.do_list_directories('') @@ -818,7 +803,7 @@ def do_delete_volttron_config(self, line): print("DRIVER NAME".ljust(16) + "| VOLTTRON PATH") for d in drivers.keys(): print("{0:15} | {1}".format(d, drivers[d])) - print ("\nEnter driver name to delete: ", end='') + print("\nEnter driver name to delete: ", end='') driver_name = input() if driver_name not in drivers: diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/helpers.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/helpers.py index f96dff5e43..5a4a83a17d 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/helpers.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/helpers.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import modbus_tk.defines as modbus_constants diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/maps/__init__.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/maps/__init__.py index 210f960510..91f7edaab5 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/maps/__init__.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/maps/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from platform_driver.interfaces.modbus_tk.client import Field, Client @@ -197,11 +183,10 @@ def _table(self): return table_map[table] except KeyError: raise Exception("Invalid modbus table '{0}' for register '{1}'".format(table, self._name)) + elif self._datatype == helpers.BOOL: + return helpers.COIL_READ_WRITE if self._writable else helpers.COIL_READ_ONLY else: - if self._datatype == helpers.BOOL: - return helpers.COIL_READ_WRITE if self._writable else helpers.COIL_READ_ONLY - else: - return helpers.REGISTER_READ_WRITE if self._writable else helpers.REGISTER_READ_ONLY + return helpers.REGISTER_READ_WRITE if self._writable else helpers.REGISTER_READ_ONLY @property def _op_mode(self): @@ -330,7 +315,7 @@ def __init__(self): yaml_path = os.path.dirname(__file__) + '/' + yaml_path with open(yaml_path, 'rb') as yaml_file: - for map in yaml.load(yaml_file): + for map in yaml.safe_load(yaml_file): map = dict((k.lower(), v) for k, v in map.items()) Catalog._data[map['name']] = Map(file=map.get('file', ''), map_dir=os.path.dirname(__file__), diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/maps/maps.yaml b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/maps/maps.yaml index 3ecf6f3237..ab387b700c 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/maps/maps.yaml +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/maps/maps.yaml @@ -48,4 +48,4 @@ - addressing: offset endian: big file: battery_meter.csv - name: battery_meter \ No newline at end of file + name: battery_meter diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/server.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/server.py index cd2f99b5ea..36046d470c 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/server.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/server.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import argparse diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/modbus_listener_agent.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/modbus_listener_agent.py index 9bf393b27c..8bb94bc49a 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/modbus_listener_agent.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/modbus_listener_agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_battery_meter.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_battery_meter.py index 43313652e2..0ac107061f 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_battery_meter.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_battery_meter.py @@ -3,8 +3,10 @@ import logging import time +from struct import pack, unpack + from volttron.platform import get_services_core, jsonapi -from volttrontesting.utils.utils import get_rand_ip_and_port +from volttrontesting.utils.utils import get_rand_ip_and_port, is_running_in_container from platform_driver.interfaces.modbus_tk.server import Server from platform_driver.interfaces.modbus_tk.maps import Map, Catalog from volttron.platform.agent.known_identities import PLATFORM_DRIVER @@ -282,12 +284,12 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus_tk', jsonapi.dumps(DRIVER_CONFIG), @@ -295,14 +297,14 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk.csv', REGISTRY_CONFIG_STRING, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk_map.csv', REGISTER_MAP, @@ -332,7 +334,8 @@ def modbus_server(request): server_process = Server(address=IP, port=PORT) server_process.define_slave(1, modbus_client, unsigned=False) - + for k in registers_dict: + server_process.set_values(1, modbus_client().field_by_name(k), unpack('f', 0))) server_process.start() time.sleep(1) yield server_process @@ -384,6 +387,7 @@ def scrape_all(self, agent, device_name): return agent.vip.rpc.call(PLATFORM_DRIVER, 'scrape_all', device_name)\ .get(timeout=10) + @pytest.mark.skip('This test has been unreliable.') def test_scrape_all(self, agent): for key in registers_dict.keys(): self.set_point(agent, 'modbus_tk', key, registers_dict[key]) diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_driver_demo_board.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_driver_demo_board.py new file mode 100644 index 0000000000..593c2a684f --- /dev/null +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_driver_demo_board.py @@ -0,0 +1,123 @@ +import os + +import gevent +import pytest + +from pathlib import Path + +from volttron.platform.agent.known_identities import CONFIGURATION_STORE, PLATFORM_DRIVER +from volttron.platform import jsonapi +from volttrontesting.utils.platformwrapper import PlatformWrapper + +MODBUS_TEST_IP = "MODBUS_TEST_IP" + +# apply skipif to all tests +skip_msg = f"Env var {MODBUS_TEST_IP} not set. Please set the env var to the proper IP to run this integration test." +pytestmark = pytest.mark.skipif(os.environ.get(MODBUS_TEST_IP) is None, reason=skip_msg) + + +def test_get_point(publish_agent): + registers = ["SupplyTemp", "ReturnTemp", "OutsideTemp"] + for point_name in registers: + point_val = publish_agent.vip.rpc.call(PLATFORM_DRIVER, "get_point", "modbustk", + point_name).get(timeout=10) + print(f"Point: {point_name} has point value of {point_val}") + assert isinstance(point_val, int) + + +def test_set_point(publish_agent): + point_name = "SecondStageCoolingDemandSetPoint" + point_val = 42 + publish_agent.vip.rpc.call(PLATFORM_DRIVER, "set_point", "modbustk", point_name, + point_val).get(timeout=10) + assert publish_agent.vip.rpc.call(PLATFORM_DRIVER, "get_point", "modbustk", + point_name).get(timeout=10) == point_val + + +@pytest.fixture(scope="module") +def publish_agent(volttron_instance: PlatformWrapper): + assert volttron_instance.is_running() + vi = volttron_instance + assert vi is not None + assert vi.is_running() + + config = { + "driver_scrape_interval": 0.05, + "publish_breadth_first_all": "false", + "publish_depth_first": "false", + "publish_breadth_first": "false" + } + puid = vi.install_agent(agent_dir=Path(__file__).parent.parent.parent.parent.parent.absolute().resolve(), + config_file=config, + start=False, + vip_identity=PLATFORM_DRIVER) + assert puid is not None + gevent.sleep(1) + assert vi.start_agent(puid) + assert vi.is_agent_running(puid) + + # create the publish agent + publish_agent = volttron_instance.build_agent() + assert publish_agent.core.identity + gevent.sleep(1) + + capabilities = {"edit_config_store": {"identity": PLATFORM_DRIVER}} + volttron_instance.add_capabilities(publish_agent.core.publickey, capabilities) + gevent.sleep(1) + + # Add Modbus Driver TK registry map to Platform Driver + registry_config_string = """Register Name,Address,Type,Units,Writable + SupplyTemp,0,uint16,degC,FALSE + ReturnTemp,1,uint16,degC,FALSE + OutsideTemp,2,uint16,degC,FALSE + SecondStageCoolingDemandSetPoint,14,uint16,degC,TRUE""" + publish_agent.vip.rpc.call(CONFIGURATION_STORE, + "manage_store", + PLATFORM_DRIVER, + "m2000_rtu_TK_map.csv", + registry_config_string, + config_type="csv").get(timeout=10) + + # Add Modbus Driver registry to Platform Driver + registry_config_string = """Register Name,Volttron Point Name + SupplyTemp,SupplyTemp + ReturnTemp,ReturnTemp + OutsideTemp,OutsideTemp + SecondStageCoolingDemandSetPoint,SecondStageCoolingDemandSetPoint""" + publish_agent.vip.rpc.call(CONFIGURATION_STORE, + "manage_store", + PLATFORM_DRIVER, + "m2000_rtu_TK.csv", + registry_config_string, + config_type="csv").get(timeout=10) + + # Add Modbus Driver config to Platform Driver + device_address = os.environ.get(MODBUS_TEST_IP) + driver_config = { + "driver_config": { + "device_address": device_address, + "slave_id": 8, + "port": 502, + "register_map": "config://m2000_rtu_TK_map.csv" + }, + "campus": "PNNL", + "building": "DEMO", + "unit": "M2000", + "driver_type": "modbus_tk", + "registry_config": "config://m2000_rtu_TK.csv", + "interval": 60, + "timezone": "Pacific", + "heart_beat_point": "heartbeat" + } + + publish_agent.vip.rpc.call(CONFIGURATION_STORE, + "manage_store", + PLATFORM_DRIVER, + "devices/modbustk", + jsonapi.dumps(driver_config), + config_type='json').get(timeout=10) + + yield publish_agent + + volttron_instance.stop_agent(puid) + publish_agent.core.stop() diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_ion6200.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_ion6200.py index e4c91934f2..6215d688c0 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_ion6200.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_ion6200.py @@ -88,12 +88,12 @@ def ion_driver_agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/ion6200', ION6200_DRIVER_CONFIG, @@ -101,14 +101,14 @@ def ion_driver_agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'ion6200.csv', ION6200_CSV_CONFIG, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'ion6200_map.csv', ION6200_CSV_MAP, diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_mixed_endian.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_mixed_endian.py index b4201a6189..e90d1df07f 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_mixed_endian.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_mixed_endian.py @@ -87,19 +87,19 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus', ORIGINAL_DRIVER_CONFIG, config_type='json') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus_tk', NEW_DRIVER_CONFIG, @@ -107,21 +107,21 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus.csv', ORIGINAL_REGISTRY_CONFIG, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk.csv', NEW_REGISTRY_CONFIG, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk_map.csv', NEW_REGISTER_MAP, diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_modbus_tk_driver.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_modbus_tk_driver.py index b422962f3f..c13d00079b 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_modbus_tk_driver.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_modbus_tk_driver.py @@ -111,19 +111,19 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus_tk', jsonapi.dumps(DRIVER_CONFIG), config_type='json') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus', jsonapi.dumps(OLD_VOLTTRON_DRIVER_CONFIG), @@ -131,21 +131,21 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk.csv', REGISTRY_CONFIG_STRING, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk_map.csv', REGISTER_MAP, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus.csv', OLD_VOLTTRON_REGISTRY_CONFIG, diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scale_reg.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scale_reg.py index 17d9f3fe92..c93d3a00e7 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scale_reg.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scale_reg.py @@ -58,12 +58,12 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus_tk', DRIVER_CONFIG_STRING, @@ -71,22 +71,22 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk.csv', REGISTRY_CONFIG_STRING, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk_map.csv', REGISTER_MAP, config_type='csv') platform_uuid = volttron_instance.install_agent(agent_dir=get_services_core("PlatformDriverAgent"), - config_file={}, - start=True) + config_file={}, + start=True) gevent.sleep(10) # wait for the agent to start and start the devices diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scale_reg_pow_10.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scale_reg_pow_10.py index bfa4e8b282..329f6b9732 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scale_reg_pow_10.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scale_reg_pow_10.py @@ -5,7 +5,7 @@ from volttron.platform import get_services_core from platform_driver.interfaces.modbus_tk.server import Server -from platform_driver.interfaces.modbus_tk.maps import Map, Catalog +from platform_driver.interfaces.modbus_tk.maps import Catalog from volttron.platform.agent.known_identities import PLATFORM_DRIVER logger = logging.getLogger(__name__) @@ -58,12 +58,12 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus_tk', DRIVER_CONFIG_STRING, @@ -71,14 +71,14 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk.csv', REGISTRY_CONFIG_STRING, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk_map.csv', REGISTER_MAP, diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scrape_all.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scrape_all.py index 9c8dcb318d..6ab19d5c17 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scrape_all.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_scrape_all.py @@ -101,19 +101,19 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus_tk', jsonapi.dumps(DRIVER_CONFIG), config_type='json') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus', jsonapi.dumps(OLD_VOLTTRON_DRIVER_CONFIG), @@ -121,21 +121,21 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk.csv', REGISTRY_CONFIG_STRING, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus_tk_map.csv', REGISTER_MAP, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus.csv', OLD_VOLTTRON_REGISTRY_CONFIG, diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_watts_on.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_watts_on.py index efb8f15515..45aba42e9a 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_watts_on.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_watts_on.py @@ -66,12 +66,12 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', 'platform.driver', 'devices/watts_on', DRIVER_CONFIG_STRING, @@ -79,14 +79,14 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', 'platform.driver', 'watts_on.csv', REGISTRY_CONFIG_STRING, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', 'platform.driver', 'watts_on_map.csv', REGISTRY_CONFIG_MAP, diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_write_single_registers.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_write_single_registers.py index b6027ee010..178dc2d4bf 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_write_single_registers.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_write_single_registers.py @@ -56,12 +56,12 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/write_single_registers', DRIVER_CONFIG_STRING, @@ -69,14 +69,14 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'write_single_registers.csv', REGISTRY_CONFIG_STRING, config_type='csv') md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'write_single_registers_map.csv', REGISTRY_CONFIG_MAP, diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/obix.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/obix.py index 117c56d7bd..16bae56960 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/obix.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/obix.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} __docformat__ = 'reStructuredText' @@ -170,5 +156,3 @@ def parse_config(self, configDict, url): units, description) self.insert_register(register) - - diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/radiothermostat.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/radiothermostat.py index 1c0791360c..a6a89dbbdc 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/radiothermostat.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/radiothermostat.py @@ -37,7 +37,7 @@ """ -from platform_driver.interfaces import BaseInterface, BaseRegister, DriverInterfaceError +from platform_driver.interfaces import BaseInterface, BaseRegister from . import thermostat_api from volttron.platform import jsonapi diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/rainforesteagle.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/rainforesteagle.py index 4f88f3eeb7..8cc569e1e9 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/rainforesteagle.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/rainforesteagle.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from csv import DictReader diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/rainforestemu2.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/rainforestemu2.py index df69140498..f21cae8a08 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/rainforestemu2.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/rainforestemu2.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from csv import DictReader diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/restful.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/restful.py index 27ab28ba86..c842bd9c86 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/restful.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/restful.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/universal.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/universal.py index 3ee2b70350..1a94d7bc8e 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/universal.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/universal.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} ''' @@ -93,13 +79,13 @@ def __init__(self, **kwargs): args = parser.parse_args() self._verboseness = args.verbosity - if (self._verboseness == 0): + if self._verboseness == 0: verbiage = logging.ERROR - if (self._verboseness == 1): + if self._verboseness == 1: verbiage = logging.WARNING # '-v' - elif (self._verboseness == 2): + elif self._verboseness == 2: verbiage = logging.INFO # '-vv' - elif (self._verboseness >= 3): + elif self._verboseness >= 3: verbiage = logging.DEBUG # '-vvv' _log.setLevel(verbiage) @@ -111,18 +97,18 @@ def configure(self, config_dict, registry_config_str): volttron/platform/vip/agent/subsystems/configstore.py which exports initial_update() which calls volttron/platform/store.py: def get_configs(self): self.vip.rpc.call(identity, "config.initial_update" sets list of registry_configs - - scripts/install_platform_driver_configs.py calls 'manage_store' rpc, which is in volttron/platform/store.py + + scripts/install_platform_driver_configs.py calls 'set_config' rpc, which is in volttron/platform/store.py which calls process_raw_config(), which stores it as a dict. - process_raw_config() is also called by process_store() in store.py + process_raw_config() is also called by process_store() in store.py when the platform starts ( class ConfigStoreService): - processing_raw_config 'registry_configs/meter.csv' (config_type: csv) + processing_raw_config 'registry_configs/meter.csv' (config_type: csv) process_store() is called by _setup using a 'PersistentDict', i.e.: store_path '/home/carl/.volttron/configuration_store/platform.driver.store' install_platform_driver_configs.py stores them as config_type="csv", it is useful for batch processing alot of files at once, like when upgrading from 3.5 to 4.0 - + to add single config to store, activate and start platform then: List current configs: volttron-ctl config list platform.driver @@ -135,10 +121,10 @@ def configure(self, config_dict, registry_config_str): To store the driver configuration run the command: delete any files from ../GridAgents/configs volttron-ctl config store platform.driver devices/PNNL/LABHOME_B ../GridAgents/configs/devices/PNNL/LABHOME_B/METER1 - + To store the registry configuration run the command (note the **--raw option) volttron-ctl config store platform.driver registry_configs/meter.csv ../GridAgents/configs/registry_configs/meter.csv --raw - + ***** NOTE: you MUST install the csv file in --raw mode for universal drivers. ***** ''' @@ -148,7 +134,7 @@ def configure(self, config_dict, registry_config_dict): # 4.0 passes in a reg D device_type = config_dict['device_type'] ''' see ./volttron/volttron/platform/vip/agent/__init__.py for Agent object definition every agent has a .core and .vip: - vip.ping + vip.ping vip.rpc vip.hello vip.pubsub @@ -156,15 +142,15 @@ def configure(self, config_dict, registry_config_dict): # 4.0 passes in a reg D vip.heartbeat vip.config ''' - if (device_type == "heater"): + if device_type == "heater": self.agent = HeaterDriver(None, config_dict['device_id']) - elif (device_type == "meter"): + elif device_type == "meter": self.agent = MeterDriver(None, config_dict['device_id'], ) - elif (device_type == "thermostat"): + elif device_type == "thermostat": self.agent = ThermostatDriver(None, config_dict['device_id']) - elif (device_type == "blinds"): + elif device_type == "blinds": self.agent = BlindsDriver(None, config_dict['device_id']) - elif (device_type == "vehicle"): + elif device_type == "vehicle": self.agent = VehicleDriver(None, config_dict['device_id']) else: raise RuntimeError("Unsupported Device Type: '{}'".format(device_type)) @@ -201,7 +187,7 @@ def _set_point(self, point_name, value): if register.read_only: raise IOError("Trying to write to a point configured read only: " + point_name) - if (self.agent.SetPoint(register, value)): + if self.agent.SetPoint(register, value): register._value = register.reg_type(value) self.point_map[point_name]._value = register._value return register._value @@ -213,7 +199,7 @@ def _scrape_all(self): read_registers = self.get_registers_by_type("byte", True) write_registers = self.get_registers_by_type("byte", False) for register in read_registers + write_registers: - if (self._verboseness == 2): + if self._verboseness == 2: _log.info("Universal Scraping Value for '{}': {}".format(register.point_name, register._value)) result[register.point_name] = register._value return result @@ -226,7 +212,7 @@ def _reset_all(self): old_value = register._value register._value = register._default_value # _log.info( "point_map[register]._value = {}".format(self.point_map[register.point_name]._value)) - if (self._verboseness == 2): + if self._verboseness == 2: _log.info("Hardware not reachable, Resetting Value for '{}' from {} to {}".format(register.point_name, old_value, register._value)) @@ -235,7 +221,7 @@ def _reset_all(self): We maybe could have used revert_point( register.point_name ), but that is more for reverting the hardware to its default value (calls set_point, which complains for read_only points), _reset_all is used to set the registry values to a default when the hardware is not reachable.... - + if register in self.defaults: self.point_map[register]._value = self.defaults[register] if( self._verboseness == 2 ): @@ -248,7 +234,7 @@ def _reset_all(self): ''' parse_config ***** NOTE: you MUST install the csv file in --raw mode for universal drivers. ***** - volttron-ctl config store platform.driver registry_configs/meter.csv + volttron-ctl config store platform.driver registry_configs/meter.csv ../GridAgents/configs/registry_configs/meter.csv --raw ''' diff --git a/services/core/PlatformDriverAgent/requirements.txt b/services/core/PlatformDriverAgent/requirements.txt index f19047e936..23203ca7eb 100644 --- a/services/core/PlatformDriverAgent/requirements.txt +++ b/services/core/PlatformDriverAgent/requirements.txt @@ -1,4 +1,4 @@ bacpypes==0.16.7 -pymodbus==2.5.2 modbus-tk==1.1.2 +pymodbus==2.5.3 pyserial==3.5 diff --git a/services/core/PlatformDriverAgent/setup.py b/services/core/PlatformDriverAgent/setup.py index cc64769bff..5284d29efb 100644 --- a/services/core/PlatformDriverAgent/setup.py +++ b/services/core/PlatformDriverAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/PlatformDriverAgent/tests/test_bacnet.py b/services/core/PlatformDriverAgent/tests/test_bacnet.py index 2eef334f90..476a4fc5f2 100644 --- a/services/core/PlatformDriverAgent/tests/test_bacnet.py +++ b/services/core/PlatformDriverAgent/tests/test_bacnet.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -91,7 +77,15 @@ def test_get_point_should_succeed(bacnet_test_agent): @pytest.fixture(scope="module") def bacnet_proxy_agent(volttron_instance): - device_address = socket.gethostbyname(socket.gethostname() + ".local") + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.settimeout(0) + try: + s.connect(('8.8.8.8', 1)) + device_address = s.getsockname()[0] + except Exception: + device_address = '127.0.0.1' + finally: + s.close() print(f"Device address for proxy agent for testing: {device_address}") bacnet_proxy_agent_config = { "device_address": device_address, @@ -184,7 +178,7 @@ def config_store(config_store_connection): # registry config config_store_connection.call( - "manage_store", + "set_config", PLATFORM_DRIVER, registry_config, registry_string, @@ -201,7 +195,7 @@ def config_store(config_store_connection): } config_store_connection.call( - "manage_store", + "set_config", PLATFORM_DRIVER, BACNET_DEVICE_TOPIC, driver_config, @@ -210,5 +204,5 @@ def config_store(config_store_connection): yield config_store_connection print("Wiping out store.") - config_store_connection.call("manage_delete_store", PLATFORM_DRIVER) + config_store_connection.call("delete_store", PLATFORM_DRIVER) gevent.sleep(0.1) diff --git a/services/core/PlatformDriverAgent/tests/test_device_groups.py b/services/core/PlatformDriverAgent/tests/test_device_groups.py index 4f4a801610..1877c7ac11 100644 --- a/services/core/PlatformDriverAgent/tests/test_device_groups.py +++ b/services/core/PlatformDriverAgent/tests/test_device_groups.py @@ -1,43 +1,29 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ -py.test cases for global platform driver settings. +pytest cases for global platform driver settings. """ import pytest @@ -136,12 +122,12 @@ def test_agent(volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config - md_agent.vip.rpc.call("config.store", "manage_delete_store", PLATFORM_DRIVER).get() + md_agent.vip.rpc.call("config.store", "delete_store", PLATFORM_DRIVER).get() # Add a fake.csv to the config store md_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, "fake.csv", registry_config_string, @@ -166,7 +152,7 @@ def setup_config(test_agent, config_name, config_string, **kwargs): print("Adding", config_name, "to store") test_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, config_name, config, @@ -177,7 +163,7 @@ def setup_config(test_agent, config_name, config_string, **kwargs): def remove_config(test_agent, config_name): print("Removing", config_name, "from store") test_agent.vip.rpc.call( - "config.store", "manage_delete_config", PLATFORM_DRIVER, config_name + "config.store", "delete_config", PLATFORM_DRIVER, config_name ).get() diff --git a/services/core/PlatformDriverAgent/tests/test_device_groups_p2.py b/services/core/PlatformDriverAgent/tests/test_device_groups_p2.py index 652b26f3f8..386eb4f648 100644 --- a/services/core/PlatformDriverAgent/tests/test_device_groups_p2.py +++ b/services/core/PlatformDriverAgent/tests/test_device_groups_p2.py @@ -1,43 +1,29 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ -a single py.test case for global platform driver settings. +a single pytest case for global platform driver settings. """ import pytest @@ -195,12 +181,12 @@ def test_agent(volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config - md_agent.vip.rpc.call("config.store", "manage_delete_store", PLATFORM_DRIVER).get() + md_agent.vip.rpc.call("config.store", "delete_store", PLATFORM_DRIVER).get() # Add a fake.csv to the config store md_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, "fake.csv", registry_config_string, @@ -225,7 +211,7 @@ def setup_config(test_agent, config_name, config_string, **kwargs): print("Adding", config_name, "to store") test_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, config_name, config, @@ -236,5 +222,5 @@ def setup_config(test_agent, config_name, config_string, **kwargs): def remove_config(test_agent, config_name): print("Removing", config_name, "from store") test_agent.vip.rpc.call( - "config.store", "manage_delete_config", PLATFORM_DRIVER, config_name + "config.store", "delete_config", PLATFORM_DRIVER, config_name ).get() diff --git a/services/core/PlatformDriverAgent/tests/test_driver.py b/services/core/PlatformDriverAgent/tests/test_driver.py index 62f9854875..5be956d4a4 100644 --- a/services/core/PlatformDriverAgent/tests/test_driver.py +++ b/services/core/PlatformDriverAgent/tests/test_driver.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/services/core/PlatformDriverAgent/tests/test_eagle.py b/services/core/PlatformDriverAgent/tests/test_eagle.py index 8856236739..5db344aac2 100644 --- a/services/core/PlatformDriverAgent/tests/test_eagle.py +++ b/services/core/PlatformDriverAgent/tests/test_eagle.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -202,19 +188,19 @@ def agent(volttron_instance): volttron_instance.add_capabilities(agent.core.publickey, capabilities) # Clean out platform driver configurations. agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get(timeout=10) # Add test configurations. agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', PLATFORM_DRIVER, "devices/campus/building/unit", driver_config_string, "json").get(timeout=10) agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', PLATFORM_DRIVER, "eagle.json", register_config_string, diff --git a/services/core/PlatformDriverAgent/tests/test_ecobee_driver.py b/services/core/PlatformDriverAgent/tests/test_ecobee_driver.py index 984e7fe264..827ec0c491 100644 --- a/services/core/PlatformDriverAgent/tests/test_ecobee_driver.py +++ b/services/core/PlatformDriverAgent/tests/test_ecobee_driver.py @@ -578,14 +578,14 @@ def test_scrape_all_trigger_refresh(mock_ecobee): # } # ecobee_driver_config = jsonapi.load(get_examples("configurations/drivers/ecobee.config")) # ecobee_driver_config["interval"] = 3 -# query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", PLATFORM_DRIVER, +# query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", PLATFORM_DRIVER, # "devices/campus/building/test_ecobee", driver_config) # # with open("configurations/drivers/ecobee.csv") as registry_file: # registry_string = registry_file.read() # registry_path = re.search("(?!config:\/\/)[a-zA-z]+\.csv", ecobee_driver_config.get("registry_config")) # -# query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", PLATFORM_DRIVER, registry_path, registry_string, +# query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", PLATFORM_DRIVER, registry_path, registry_string, # config_type="csv") # # ecobee_driver_config.update(driver_config) diff --git a/services/core/PlatformDriverAgent/tests/test_global_override.py b/services/core/PlatformDriverAgent/tests/test_global_override.py index 4c0f3a17c7..96b976ba5c 100644 --- a/services/core/PlatformDriverAgent/tests/test_global_override.py +++ b/services/core/PlatformDriverAgent/tests/test_global_override.py @@ -1,43 +1,29 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ -py.test cases for global override settings. +pytest cases for global override settings. """ import pytest @@ -88,12 +74,12 @@ def test_agent(volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config - md_agent.vip.rpc.call("config.store", "manage_delete_store", PLATFORM_DRIVER).get() + md_agent.vip.rpc.call("config.store", "delete_store", PLATFORM_DRIVER).get() # Add configuration for platform driver md_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, "config", jsonapi.dumps(PLATFORM_DRIVER_CONFIG), @@ -108,7 +94,7 @@ def test_agent(volttron_instance): registry_config_string = f.read() md_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, "fake.csv", registry_config_string, @@ -120,7 +106,7 @@ def test_agent(volttron_instance): config_name = f"devices/fakedriver{i}" md_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, config_name, jsonapi.dumps(FAKE_DEVICE_CONFIG), @@ -790,7 +776,7 @@ def test_override_pattern(test_agent): config_name = config_path.format(camel_device_path) test_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, config_name, jsonapi.dumps(FAKE_DEVICE_CONFIG), diff --git a/services/core/PlatformDriverAgent/tests/test_global_settings.py b/services/core/PlatformDriverAgent/tests/test_global_settings.py index 67a245019e..fedce5ceea 100644 --- a/services/core/PlatformDriverAgent/tests/test_global_settings.py +++ b/services/core/PlatformDriverAgent/tests/test_global_settings.py @@ -1,43 +1,29 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ -py.test cases for global platform driver settings. +pytest cases for global platform driver settings. """ import pytest @@ -167,12 +153,12 @@ def test_agent(volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config - md_agent.vip.rpc.call("config.store", "manage_delete_store", PLATFORM_DRIVER).get() + md_agent.vip.rpc.call("config.store", "delete_store", PLATFORM_DRIVER).get() # Add a fake.csv to the config store md_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, "fake.csv", registry_config_string, @@ -197,7 +183,7 @@ def setup_config(test_agent, config_name, config_string, **kwargs): print("Adding", config_name, "to store") test_agent.vip.rpc.call( "config.store", - "manage_store", + "set_config", PLATFORM_DRIVER, config_name, config, diff --git a/services/core/PlatformDriverAgent/tests/test_home_assistant.py b/services/core/PlatformDriverAgent/tests/test_home_assistant.py new file mode 100644 index 0000000000..6d7b09b115 --- /dev/null +++ b/services/core/PlatformDriverAgent/tests/test_home_assistant.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} + +import json +import logging +import pytest +import gevent + +from volttron.platform.agent.known_identities import ( + PLATFORM_DRIVER, + CONFIGURATION_STORE, +) +from volttron.platform import get_services_core +from volttron.platform.agent import utils +from volttron.platform.keystore import KeyStore +from volttrontesting.utils.platformwrapper import PlatformWrapper + +utils.setup_logging() +logger = logging.getLogger(__name__) + +# To run these tests, create a helper toggle named volttrontest in your Home Assistant instance. +# This can be done by going to Settings > Devices & services > Helpers > Create Helper > Toggle +HOMEASSISTANT_TEST_IP = "" +ACCESS_TOKEN = "" +PORT = "" + +skip_msg = "Some configuration variables are not set. Check HOMEASSISTANT_TEST_IP, ACCESS_TOKEN, and PORT" + +# Skip tests if variables are not set +pytestmark = pytest.mark.skipif( + not (HOMEASSISTANT_TEST_IP and ACCESS_TOKEN and PORT), + reason=skip_msg +) +HOMEASSISTANT_DEVICE_TOPIC = "devices/home_assistant" + + +# Get the point which will should be off +def test_get_point(volttron_instance, config_store): + expected_values = 0 + agent = volttron_instance.dynamic_agent + result = agent.vip.rpc.call(PLATFORM_DRIVER, 'get_point', 'home_assistant', 'bool_state').get(timeout=20) + assert result == expected_values, "The result does not match the expected result." + + +# The default value for this fake light is 3. If the test cannot reach out to home assistant, +# the value will default to 3 making the test fail. +def test_data_poll(volttron_instance: PlatformWrapper, config_store): + expected_values = [{'bool_state': 0}, {'bool_state': 1}] + agent = volttron_instance.dynamic_agent + result = agent.vip.rpc.call(PLATFORM_DRIVER, 'scrape_all', 'home_assistant').get(timeout=20) + assert result in expected_values, "The result does not match the expected result." + + +# Turn on the light. Light is automatically turned off every 30 seconds to allow test to turn +# it on and receive the correct value. +def test_set_point(volttron_instance, config_store): + expected_values = {'bool_state': 1} + agent = volttron_instance.dynamic_agent + agent.vip.rpc.call(PLATFORM_DRIVER, 'set_point', 'home_assistant', 'bool_state', 1) + gevent.sleep(10) + result = agent.vip.rpc.call(PLATFORM_DRIVER, 'scrape_all', 'home_assistant').get(timeout=20) + assert result == expected_values, "The result does not match the expected result." + + +@pytest.fixture(scope="module") +def config_store(volttron_instance, platform_driver): + + capabilities = [{"edit_config_store": {"identity": PLATFORM_DRIVER}}] + volttron_instance.add_capabilities(volttron_instance.dynamic_agent.core.publickey, capabilities) + + registry_config = "homeassistant_test.json" + registry_obj = [{ + "Entity ID": "input_boolean.volttrontest", + "Entity Point": "state", + "Volttron Point Name": "bool_state", + "Units": "On / Off", + "Units Details": "off: 0, on: 1", + "Writable": True, + "Starting Value": 3, + "Type": "int", + "Notes": "lights hallway" + }] + + volttron_instance.dynamic_agent.vip.rpc.call(CONFIGURATION_STORE, + "manage_store", + PLATFORM_DRIVER, + registry_config, + json.dumps(registry_obj), + config_type="json") + gevent.sleep(2) + # driver config + driver_config = { + "driver_config": {"ip_address": HOMEASSISTANT_TEST_IP, "access_token": ACCESS_TOKEN, "port": PORT}, + "driver_type": "home_assistant", + "registry_config": f"config://{registry_config}", + "timezone": "US/Pacific", + "interval": 30, + } + + volttron_instance.dynamic_agent.vip.rpc.call(CONFIGURATION_STORE, + "manage_store", + PLATFORM_DRIVER, + HOMEASSISTANT_DEVICE_TOPIC, + json.dumps(driver_config), + config_type="json" + ) + gevent.sleep(2) + + yield platform_driver + + print("Wiping out store.") + volttron_instance.dynamic_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_delete_store", PLATFORM_DRIVER) + gevent.sleep(0.1) + + +@pytest.fixture(scope="module") +def platform_driver(volttron_instance): + # Start the platform driver agent which would in turn start the bacnet driver + platform_uuid = volttron_instance.install_agent( + agent_dir=get_services_core("PlatformDriverAgent"), + config_file={ + "publish_breadth_first_all": False, + "publish_depth_first": False, + "publish_breadth_first": False, + }, + start=True, + ) + gevent.sleep(2) # wait for the agent to start and start the devices + assert volttron_instance.is_agent_running(platform_uuid) + yield platform_uuid + + volttron_instance.stop_agent(platform_uuid) + if not volttron_instance.debug_mode: + volttron_instance.remove_agent(platform_uuid) diff --git a/services/core/PlatformDriverAgent/tests/test_modbus_driver.py b/services/core/PlatformDriverAgent/tests/test_modbus_driver.py index b70491ab6b..41320a1f0a 100644 --- a/services/core/PlatformDriverAgent/tests/test_modbus_driver.py +++ b/services/core/PlatformDriverAgent/tests/test_modbus_driver.py @@ -80,12 +80,12 @@ def agent(request, volttron_instance): # Clean out platform driver configurations # wait for it to return before adding new config md_agent.vip.rpc.call('config.store', - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get() # Add driver configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'devices/modbus', jsonapi.dumps(DRIVER_CONFIG), @@ -93,7 +93,7 @@ def agent(request, volttron_instance): # Add csv configurations md_agent.vip.rpc.call('config.store', - 'manage_store', + 'set_config', PLATFORM_DRIVER, 'modbus.csv', REGISTRY_CONFIG_STRING, diff --git a/services/core/PlatformDriverAgent/tests/test_platform_driver.py b/services/core/PlatformDriverAgent/tests/test_platform_driver.py index 1b7a2ea882..6d329b3e21 100644 --- a/services/core/PlatformDriverAgent/tests/test_platform_driver.py +++ b/services/core/PlatformDriverAgent/tests/test_platform_driver.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import contextlib diff --git a/services/core/PlatformDriverAgent/tests/test_platform_driver_forward_cov.py b/services/core/PlatformDriverAgent/tests/test_platform_driver_forward_cov.py index bf10c871b4..ffe7713f75 100644 --- a/services/core/PlatformDriverAgent/tests/test_platform_driver_forward_cov.py +++ b/services/core/PlatformDriverAgent/tests/test_platform_driver_forward_cov.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging import os diff --git a/services/core/PlatformDriverAgent/tests/test_rest_driver.py b/services/core/PlatformDriverAgent/tests/test_rest_driver.py index f93c4a3cb8..263a147664 100644 --- a/services/core/PlatformDriverAgent/tests/test_rest_driver.py +++ b/services/core/PlatformDriverAgent/tests/test_rest_driver.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest @@ -82,19 +68,19 @@ def agent(request, volttron_instance): capabilities = {'edit_config_store': {'identity': PLATFORM_DRIVER}} volttron_instance.add_capabilities(agent.core.publickey, capabilities) agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_delete_store', + 'delete_store', PLATFORM_DRIVER).get(timeout=10) # Add test configurations. agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', PLATFORM_DRIVER, "devices/campus/building/unit", driver_config_dict_string, "json").get(timeout=10) agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', PLATFORM_DRIVER, "restful.csv", restful_csv_string, diff --git a/services/core/PlatformDriverAgent/tests/test_revert_mixin.py b/services/core/PlatformDriverAgent/tests/test_revert_mixin.py index 2247131d9b..2d57e4b62e 100644 --- a/services/core/PlatformDriverAgent/tests/test_revert_mixin.py +++ b/services/core/PlatformDriverAgent/tests/test_revert_mixin.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest @@ -55,11 +41,11 @@ def test_revert_point(): interface.configure({}, registry_config) value = interface.get_point("Float") assert value == 50.0 - + interface.set_point("Float", 25.0) value = interface.get_point("Float") assert value == 25.0 - + interface.revert_point("Float") value = interface.get_point("Float") assert value == 50.0 @@ -71,11 +57,11 @@ def test_revert_device(): interface.configure({}, registry_config) value = interface.get_point("Float") assert value == 50.0 - + interface.set_point("Float", 25.0) value = interface.get_point("Float") assert value == 25.0 - + interface.revert_all() value = interface.get_point("Float") assert value == 50.0 @@ -86,26 +72,26 @@ def test_revert_point_no_default(): interface = Interface() interface.configure({}, registry_config) initial_value = interface.get_point("FloatNoDefault") - + scrape_values = interface.scrape_all() - + assert scrape_values["FloatNoDefault"] == initial_value - + test_value = initial_value + 1.0 - + interface.set_point("FloatNoDefault", test_value) temp_value = interface.get_point("FloatNoDefault") assert temp_value == test_value - + interface.revert_point("FloatNoDefault") temp_value = interface.get_point("FloatNoDefault") assert temp_value == initial_value - + # Do it twice to make sure it restores state after revert interface.set_point("FloatNoDefault", test_value) temp_value = interface.get_point("FloatNoDefault") assert temp_value == test_value - + interface.revert_point("FloatNoDefault") temp_value = interface.get_point("FloatNoDefault") assert temp_value == initial_value @@ -116,26 +102,26 @@ def test_revert_all_no_default(): interface = Interface() interface.configure({}, registry_config) initial_value = interface.get_point("FloatNoDefault") - + scrape_values = interface.scrape_all() - + assert scrape_values["FloatNoDefault"] == initial_value - + test_value = initial_value + 1.0 - + interface.set_point("FloatNoDefault", test_value) temp_value = interface.get_point("FloatNoDefault") assert temp_value == test_value - + interface.revert_all() temp_value = interface.get_point("FloatNoDefault") assert temp_value == initial_value - + # Do it twice to make sure it restores state after revert interface.set_point("FloatNoDefault", test_value) temp_value = interface.get_point("FloatNoDefault") assert temp_value == test_value - + interface.revert_all() temp_value = interface.get_point("FloatNoDefault") assert temp_value == initial_value @@ -146,36 +132,36 @@ def test_revert_no_default_changing_value(): interface = Interface() interface.configure({}, registry_config) initial_value = interface.get_point("FloatNoDefault") - + # Initialize the revert value. interface.scrape_all() - + new_value = initial_value + 1.0 - + # Manually update the register values to give us something different to revert to. register = interface.get_register_by_name("FloatNoDefault") register.value = new_value - + # Update the revert value. interface.scrape_all() - + test_value = new_value + 1.0 - + interface.set_point("FloatNoDefault", test_value) temp_value = interface.get_point("FloatNoDefault") assert temp_value == test_value - + interface.revert_point("FloatNoDefault") temp_value = interface.get_point("FloatNoDefault") assert temp_value == new_value - + assert temp_value != initial_value - + # Do it twice to make sure it restores state after revert interface.set_point("FloatNoDefault", test_value) temp_value = interface.get_point("FloatNoDefault") assert temp_value == test_value - + interface.revert_point("FloatNoDefault") temp_value = interface.get_point("FloatNoDefault") assert temp_value == new_value diff --git a/services/core/SQLAggregateHistorian/setup.py b/services/core/SQLAggregateHistorian/setup.py index d2a4ab07cd..8bc5b446d1 100644 --- a/services/core/SQLAggregateHistorian/setup.py +++ b/services/core/SQLAggregateHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/SQLAggregateHistorian/sqlaggregator/aggregator.py b/services/core/SQLAggregateHistorian/sqlaggregator/aggregator.py index 52070248c5..204fba44fa 100644 --- a/services/core/SQLAggregateHistorian/sqlaggregator/aggregator.py +++ b/services/core/SQLAggregateHistorian/sqlaggregator/aggregator.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/SQLHistorian/setup.py b/services/core/SQLHistorian/setup.py index 72d5048278..156849db48 100644 --- a/services/core/SQLHistorian/setup.py +++ b/services/core/SQLHistorian/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/SQLHistorian/sqlhistorian/historian.py b/services/core/SQLHistorian/sqlhistorian/historian.py index bd63e2a23c..343fdd3981 100644 --- a/services/core/SQLHistorian/sqlhistorian/historian.py +++ b/services/core/SQLHistorian/sqlhistorian/historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/SQLHistorian/tests/test_sqlitehistorian.py b/services/core/SQLHistorian/tests/test_sqlitehistorian.py index a9b8333396..d8d6ffbada 100644 --- a/services/core/SQLHistorian/tests/test_sqlitehistorian.py +++ b/services/core/SQLHistorian/tests/test_sqlitehistorian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -43,7 +29,7 @@ import gevent import pytest from pytest import approx -from datetime import datetime, timedelta +from datetime import datetime from volttron.platform import get_services_core from volttron.platform.agent import utils @@ -237,7 +223,7 @@ def test_sqlite_timeout(request, publish_agent, volttron_instance, config): assert (len(result['values']) == 1) (now_date, now_time) = now.split("T") assert result['values'][0][0] == now_date + 'T' + now_time + '+00:00' - assert (result['values'][0][1] == approx(oat_reading)) + assert result['values'][0][1] == approx(oat_reading) assert set(result['metadata'].items()) == set(float_meta.items()) except Exception as e: print(e) diff --git a/services/core/SQLiteTaggingService/setup.py b/services/core/SQLiteTaggingService/setup.py index 38d236e876..ef95843d97 100644 --- a/services/core/SQLiteTaggingService/setup.py +++ b/services/core/SQLiteTaggingService/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/SQLiteTaggingService/sqlite/tagging.py b/services/core/SQLiteTaggingService/sqlite/tagging.py index 8e042fedc0..e9c9dd610a 100644 --- a/services/core/SQLiteTaggingService/sqlite/tagging.py +++ b/services/core/SQLiteTaggingService/sqlite/tagging.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -102,7 +88,7 @@ class SQLiteTaggingService(BaseTaggingService): def __init__(self, connection, table_prefix=None, **kwargs): """Initialise the tagging service. - :param connection: dictionary object containing the database + :param connection: dictionary object containing the database connection details :param table_prefix: optional prefix to be used for all tag tables :param kwargs: additional keyword arguments. (optional identity and @@ -328,9 +314,9 @@ def query_categories(self, include_description=False, skip=0, count=None, order="FIRST_TO_LAST"): query = '''SELECT name, description FROM ''' \ - + self.categories_table + ''' - {order_by} - {limit} + + self.categories_table + ''' + {order_by} + {limit} {offset}''' order_by = ' ORDER BY name ASC' if order == 'LAST_TO_FIRST': diff --git a/services/core/VolttronCentral/setup.py b/services/core/VolttronCentral/setup.py index f9da1b0c0c..080a4c0cde 100644 --- a/services/core/VolttronCentral/setup.py +++ b/services/core/VolttronCentral/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/VolttronCentral/tests/test_vc.py b/services/core/VolttronCentral/tests/test_vc.py index 262f89361b..3c58affcfd 100644 --- a/services/core/VolttronCentral/tests/test_vc.py +++ b/services/core/VolttronCentral/tests/test_vc.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from __future__ import annotations from unittest import mock diff --git a/services/core/VolttronCentral/tests/test_vc_autoregister.py b/services/core/VolttronCentral/tests/test_vc_autoregister.py index d50e752ba7..cf0bb838ca 100644 --- a/services/core/VolttronCentral/tests/test_vc_autoregister.py +++ b/services/core/VolttronCentral/tests/test_vc_autoregister.py @@ -32,12 +32,12 @@ def multi_messagebus_vc_vcp(volttron_multi_messagebus): # capabilities = {'edit_config_store': {'identity': VOLTTRON_CENTRAL_PLATFORM}} # vcp_instance.add_capabilities(vcp_instance.dynamic_agent.core.publickey, capabilities) vcp_instance.dynamic_agent.vip.rpc.call(CONFIGURATION_STORE, - "manage_store", + "set_config", VOLTTRON_CENTRAL_PLATFORM, "config", config, "json").get() - # "manage_store", opts.identity, opts.name, file_contents, config_type = opts.config_type + # "set_config", opts.identity, opts.name, file_contents, config_type = opts.config_type # Allows connections between platforms to be established. gevent.sleep(20) yield vcp_instance, vc_instance, vcp_uuid @@ -52,10 +52,10 @@ def test_able_to_register_unregister(multi_messagebus_vc_vcp): vcp_instance, vc_instance, vcp_uuid = multi_messagebus_vc_vcp if vcp_instance.param['sink'] == 'rmq_web' and vcp_instance.param['source'] != 'rmq': pytest.mark.xfail("Combination of rmq<-zmq is not valid") - pytest.fail("Combination of rmq<-zmq is not valid") + pytest.skip("Combination of rmq<-zmq is not valid") elif vcp_instance.param['sink'] == 'zmq_web' and vcp_instance.param['source'] != 'zmq': pytest.mark.xfail("Combination of zmq<-rmq does not work") - pytest.fail("Combination of rmq<-zmq is not valid") + pytest.skip("Combination of zmq<-rmq is not valid") apitester = APITester(vc_instance) diff --git a/services/core/VolttronCentral/tests/vctestutils.py b/services/core/VolttronCentral/tests/vctestutils.py index 7ead874c00..bdff3f9e7d 100644 --- a/services/core/VolttronCentral/tests/vctestutils.py +++ b/services/core/VolttronCentral/tests/vctestutils.py @@ -1,7 +1,5 @@ import requests -from volttron.platform import jsonapi - class APITester: def __init__(self, wrapper, username='admin', password='admin'): diff --git a/services/core/VolttronCentral/volttroncentral/agent.py b/services/core/VolttronCentral/volttroncentral/agent.py index 57123074ca..b995ea33d7 100644 --- a/services/core/VolttronCentral/volttroncentral/agent.py +++ b/services/core/VolttronCentral/volttroncentral/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/services/core/VolttronCentral/volttroncentral/platforms.py b/services/core/VolttronCentral/volttroncentral/platforms.py index 2e4a78d6cb..f0f7ff1004 100644 --- a/services/core/VolttronCentral/volttroncentral/platforms.py +++ b/services/core/VolttronCentral/volttroncentral/platforms.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import base64 @@ -42,17 +28,14 @@ from collections import defaultdict import gevent -from copy import deepcopy from volttron.platform import jsonrpc from volttron.platform.agent.known_identities import VOLTTRON_CENTRAL_PLATFORM from volttron.platform.agent.utils import format_timestamp, get_aware_utc_now, \ get_utc_seconds_from_epoch -from volttron.platform.jsonrpc import INVALID_PARAMS, UNAVAILABLE_PLATFORM, \ - INTERNAL_ERROR, RemoteError +from volttron.platform.jsonrpc import INVALID_PARAMS, INTERNAL_ERROR, RemoteError from volttron.platform.messaging.health import Status, UNKNOWN_STATUS, \ GOOD_STATUS, BAD_STATUS -from volttron.platform.vip.agent import Unreachable from volttron.platform.vip.agent.utils import build_connection from volttron.platform import jsonapi diff --git a/services/core/VolttronCentralPlatform/setup.py b/services/core/VolttronCentralPlatform/setup.py index 43400be0db..e3d8cc730f 100644 --- a/services/core/VolttronCentralPlatform/setup.py +++ b/services/core/VolttronCentralPlatform/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/core/VolttronCentralPlatform/tests/test_platform_agent_rpc.py b/services/core/VolttronCentralPlatform/tests/test_platform_agent_rpc.py index f52594a398..0f4f42d260 100644 --- a/services/core/VolttronCentralPlatform/tests/test_platform_agent_rpc.py +++ b/services/core/VolttronCentralPlatform/tests/test_platform_agent_rpc.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -226,7 +212,7 @@ def test_can_change_topic_map(setup_platform, vc_agent): # now update the config store for vcp vc.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', VOLTTRON_CENTRAL_PLATFORM, 'config', jsonapi.dumps(replace_map), @@ -247,7 +233,7 @@ def test_can_change_topic_map(setup_platform, vc_agent): # now update the config store for vcp vc.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', VOLTTRON_CENTRAL_PLATFORM, 'config', jsonapi.dumps(replace_map), diff --git a/services/core/VolttronCentralPlatform/tests/test_platformagent.py b/services/core/VolttronCentralPlatform/tests/test_platformagent.py index 92a32a196b..e7ea10eafb 100644 --- a/services/core/VolttronCentralPlatform/tests/test_platformagent.py +++ b/services/core/VolttronCentralPlatform/tests/test_platformagent.py @@ -3,7 +3,6 @@ import tempfile import uuid -import gevent import pytest import requests from volttron.platform.agent.known_identities import ( @@ -13,7 +12,6 @@ from volttron.platform.keystore import KeyStore from volttron.platform.messaging.health import STATUS_GOOD from volttron.platform.vip.agent import Agent -from volttron.platform.vip.agent.connection import Connection from volttron.platform.web import DiscoveryInfo from volttrontesting.utils.agent_additions import \ add_volttron_central_platform diff --git a/services/core/VolttronCentralPlatform/vcplatform/agent.py b/services/core/VolttronCentralPlatform/vcplatform/agent.py index 546705913e..2bf2d3b856 100644 --- a/services/core/VolttronCentralPlatform/vcplatform/agent.py +++ b/services/core/VolttronCentralPlatform/vcplatform/agent.py @@ -1,45 +1,30 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import base64 import datetime -import hashlib import logging import os import re @@ -69,7 +54,6 @@ from volttron.platform.agent.utils import (get_aware_utc_now) from volttron.platform.agent.utils import (get_utc_seconds_from_epoch, format_timestamp, normalize_identity) -from volttron.platform.auth.auth_entry import AuthEntry from volttron.platform.auth.auth_file import AuthFile from volttron.platform.jsonrpc import (INTERNAL_ERROR, INVALID_PARAMS) from volttron.platform.messaging import topics @@ -814,21 +798,21 @@ def list_agents(self): def store_agent_config(self, agent_identity, config_name, raw_contents, config_type='raw'): _log.debug("Storeing configuration file: {}".format(config_name)) - self.vip.rpc.call(CONFIGURATION_STORE, "manage_store", agent_identity, + self.vip.rpc.call(CONFIGURATION_STORE, "set_config", agent_identity, config_name, raw_contents, config_type) def list_agent_configs(self, agent_identity): - return self.vip.rpc.call(CONFIGURATION_STORE, "manage_list_configs", + return self.vip.rpc.call(CONFIGURATION_STORE, "list_configs", agent_identity).get(timeout=5) def get_agent_config(self, agent_identity, config_name, raw=True): - data = self.vip.rpc.call(CONFIGURATION_STORE, "manage_get", + data = self.vip.rpc.call(CONFIGURATION_STORE, "get_config", agent_identity, config_name, raw).get( timeout=5) return data or "" def delete_agent_config(self, agent_identity, config_name): - data = self.vip.rpc.call(CONFIGURATION_STORE, "manage_delete_config", + data = self.vip.rpc.call(CONFIGURATION_STORE, "delete_config", agent_identity, config_name).get( timeout=5) return data or "" @@ -909,8 +893,8 @@ def _replace_topic(self, original): def get_renamed_topic(self, input_topic): """ replace topic name based on configured topic replace list, is any - :param input_topic: - :return: + :param input_topic: + :return: """ output_topic = input_topic _log.debug( @@ -979,7 +963,7 @@ def get_devices(self): devices = defaultdict(dict) for platform_driver_id in self._platform_driver_ids: config_list = self.vip.rpc.call(CONFIGURATION_STORE, - 'manage_list_configs', + 'list_configs', platform_driver_id).get(timeout=5) _log.debug('Config list is: {}'.format(config_list)) @@ -989,7 +973,7 @@ def get_devices(self): continue device_config = self.vip.rpc.call(CONFIGURATION_STORE, - 'manage_get', + 'get_config', platform_driver_id, cfg_name, raw=False).get(timeout=5) @@ -1001,7 +985,7 @@ def get_devices(self): reg_cfg_name )) registry_config = self.vip.rpc.call(CONFIGURATION_STORE, - 'manage_get', + 'get_config', platform_driver_id, reg_cfg_name, raw=False).get(timeout=5) diff --git a/services/core/VolttronCentralPlatform/vcplatform/vcconnection.py b/services/core/VolttronCentralPlatform/vcplatform/vcconnection.py index 3a18955c10..0583bf6bef 100644 --- a/services/core/VolttronCentralPlatform/vcplatform/vcconnection.py +++ b/services/core/VolttronCentralPlatform/vcplatform/vcconnection.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/WeatherDotGov/setup.py b/services/core/WeatherDotGov/setup.py index fa3c80d063..5090c7c75d 100644 --- a/services/core/WeatherDotGov/setup.py +++ b/services/core/WeatherDotGov/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/core/WeatherDotGov/tests/test_weatherdotgov.py b/services/core/WeatherDotGov/tests/test_weatherdotgov.py index 9e7258a35e..6b243ffaf7 100644 --- a/services/core/WeatherDotGov/tests/test_weatherdotgov.py +++ b/services/core/WeatherDotGov/tests/test_weatherdotgov.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os diff --git a/services/core/WeatherDotGov/weatherdotgov/agent.py b/services/core/WeatherDotGov/weatherdotgov/agent.py index d309b88bbd..705295342d 100644 --- a/services/core/WeatherDotGov/weatherdotgov/agent.py +++ b/services/core/WeatherDotGov/weatherdotgov/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} __docformat__ = 'reStructuredText' @@ -43,7 +29,7 @@ import sys import grequests import datetime -import pkg_resources +from importlib.resources import files as get_resource_files from volttron.platform.agent.base_weather import BaseWeatherAgent from volttron.platform.agent import utils from volttron.utils.docs import doc_inherit @@ -52,7 +38,6 @@ # requests should be imported after grequests # as grequests monkey patches ssl and requests imports ssl -# TODO do we need the requests at all.. TODO test with RMQ import requests __version__ = "2.0.0" @@ -121,7 +106,7 @@ def get_point_name_defs_file(self): """ # returning resource file instead of stream, as csv.DictReader require file path or file like object opened in # text mode. - return pkg_resources.get_resource_filename(__name__, "data/name_mapping.csv") + return str(get_resource_files("weatherdotgov").joinpath("data/name_mapping.csv")) def get_location_string(self, location): """ @@ -382,13 +367,11 @@ def get_forecast_url(self, location): return url def make_web_request(self, url): - grequest = [grequests.get(url, verify=requests.certs.where(), - headers=self.headers, timeout=3)] - gresponse = grequests.map(grequest)[0] - if gresponse is None: + response = requests.get(url, headers=self.headers, verify=requests.certs.where()) + if response is None: raise RuntimeError("get request did not return any " "response") - return gresponse + return response def extract_forecast_data(self, url, gresponse): try: diff --git a/services/ops/AgentWatcher/setup.py b/services/ops/AgentWatcher/setup.py index cc64769bff..5284d29efb 100644 --- a/services/ops/AgentWatcher/setup.py +++ b/services/ops/AgentWatcher/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/ops/AgentWatcher/tests/test_agent_watcher.py b/services/ops/AgentWatcher/tests/test_agent_watcher.py index daa4c3cb36..fea3350585 100644 --- a/services/ops/AgentWatcher/tests/test_agent_watcher.py +++ b/services/ops/AgentWatcher/tests/test_agent_watcher.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os diff --git a/services/ops/AgentWatcher/watcher/agent.py b/services/ops/AgentWatcher/watcher/agent.py index e9675ff5ab..5503f249f0 100644 --- a/services/ops/AgentWatcher/watcher/agent.py +++ b/services/ops/AgentWatcher/watcher/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/services/ops/EmailerAgent/emailer/agent.py b/services/ops/EmailerAgent/emailer/agent.py index 6dab6ef69c..00cdef0b14 100644 --- a/services/ops/EmailerAgent/emailer/agent.py +++ b/services/ops/EmailerAgent/emailer/agent.py @@ -1,45 +1,28 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} - -from collections import defaultdict - # Import the email modules we'll need from email.mime.text import MIMEText import logging @@ -51,7 +34,7 @@ import gevent from volttron.platform.agent.utils import get_utc_seconds_from_epoch -from volttron.platform.vip.agent import Agent, Core, PubSub, compat +from volttron.platform.vip.agent import Agent, PubSub, compat from volttron.platform.agent import utils from volttron.platform.messaging import topics from volttron.platform.messaging.health import ALERT_KEY, STATUS_BAD, Status, \ @@ -117,7 +100,7 @@ def __init__(self, config_path, **kwargs): self.vip.config.subscribe(self.configure_main, actions=["NEW", "UPDATE"], pattern="*") - + # Keep track of keys that have been added to send with. self.tosend = {} # Keep track of how often we send an email out based on key so we don't overload admins. @@ -390,5 +373,3 @@ def main(argv=sys.argv): sys.exit(main()) except KeyboardInterrupt: pass - - diff --git a/services/ops/EmailerAgent/setup.py b/services/ops/EmailerAgent/setup.py index c309604c50..298accfcfe 100644 --- a/services/ops/EmailerAgent/setup.py +++ b/services/ops/EmailerAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from setuptools import setup, find_packages diff --git a/services/ops/FileWatchPublisher/Tests/test_file_watcher.py b/services/ops/FileWatchPublisher/Tests/test_file_watcher.py index 2e309c902f..713ee595ca 100644 --- a/services/ops/FileWatchPublisher/Tests/test_file_watcher.py +++ b/services/ops/FileWatchPublisher/Tests/test_file_watcher.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os diff --git a/services/ops/FileWatchPublisher/filewatchpublisher/agent.py b/services/ops/FileWatchPublisher/filewatchpublisher/agent.py index ef990f53b4..a7c4e9b2db 100644 --- a/services/ops/FileWatchPublisher/filewatchpublisher/agent.py +++ b/services/ops/FileWatchPublisher/filewatchpublisher/agent.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} diff --git a/services/ops/FileWatchPublisher/setup.py b/services/ops/FileWatchPublisher/setup.py index 8567648200..e0cb315c61 100644 --- a/services/ops/FileWatchPublisher/setup.py +++ b/services/ops/FileWatchPublisher/setup.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} diff --git a/services/ops/LogStatisticsAgent/Tests/test_log_statistics.py b/services/ops/LogStatisticsAgent/Tests/test_log_statistics.py index 284cbd58c2..786726819c 100644 --- a/services/ops/LogStatisticsAgent/Tests/test_log_statistics.py +++ b/services/ops/LogStatisticsAgent/Tests/test_log_statistics.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -43,7 +29,7 @@ from volttron.platform.messaging.health import STATUS_GOOD from volttron.platform.vip.agent import Agent -from volttron.platform import get_ops, get_home +from volttron.platform import get_ops test_config = { "analysis_interval_sec": 2, diff --git a/services/ops/LogStatisticsAgent/logstatisticsagent/agent.py b/services/ops/LogStatisticsAgent/logstatisticsagent/agent.py index 71e45913a1..0a624ea1d3 100644 --- a/services/ops/LogStatisticsAgent/logstatisticsagent/agent.py +++ b/services/ops/LogStatisticsAgent/logstatisticsagent/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import datetime @@ -42,7 +28,7 @@ import sys import statistics -from volttron.platform.vip.agent import Agent, RPC, Core +from volttron.platform.vip.agent import Agent, Core from volttron.platform.agent import utils from volttron.platform.agent.utils import get_aware_utc_now diff --git a/services/ops/LogStatisticsAgent/setup.py b/services/ops/LogStatisticsAgent/setup.py index 17c11f1f2e..0836e431a9 100644 --- a/services/ops/LogStatisticsAgent/setup.py +++ b/services/ops/LogStatisticsAgent/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from setuptools import setup, find_packages diff --git a/services/ops/SysMonAgent/setup.py b/services/ops/SysMonAgent/setup.py index 8567648200..e0cb315c61 100644 --- a/services/ops/SysMonAgent/setup.py +++ b/services/ops/SysMonAgent/setup.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} diff --git a/services/ops/SysMonAgent/sysmon/agent.py b/services/ops/SysMonAgent/sysmon/agent.py index f5b7e59f4e..dcd391bcf7 100644 --- a/services/ops/SysMonAgent/sysmon/agent.py +++ b/services/ops/SysMonAgent/sysmon/agent.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} diff --git a/services/ops/SysMonAgent/tests/test_sysmonagent.py b/services/ops/SysMonAgent/tests/test_sysmonagent.py index 8cc07cf5f0..87611dfed5 100644 --- a/services/ops/SysMonAgent/tests/test_sysmonagent.py +++ b/services/ops/SysMonAgent/tests/test_sysmonagent.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} diff --git a/services/ops/ThresholdDetectionAgent/setup.py b/services/ops/ThresholdDetectionAgent/setup.py index 8567648200..e0cb315c61 100644 --- a/services/ops/ThresholdDetectionAgent/setup.py +++ b/services/ops/ThresholdDetectionAgent/setup.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} diff --git a/services/ops/ThresholdDetectionAgent/tests/test_threshold_agent.py b/services/ops/ThresholdDetectionAgent/tests/test_threshold_agent.py index eb2816706e..62e1c75a63 100644 --- a/services/ops/ThresholdDetectionAgent/tests/test_threshold_agent.py +++ b/services/ops/ThresholdDetectionAgent/tests/test_threshold_agent.py @@ -2,47 +2,32 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2017, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== # }}} #}}} import logging import sys -import uuid import unittest import mock from mock import Mock @@ -91,7 +76,7 @@ def test_alert_low(self): def main(argv=sys.argv): agent = ThresholdDetectionAgent() - + if __name__ == '__main__': # Entry point for script diff --git a/services/ops/ThresholdDetectionAgent/tests/test_threshold_detection.py b/services/ops/ThresholdDetectionAgent/tests/test_threshold_detection.py index ec99ac41df..0574cafcfc 100644 --- a/services/ops/ThresholdDetectionAgent/tests/test_threshold_detection.py +++ b/services/ops/ThresholdDetectionAgent/tests/test_threshold_detection.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -109,7 +95,7 @@ def clear_keys(self): def reset_store(self): self.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', 'platform.thresholddetection', 'config', jsonapi.dumps(_test_config), @@ -137,7 +123,7 @@ def threshold_tester_agent(volttron_instance): agent.reset_store() # agent.vip.rpc.call(CONFIGURATION_STORE, - # 'manage_store', + # 'set_config', # 'platform.thresholddetection', # 'config', # jsonapi.dumps(_test_config), @@ -146,7 +132,7 @@ def threshold_tester_agent(volttron_instance): yield agent agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_delete_store', + 'delete_store', 'platform.thresholddetection').get() volttron_instance.remove_agent(threshold_detection_uuid) @@ -211,7 +197,7 @@ def test_update_config(threshold_tester_agent): # threshold_tester_agent.vip.pubsub.publish('pubsub', topic="alerts/woot", headers={"foo": "bar"}) # threshold_tester_agent.vip .config.set('config', updated_config, True) threshold_tester_agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', 'platform.thresholddetection', 'config', jsonapi.dumps(updated_config), @@ -254,7 +240,7 @@ def test_device_publish(threshold_tester_agent): def test_remove_from_config_store(threshold_tester_agent): threshold_tester_agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_delete_config', + 'delete_config', 'platform.thresholddetection', 'config').get() publish(threshold_tester_agent, _test_config, lambda x: x+1) diff --git a/services/ops/ThresholdDetectionAgent/thresholddetection/agent.py b/services/ops/ThresholdDetectionAgent/thresholddetection/agent.py index d7f4dd0def..65847d5296 100644 --- a/services/ops/ThresholdDetectionAgent/thresholddetection/agent.py +++ b/services/ops/ThresholdDetectionAgent/thresholddetection/agent.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} @@ -239,7 +225,7 @@ def _alert(self, topic, threshold, data, point=''): def main(argv=sys.argv): """Main method called by the platform.""" utils.vip_main(thresholddetection_agent, - identity='platform.thresholddetection', + identity='platform.thresholddetection', version=__version__) diff --git a/services/ops/TopicWatcher/setup.py b/services/ops/TopicWatcher/setup.py index cc64769bff..5284d29efb 100644 --- a/services/ops/TopicWatcher/setup.py +++ b/services/ops/TopicWatcher/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from os import path diff --git a/services/ops/TopicWatcher/tests/test_remote_topic_watcher.py b/services/ops/TopicWatcher/tests/test_remote_topic_watcher.py index 1dcb30e142..eb2b5cdb35 100644 --- a/services/ops/TopicWatcher/tests/test_remote_topic_watcher.py +++ b/services/ops/TopicWatcher/tests/test_remote_topic_watcher.py @@ -1,40 +1,26 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/services/ops/TopicWatcher/tests/test_topic_watcher.py b/services/ops/TopicWatcher/tests/test_topic_watcher.py index 51dd500fc5..a38125161e 100644 --- a/services/ops/TopicWatcher/tests/test_topic_watcher.py +++ b/services/ops/TopicWatcher/tests/test_topic_watcher.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -135,7 +121,7 @@ def test_basic(agent): """ global alert_messages, db_connection publish_time = get_aware_utc_now() - print (f"publish time is {publish_time}") + print(f"publish time is {publish_time}") for _ in range(5): alert_messages.clear() agent.vip.pubsub.publish(peer='pubsub', @@ -533,5 +519,3 @@ def test_for_duplicate_logs(volttron_instance, agent, cleanup_db): assert r[1] is None naive_timestamp = publish_time.replace(tzinfo=None) assert r[2] >= naive_timestamp - - diff --git a/services/ops/TopicWatcher/topic_watcher/agent.py b/services/ops/TopicWatcher/topic_watcher/agent.py index 697c603f8c..2022282f7e 100644 --- a/services/ops/TopicWatcher/topic_watcher/agent.py +++ b/services/ops/TopicWatcher/topic_watcher/agent.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/services/unsupported/OpenADRVenAgent/openadrven/agent.py b/services/unsupported/OpenADRVenAgent/openadrven/agent.py new file mode 100644 index 0000000000..6b22494c9a --- /dev/null +++ b/services/unsupported/OpenADRVenAgent/openadrven/agent.py @@ -0,0 +1,1752 @@ +# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} + + + +from collections import namedtuple +from datetime import datetime as dt +from datetime import timedelta +from dateutil import parser +import gevent +# OpenADR rule 1: use ISO8601 timestamp +import logging +import lxml.etree as etree_ +import os +import random +import requests +from requests.exceptions import ConnectionError +import signxml +import io +import sys + +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from volttron.platform.agent import utils +# OpenADR rule 1: use ISO8601 timestamp +from volttron.platform.agent.utils import format_timestamp +from volttron.platform.messaging import topics, headers +from volttron.platform.vip.agent import Agent, Core, RPC +from volttron.platform.scheduling import periodic +from volttron.platform import jsonapi + +from .oadr_builder import * +from .oadr_extractor import * +from .oadr_20b import parseString, oadrSignedObject +from .oadr_common import * +from .models import ORMBase +from .models import EiEvent, EiReport, EiTelemetryValues + +utils.setup_logging() +_log = logging.getLogger(__name__) + +__version__ = '1.0' + +ENDPOINT_BASE = '/OpenADR2/Simple/2.0b/' +EIEVENT = ENDPOINT_BASE + 'EiEvent' +EIREPORT = ENDPOINT_BASE + 'EiReport' +EIREGISTERPARTY = ENDPOINT_BASE + 'EiRegisterParty' +POLL = ENDPOINT_BASE + 'OadrPoll' + +Endpoint = namedtuple('Endpoint', ['url', 'callback']) +OPENADR_ENDPOINTS = { + 'EiEvent': Endpoint(url=EIEVENT, callback='push_request'), + 'EiReport': Endpoint(url=EIREPORT, callback='push_request'), + 'EiRegisterParty': Endpoint(url=EIREGISTERPARTY, callback='push_request')} + +VTN_REQUESTS = { + 'oadrDistributeEvent': 'handle_oadr_distribute_event', + 'oadrRegisterReport': 'handle_oadr_register_report', + 'oadrRegisteredReport': 'handle_oadr_registered_report', + 'oadrCreateReport': 'handle_oadr_create_report', + 'oadrUpdatedReport': 'handle_oadr_updated_report', + 'oadrCancelReport': 'handle_oadr_cancel_report', + 'oadrResponse': 'handle_oadr_response', + 'oadrCreatedPartyRegistration': 'handle_oadr_created_party_registration'} + +PROCESS_LOOP_FREQUENCY_SECS = 5 +DEFAULT_REPORT_INTERVAL_SECS = 15 +DEFAULT_OPT_IN_TIMEOUT_SECS = 30 * 60 # If no optIn timeout was configured, use 30 minutes. + +# These parameters control behavior that is sometimes temporarily disabled during software development. +USE_REPORTS = True +SEND_POLL = True + +# Paths to sample X509 certificates, generated by Kyrio. These are needed when security_level = 'high'. +CERTS_DIRECTORY = '$VOLTTRON_ROOT/services/core/OpenADRVenAgent/certs/' +CERT_FILENAME = CERTS_DIRECTORY + 'TEST_RSA_VEN_171024145702_cert.pem' +KEY_FILENAME = CERTS_DIRECTORY + 'TEST_RSA_VEN_171024145702_privkey.pem' +VTN_CA_CERT_FILENAME = CERTS_DIRECTORY + 'TEST_OpenADR_RSA_BOTH0002_Cert.pem' + + +def ven_agent(config_path, **kwargs): + """ + Parse the OpenADRVenAgent configuration file and return an instance of + the agent that has been created using that configuration. + + See initialize_config() method documentation for a description of each configurable parameter. + + :param config_path: (str) Path to a configuration file. + :returns: OpenADRVenAgent instance + """ + try: + config = utils.load_config(config_path) + except Exception as err: + _log.error("Error loading configuration: {}".format(err)) + config = {} + db_path = config.get('db_path') + ven_id = config.get('ven_id') + ven_name = config.get('ven_name') + vtn_id = config.get('vtn_id') + vtn_address = config.get('vtn_address') + send_registration = config.get('send_registration') + security_level = config.get('security_level') + poll_interval_secs = config.get('poll_interval_secs') + log_xml = config.get('log_xml') + opt_in_timeout_secs = config.get('opt_in_timeout_secs') + opt_in_default_decision = config.get('opt_in_default_decision') + request_events_on_startup = config.get('request_events_on_startup') + report_parameters = config.get('report_parameters') + return OpenADRVenAgent(db_path, ven_id, ven_name, vtn_id, vtn_address, send_registration, security_level, + poll_interval_secs, log_xml, opt_in_timeout_secs, opt_in_default_decision, + request_events_on_startup, report_parameters, **kwargs) + + +class OpenADRVenAgent(Agent): + """ + OpenADR (Automated Demand Response) is a standard for alerting and responding + to the need to adjust electric power consumption in response to fluctuations + in grid demand. + + For further information about OpenADR and this agent, please see + the OpenADR documentation in VOLTTRON ReadTheDocs. + + OpenADR communications are conducted between Virtual Top Nodes (VTNs) and Virtual End Nodes (VENs). + In this implementation, a VOLTTRON agent is a VEN, implementing EiEvent and EiReport services + in conformance with a subset of the OpenADR 2.0b specification. + + The VEN receives VTN requests via the VOLTTRON web service. + + The VTN can 'call an event', indicating that a load-shed event should occur. + The VEN responds with an 'optIn' acknowledgment. + + In conjunction with an event (or independent of events), the VEN reports device status + and usage telemetry, relying on data received periodically from other VOLTTRON agents. + + Events: + The VEN agent maintains a persistent record of DR events. + Event updates (including creation) trigger publication of event JSON on the VOLTTRON message bus. + Other VOLTTRON agents can also call a get_events() RPC to retrieve the current status + of particular events, or of all active events. + + Reporting: + The VEN agent configuration defines telemetry values (data points) to be reported to the VTN. + The VEN agent maintains a persistent record of reportable/reported telemetry values over time. + Other VOLTTRON agents are expected to call a report_telemetry() RPC to supply the VEN agent + with a regular stream of telemetry values for reporting. + Other VOLTTRON agents can receive notification of changes in telemetry reporting requirements + by subscribing to publication of telemetry parameters. + + Pub/Sub (see method documentation): + publish_event() + publish_telemetry_parameters_for_report() + + RPC calls (see method documentation): + respond_to_event(event_id, opt_in=True): + get_events(in_progress_only=True, started_after=None, end_time_before=None) + get_telemetry_parameters() + set_telemetry_status(online, manual_override) + report_telemetry(telemetry_values) + + Supported requests/responses in the OpenADR VTN interface: + VTN: + oadrDistributeEvent (needed for event cancellation) + oadrResponse + oadrRegisteredReport + oadrCreateReport + oadrUpdatedReport + oadrCancelReport + oadrCreatedPartyRegistration + VEN: + oadrPoll + oadrRequestEvent + oadrCreatedEvent + oadrResponse + oadrRegisterReport + oadrCreatedReport + oadrUpdateReport + oadrCanceledReport + oadrCreatePartyRegistration + oadrQueryRegistration + """ + + _db_session = None + _last_poll = None + _active_events = {} + _active_reports = {} + + def __init__(self, db_path, ven_id, ven_name, vtn_id, vtn_address, send_registration, security_level, + poll_interval_secs, log_xml, opt_in_timeout_secs, opt_in_default_decision, + request_events_on_startup, report_parameters, + **kwargs): + super(OpenADRVenAgent, self).__init__(enable_web=True, **kwargs) + + self.db_path = None + self.ven_id = None + self.ven_name = None + self.vtn_id = None + self.vtn_address = None + self.send_registration = False + self.security_level = None + self.poll_interval_secs = None + self.log_xml = True + self.opt_in_timeout_secs = None + self.opt_in_default_decision = 'optIn' + self.request_events_on_startup = None + self.report_parameters = {} + self.default_config = {"db_path": db_path, + "ven_id": ven_id, + "ven_name": ven_name, + "vtn_id": vtn_id, + "vtn_address": vtn_address, + "send_registration": send_registration, + "security_level": security_level, + "poll_interval_secs": poll_interval_secs, + "log_xml": log_xml, + "opt_in_timeout_secs": opt_in_timeout_secs, + "opt_in_default_decision": opt_in_default_decision, + "request_events_on_startup": request_events_on_startup, + "report_parameters": report_parameters} + self.vip.config.set_default("config", self.default_config) + self.vip.config.subscribe(self._configure, actions=["NEW", "UPDATE"], pattern="config") + self.initialize_config(self.default_config) + # State variables for VTN request/response processing + self.oadr_current_service = None + self.oadr_current_request_id = None + # The following parameters can be adjusted by issuing a set_telemetry_status() RPC call. + self.ven_online = 'false' + self.ven_manual_override = 'false' + + def _configure(self, config_name, action, contents): + """The agent's config may have changed. Re-initialize it.""" + config = self.default_config.copy() + config.update(contents) + self.initialize_config(config) + + def initialize_config(self, config): + """ + Initialize the agent's configuration. + + Configuration parameters (see config for a sample config file): + + db_path: Pathname of the agent's sqlite database. + ~ and shell variables will be expanded if present. + ven_id: (string) OpenADR ID of this virtual end node. Identifies this VEN to the VTN. + ven_name: Name of this virtual end node. Identifies this VEN during registration, + before its ID is known. + vtn_id: (string) OpenADR ID of the VTN with which this VEN communicates. + vtn_address: URL and port number of the VTN. + send_registration: ('True' or 'False') If 'True', send a one-time registration request to the VTN, + obtaining the VEN ID. The agent should be run in this mode initially, + then shut down and run with this parameter set to 'False' thereafter. + security_level: If 'high', the VTN and VEN use a third-party signing authority to sign + and authenticate each request. + Default is 'standard' (XML payloads do not contain Signature elements). + poll_interval_secs: (integer) How often the VEN should send an OadrPoll to the VTN. + log_xml: ('True' or 'False') Whether to write inbound/outbound XML to the agent's log. + opt_in_timeout_secs: (integer) How long to wait before making a default optIn/optOut decision. + opt_in_default_decision: ('True' or 'False') What optIn/optOut choice to make by default. + request_events_on_startup: ('True' or 'False') Whether to send oadrRequestEvent to the VTN on startup. + report_parameters: A dictionary of definitions of reporting/telemetry parameters. + """ + _log.debug("Configuring agent") + self.db_path = config.get('db_path') + self.ven_id = config.get('ven_id') + self.ven_name = config.get('ven_name') + self.vtn_id = config.get('vtn_id') + self.vtn_address = config.get('vtn_address') + self.send_registration = (config.get('send_registration') == 'True') + self.security_level = config.get('security_level') + self.log_xml = (config.get('log_xml') != 'False') + opt_in_timeout = config.get('opt_in_timeout_secs') + self.opt_in_timeout_secs = int(opt_in_timeout if opt_in_timeout else DEFAULT_OPT_IN_TIMEOUT_SECS) + self.opt_in_default_decision = config.get('opt_in_default_decision') + loop_frequency = config.get('poll_interval_secs') + self.poll_interval_secs = int(loop_frequency if loop_frequency else PROCESS_LOOP_FREQUENCY_SECS) + self.request_events_on_startup = (config.get('request_events_on_startup') == 'True') + self.report_parameters = config.get('report_parameters') + + # Validate and adjust the configuration parameters. + if type(self.db_path) == str: + self.db_path = os.path.expanduser(self.db_path) + self.db_path = os.path.expandvars(self.db_path) + try: + self.opt_in_timeout_secs = int(self.opt_in_timeout_secs) + except ValueError: + # If opt_in_timeout_secs was not supplied or was not an integer, default to a 10-minute timeout. + self.opt_in_timeout_secs = 600 + + if self.poll_interval_secs < PROCESS_LOOP_FREQUENCY_SECS: + _log.warning('Poll interval is too frequent: resetting it to {}'.format(PROCESS_LOOP_FREQUENCY_SECS)) + self.poll_interval_secs = PROCESS_LOOP_FREQUENCY_SECS + + _log.info('Configuration parameters:') + _log.info('\tDatabase = {}'.format(self.db_path)) + _log.info('\tVEN ID = {}'.format(self.ven_id)) + _log.info('\tVEN name = {}'.format(self.ven_name)) + _log.info('\tVTN ID = {}'.format(self.vtn_id)) + _log.info('\tVTN address = {}'.format(self.vtn_address)) + _log.info('\tSend registration = {}'.format(self.send_registration)) + _log.info('\tSecurity level = {}'.format(self.security_level)) + _log.info('\tPoll interval = {} seconds'.format(self.poll_interval_secs)) + _log.info('\tLog XML = {}'.format(self.log_xml)) + _log.info('\toptIn timeout (secs) = {}'.format(self.opt_in_timeout_secs)) + _log.info('\toptIn default decision = {}'.format(self.opt_in_default_decision)) + _log.info('\tRequest events on startup = {}'.format(self.request_events_on_startup)) + _log.info("\treport parameters = {}".format(self.report_parameters)) + + @Core.receiver('onstart') + def onstart_method(self, sender): + """The agent has started. Perform initialization and spawn the main process loop.""" + _log.debug('Starting agent') + + self.register_endpoints() + + if self.send_registration: + # VEN registration with the VTN server. + # Register the VEN, obtaining the VEN ID. This is a one-time action. + self.send_oadr_create_party_registration() + else: + # Schedule an hourly database-cleanup task. + self.core.schedule(periodic(60 * 60), self.telemetry_cleanup) + + # Populate the caches with all of the database's events and reports that are active. + for event in self._get_events(): + _log.debug('Re-caching event with ID {}'.format(event.event_id)) + self._active_events[event.event_id] = event + for report in self._get_reports(): + _log.debug('Re-caching report with ID {}'.format(report.report_request_id)) + self._active_reports[report.report_request_id] = report + + try: + if self.request_events_on_startup: + # After a restart, the VEN asks the VTN for the status of all current events. + # When this is sent to the EPRI VTN server, it returns a 500 and logs a "method missing" traceback. + self.send_oadr_request_event() + + if USE_REPORTS: + # Send an initial report-registration request to the VTN. + self.send_oadr_register_report() + except Exception as err: + _log.error('Error in agent startup: {}'.format(err), exc_info=True) + self.core.schedule(periodic(PROCESS_LOOP_FREQUENCY_SECS), self.main_process_loop) + + def main_process_loop(self): + """ + gevent thread. Perform periodic tasks, executing them serially. + + Periodic tasks include: + Poll the VTN server. + Perform event-management tasks: + Force an optIn/optOut decision if too much time has elapsed. + Transition event state when appropriate. + Expire events that have become completed or canceled. + Perform report-management tasks: + Send telemetry to the VTN for any active report. + Transition report state when appropriate. + Expire reports that have become completed or canceled. + + This is intended to be a long-running gevent greenlet -- it should never crash. + If exceptions occur, they are logged, but no process failure occurs. + """ + try: + # If it's been poll_interval_secs since the last poll request, issue a new one. + if self._last_poll is None or \ + ((utils.get_aware_utc_now() - self._last_poll).total_seconds() > self.poll_interval_secs): + if SEND_POLL: + self.send_oadr_poll() + + for event in self.active_events(): + self.process_event(event) + + if USE_REPORTS: + for report in self.active_reports(): + self.process_report(report) + + except Exception as err: + _log.error('Error in main process loop: {}'.format(err), exc_info=True) + + def process_event(self, evt): + """ + Perform periodic maintenance for an event that's in the cache. + + Transition its state when appropriate. + Expire it from the cache if it has become completed or canceled. + + @param evt: An EiEvent instance. + """ + now = utils.get_aware_utc_now() + if evt.is_active(): + if evt.end_time is not None and now > evt.end_time: + _log.debug('Setting event {} to status {}'.format(evt.event_id, evt.STATUS_COMPLETED)) + self.set_event_status(evt, evt.STATUS_COMPLETED) + self.publish_event(evt) + else: + if evt.status == evt.STATUS_ACTIVE: + # It's an active event. Which is fine; nothing special needs to be done here. + pass + else: + if now > evt.start_time and evt.opt_type == evt.OPT_TYPE_OPT_IN: + _log.debug('Setting event {} to status {}'.format(evt.event_id, evt.STATUS_ACTIVE)) + self.set_event_status(evt, evt.STATUS_ACTIVE) + self.publish_event(evt) + else: + # Expire events from the cache if they're completed or canceled. + _log.debug('Expiring event {}'.format(evt.event_id)) + self.expire_event(evt) + + def process_report(self, rpt): + """ + Perform periodic maintenance for a report that's in the cache. + + Send telemetry to the VTN if the report is active. + Transition its state when appropriate. + Expire it from the cache if it has become completed or canceled. + + @param rpt: An EiReport instance. + """ + if rpt.is_active(): + now = utils.get_aware_utc_now() + if rpt.status == rpt.STATUS_ACTIVE: + if rpt.end_time is None or rpt.end_time > now: + rpt_interval = rpt.interval_secs if rpt.interval_secs is not None else DEFAULT_REPORT_INTERVAL_SECS + next_report_time = rpt.last_report + timedelta(seconds=rpt_interval) + if utils.get_aware_utc_now() > next_report_time: + # Possible enhancement: Use a periodic gevent instead of a timeout? + self.send_oadr_update_report(rpt) + if rpt_interval == 0: + # OADR rule 324: If rpt_interval == 0 it's a one-time report, so set status to COMPLETED. + rpt.status = rpt.STATUS_COMPLETED + self.commit() + else: + _log.debug('Setting report {} to status {}'.format(rpt.report_request_id, rpt.STATUS_COMPLETED)) + self.set_report_status(rpt, rpt.STATUS_COMPLETED) + self.publish_telemetry_parameters_for_report(rpt) + else: + if rpt.start_time < now and (rpt.end_time is None or now < rpt.end_time): + _log.debug('Setting report {} to status {}'.format(rpt.report_request_id, rpt.STATUS_ACTIVE)) + self.set_report_status(rpt, rpt.STATUS_ACTIVE) + self.publish_telemetry_parameters_for_report(rpt) + else: + # Expire reports from the cache if they're completed or canceled. + _log.debug('Expiring report {} from cache'.format(rpt.report_request_id)) + self.expire_event(rpt) + + def force_opt_type_decision(self, event_id): + """ + Force an optIn/optOut default decision if lots of time has elapsed with no decision from the control agent. + + Scheduled gevent thread, kicked off when an event is first published. + The default choice comes from "opt_in_default_decision" in the agent config. + + @param event_id: (String) ID of the event for which a decision will be made. + """ + event = self.get_event_for_id(event_id) + if event and event.is_active() and event.opt_type not in [EiEvent.OPT_TYPE_OPT_IN, + EiEvent.OPT_TYPE_OPT_OUT]: + event.opt_type = self.opt_in_default_decision + self.commit() + _log.info('Forcing an {} decision for event {}'.format(event.opt_type, event.event_id)) + if event.status == event.STATUS_ACTIVE: + # Odd exception scenario: If the event was already active, roll its status back to STATUS_FAR. + self.set_event_status(event, event.STATUS_FAR) + self.publish_event(event) # Tell the volttron message bus. + self.send_oadr_created_event(event) # Tell the VTN. + + # ***************** Methods for Servicing VTN Requests ******************** + + def push_request(self, env, request): + """Callback. The VTN pushed an http request. Service it.""" + _log.debug('Servicing a VTN push request') + self.core.spawn(self.service_vtn_request, request) + # Return an empty response. + return [HTTP_STATUS_CODES[204], '', [("Content-Length", "0")]] + + def service_vtn_request(self, request): + """ + An HTTP request/response was received. Handle it. + + Event workflow (see OpenADR Profile Specification section 8.1)... + + Event poll / creation: + (VEN) oadrPoll + (VTN) oadrDistributeEvent (all events are included; one oadrEvent element per event) + (VEN) oadrCreatedEvent with optIn/optOut (if events had oadrResponseRequired) + If "always", an oadrCreatedEvent must be sent for each event. + If "never", it was a "broadcast" event -- never create an event in response. + Otherwise, respond if event state (eventID, modificationNumber) has changed. + (VTN) oadrResponse + + Event change: + (VEN) oadrCreatedEvent (sent if the optIn/optOut status has changed) + (VTN) oadrResponse + + Sample oadrDistributeEvent use case from the OpenADR Program Guide: + + Event: + Notification: Day before event + Start Time: midnight + Duration: 24 hours + Randomization: None + Ramp Up: None + Recovery: None + Number of signals: 2 + Signal Name: simple + Signal Type: level + Units: LevN/A + Number of intervals: equal TOU Tier change in 24 hours (2 - 6) + Interval Duration(s): TOU tier active time frame (i.e. 6 hours) + Typical Interval Value(s): 0 - 4 mapped to TOU Tiers (0 - Cheapest Tier) + Signal Target: None + Signal Name: ELECTRICITY_PRICE + Signal Type: price + Units: USD per Kwh + Number of intervals: equal TOU Tier changes in 24 hours (2 - 6) + Interval Duration(s): TOU tier active time frame (i.e. 6 hours) + Typical Interval Value(s): $0.10 to $1.00 (current tier rate) + Signal Target: None + Event Targets: venID_1234 + Priority: 1 + VEN Response Required: always + VEN Expected Response: optIn + Reports: + None + + Report workflow (see OpenADR Profile Specification section 8.3)... + + Report registration interaction: + (VEN) oadrRegisterReport (METADATA report) + VEN sends its reporting capabilities to VTN. + Each report, identified by a reportSpecifierID, is described as elements and attributes. + (VTN) oadrRegisteredReport (with optional oadrReportRequests) + VTN acknowledges that capabilities have been registered. + VTN optionally requests one or more reports by reportSpecifierID. + Even if reports were previously requested, they should be requested again at this point. + (VEN) oadrCreatedReport (if report requested) + VEN acknowledges that it has received the report request and is generating the report. + If any reports were pending delivery, they are included in the payload. + (VTN) oadrResponse + Why?? + + Report creation interaction: + (VTN) oadrCreateReport + See above - this is like the "request" portion of oadrRegisteredReport + (VEN) oadrCreatedReport + See above. + + Report update interaction - this is the actual report: + (VEN) oadrUpdateReport (report with reportRequestID and reportSpecifierID) + Send a report update containing actual data values + (VTN) oadrUpdatedReport (optional oadrCancelReport) + Acknowledge report receipt, and optionally cancel the report + + Report cancellation: + (VTN) oadrCancelReport (reportRequestID) + This can be sent to cancel a report that is in progress. + It should also be sent if the VEN keeps sending oadrUpdateReport + after an oadrUpdatedReport cancellation. + If reportToFollow = True, the VEN is expected to send one final additional report. + (VEN) oadrCanceledReport + Acknowledge the cancellation. + If any reports were pending delivery, they are included in the payload. + + Key elements in the METADATA payload: + reportSpecifierID: Report identifier, used by subsequent oadrCreateReport requests + rid: Data point identifier + This VEN reports only two data points: baselinePower, actualPower + Duration: the amount of time that data can be collected + SamplingRate.oadrMinPeriod: maximum sampling frequency + SamplingRate.oadrMaxPeriod: minimum sampling frequency + SamplingRate.onChange: whether or not data is sampled as it changes + + For an oadrCreateReport example from the OpenADR Program Guide, see test/xml/sample_oadrCreateReport.xml. + + @param request: The request's XML payload. + """ + try: + if self.log_xml: + _log.debug('VTN PAYLOAD:') + _log.debug('\n{}'.format(etree_.tostring(etree_.fromstring(request), pretty_print=True))) + payload = parseString(request, silence=True) + signed_object = payload.oadrSignedObject + if signed_object is None: + raise OpenADRInterfaceException('No SignedObject in payload', OADR_BAD_DATA) + + if self.security_level == 'high': + # At high security, the request is accompanied by a Signature. + # (not implemented) The VEN should use a certificate authority to validate and decode the request. + pass + + # Call an appropriate method to handle the VTN request. + element_name = self.vtn_request_element_name(signed_object) + _log.debug('VTN: {}'.format(element_name)) + request_object = getattr(signed_object, element_name) + request_method = getattr(self, VTN_REQUESTS[element_name]) + request_method(request_object) + + if request_object.__class__.__name__ != 'oadrResponseType': + # A non-default response was received from the VTN. Issue a followup poll request. + self.send_oadr_poll() + + except OpenADRInternalException as err: + if err.error_code == OADR_EMPTY_DISTRIBUTE_EVENT: + _log.warning('Error handling VTN request: {}'.format(err)) # No need for a stack trace + else: + _log.warning('Error handling VTN request: {}'.format(err), exc_info=True) + except OpenADRInterfaceException as err: + _log.warning('Error handling VTN request: {}'.format(err), exc_info=True) + # OADR rule 48: Log the validation failure, send an oadrResponse.eiResponse with an error code. + self.send_oadr_response(err, err.error_code or OADR_BAD_DATA) + except Exception as err: + _log.error("Error handling VTN request: {}".format(err), exc_info=True) + self.send_oadr_response(err, OADR_BAD_DATA) + + @staticmethod + def vtn_request_element_name(signed_object): + """Given a SignedObject from the VTN, return the element name of the request that it wraps.""" + non_null_elements = [name for name in VTN_REQUESTS.keys() if getattr(signed_object, name)] + element_count = len(non_null_elements) + if element_count == 1: + return non_null_elements[0] + + if element_count == 0: + error_msg = 'Bad request {}, supported types are {}'.format(signed_object, VTN_REQUESTS.keys()) + else: + error_msg = 'Bad request {}, too many signedObject elements'.format(signed_object) + raise OpenADRInterfaceException(error_msg, None) + + # ***************** Handle Requests from the VTN to the VEN ******************** + + def handle_oadr_created_party_registration(self, oadr_created_party_registration): + """ + The VTN has responded to an oadrCreatePartyRegistration by sending an oadrCreatedPartyRegistration. + + @param oadr_created_party_registration: The VTN's request. + """ + self.oadr_current_service = EIREGISTERPARTY + self.check_ei_response(oadr_created_party_registration.eiResponse) + extractor = OadrCreatedPartyRegistrationExtractor(registration=oadr_created_party_registration) + _log.info('***********') + ven_id = extractor.extract_ven_id() + if ven_id: + _log.info('The VTN supplied {} as the ID of this VEN (ven_id).'.format(ven_id)) + poll_freq = extractor.extract_poll_freq() + if poll_freq: + _log.info('The VTN requested a poll frequency of {} (poll_interval_secs).'.format(poll_freq)) + vtn_id = extractor.extract_vtn_id() + if vtn_id: + _log.info('The VTN supplied {} as its ID (vtn_id).'.format(vtn_id)) + _log.info('Please set these values in the VEN agent config.') + _log.info('Registration is complete. Set send_registration to False in the VEN config and restart the agent.') + _log.info('***********') + + def handle_oadr_distribute_event(self, oadr_distribute_event): + """ + The VTN has responded to an oadrPoll by sending an oadrDistributeEvent. + + Create or update an event, then respond with oadrCreatedEvent. + + For sample XML, see test/xml/sample_oadrDistributeEvent.xml. + + @param oadr_distribute_event: (OadrDistributeEventType) The VTN's request. + """ + self.oadr_current_service = EIEVENT + self.oadr_current_request_id = None + if getattr(oadr_distribute_event, 'eiResponse'): + self.check_ei_response(oadr_distribute_event.eiResponse) + + # OADR rule 41: requestID does not need to be unique. + self.oadr_current_request_id = oadr_distribute_event.requestID + + vtn_id = oadr_distribute_event.vtnID + if vtn_id is not None and vtn_id != self.vtn_id: + raise OpenADRInterfaceException('vtnID failed to match agent config: {}'.format(vtn_id), OADR_BAD_DATA) + + oadr_event_list = oadr_distribute_event.oadrEvent + if len(oadr_event_list) == 0: + raise OpenADRInternalException('oadrDistributeEvent received with no events', OADR_EMPTY_DISTRIBUTE_EVENT) + + oadr_event_ids = [] + for oadr_event in oadr_event_list: + try: + event = self.handle_oadr_event(oadr_event) + if event: + oadr_event_ids.append(event.event_id) + except OpenADRInterfaceException as err: + # OADR rule 19: If a VTN message contains a mix of valid and invalid events, + # respond to the valid ones. Don't reject the entire message due to invalid events. + # OADR rule 48: Log the validation failure and send the error code in oadrCreatedEvent.eventResponse. + # (The oadrCreatedEvent's eiResponse should contain a 200 -- normal -- status code.) + _log.warning('Event error: {}'.format(err), exc_info=True) + # Construct a temporary EIEvent to hold data that will be reported in the error return. + if oadr_event.eiEvent and oadr_event.eiEvent.eventDescriptor: + event_id = oadr_event.eiEvent.eventDescriptor.eventID + modification_number = oadr_event.eiEvent.eventDescriptor.modificationNumber + else: + event_id = None + modification_number = None + error_event = EiEvent(self.oadr_current_request_id, event_id) + error_event.modification_number = modification_number + self.send_oadr_created_event(error_event, + error_code=err.error_code or OADR_BAD_DATA, + error_message=err) + except Exception as err: + _log.warning('Unanticipated error during event processing: {}'.format(err), exc_info=True) + self.send_oadr_response(err, OADR_BAD_DATA) + + for agent_event in self._get_events(): + if agent_event.event_id not in oadr_event_ids: + # "Implied cancel:" + # OADR rule 61: If the VTN request omitted an active event, cancel it. + # Also, think about whether to alert the VTN about this cancellation by sending it an oadrCreatedEvent. + _log.debug('Event ID {} not in distributeEvent: canceling it.'.format(agent_event.event_id)) + self.handle_event_cancellation(agent_event, 'never') + + def handle_oadr_event(self, oadr_event): + """ + An oadrEvent was received, usually as part of an oadrDistributeEvent. Handle the event creation/update. + + Respond with oadrCreatedEvent. + + For sample XML, see test/xml/sample_oadrDistributeEvent.xml. + + @param oadr_event: (OadrEventType) The VTN's request. + @return: (EiEvent) The event that was created or updated. + """ + + def create_temp_event(received_ei_event): + """Create a temporary EiEvent in preparation for an event creation or update.""" + event_descriptor = received_ei_event.eventDescriptor + if event_descriptor is None: + raise OpenADRInterfaceException('Missing eiEvent.eventDescriptor', OADR_BAD_DATA) + event_id = event_descriptor.eventID + if event_id is None: + raise OpenADRInterfaceException('Missing eiEvent.eventDescriptor.eventID', OADR_BAD_DATA) + _log.debug('Processing received event, ID = {}'.format(event_id)) + tmp_event = EiEvent(self.oadr_current_request_id, event_id) + extractor = OadrEventExtractor(event=tmp_event, ei_event=received_ei_event) + extractor.extract_event_descriptor() + extractor.extract_active_period() + extractor.extract_signals() + return tmp_event + + def update_event(temp_event, event): + """Update the current event based on the contents of temp_event.""" + _log.debug('Modification number has changed: {}'.format(temp_event.modification_number)) + # OADR rule 57: If modificationNumber increments, replace the event with the modified version. + if event.opt_type == EiEvent.OPT_TYPE_OPT_OUT: + # OADR rule 50: The VTN may continue to send events that the VEN has opted out of. + pass # Take no action, other than responding to the VTN. + else: + if temp_event.status == EiEvent.STATUS_CANCELED: + if event.status != EiEvent.STATUS_CANCELED: + # OADR rule 59: The event was just canceled. Process an event cancellation. + self.handle_event_cancellation(event, response_required) + else: + event.copy_from_event(temp_event) + # A VEN may ignore the received event status, calculating it based on the time. + # OADR rule 66: Do not treat status == completed as a cancellation. + if event.status == EiEvent.STATUS_CANCELED and temp_event.status != EiEvent.STATUS_CANCELED: + # If the VEN thinks the event is canceled and the VTN doesn't think that, un-cancel it. + event.status = temp_event.status + self.commit() + # Tell the VOLTTRON world about the event update. + self.publish_event(event) + + def create_event(event): + self.add_event(event) + if event.status == EiEvent.STATUS_CANCELED: + # OADR rule 60: Ignore a new event if it's cancelled - this is NOT a validation error. + pass + else: + opt_deadline = utils.get_aware_utc_now() + timedelta(seconds=self.opt_in_timeout_secs) + self.core.schedule(opt_deadline, self.force_opt_type_decision, event.event_id) + _log.debug('Scheduled a default optIn/optOut decision for {}'.format(opt_deadline)) + self.publish_event(event) # Tell the VOLTTRON world about the event creation. + + # Create a temporary EiEvent, constructed from the OadrDistributeEventType. + ei_event = oadr_event.eiEvent + response_required = oadr_event.oadrResponseRequired + + if ei_event.eiTarget and ei_event.eiTarget.venID and self.ven_id not in ei_event.eiTarget.venID: + # Rule 22: If an eiTarget is furnished, handle the event only if this venID is in the target list. + event = None + else: + temp_event = create_temp_event(ei_event) + event = self.get_event_for_id(temp_event.event_id) + if event: + if temp_event.modification_number < event.modification_number: + _log.debug('Out-of-order modification number: {}'.format(temp_event.modification_number)) + # OADR rule 58: Respond with error code 450. + raise OpenADRInterfaceException('Invalid modification number (too low)', + OADR_MOD_NUMBER_OUT_OF_ORDER) + elif temp_event.modification_number > event.modification_number: + update_event(temp_event, event) + else: + _log.debug('No modification number change, taking no action') + else: + # OADR rule 56: If the received event has an unrecognized event_id, create a new event. + _log.debug('Creating event for ID {}'.format(temp_event.event_id)) + event = temp_event + create_event(event) + + if response_required == 'always': + # OADR rule 12, 62: Send an oadrCreatedEvent if response_required == 'always'. + # OADR rule 12, 62: If response_required == 'never', do not send an oadrCreatedEvent. + self.send_oadr_created_event(event) + + return event + + def handle_event_cancellation(self, event, response_required): + """ + An event was canceled by the VTN. Update local state and publish the news. + + @param event: (EiEvent) The event that was canceled. + @param response_required: (string) Indicates when the VTN expects a confirmation/response to its request. + """ + if event.start_after: + # OADR rule 65: If the event has a startAfter value, + # schedule cancellation for a random future time between now and (now + startAfter). + max_delay = isodate.parse_duration(event.start_after) + cancel_time = utils.get_aware_utc_now() + timedelta(seconds=(max_delay.seconds * random.random())) + self.core.schedule(cancel_time, self._handle_event_cancellation, event, response_required) + else: + self._handle_event_cancellation(event, response_required) + + def _handle_event_cancellation(self, event, response_required): + """ + (Internal) An event was canceled by the VTN. Update local state and publish the news. + + @param event: (EiEvent) The event that was canceled. + @param response_required: (string) Indicates when the VTN expects a confirmation/response to its request. + """ + event.status = EiEvent.STATUS_CANCELED + if response_required != 'never': + # OADR rule 36: If response_required != never, confirm cancellation with optType = optIn. + event.optType = event.OPT_TYPE_OPT_IN + self.commit() + self.publish_event(event) # Tell VOLTTRON agents about the cancellation. + + def handle_oadr_register_report(self, request): + """ + The VTN is sending METADATA, registering the reports that it can send to the VEN. + + Send no response -- the VEN doesn't want any of the VTN's crumby reports. + + @param request: The VTN's request. + """ + self.oadr_current_service = EIREPORT + self.oadr_current_request_id = None + # OADR rule 301: Sent when the VTN wakes up. + pass + + def handle_oadr_registered_report(self, oadr_registered_report): + """ + The VTN acknowledged receipt of the METADATA in oadrRegisterReport. + + If the VTN requested any reports (by specifier ID), create them. + Send an oadrCreatedReport acknowledgment for each request. + + @param oadr_registered_report: (oadrRegisteredReportType) The VTN's request. + """ + self.oadr_current_service = EIREPORT + self.check_ei_response(oadr_registered_report.eiResponse) + self.create_or_update_reports(oadr_registered_report.oadrReportRequest) + + def handle_oadr_create_report(self, oadr_create_report): + """ + Handle an oadrCreateReport request from the VTN. + + The request could have arrived in response to a poll, + or it could have been part of an oadrRegisteredReport response. + + Create a report for each oadrReportRequest in the list, sending an oadrCreatedReport in response. + + @param oadr_create_report: The VTN's oadrCreateReport request. + """ + self.oadr_current_service = EIREPORT + self.oadr_current_request_id = None + self.create_or_update_reports(oadr_create_report.oadrReportRequest) + + def handle_oadr_updated_report(self, oadr_updated_report): + """ + The VTN acknowledged receipt of an oadrUpdatedReport, and may have sent a report cancellation. + + Check for report cancellation, and cancel the report if necessary. No need to send a response to the VTN. + + @param oadr_updated_report: The VTN's request. + """ + self.oadr_current_service = EIREPORT + self.check_ei_response(oadr_updated_report.eiResponse) + oadr_cancel_report = oadr_updated_report.oadrCancelReport + if oadr_cancel_report: + self.cancel_report(oadr_cancel_report.reportRequestID, acknowledge=False) + + def handle_oadr_cancel_report(self, oadr_cancel_report): + """ + The VTN responded to an oadrPoll by requesting a report cancellation. + + Respond by canceling the report, then send oadrCanceledReport to the VTN. + + @param oadr_cancel_report: (oadrCancelReportType) The VTN's request. + """ + self.oadr_current_service = EIREPORT + self.oadr_current_request_id = oadr_cancel_report.requestID + self.cancel_report(oadr_cancel_report.reportRequestID, acknowledge=True) + + def handle_oadr_response(self, oadr_response): + """ + The VTN has acknowledged a VEN request such as oadrCreatedReport. + + No response is needed. + + @param oadr_response: The VTN's request. + """ + self.check_ei_response(oadr_response.eiResponse) + + def check_ei_response(self, ei_response): + """ + An eiResponse can appear in multiple kinds of VTN requests. + + If an eiResponse has been received, check for a '200' (OK) response code. + If any other code is received, the VTN is reporting an error -- log it and raise an exception. + + @param ei_response: (eiResponseType) The VTN's eiResponse. + """ + self.oadr_current_request_id = ei_response.requestID + response_code, response_description = OadrResponseExtractor(ei_response=ei_response).extract() + if response_code != OADR_VALID_RESPONSE: + error_text = 'Error response from VTN, code={}, description={}'.format(response_code, response_description) + _log.error(error_text) + raise OpenADRInternalException(error_text, response_code) + + def create_or_update_reports(self, report_list): + """ + Process report creation/update requests from the VTN (which could have arrived in different payloads). + + The requests could have arrived in response to a poll, + or they could have been part of an oadrRegisteredReport response. + + Create/Update reports, and publish info about them on the volttron message bus. + Send an oadrCreatedReport response to the VTN for each report. + + @param report_list: A list of oadrReportRequest. Can be None. + """ + + def create_temp_rpt(report_request): + """Validate the report request, creating a temporary EiReport instance in the process.""" + extractor = OadrReportExtractor(request=report_request) + tmp_report = EiReport(None, + extractor.extract_report_request_id(), + extractor.extract_specifier_id()) + rpt_params = self.report_parameters.get(tmp_report.report_specifier_id, None) + if rpt_params is None: + err_msg = 'No parameters found for report with specifier ID {}'.format(tmp_report.report_specifier_id) + _log.error(err_msg) + raise OpenADRInterfaceException(err_msg, OADR_BAD_DATA) + extractor.report_parameters = rpt_params + extractor.report = tmp_report + extractor.extract_report() + return tmp_report + + def update_rpt(tmp_rpt, rpt): + """If the report changed, update its parameters in the database, and publish them on the message bus.""" + if rpt.report_specifier_id != tmp_rpt.report_specifier_id \ + or rpt.start_time != tmp_rpt.start_time \ + or rpt.end_time != tmp_rpt.end_time \ + or rpt.interval_secs != tmp_rpt.interval_secs: + rpt.copy_from_report(tmp_rpt) + self.commit() + self.publish_telemetry_parameters_for_report(rpt) + + def create_rpt(tmp_rpt): + """Store the new report request in the database, and publish it on the message bus.""" + self.add_report(tmp_rpt) + self.publish_telemetry_parameters_for_report(tmp_rpt) + + def cancel_rpt(rpt): + """A report cancellation was received. Process it and notify interested parties.""" + rpt.status = rpt.STATUS_CANCELED + self.commit() + self.publish_telemetry_parameters_for_report(rpt) + + oadr_report_request_ids = [] + + try: + if report_list: + for oadr_report_request in report_list: + temp_report = create_temp_rpt(oadr_report_request) + existing_report = self.get_report_for_report_request_id(temp_report.report_request_id) + if temp_report.status == temp_report.STATUS_CANCELED: + if existing_report: + oadr_report_request_ids.append(temp_report.report_request_id) + cancel_rpt(existing_report) + self.send_oadr_created_report(oadr_report_request) + else: + # Received notification of a new report, but it's already canceled. Take no action. + pass + else: + oadr_report_request_ids.append(temp_report.report_request_id) + if temp_report.report_specifier_id == 'METADATA': + # Rule 301/327: If the request's specifierID is 'METADATA', send an oadrRegisterReport. + self.send_oadr_created_report(oadr_report_request) + self.send_oadr_register_report() + elif existing_report: + update_rpt(temp_report, existing_report) + self.send_oadr_created_report(oadr_report_request) + else: + create_rpt(temp_report) + self.send_oadr_created_report(oadr_report_request) + except OpenADRInterfaceException as err: + # If a VTN message contains a mix of valid and invalid reports, respond to the valid ones. + # Don't reject the entire message due to an invalid report. + _log.warning('Report error: {}'.format(err), exc_info=True) + self.send_oadr_response(err, err.error_code or OADR_BAD_DATA) + except Exception as err: + _log.warning('Unanticipated error during report processing: {}'.format(err), exc_info=True) + self.send_oadr_response(err, OADR_BAD_DATA) + + all_active_reports = self._get_reports() + for agent_report in all_active_reports: + if agent_report.report_request_id not in oadr_report_request_ids: + # If the VTN's request omitted an active report, treat it as an implied cancellation. + report_request_id = agent_report.report_request_id + _log.debug('Report request ID {} not sent by VTN, canceling the report.'.format(report_request_id)) + self.cancel_report(report_request_id, acknowledge=True) + + def cancel_report(self, report_request_id, acknowledge=False): + """ + The VTN asked to cancel a report, in response to either report telemetry or an oadrPoll. Cancel it. + + @param report_request_id: (string) The report_request_id of the report to be canceled. + @param acknowledge: (boolean) If True, send an oadrCanceledReport acknowledgment to the VTN. + """ + if report_request_id is None: + raise OpenADRInterfaceException('Missing oadrCancelReport.reportRequestID', OADR_BAD_DATA) + report = self.get_report_for_report_request_id(report_request_id) + if report: + report.status = report.STATUS_CANCELED + self.commit() + self.publish_telemetry_parameters_for_report(report) + if acknowledge: + self.send_oadr_canceled_report(report_request_id) + else: + # The VEN got asked to cancel a report that it doesn't have. Do nothing. + pass + + # ***************** Send Requests from the VEN to the VTN ******************** + + def send_oadr_poll(self): + """Send oadrPoll to the VTN.""" + _log.debug('VEN: oadrPoll') + self.oadr_current_service = POLL + # OADR rule 37: The VEN must support the PULL implementation. + self._last_poll = utils.get_aware_utc_now() + self.send_vtn_request('oadrPoll', OadrPollBuilder(ven_id=self.ven_id).build()) + + def send_oadr_query_registration(self): + """Send oadrQueryRegistration to the VTN.""" + _log.debug('VEN: oadrQueryRegistration') + self.oadr_current_service = EIREGISTERPARTY + self.send_vtn_request('oadrQueryRegistration', OadrQueryRegistrationBuilder().build()) + + def send_oadr_create_party_registration(self): + """Send oadrCreatePartyRegistration to the VTN.""" + _log.debug('VEN: oadrCreatePartyRegistration') + self.oadr_current_service = EIREGISTERPARTY + send_signature = (self.security_level == 'high') + # OADR rule 404: If the VEN hasn't registered before, venID and registrationID should be empty. + builder = OadrCreatePartyRegistrationBuilder(ven_id=None, xml_signature=send_signature, ven_name=self.ven_name) + self.send_vtn_request('oadrCreatePartyRegistration', builder.build()) + + def send_oadr_request_event(self): + """Send oadrRequestEvent to the VTN.""" + _log.debug('VEN: oadrRequestEvent') + self.oadr_current_service = EIEVENT + self.send_vtn_request('oadrRequestEvent', OadrRequestEventBuilder(ven_id=self.ven_id).build()) + + def send_oadr_created_event(self, event, error_code=None, error_message=None): + """ + Send oadrCreatedEvent to the VTN. + + @param event: (EiEvent) The event that is the subject of the request. + @param error_code: (string) eventResponse error code. Used when reporting event protocol errors. + @param error_message: (string) eventResponse error message. Used when reporting event protocol errors. + """ + _log.debug('VEN: oadrCreatedEvent') + self.oadr_current_service = EIEVENT + builder = OadrCreatedEventBuilder(event=event, ven_id=self.ven_id, + error_code=error_code, error_message=error_message) + self.send_vtn_request('oadrCreatedEvent', builder.build()) + + def send_oadr_register_report(self): + """ + Send oadrRegisterReport (METADATA) to the VTN. + + Sample oadrRegisterReport from the OpenADR Program Guide: + + + RegReq120615_122508_975 + + --- See oadr_report() --- + + ec27de207837e1048fd3 + + """ + _log.debug('VEN: oadrRegisterReport') + self.oadr_current_service = EIREPORT + # The VEN is currently hard-coded to support the 'telemetry' report, which sends baseline and measured power, + # and the 'telemetry_status' report, which sends online and manual_override status. + # In order to support additional reports and telemetry types, the VEN would need to store other data elements + # as additional columns in its SQLite database. + builder = OadrRegisterReportBuilder(reports=self.metadata_reports(), ven_id=self.ven_id) + # The EPRI VTN server responds to this request with "452: Invalid ID". Why? + self.send_vtn_request('oadrRegisterReport', builder.build()) + + def send_oadr_update_report(self, report): + """ + Send oadrUpdateReport to the VTN. + + Sample oadrUpdateReport from the OpenADR Program Guide: + + + ReportUpdReqID130615_192730_445 + + --- See OadrUpdateReportBuilder --- + + VEN130615_192312_582 + + + @param report: (EiReport) The report for which telemetry should be sent. + """ + _log.debug('VEN: oadrUpdateReport (report {})'.format(report.report_request_id)) + self.oadr_current_service = EIREPORT + telemetry = self.get_new_telemetry_for_report(report) if report.report_specifier_id == 'telemetry' else [] + builder = OadrUpdateReportBuilder(report=report, + telemetry=telemetry, + online=self.ven_online, + manual_override=self.ven_manual_override, + ven_id=self.ven_id) + self.send_vtn_request('oadrUpdateReport', builder.build()) + report.last_report = utils.get_aware_utc_now() + self.commit() + + def send_oadr_created_report(self, report_request): + """ + Send oadrCreatedReport to the VTN. + + @param report_request: (oadrReportRequestType) The VTN's report request. + """ + _log.debug('VEN: oadrCreatedReport') + self.oadr_current_service = EIREPORT + builder = OadrCreatedReportBuilder(report_request_id=report_request.reportRequestID, + ven_id=self.ven_id, + pending_report_request_ids=self.get_pending_report_request_ids()) + self.send_vtn_request('oadrCreatedReport', builder.build()) + + def send_oadr_canceled_report(self, report_request_id): + """ + Send oadrCanceledReport to the VTN. + + @param report_request_id: (string) The reportRequestID of the report that has been canceled. + """ + _log.debug('VEN: oadrCanceledReport') + self.oadr_current_service = EIREPORT + builder = OadrCanceledReportBuilder(request_id=self.oadr_current_request_id, + report_request_id=report_request_id, + ven_id=self.ven_id, + pending_report_request_ids=self.get_pending_report_request_ids()) + self.send_vtn_request('oadrCanceledReport', builder.build()) + + def send_oadr_response(self, response_description, response_code): + """ + Send an oadrResponse to the VTN. + + @param response_description: (string The response description. + @param response_code: (string) The response code, 200 if OK. + """ + _log.debug('VEN: oadrResponse') + builder = OadrResponseBuilder(response_code=response_code, + response_description=response_description, + request_id=self.oadr_current_request_id or '0', + ven_id=self.ven_id) + self.send_vtn_request('oadrResponse', builder.build()) + + def send_vtn_request(self, request_name, request_object): + """ + Send a request to the VTN. If the VTN returns a non-empty response, service that request. + + Wrap the request in a SignedObject and then in Payload XML, and post it to the VTN via HTTP. + If using high security, calculate a digital signature and include it in the request payload. + + @param request_name: (string) The name of the SignedObject attribute where the request is attached. + @param request_object: (various oadr object types) The request to send. + """ + signed_object = oadrSignedObject(**{request_name: request_object}) + try: + # Export the SignedObject as an XML string. + buff = io.StringIO() + signed_object.export(buff, 1, pretty_print=True) + signed_object_xml = buff.getvalue() + except Exception as err: + raise OpenADRInterfaceException('Error exporting the SignedObject: {}'.format(err), None) + + if self.security_level == 'high': + try: + signature_lxml, signed_object_lxml = self.calculate_signature(signed_object_xml) + except Exception as err: + raise OpenADRInterfaceException('Error signing the SignedObject: {}'.format(err), None) + payload_lxml = self.payload_element(signature_lxml, signed_object_lxml) + try: + # Verify that the payload, with signature, is well-formed and can be validated. + signxml.XMLVerifier().verify(payload_lxml, ca_pem_file=VTN_CA_CERT_FILENAME) + except Exception as err: + raise OpenADRInterfaceException('Error verifying the SignedObject: {}'.format(err), None) + else: + signed_object_lxml = etree_.fromstring(signed_object_xml) + payload_lxml = self.payload_element(None, signed_object_lxml) + + if self.log_xml: + _log.debug('VEN PAYLOAD:') + _log.debug('\n{}'.format(etree_.tostring(payload_lxml, pretty_print=True))) + + # Post payload XML to the VTN as an HTTP request. Return the VTN's response, if any. + endpoint = self.vtn_address + (self.oadr_current_service or POLL) + try: + payload_xml = etree_.tostring(payload_lxml) + # OADR rule 53: If simple HTTP mode is used, send the following headers: Host, Content-Length, Content-Type. + # The EPRI VTN server responds with a 400 "bad request" if a "Host" header is sent. + _log.debug('Posting VEN request to {}'.format(endpoint)) + response = requests.post(endpoint, data=payload_xml, headers={ + # "Host": endpoint, + "Content-Length": str(len(payload_xml)), + "Content-Type": "application/xml"}) + http_code = response.status_code + if http_code == 200: + if len(response.content) > 0: + self.core.spawn(self.service_vtn_request, response.content) + else: + _log.warning('Received zero-length request from VTN') + elif http_code == 204: + # Empty response received. Take no action. + _log.debug('Empty response received from {}'.format(endpoint)) + else: + _log.error('Error in http request to {}: response={}'.format(endpoint, http_code), exc_info=True) + raise OpenADRInterfaceException('Error in VTN request: {}'.format(http_code), None) + except ConnectionError: + _log.warning('ConnectionError in http request to {} (is the VTN offline?)'.format(endpoint)) + return None + except Exception as err: + raise OpenADRInterfaceException('Error posting OADR XML: {}'.format(err), None) + + # ***************** VOLTTRON RPCs ******************** + + @RPC.export + def respond_to_event(self, event_id, opt_in_choice=None): + """ + Respond to an event, opting in or opting out. + + If an event's status=unresponded, it is awaiting this call. + When this RPC is received, the VENAgent sends an eventResponse to + the VTN, indicating whether optIn or optOut has been chosen. + If an event remains unresponded for a set period of time, + it times out and automatically optsIn to the event. + + Since this call causes a change in the event's status, it triggers + a PubSub call for the event update, as described above. + + @param event_id: (String) ID of an event. + @param opt_in_choice: (String) 'OptIn' to opt into the event, anything else is treated as 'OptOut'. + """ + event = self.get_event_for_id(event_id) + if event: + if opt_in_choice == event.OPT_TYPE_OPT_IN: + event.opt_type = opt_in_choice + else: + event.opt_type = event.OPT_TYPE_OPT_OUT + self.commit() + _log.debug('RPC respond_to_event: Sending {} for event ID {}'.format(event.opt_type, event_id)) + self.send_oadr_created_event(event) + else: + raise OpenADRInterfaceException('No event found for event_id {}'.format(event_id), None) + + @RPC.export + def add_event_for_test(self, event_id, request_id, start_time): + """Add an event to the database and cache. Used during regression testing only.""" + _log.debug('RPC add_event_for_test: Creating event with ID {}'.format(event_id)) + event = EiEvent(event_id, request_id) + event.start_time = parser.parse(start_time) + self.add_event(event) + + @RPC.export + def get_events(self, **kwargs): + """ + Return a list of events as a JSON string. + + See _get_eievents() for a list of parameters and a description of method behavior. + + Sample request: + self.get_events(started_after=utils.get_aware_utc_now() - timedelta(hours=1), + end_time_before=utils.get_aware_utc_now()) + + @return: (JSON) A list of EiEvents -- see 'PubSub: event update'. + """ + _log.debug('RPC get_events') + events = self._get_events(**kwargs) + return None if events is None else self.json_object([e.as_json_compatible_object() for e in events]) + + @RPC.export + def get_telemetry_parameters(self): + """ + Return the VENAgent's current set of telemetry parameters. + + @return: (JSON) Current telemetry parameters -- see 'PubSub: telemetry parameters update'. + """ + _log.debug('RPC get_telemetry_parameters') + # If there is an active report, return its telemetry parameters. + # Otherwise return the telemetry report parameters in agent config. + rpts = self.active_reports() + report = rpts[0] if len(rpts) > 0 else self.metadata_report('telemetry') + # Extend what's reported to include parameters other than just telemetry parameters. + return {'online': self.ven_online, + 'manual_override': self.ven_manual_override, + 'telemetry': report.telemetry_parameters, + 'report parameters': self.json_object(report.as_json_compatible_object())} + + @RPC.export + def set_telemetry_status(self, online, manual_override): + """ + Update the VENAgent's reporting status. + + To be compliant with the OADR profile spec, set these properties to either 'TRUE' or 'FALSE'. + + @param online: (Boolean) Whether the VENAgent's resource is online. + @param manual_override: (Boolean) Whether resource control has been overridden. + """ + _log.debug('RPC set_telemetry_status: online={}, manual_override={}'.format(online, manual_override)) + # OADR rule 510: Provide a TELEMETRY_STATUS report that includes oadrOnline and oadrManualOverride values. + self.ven_online = online + self.ven_manual_override = manual_override + + @RPC.export + def report_telemetry(self, telemetry): + """ + Receive an update of the VENAgent's report metrics, and store them in the agent's database. + + Examples of telemetry are: + { + 'baseline_power_kw': '15.2', + 'current_power_kw': '371.1', + 'start_time': '2017-11-21T23:41:46.051405', + 'end_time': '2017-11-21T23:42:45.951405' + } + + @param telemetry: (JSON) Current value of each report metric, with reporting-interval start/end timestamps. + """ + _log.debug('RPC report_telemetry: {}'.format(telemetry)) + baseline_power_kw = telemetry.get('baseline_power_kw') + current_power_kw = telemetry.get('current_power_kw') + start_time = utils.parse_timestamp_string(telemetry.get('start_time')) + end_time = utils.parse_timestamp_string(telemetry.get('end_time')) + for report in self.active_reports(): + self.add_telemetry(EiTelemetryValues(report_request_id=report.report_request_id, + baseline_power_kw=baseline_power_kw, + current_power_kw=current_power_kw, + start_time=start_time, + end_time=end_time)) + + # ***************** VOLTTRON Pub/Sub Requests ******************** + + def publish_event(self, an_event): + """ + Publish an event. + + When an event is created/updated, it is published to the VOLTTRON bus + with a topic that includes 'openadr/event_update'. + + Event JSON structure: + { + "event_id" : String, + "creation_time" : DateTime, + "start_time" : DateTime, + "end_time" : DateTime or None, + "priority" : Integer, # Values: 0, 1, 2, 3. Usually expected to be 1. + "signals" : String, # Values: json string describing one or more signals. + "status" : String, # Values: unresponded, far, near, active, + # completed, canceled. + "opt_type" : String # Values: optIn, optOut, none. + } + + If an event status is 'unresponded', the VEN agent is awaiting a decision on + whether to optIn or optOut. The downstream agent that subscribes to this PubSub + message should communicate that choice to the VEN agent by calling respond_to_event() + (see below). The VEN agent then relays the choice to the VTN. + + @param an_event: an EiEvent. + """ + if an_event.test_event != 'false': + # OADR rule 6: If testEvent is present and != "false", handle the event as a test event. + _log.debug('Suppressing publication of test event {}'.format(an_event)) + else: + _log.debug('Publishing event {}'.format(an_event)) + request_headers = {headers.TIMESTAMP: format_timestamp(utils.get_aware_utc_now())} + self.vip.pubsub.publish(peer='pubsub', + topic=topics.OPENADR_EVENT+'/'+self.ven_id, + headers=request_headers, + message=self.json_object(an_event.as_json_compatible_object())) + + def publish_telemetry_parameters_for_report(self, report): + """ + Publish telemetry parameters. + + When the VEN agent telemetry reporting parameters have been updated (by the VTN), + they are published with a topic that includes 'openadr/telemetry_parameters'. + If a particular report has been updated, the reported parameters are for that report. + + Telemetry parameters JSON example: + { + "telemetry": { + "baseline_power_kw": { + "r_id": "baseline_power", + "min_frequency": "30", + "max_frequency": "60", + "report_type": "baseline", + "reading_type": "Direct Read", + "units": "powerReal", + "method_name": "get_baseline_power" + } + "current_power_kw": { + "r_id": "actual_power", + "min_frequency": "30", + "max_frequency": "60", + "report_type": "reading", + "reading_type": "Direct Read", + "units": "powerReal", + "method_name": "get_current_power" + } + "manual_override": "False", + "report_status": "active", + "online": "False", + } + } + + The above example indicates that, for reporting purposes, telemetry values + for baseline_power and actual_power should be updated -- via report_telemetry() -- at + least once every 30 seconds. + + Telemetry value definitions such as baseline_power and actual_power come from the + agent configuration. + + @param report: (EiReport) The report whose parameters should be published. + """ + _log.debug('Publishing telemetry parameters') + request_headers = {headers.TIMESTAMP: format_timestamp(utils.get_aware_utc_now())} + self.vip.pubsub.publish(peer='pubsub', + topic=topics.OPENADR_STATUS+'/'+self.ven_id, + headers=request_headers, + message=report.telemetry_parameters) + + # ***************** Database Requests ******************** + + def active_events(self): + """Return a list of events that are neither COMPLETED nor CANCELED.""" + return self._get_events() + + def get_event_for_id(self, event_id): + """Return the event with ID event_id, or None if not found.""" + event_list = self._get_events(event_id=event_id, in_progress_only=False) + return event_list[0] if len(event_list) == 1 else None + + def _get_events(self, event_id=None, in_progress_only=True, started_after=None, end_time_before=None): + """ + Return a list of EiEvents. (internal method) + + By default, return only event requests with status=active or status=unresponded. + + If an event's status=active, a DR event is currently in progress. + + @param event_id: (String) Default None. + @param in_progress_only: (Boolean) Default True. + @param started_after: (DateTime) Default None. + @param end_time_before: (DateTime) Default None. + @return: A list of EiEvents. + """ + # For requests by event ID, query the cache first before querying the database. + if event_id: + event = self._active_events.get(event_id, None) + if event: + return [event] + + db_event = globals()['EiEvent'] + events = self.get_db_session().query(db_event) + if event_id is not None: + events = events.filter(db_event.event_id == event_id) + if in_progress_only: + events = events.filter(~db_event.status.in_([EiEvent.STATUS_COMPLETED, EiEvent.STATUS_CANCELED])) + if started_after: + events = events.filter(db_event.start_time > started_after) + if end_time_before and db_event.end_time: + # An event's end_time can be None, indicating that it doesn't expire until Canceled. + # If the event's end_time is None, don't apply this filter to it. + events = events.filter(db_event.end_time < end_time_before) + return events.all() + + def add_event(self, event): + """A new event has been created. Add it to the event cache, and also to the database.""" + self._active_events[event.event_id] = event + self.get_db_session().add(event) + self.commit() + + def set_event_status(self, event, status): + _log.debug('Transitioning status to {} for event ID {}'.format(status, event.event_id)) + event.status = status + self.commit() + + def expire_event(self, event): + """Remove the event from the event cache. (It remains in the SQLite database.)""" + self._active_events.pop(event.event_id) + + def active_reports(self): + """Return a list of reports that are neither COMPLETED nor CANCELED.""" + return self._get_reports() + + def add_report(self, report): + """A new report has been created. Add it to the report cache, and also to the database.""" + self._active_reports[report.report_request_id] = report + self.get_db_session().add(report) + self.commit() + + def set_report_status(self, report, status): + _log.debug('Transitioning status to {} for report request ID {}'.format(status, report.report_request_id)) + report.status = status + self.commit() + + def expire_report(self, report): + """Remove the report from the report cache. (It remains in the SQLite database.)""" + self._active_reports.pop(report.report_request_id) + + def get_report_for_report_request_id(self, report_request_id): + """Return the EiReport with request ID report_request_id, or None if not found.""" + report_list = self._get_reports(report_request_id=report_request_id, active_only=False) + return report_list[0] if len(report_list) == 1 else None + + def get_reports_for_report_specifier_id(self, report_specifier_id): + """Return the EiReport with request ID report_request_id, or None if not found.""" + return self._get_reports(report_specifier_id=report_specifier_id, active_only=True) + + def get_pending_report_request_ids(self): + """Return a list of reportRequestIDs for each active report.""" + # OpenADR rule 329: Include all current report request IDs in the oadrPendingReports list. + return [r.report_request_id for r in self._get_reports()] + + def _get_reports(self, report_request_id=None, report_specifier_id=None, active_only=True, + started_after=None, end_time_before=None): + """ + Return a list of EiReport. + + By default, return only report requests with status=active. + + @param report_request_id: (String) Default None. + @param report_specifier_id: (String) Default None. + @param active_only: (Boolean) Default True. + @param started_after: (DateTime) Default None. + @param end_time_before: (DateTime) Default None. + @return: A list of EiReports. + """ + # For requests by report ID, query the cache first before querying the database. + if report_request_id: + report = self._active_reports.get(report_request_id, None) + if report: + return [report] + + db_report = globals()['EiReport'] + reports = self.get_db_session().query(db_report) + if report_request_id is not None: + reports = reports.filter(db_report.report_request_id == report_request_id) + if report_specifier_id is not None: + reports = reports.filter(db_report.report_specifier_id == report_specifier_id) + if active_only: + reports = reports.filter(~db_report.status.in_([EiReport.STATUS_COMPLETED, EiReport.STATUS_CANCELED])) + if started_after: + reports = reports.filter(db_report.start_time > started_after) + if end_time_before and db_report.end_time: + # A report's end_time can be None, indicating that it doesn't expire until Canceled. + # If the report's end_time is None, don't apply this filter to it. + reports = reports.filter(db_report.end_time < end_time_before) + return reports.all() + + def metadata_reports(self): + """Return an EiReport instance containing telemetry metadata for each report definition in agent config.""" + return [self.metadata_report(rpt_name) for rpt_name in self.report_parameters.keys()] + + def metadata_report(self, specifier_id): + """Return an EiReport instance for the indicated specifier_id, or None if its' not in agent config.""" + params = self.report_parameters.get(specifier_id, None) + report = EiReport('', '', specifier_id) # No requestID, no reportRequestID + report.name = params.get('report_name_metadata', None) + try: + interval_secs = int(params.get('report_interval_secs_default', None)) + except ValueError: + error_msg = 'Default report interval {} is not an integer number of seconds'.format(default) + raise OpenADRInternalException(error_msg, OADR_BAD_DATA) + report.interval_secs = interval_secs + report.telemetry_parameters = jsonapi.dumps(params.get('telemetry_parameters', None)) + report.report_specifier_id = specifier_id + report.status = report.STATUS_INACTIVE + return report + + def get_new_telemetry_for_report(self, report): + """Query for relevant telemetry that's arrived since the report was last sent to the VTN.""" + db_telemetry_values = globals()['EiTelemetryValues'] + telemetry = self.get_db_session().query(db_telemetry_values) + telemetry = telemetry.filter(db_telemetry_values.report_request_id == report.report_request_id) + telemetry = telemetry.filter(db_telemetry_values.created_on > report.last_report) + return telemetry.all() + + def add_telemetry(self, telemetry): + """New telemetry has been received. Add it to the database.""" + self.get_db_session().add(telemetry) + self.commit() + + def telemetry_cleanup(self): + """gevent thread for periodically deleting week-old telemetry from the database.""" + db_telemetry_values = globals()['EiTelemetryValues'] + telemetry = self.get_db_session().query(db_telemetry_values) + total_rows = telemetry.count() + telemetry = telemetry.filter(db_telemetry_values.created_on < utils.get_aware_utc_now() - timedelta(days=7)) + deleted_row_count = telemetry.delete() + if deleted_row_count: + _log.debug('Deleting {} outdated of {} total telemetry rows in db'.format(deleted_row_count, total_rows)) + self.commit() + + def commit(self): + """Flush any modified objects to the SQLite database.""" + self.get_db_session().commit() + + def get_db_session(self): + """Return the SQLite database session. Initialize the session if this is the first time in.""" + if not self._db_session: + # First time: create a SQLAlchemy engine and session. + try: + database_dir = os.path.dirname(self.db_path) + if not os.path.exists(database_dir): + _log.debug('Creating sqlite database directory {}'.format(database_dir)) + os.makedirs(database_dir) + engine_path = 'sqlite:///' + self.db_path + _log.debug('Connecting to sqlite database {}'.format(engine_path)) + engine = create_engine(engine_path).connect() + ORMBase.metadata.create_all(engine) + self._db_session = sessionmaker(bind=engine)() + except AttributeError as err: + error_msg = 'Unable to open sqlite database named {}: {}'.format(self.db_path, err) + raise OpenADRInterfaceException(error_msg, None) + return self._db_session + + # ***************** Utility Methods ******************** + + @staticmethod + def payload_element(signature_lxml, signed_object_lxml): + """ + Construct and return an XML element for Payload. + + Append a child Signature element if one is provided. + Append a child SignedObject element. + + @param signature_lxml: (Element or None) Signature element. + @param signed_object_lxml: (Element) SignedObject element. + @return: (Element) Payload element. + """ + payload = etree_.Element("{http://openadr.org/oadr-2.0b/2012/07}oadrPayload", + nsmap=signed_object_lxml.nsmap) + if signature_lxml: + payload.append(signature_lxml) + payload.append(signed_object_lxml) + return payload + + @staticmethod + def calculate_signature(signed_object_xml): + """ + Calculate a digital signature for the SignedObject to be sent to the VTN. + + @param signed_object_xml: (xml string) A SignedObject. + @return: (lxml) A Signature and a SignedObject. + """ + signed_object_lxml = etree_.fromstring(signed_object_xml) + signed_object_lxml.set('Id', 'signedObject') + # Use XMLSigner to create a Signature. + # Use "detached method": the signature lives alonside the signed object in the XML element tree. + # Use c14n "exclusive canonicalization": the signature is independent of namespace inclusion/exclusion. + signer = signxml.XMLSigner(method=signxml.methods.detached, + c14n_algorithm='http://www.w3.org/2001/10/xml-exc-c14n#') + signature_lxml = signer.sign(signed_object_lxml, + key=open(KEY_FILENAME, 'rb').read(), + cert=open(CERT_FILENAME, 'rb').read(), + key_name='123') + # This generated Signature lacks the ReplayProtect property described in OpenADR profile spec section 10.6.3. + return signature_lxml, signed_object_lxml + + def register_endpoints(self): + """ + Register each endpoint URL and its callback. + + These endpoint definitions are used only by "PUSH" style VTN communications, + not by responses to VEN polls. + """ + _log.debug("Registering Endpoints: {}".format(self.__class__.__name__)) + for endpoint in OPENADR_ENDPOINTS.values(): + self.vip.web.register_endpoint(endpoint.url, getattr(self, endpoint.callback), "raw") + + def json_object(self, obj): + """Ensure that an object is valid JSON by dumping it with json_converter and then reloading it.""" + obj_string = jsonapi.dumps(obj, default=self.json_converter) + obj_json = jsonapi.loads(obj_string) + return obj_json + + @staticmethod + def json_converter(object_to_dump): + """When calling jsonapi.dumps, convert datetime instances to strings.""" + if isinstance(object_to_dump, dt): + return object_to_dump.__str__() + + +def main(): + """Start the agent.""" + utils.vip_main(ven_agent, identity='venagent', version=__version__) + + +if __name__ == '__main__': + try: + sys.exit(main()) + except KeyboardInterrupt: + pass diff --git a/setup.py b/setup.py index 5295786323..87c3a46377 100644 --- a/setup.py +++ b/setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import contextlib diff --git a/services/core/IEEE2030_5Agent/setup.py b/update_copyright.py similarity index 53% rename from services/core/IEEE2030_5Agent/setup.py rename to update_copyright.py index cc64769bff..7c4b0e2436 100644 --- a/services/core/IEEE2030_5Agent/setup.py +++ b/update_copyright.py @@ -1,4 +1,6 @@ -# -*- coding: utf-8 -*- {{{ +from pathlib import Path + +text_to_find = """# -*- coding: utf-8 -*- {{{ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # # Copyright 2020, Battelle Memorial Institute. @@ -14,7 +16,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# +#green # This material was prepared as an account of work sponsored by an agency of # the United States Government. Neither the United States Government nor the # United States Department of Energy, nor Battelle, nor any of their @@ -35,38 +37,51 @@ # BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY # under Contract DE-AC05-76RL01830 # }}} +""" -from os import path -from setuptools import setup, find_packages +text_to_replace = """# -*- coding: utf-8 -*- {{{ +# ===----------------------------------------------------------------------=== +# +# Component of Eclipse VOLTTRON +# +# ===----------------------------------------------------------------------=== +# +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# ===----------------------------------------------------------------------=== +# }}} +""" -MAIN_MODULE = 'agent' +def replace_text_in_file(file: Path): + if file == Path(__file__): + return + with file.open('r') as f: + text = f.read() + if text_to_find in text: + print(f'Replacing in', file) + text = text.replace(text_to_find, text_to_replace) + with file.open('w') as f: + f.write(text) -# Find the agent package that contains the main module -packages = find_packages('.') -agent_package = '' -for package in find_packages(): - # Because there could be other packages such as tests - if path.isfile(package + '/' + MAIN_MODULE + '.py') is True: - agent_package = package -if not agent_package: - raise RuntimeError('None of the packages under {dir} contain the file ' - '{main_module}'.format(main_module=MAIN_MODULE + '.py', - dir=path.abspath('.'))) +def replace_files_in_path(path: Path): + for file in path.iterdir(): + if file.is_dir(): + replace_files_in_path(file) + elif file.is_file() and file.suffix == '.py': + replace_text_in_file(file) -# Find the version number from the main module -agent_module = agent_package + '.' + MAIN_MODULE -_temp = __import__(agent_module, globals(), locals(), ['__version__'], 0) -__version__ = _temp.__version__ -# Setup -setup( - name=agent_package + 'agent', - version=__version__, - install_requires=['volttron'], - packages=packages, - entry_points={ - 'setuptools.installation': [ - 'eggsecutable = ' + agent_module + ':main', - ] - } -) +if __name__ == '__main__': + replace_files_in_path(Path(__file__).parent) diff --git a/volttron/__init__.py b/volttron/__init__.py index e78403ae4e..3999d69c5b 100644 --- a/volttron/__init__.py +++ b/volttron/__init__.py @@ -1,3 +1,4 @@ # This is a namespace package; do not add anything else to this file. +# from pkgutil import extend_path __path__ = extend_path(__path__, __name__) diff --git a/volttron/lint/__init__.py b/volttron/lint/__init__.py index e56fc543b9..18deff9fc8 100644 --- a/volttron/lint/__init__.py +++ b/volttron/lint/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} ''' diff --git a/volttron/lint/bacpypes.debugging.py b/volttron/lint/bacpypes.debugging.py index 0a0f4ed7ff..b88a37bc6e 100644 --- a/volttron/lint/bacpypes.debugging.py +++ b/volttron/lint/bacpypes.debugging.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} class Logging: diff --git a/volttron/lint/clock.py b/volttron/lint/clock.py index e5d76462e8..6f0c8fa8fd 100644 --- a/volttron/lint/clock.py +++ b/volttron/lint/clock.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} def monotonic(): diff --git a/volttron/lint/gevent.socket.py b/volttron/lint/gevent.socket.py index 6228fad253..33ad43d879 100644 --- a/volttron/lint/gevent.socket.py +++ b/volttron/lint/gevent.socket.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} AF_UNIX = 1 diff --git a/volttron/lint/greenlet.py b/volttron/lint/greenlet.py index 9ac82c9ffe..4c9a48930c 100644 --- a/volttron/lint/greenlet.py +++ b/volttron/lint/greenlet.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import gevent as _gevent diff --git a/volttron/lint/twisted.internet.reactor.py b/volttron/lint/twisted.internet.reactor.py index 5401721c9a..bc6731f0b9 100644 --- a/volttron/lint/twisted.internet.reactor.py +++ b/volttron/lint/twisted.internet.reactor.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} def callLater(_seconds, _f, *args, **kw): diff --git a/volttron/lint/zmq.py b/volttron/lint/zmq.py index ea35c22d48..d672ca76da 100644 --- a/volttron/lint/zmq.py +++ b/volttron/lint/zmq.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} NOBLOCK = 1 diff --git a/volttron/platform/__init__.py b/volttron/platform/__init__.py index 375fdb6f31..d6ce14cdd2 100644 --- a/volttron/platform/__init__.py +++ b/volttron/platform/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -49,7 +35,7 @@ from urllib.parse import urlparse from ..utils.frozendict import FrozenDict -__version__ = '8.2' +__version__ = '9.0rc0' _log = logging.getLogger(__name__) @@ -281,17 +267,19 @@ def build_vip_address_string(vip_root, serverkey, publickey, secretkey): :raises ValueError if one of the parameters is None. """ + from volttron.platform.agent.utils import is_auth_enabled + _log.debug("root: {}, serverkey: {}, publickey: {}, secretkey: {}".format( vip_root, serverkey, publickey, secretkey)) parsed = urlparse(vip_root) - if parsed.scheme == 'tcp': + if parsed.scheme == 'tcp' and is_auth_enabled(): if not (serverkey and publickey and secretkey and vip_root): raise ValueError("All parameters must be entered.") root = "{}?serverkey={}&publickey={}&secretkey={}".format( vip_root, serverkey, publickey, secretkey) - elif parsed.scheme == 'ipc': + elif parsed.scheme == 'ipc' or not is_auth_enabled(): root = vip_root else: raise ValueError('Invalid vip root specified!') diff --git a/volttron/platform/agent/__init__.py b/volttron/platform/agent/__init__.py index e23a02d27b..f34fcca694 100644 --- a/volttron/platform/agent/__init__.py +++ b/volttron/platform/agent/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from . import matching diff --git a/volttron/platform/agent/bacnet_proxy_reader.py b/volttron/platform/agent/bacnet_proxy_reader.py index 17c7f1affb..36312405c2 100644 --- a/volttron/platform/agent/bacnet_proxy_reader.py +++ b/volttron/platform/agent/bacnet_proxy_reader.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/agent/base.py b/volttron/platform/agent/base.py index 76da49665f..6b7dd62f77 100644 --- a/volttron/platform/agent/base.py +++ b/volttron/platform/agent/base.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ base agent and helper classes/functions.''' @@ -41,7 +27,7 @@ import random -import string +import secrets import time as time_mod import zmq @@ -62,11 +48,9 @@ min_compatible_version = '1' max_compatible_version = '2' -_COOKIE_CHARS = string.ascii_letters + string.digits - -def random_cookie(length=40, choices=_COOKIE_CHARS): - return ''.join(random.choice(choices) for i in range(length)) +def random_cookie(length=40): + return secrets.token_hex(length) def remove_matching(test, items): diff --git a/volttron/platform/agent/base_aggregate_historian.py b/volttron/platform/agent/base_aggregate_historian.py index 2269a424ce..464e2356ac 100644 --- a/volttron/platform/agent/base_aggregate_historian.py +++ b/volttron/platform/agent/base_aggregate_historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/agent/base_historian.py b/volttron/platform/agent/base_historian.py index 84ce5ec0a1..a9ed1d41b1 100644 --- a/volttron/platform/agent/base_historian.py +++ b/volttron/platform/agent/base_historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -759,8 +745,8 @@ def parse_table_def(self, tables_def): def get_renamed_topic(self, input_topic): """ replace topic name based on configured topic replace list, is any - :param input_topic: - :return: + :param input_topic: + :return: """ output_topic = input_topic input_topic_lower = input_topic.lower() @@ -1757,12 +1743,12 @@ def _setupdb(self, check_same_thread): # directory in agent isolation mode if os.path.exists(os.path.join(os.getcwd(), os.path.basename(os.getcwd()) + ".agent-data")): backup_db = os.path.join(os.getcwd(), os.path.basename(os.getcwd()) + ".agent-data", 'backup.sqlite') - else: + else: # means its a dynamic agent backup_db = os.path.join(os.getcwd(), 'backup.sqlite') - + _log.info(f"Creating backup db at {backup_db}") - + self._connection = sqlite3.connect( backup_db, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES, @@ -2103,11 +2089,10 @@ def query(self, topic=None, start=None, end=None, agg_type=None, raise TypeError("You should provide both aggregation type" "(agg_type) and aggregation time period" "(agg_period) to query aggregate data") - else: - if agg_period: - raise TypeError("You should provide both aggregation type" - "(agg_type) and aggregation time period" - "(agg_period) to query aggregate data") + elif agg_period: + raise TypeError("You should provide both aggregation type" + "(agg_type) and aggregation time period" + "(agg_period) to query aggregate data") if agg_period: agg_period = AggregateHistorian.normalize_aggregation_time_period( diff --git a/volttron/platform/agent/base_market_agent/__init__.py b/volttron/platform/agent/base_market_agent/__init__.py index 51c0d9b5f9..8b4da1db5a 100644 --- a/volttron/platform/agent/base_market_agent/__init__.py +++ b/volttron/platform/agent/base_market_agent/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -172,4 +158,3 @@ def make_offer(self, market_name, buyer_seller, curve): """ result = self.registrations.make_offer(market_name, buyer_seller, curve) return result - diff --git a/volttron/platform/agent/base_market_agent/buy_sell.py b/volttron/platform/agent/base_market_agent/buy_sell.py index 606d5e3a32..49fc05d75e 100644 --- a/volttron/platform/agent/base_market_agent/buy_sell.py +++ b/volttron/platform/agent/base_market_agent/buy_sell.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} BUYER = 'buyer' diff --git a/volttron/platform/agent/base_market_agent/error_codes.py b/volttron/platform/agent/base_market_agent/error_codes.py index 2ac5bbd067..91594a3c97 100644 --- a/volttron/platform/agent/base_market_agent/error_codes.py +++ b/volttron/platform/agent/base_market_agent/error_codes.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} NOT_FORMED = 'not formed' diff --git a/volttron/platform/agent/base_market_agent/market_registration.py b/volttron/platform/agent/base_market_agent/market_registration.py index de0e82cc86..1074c47a0f 100644 --- a/volttron/platform/agent/base_market_agent/market_registration.py +++ b/volttron/platform/agent/base_market_agent/market_registration.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/volttron/platform/agent/base_market_agent/offer.py b/volttron/platform/agent/base_market_agent/offer.py index 3234891ff3..9753fc3f60 100644 --- a/volttron/platform/agent/base_market_agent/offer.py +++ b/volttron/platform/agent/base_market_agent/offer.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} class Offer: diff --git a/volttron/platform/agent/base_market_agent/point.py b/volttron/platform/agent/base_market_agent/point.py index b9fa08d400..ccb0639ef6 100644 --- a/volttron/platform/agent/base_market_agent/point.py +++ b/volttron/platform/agent/base_market_agent/point.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from builtins import property as _property, tuple as _tuple diff --git a/volttron/platform/agent/base_market_agent/poly_line.py b/volttron/platform/agent/base_market_agent/poly_line.py index 943e180587..dd86660c3b 100644 --- a/volttron/platform/agent/base_market_agent/poly_line.py +++ b/volttron/platform/agent/base_market_agent/poly_line.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import numpy as np diff --git a/volttron/platform/agent/base_market_agent/poly_line_factory.py b/volttron/platform/agent/base_market_agent/poly_line_factory.py index 20ad8bb3cf..323bf20cf7 100644 --- a/volttron/platform/agent/base_market_agent/poly_line_factory.py +++ b/volttron/platform/agent/base_market_agent/poly_line_factory.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import numpy as np @@ -138,4 +124,3 @@ def fromTupples(points): if p is not None and len(p) == 2: poly_line.add(Point(p[0], p[1])) return poly_line - diff --git a/volttron/platform/agent/base_market_agent/registration_manager.py b/volttron/platform/agent/base_market_agent/registration_manager.py index d4ffb68558..5343c0959e 100644 --- a/volttron/platform/agent/base_market_agent/registration_manager.py +++ b/volttron/platform/agent/base_market_agent/registration_manager.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/volttron/platform/agent/base_market_agent/rpc_proxy.py b/volttron/platform/agent/base_market_agent/rpc_proxy.py index 71c4b80752..4a32700f7b 100644 --- a/volttron/platform/agent/base_market_agent/rpc_proxy.py +++ b/volttron/platform/agent/base_market_agent/rpc_proxy.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -109,5 +95,3 @@ def make_offer(self, market_name, buyer_seller, curve): result = (False, e.message) _log.info("Market: {} {} has had an offer rejected because {}".format(market_name, buyer_seller, e.message)) return result - - diff --git a/volttron/platform/agent/base_simulation_integration/base_sim_integration.py b/volttron/platform/agent/base_simulation_integration/base_sim_integration.py index bd726f6e77..097ca90269 100644 --- a/volttron/platform/agent/base_simulation_integration/base_sim_integration.py +++ b/volttron/platform/agent/base_simulation_integration/base_sim_integration.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -65,6 +51,3 @@ def is_sim_installed(self, *args, **kwargs): def stop_simulation(self, *args, **kwargs): pass - - - diff --git a/volttron/platform/agent/base_tagging.py b/volttron/platform/agent/base_tagging.py index c2e85bdd55..54c50db051 100644 --- a/volttron/platform/agent/base_tagging.py +++ b/volttron/platform/agent/base_tagging.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -84,7 +70,7 @@ class BaseTaggingService(Agent): """This is the base class for tagging service implementations. There can - be different implementations based on backend/data store used to persist + be different implementations based on backend/data store used to persist the tag details """ @@ -129,7 +115,7 @@ def on_start(self, sender, **kwargs): def setup(self): """ Called on start of agent - Method to establish database connection, do any initial + Method to establish database connection, do any initial bootstrap necessary. Example - load master list of tags, units, categories etc. into data store/memory """ @@ -207,26 +193,26 @@ def get_tags_by_category(self, category, include_kind=False, include_description=False, skip=0, count=None, order="FIRST_TO_LAST"): """ - Get the list of tags for a given category name. category can have + Get the list of tags for a given category name. category can have multiple tags and tags could belong to multiple categories - - :param category: name of the category for which associated tags + + :param category: name of the category for which associated tags should be returned - :param include_kind: indicate if result should include the + :param include_kind: indicate if result should include the kind/datatype for tags returned - :param include_description: indicate if result should include + :param include_description: indicate if result should include available description for tags returned :param skip: number of tags to skip. usually used with order :param count: limit on the number of tags to return :param order: order of result - "FIRST_TO_LAST" or "LAST_TO_FIRST" :return: Will return one of the following - - - list of tag names - - list of (tags, its data type/kind) if include_kind is True + + - list of tag names + - list of (tags, its data type/kind) if include_kind is True - list of (tags, description) if include_description is True - list of (tags, its data type/kind, description) if include_kind is True and include_description is true - + :type category: str :type include_kind: bool :type include_description: bool @@ -282,17 +268,17 @@ def get_tags_by_topic(self, topic_prefix, include_kind=False, """ Get the list of tags for a given topic prefix or name. - :param topic_prefix: topic_prefix for which associated tags should + :param topic_prefix: topic_prefix for which associated tags should be returned - :param include_kind: indicate if result should include the + :param include_kind: indicate if result should include the kind/datatype for tags returned - :param include_description: indicate if result should include + :param include_description: indicate if result should include available description for tags returned :param skip: number of tags to skip. usually used with order :param count: limit on the number of tags to return :param order: order of result - "FIRST_TO_LAST" or "LAST_TO_FIRST" :return: Will return one of the following - + - list of (tag name, value) - list of (tag name, value, data type/kind) if include_kind is True - list of (tag name, value, description) if include_description is True @@ -403,14 +389,14 @@ def get_topics_by_tags(self, and_condition=None, or_condition=None, :param count: limit on the number of tags to return :param order: order of result - "FIRST_TO_LAST" or "LAST_TO_FIRST" - + :type and_condition: dict or list :type or_condition: dict or list :type condition: str :type skip: int :type count: int :type order: str - :return: list of topics/topic_prefix that match the given query + :return: list of topics/topic_prefix that match the given query conditions :rtype: list """ @@ -500,9 +486,9 @@ def add_topic_tags(self, topic_prefix, tags, update_version=False): matching any given input topic pattern or specific topic prefix. :param topic_prefix: topic name or topic name prefix - :param tags: dictionary of tag and value in the format + :param tags: dictionary of tag and value in the format {:value, : value,... } - :param update_version: True/False. Default to False. + :param update_version: True/False. Default to False. If set to True and if any of the tags update an existing tag value the older value would be preserved as part of tag version history :type topic_prefix: str @@ -521,7 +507,7 @@ def add_tags(self, tags, update_version=False): :py:meth:`BaseTaggingService.get_matching_topic_prefixes` to get the list of topic prefix or topic names for a given topic pattern. - :param tags: dictionary object or file containing the topic and the + :param tags: dictionary object or file containing the topic and the tag details. Dictionary object or the file content should be of the format : {:, @@ -1054,7 +1040,3 @@ def parse_query(query, tags, refs): print("SQLITE QUERY:") print(SqlLiteFuncts.get_tagging_query_from_ast("topic_tags", ast, tag_refs)) - - - - diff --git a/volttron/platform/agent/base_weather.py b/volttron/platform/agent/base_weather.py index ac459e16e5..c223a59b8c 100644 --- a/volttron/platform/agent/base_weather.py +++ b/volttron/platform/agent/base_weather.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -41,13 +27,14 @@ import csv import sqlite3 import datetime +import os from functools import wraps from abc import abstractmethod from gevent import get_hub from volttron.platform.agent.utils import fix_sqlite3_datetime, \ get_aware_utc_now, format_timestamp, process_timestamp, \ parse_timestamp_string -from volttron.platform.vip.agent import * +from volttron.platform.vip.agent import Agent, RPC, Core from volttron.platform.async_ import AsyncCall from volttron.platform.messaging import headers from volttron.platform.messaging.health import (STATUS_BAD, @@ -69,7 +56,7 @@ CREATE_STMT_CURRENT = """CREATE TABLE {table} (ID INTEGER PRIMARY KEY ASC, LOCATION TEXT NOT NULL, - OBSERVATION_TIME TIMESTAMP NOT NULL, + OBSERVATION_TIME TIMESTAMP NOT NULL, POINTS TEXT NOT NULL);""" CREATE_STMT_FORECAST = """CREATE TABLE {table} @@ -1429,7 +1416,7 @@ def get_current_data(self, service_name, location): query = "" cursor = self._sqlite_conn.cursor() - query = """SELECT max(OBSERVATION_TIME), POINTS + query = """SELECT max(OBSERVATION_TIME), POINTS FROM {table} WHERE LOCATION = ?;""".format(table=service_name) _log.debug(query) @@ -1460,15 +1447,15 @@ def get_forecast_data(self, service_name, service_length, location, # 2-8 when the request time is hour 1. forecast_start, forecast_end = get_forecast_start_stop(request_time, quantity, service_name) cursor = self._sqlite_conn.cursor() - query = """SELECT GENERATION_TIME, FORECAST_TIME, POINTS - FROM {table} - WHERE LOCATION = ? - AND FORECAST_TIME >= ? - AND FORECAST_TIME < ? - AND GENERATION_TIME = - (SELECT MAX(GENERATION_TIME) + query = """SELECT GENERATION_TIME, FORECAST_TIME, POINTS + FROM {table} + WHERE LOCATION = ? + AND FORECAST_TIME >= ? + AND FORECAST_TIME < ? + AND GENERATION_TIME = + (SELECT MAX(GENERATION_TIME) FROM {table} - WHERE LOCATION = ?) + WHERE LOCATION = ?) ORDER BY FORECAST_TIME ASC;""".format(table=service_name) _log.debug(query) cursor.execute(query, (location, forecast_start, forecast_end, @@ -1518,12 +1505,12 @@ def store_weather_records(self, service_name, records): cursor = self._sqlite_conn.cursor() request_type = self._api_services[service_name]["type"] if request_type == "forecast": - query = """INSERT INTO {} - (LOCATION, GENERATION_TIME, FORECAST_TIME, POINTS) + query = """INSERT INTO {} + (LOCATION, GENERATION_TIME, FORECAST_TIME, POINTS) VALUES (?, ?, ?, ?)""".format(service_name) else: - query = """INSERT INTO {} - (LOCATION, OBSERVATION_TIME, POINTS) + query = """INSERT INTO {} + (LOCATION, OBSERVATION_TIME, POINTS) VALUES (?, ?, ?)""".format(service_name) _log.debug(query) @@ -1575,7 +1562,7 @@ def manage_cache_size(self): for table_name, service in self._api_services.items(): # Remove all data that is older than update interval if service["type"] == "current": - query = """DELETE FROM {table} + query = """DELETE FROM {table} WHERE OBSERVATION_TIME < ?;""" \ .format(table=table_name) cursor.execute(query, @@ -1584,7 +1571,7 @@ def manage_cache_size(self): for table_name, service in self._api_services.items(): # Remove all data that is older than update interval if service["type"] == "forecast": - query = """DELETE FROM {table} + query = """DELETE FROM {table} WHERE GENERATION_TIME < ?""".format( table=table_name) cursor.execute(query, @@ -1608,8 +1595,8 @@ def manage_cache_size(self): # if we still don't have space in cache while page_count >= self._max_pages: for table_name in self._api_services: - query = """DELETE FROM {table} WHERE ID IN - (SELECT ID FROM {table} + query = """DELETE FROM {table} WHERE ID IN + (SELECT ID FROM {table} ORDER BY ID ASC LIMIT 100)""".format( table=table_name) cursor.execute(query) diff --git a/volttron/platform/agent/driven.py b/volttron/platform/agent/driven.py index 28ee42e6b8..ffde9c754a 100644 --- a/volttron/platform/agent/driven.py +++ b/volttron/platform/agent/driven.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ abstract agent for to drive VOLTTRON Nation apps.''' diff --git a/volttron/platform/agent/exit_codes.py b/volttron/platform/agent/exit_codes.py index a96bc2cf1e..680f2ee647 100644 --- a/volttron/platform/agent/exit_codes.py +++ b/volttron/platform/agent/exit_codes.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} INVALID_CONFIGURATION_CODE = 105 diff --git a/volttron/platform/agent/green.py b/volttron/platform/agent/green.py index 61ae1d236f..51b604d0f6 100644 --- a/volttron/platform/agent/green.py +++ b/volttron/platform/agent/green.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ greenlet coroutine helper classes/functions. @@ -101,4 +87,3 @@ def kill_all(self): tasks, self.tasks = self.tasks, [] for task in tasks: task.throw() - diff --git a/volttron/platform/agent/known_identities.py b/volttron/platform/agent/known_identities.py index ce921c2a04..162b59b1e4 100644 --- a/volttron/platform/agent/known_identities.py +++ b/volttron/platform/agent/known_identities.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} AUTH = 'platform.auth' diff --git a/volttron/platform/agent/matching.py b/volttron/platform/agent/matching.py index fc68634237..187043d1db 100644 --- a/volttron/platform/agent/matching.py +++ b/volttron/platform/agent/matching.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -215,7 +201,7 @@ def _split_glob(pattern): def test_glob(pattern): """ Return static prefix and regex test for glob pattern. - + The pattern may include the following special wildcard patterns:: * Matches zero or more characters. @@ -315,4 +301,3 @@ def wrapper(self, topic, headers, message, match): wrapper.__dict__.update(func.__dict__) return wrapper return decorator - diff --git a/volttron/platform/agent/math_utils.py b/volttron/platform/agent/math_utils.py index 33a4969dd1..03b3b90e3e 100644 --- a/volttron/platform/agent/math_utils.py +++ b/volttron/platform/agent/math_utils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''Dumping ground for VOLTTRON platform™ agent math helper functions. @@ -41,7 +27,7 @@ Not meant to replace numpy in all cases. A basic set common math routines to remove the need for numpy in simple cases. -This module should NEVER import numpy as that would defeat the +This module should NEVER import numpy as that would defeat the purpose.''' def mean(data): @@ -74,5 +60,3 @@ def stdev(data): ss = _ss(data) pvar = ss/(n-1) # sample variance return pvar**0.5 - - diff --git a/volttron/platform/agent/multithreading.py b/volttron/platform/agent/multithreading.py index 0c2f09cf59..648ac7b56f 100644 --- a/volttron/platform/agent/multithreading.py +++ b/volttron/platform/agent/multithreading.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ multi-threaded agent helper classes/functions. @@ -66,7 +52,7 @@ def wait(self, timeout=None): ''' with self.condition: return self._wait(timeout) - + def _wait(self, timeout=None): counter = self.counter self.condition.wait(timeout) @@ -87,4 +73,3 @@ def notify(self, data, n=1): self.data = data self.counter += 1 self.condition.notify(n) - diff --git a/volttron/platform/agent/sched.py b/volttron/platform/agent/sched.py index c7f3feff5f..7d0e92a552 100644 --- a/volttron/platform/agent/sched.py +++ b/volttron/platform/agent/sched.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ agent event scheduling classes.''' @@ -63,8 +49,8 @@ def __call__(self, deadline): if not self.canceled: self.function(*self.args, **self.kwargs) self.finished = True - -class EventWithTime(Event): + +class EventWithTime(Event): '''Event that passes deadline to event handler.''' def __call__(self, deadline): if not self.canceled: @@ -116,4 +102,3 @@ def delay(self, time): def __bool__(self): return bool(self._queue) - diff --git a/volttron/platform/agent/utils.py b/volttron/platform/agent/utils.py index 5259b232c4..eb9f2ec238 100644 --- a/volttron/platform/agent/utils.py +++ b/volttron/platform/agent/utils.py @@ -1,58 +1,46 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} - """VOLTTRON platform™ agent helper classes/functions.""" - import argparse import calendar import errno import logging -import warnings import os - import subprocess import sys +import warnings +from pathlib import Path +from typing import Callable + try: HAS_SYSLOG = True import syslog except ImportError: HAS_SYSLOG = False +import re +import stat import traceback from configparser import ConfigParser from datetime import datetime @@ -60,33 +48,29 @@ import gevent import psutil import pytz -import re -import stat import yaml from dateutil.parser import parse -from dateutil.tz import tzutc, tzoffset +from dateutil.tz import tzoffset, tzutc from tzlocal import get_localzone +from watchdog.events import FileClosedEvent, FileSystemEventHandler from watchdog_gevent import Observer -from volttron.platform import get_home, get_address -from volttron.platform import jsonapi -from volttron.utils import VolttronHomeFileReloader, AbsolutePathFileReloader +from volttron.platform import get_address, get_home, jsonapi +from volttron.utils import AbsolutePathFileReloader, VolttronHomeFileReloader from volttron.utils.prompt import prompt_response - -__all__ = ['load_config', 'run_agent', 'start_agent_thread', - 'is_valid_identity', 'load_platform_config', 'get_messagebus', - 'get_fq_identity', 'execute_command', 'get_aware_utc_now', - 'is_secure_mode', 'is_web_enabled', 'is_auth_enabled', - 'wait_for_volttron_shutdown', 'is_volttron_running'] +__all__ = [ + 'load_config', 'run_agent', 'start_agent_thread', 'is_valid_identity', 'load_platform_config', + 'get_messagebus', 'get_fq_identity', 'execute_command', 'get_aware_utc_now', 'is_secure_mode', + 'is_web_enabled', 'is_auth_enabled', 'wait_for_volttron_shutdown', 'is_volttron_running' +] __author__ = 'Brandon Carpenter ' __copyright__ = 'Copyright (c) 2016, Battelle Memorial Institute' __license__ = 'Apache 2.0' -_comment_re = re.compile( - r'((["\'])(?:\\?.)*?\2)|(/\*.*?\*/)|((?:#|//).*?(?=\n|$))', - re.MULTILINE | re.DOTALL) +_comment_re = re.compile(r'((["\'])(?:\\?.)*?\2)|(/\*.*?\*/)|((?:#|//).*?(?=\n|$))', + re.MULTILINE | re.DOTALL) _log = logging.getLogger(__name__) @@ -146,11 +130,15 @@ def strip_comments(string): def load_config(config_path): """Load a JSON-encoded configuration file.""" if config_path is None: - _log.info("AGENT_CONFIG does not exist in environment. load_config returning empty configuration.") + _log.info( + "AGENT_CONFIG does not exist in environment. load_config returning empty configuration." + ) return {} if not os.path.exists(config_path): - raise ValueError(f"Config file specified by AGENT_CONFIG path {config_path} does not exist.") + raise ValueError( + f"Config file specified by path {config_path} does not exist." + ) # First attempt parsing the file with a yaml parser (allows comments natively) # Then if that fails we fallback to our modified json parser. @@ -165,7 +153,7 @@ def load_config(config_path): with open(config_path) as f: return parse_json_config(f.read()) except Exception as e: - _log.error("Problem parsing agent configuration") + _log.error(f"Problem parsing configuration {config_path}: {e}") raise @@ -194,7 +182,8 @@ def get_platform_instance_name(vhome=None, prompt=False): if not instance_name: instance_name = 'volttron1' instance_name = prompt_response("Name of this volttron instance:", - mandatory=True, default=instance_name) + mandatory=True, + default=instance_name) else: if not instance_name: _log.warning("Using hostname as instance name.") @@ -237,6 +226,7 @@ def get_messagebus(): message_bus = config.get('message-bus', 'zmq') return message_bus + def is_auth_enabled(): """Get type of message bus - zeromq or rabbbitmq.""" allow_auth = os.environ.get('AUTH_ENABLED') @@ -246,6 +236,7 @@ def is_auth_enabled(): allow_auth = False if allow_auth == 'False' else True return allow_auth + def is_web_enabled(): """Returns True if web enabled, False otherwise""" is_web = os.environ.get('BIND_WEB_ADDRESS') @@ -294,7 +285,7 @@ def store_message_bus_config(message_bus, instance_name): config = ConfigParser() config.read(config_path) config.set('volttron', 'message-bus', message_bus) - config.set('volttron','instance-name', instance_name) + config.set('volttron', 'instance-name', instance_name) with open(config_path, 'w') as configfile: config.write(configfile) else: @@ -314,13 +305,13 @@ def store_message_bus_config(message_bus, instance_name): def update_kwargs_with_config(kwargs, config): """ Loads the user defined configurations into kwargs. - + 1. Converts any dash/hyphen in config variables into underscores - 2. Checks for configured "identity" value. Prints a deprecation - warning and uses it. - 3. Checks for configured "agentid" value. Prints a deprecation warning + 2. Checks for configured "identity" value. Prints a deprecation + warning and uses it. + 3. Checks for configured "agentid" value. Prints a deprecation warning and ignores it - + :param kwargs: kwargs to be updated :param config: dictionary of user/agent configuration """ @@ -329,10 +320,9 @@ def update_kwargs_with_config(kwargs, config): _log.warning("DEPRECATION WARNING: Setting a historian's VIP IDENTITY" " from its configuration file will no longer be supported" " after VOLTTRON 4.0") - _log.warning( - "DEPRECATION WARNING: Using the identity configuration setting " - "will override the value provided by the platform. This new value " - "will not be reported correctly by 'volttron-ctl status'") + _log.warning("DEPRECATION WARNING: Using the identity configuration setting " + "will override the value provided by the platform. This new value " + "will not be reported correctly by 'volttron-ctl status'") _log.warning("DEPRECATION WARNING: Please remove 'identity' from your " "configuration file and use the new method provided by " "the platform to set an agent's identity. See " @@ -354,8 +344,7 @@ def parse_json_config(config_str): return jsonapi.loads(strip_comments(config_str)) -def run_agent(cls, subscribe_address=None, publish_address=None, - config_path=None, **kwargs): +def run_agent(cls, subscribe_address=None, publish_address=None, config_path=None, **kwargs): """Instantiate an agent and run it in the current thread. Attempts to get keyword parameters from the environment if they @@ -395,8 +384,11 @@ def isapipe(fd): return stat.S_ISFIFO(os.fstat(fd).st_mode) -def default_main(agent_class, description=None, argv=sys.argv, - parser_class=argparse.ArgumentParser, **kwargs): +def default_main(agent_class, + description=None, + argv=sys.argv, + parser_class=argparse.ArgumentParser, + **kwargs): """Default main entry point implementation for legacy agents. description and parser_class are depricated. Please avoid using them. @@ -413,8 +405,7 @@ def default_main(agent_class, description=None, argv=sys.argv, sub_addr = os.environ['AGENT_SUB_ADDR'] pub_addr = os.environ['AGENT_PUB_ADDR'] except KeyError as exc: - sys.stderr.write( - 'missing environment variable: {}\n'.format(exc.args[0])) + sys.stderr.write('missing environment variable: {}\n'.format(exc.args[0])) sys.exit(1) if sub_addr.startswith('ipc://') and sub_addr[6:7] != '@': if not os.path.exists(sub_addr[6:]): @@ -427,7 +418,8 @@ def default_main(agent_class, description=None, argv=sys.argv, config = os.environ.get('AGENT_CONFIG') agent = agent_class(subscribe_address=sub_addr, publish_address=pub_addr, - config_path=config, **kwargs) + config_path=config, + **kwargs) agent.run() except KeyboardInterrupt: pass @@ -445,7 +437,7 @@ def vip_main(agent_class, identity=None, version='0.1', **kwargs): # Quiet printing of KeyboardInterrupt by greenlets Hub = gevent.hub.Hub - Hub.NOT_ERROR = Hub.NOT_ERROR + (KeyboardInterrupt,) + Hub.NOT_ERROR = Hub.NOT_ERROR + (KeyboardInterrupt, ) config = os.environ.get('AGENT_CONFIG') identity = os.environ.get('AGENT_VIP_IDENTITY', identity) @@ -453,9 +445,29 @@ def vip_main(agent_class, identity=None, version='0.1', **kwargs): if identity is not None: if not is_valid_identity(identity): _log.warning('Deprecation warining') - _log.warning( - 'All characters in {identity} are not in the valid set.' - .format(idenity=identity)) + _log.warning(f'All characters in {identity} are not in the valid set.') + + publickey = kwargs.pop("publickey", None) + if not publickey: + publickey = os.environ.get("AGENT_PUBLICKEY") + secretkey = kwargs.pop("secretkey", None) + if not secretkey: + secretkey = os.environ.get("AGENT_SECRETKEY") + serverkey = kwargs.pop("serverkey", None) + if not serverkey: + serverkey = os.environ.get("VOLTTRON_SERVERKEY") + + # AGENT_PUBLICKEY and AGENT_SECRETKEY must be specified + # for the agent to execute successfully. aip should set these + # if the agent is run from the platform. If run from the + # run command it should be set automatically from vctl and + # added to the server. + # + # TODO: Make required for all agents. Handle it through vctl and aip. + if not os.environ.get("_LAUNCHED_BY_PLATFORM"): + if not publickey or not secretkey: + raise ValueError("AGENT_PUBLIC and AGENT_SECRET environmental variables must " + "be set to run without the platform.") address = get_address() agent_uuid = os.environ.get('AGENT_UUID') @@ -463,12 +475,18 @@ def vip_main(agent_class, identity=None, version='0.1', **kwargs): from volttron.platform.auth.certs import Certs certs = Certs() - agent = agent_class(config_path=config, identity=identity, - address=address, agent_uuid=agent_uuid, + agent = agent_class(config_path=config, + identity=identity, + address=address, + agent_uuid=agent_uuid, volttron_home=volttron_home, version=version, - message_bus=message_bus, **kwargs) - + message_bus=message_bus, + publickey=publickey, + secretkey=secretkey, + serverkey=serverkey, + **kwargs) + try: run = agent.run except AttributeError: @@ -485,20 +503,23 @@ def vip_main(agent_class, identity=None, version='0.1', **kwargs): # Keep the ability to have system log output for linux # this will fail on windows because no syslog. if HAS_SYSLOG: + class SyslogFormatter(logging.Formatter): - _level_map = {logging.DEBUG: syslog.LOG_DEBUG, - logging.INFO: syslog.LOG_INFO, - logging.WARNING: syslog.LOG_WARNING, - logging.ERROR: syslog.LOG_ERR, - logging.CRITICAL: syslog.LOG_CRIT} + _level_map = { + logging.DEBUG: syslog.LOG_DEBUG, + logging.INFO: syslog.LOG_INFO, + logging.WARNING: syslog.LOG_WARNING, + logging.ERROR: syslog.LOG_ERR, + logging.CRITICAL: syslog.LOG_CRIT + } def format(self, record): level = self._level_map.get(record.levelno, syslog.LOG_INFO) - return '<{}>'.format(level) + super(SyslogFormatter, self).format( - record) + return '<{}>'.format(level) + super(SyslogFormatter, self).format(record) class JsonFormatter(logging.Formatter): + def format(self, record): dct = record.__dict__.copy() dct["msg"] = record.getMessage() @@ -510,6 +531,7 @@ def format(self, record): class AgentFormatter(logging.Formatter): + def __init__(self, fmt=None, datefmt=None): if fmt is None: fmt = '%(asctime)s %(composite_name)s %(levelname)s: %(message)s' @@ -517,12 +539,12 @@ def __init__(self, fmt=None, datefmt=None): def composite_name(self, record): if record.name == 'agents.log': - cname = '(%(processName)s %(process)d) %(remote_name)s' + cname = '(%(processName)s %(process)d [%(lineno)d]) %(remote_name)s' elif record.name.startswith('agents.std'): - cname = '(%(processName)s %(process)d) <{}>'.format( + cname = '(%(processName)s %(process)d [%(lineno)d]) <{}>'.format( record.name.split('.', 2)[1]) else: - cname = '() %(name)s' + cname = '() %(name)s [%(lineno)d]' return cname % record.__dict__ def format(self, record): @@ -546,7 +568,7 @@ def setup_logging(level=logging.DEBUG, console=False): # Below format is more readable for console handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) else: - fmt = '%(asctime)s %(name)s %(levelname)s: %(message)s' + fmt = '%(asctime)s %(name)s %(lineno)d %(levelname)s: %(message)s' handler.setFormatter(logging.Formatter(fmt)) if level != logging.DEBUG: # import it here so that when urllib3 imports the requests package, ssl would already got @@ -561,10 +583,10 @@ def setup_logging(level=logging.DEBUG, console=False): def format_timestamp(time_stamp): """Create a consistent datetime string representation based on ISO 8601 format. - + YYYY-MM-DDTHH:MM:SS.mmmmmm for unaware datetime objects. YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM for aware datetime objects - + :param time_stamp: value to convert :type time_stamp: datetime :returns: datetime in string format @@ -583,9 +605,7 @@ def format_timestamp(time_stamp): seconds = td.seconds minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) - time_str += "{sign}{HH:02}:{MM:02}".format(sign=sign, - HH=hours, - MM=minutes) + time_str += "{sign}{HH:02}:{MM:02}".format(sign=sign, HH=hours, MM=minutes) return time_str @@ -637,7 +657,7 @@ def parse_timestamp_string(time_stamp_str): def get_aware_utc_now(): """Create a timezone aware UTC datetime object from the system time. - + :returns: an aware UTC datetime object :rtype: datetime """ @@ -685,8 +705,8 @@ def process_timestamp(timestamp_string, topic=''): try: timestamp = parse_timestamp_string(timestamp_string) except (ValueError, TypeError): - _log.error("message for {topic} bad timetamp string: {ts_string}" - .format(topic=topic, ts_string=timestamp_string)) + _log.error("message for {topic} bad timetamp string: {ts_string}".format( + topic=topic, ts_string=timestamp_string)) return if timestamp.tzinfo is None: @@ -698,21 +718,34 @@ def process_timestamp(timestamp_string, topic=''): return timestamp, original_tz -def watch_file(fullpath, callback): - """Run callback method whenever the file changes +def watch_file(path: str, callback: Callable): + """Run callback method whenever `path` changes. - Not available on OS X/MacOS. + If `path` is not rooted the function assumes relative to the $VOLTTRON_HOME + environmental variable + + The watch_file will create a watchdog event handler and will trigger when + the close event happens for writing to the file. + + Not available on OS X/MacOS. """ + file_path = Path(path) + if not file_path.is_absolute(): + file_path = Path(get_home()) / file_path - dirname, filename = os.path.split(fullpath) - _log.info("Adding file watch for %s dirname=%s, filename=%s", fullpath, get_home(), filename) + class Reloader(FileSystemEventHandler): + + def on_closed(self, event): + """ Only called after a write to file has been closed + """ + callback() + + _log.debug(f"Watch file added for filename {file_path}") observer = Observer() - observer.schedule( - VolttronHomeFileReloader(filename, callback), - path=get_home() - ) + + observer.schedule(Reloader(), str(file_path)) observer.start() - _log.info("Added file watch for %s", fullpath) + _log.debug("Added file watch for %s", path) def watch_file_with_fullpath(fullpath, callback): @@ -723,10 +756,7 @@ def watch_file_with_fullpath(fullpath, callback): dirname, filename = os.path.split(fullpath) _log.info("Adding file watch for %s", fullpath) _observer = Observer() - _observer.schedule( - AbsolutePathFileReloader(fullpath, callback), - dirname - ) + _observer.schedule(AbsolutePathFileReloader(fullpath, callback), dirname) _log.info("Added file watch for %s", fullpath) _observer.start() @@ -764,12 +794,12 @@ def create_file_if_missing(path, permission=0o660, contents=None): def fix_sqlite3_datetime(sql=None): """Primarily for fixing the base historian cache on certain versions of python. - + Registers a new datetime converter to that uses dateutil parse. This should better resolve #216, #174, and #91 without the goofy workarounds that change data. - + Optional sql argument is for testing only. """ if sql is None: @@ -777,11 +807,17 @@ def fix_sqlite3_datetime(sql=None): def parse(time_stamp_bytes): return parse_timestamp_string(time_stamp_bytes.decode("utf-8")) + sql.register_adapter(datetime, format_timestamp) sql.register_converter("timestamp", parse) -def execute_command(cmds, env=None, cwd=None, logger=None, err_prefix=None, use_shell=False) -> str: +def execute_command(cmds, + env=None, + cwd=None, + logger=None, + err_prefix=None, + use_shell=False) -> str: """ Executes a command as a subprocess If the return code of the call is 0 then return stdout otherwise @@ -798,8 +834,12 @@ def execute_command(cmds, env=None, cwd=None, logger=None, err_prefix=None, use_ :raises RuntimeError: if the return code is not 0 from suprocess.run """ - results = subprocess.run(cmds, env=env, cwd=cwd, - stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=use_shell) + results = subprocess.run(cmds, + env=env, + cwd=cwd, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + shell=use_shell) if results.returncode != 0: err_prefix = err_prefix if err_prefix is not None else "Error executing command" err_message = "\n{}: Below Command failed with non zero exit code.\n" \ @@ -814,6 +854,7 @@ def execute_command(cmds, env=None, cwd=None, logger=None, err_prefix=None, use_ return results.stdout.decode('utf-8') + # # def execute_command_p(cmds, env=None, cwd=None, logger=None, err_prefix=None): # """ Executes a given command using a subprocess. @@ -886,4 +927,5 @@ def wait_for_volttron_shutdown(vhome, timeout): gevent.sleep(1) sleep_time += 1 if sleep_time >= timeout: - raise Exception("Platform shutdown failed. Please check volttron.cfg.log in {}".format(vhome)) + raise Exception( + "Platform shutdown failed. Please check volttron.cfg.log in {}".format(vhome)) diff --git a/volttron/platform/aip.py b/volttron/platform/aip.py index 0af5fb7f7c..dc7859ec89 100644 --- a/volttron/platform/aip.py +++ b/volttron/platform/aip.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -66,8 +52,7 @@ get_messagebus, get_platform_instance_name) from volttron.platform import get_home -from volttron.platform.agent.utils import load_platform_config, \ - get_utc_seconds_from_epoch +from volttron.platform.agent.utils import get_utc_seconds_from_epoch from volttron.platform.packages import UnpackedPackage from volttron.platform.vip.agent import Agent from volttron.platform.auth.auth_entry import AuthEntry diff --git a/volttron/platform/async_.py b/volttron/platform/async_.py index 87b9613ceb..320cbbff52 100644 --- a/volttron/platform/async_.py +++ b/volttron/platform/async_.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''Run gevent Greenlets in their own threads. diff --git a/volttron/platform/auth/__init__.py b/volttron/platform/auth/__init__.py index b768b50863..cc76e20c09 100644 --- a/volttron/platform/auth/__init__.py +++ b/volttron/platform/auth/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from volttron.platform.auth.auth import AuthService @@ -47,17 +33,17 @@ __all__ = [ # Auth Service "AuthService", - # Auth Entry - "AuthEntry", - "AuthEntryInvalid", + # Auth Entry + "AuthEntry", + "AuthEntryInvalid", # Auth File - "AuthFile", - "AuthFileEntryAlreadyExists", + "AuthFile", + "AuthFileEntryAlreadyExists", "AuthFileUserIdAlreadyExists", "AuthFileIndexError" # Auth Exception - "AuthException", + "AuthException", # Certs - "Certs", - "CertError", + "Certs", + "CertError", "CertWrapper"] diff --git a/volttron/platform/auth/auth.py b/volttron/platform/auth/auth.py index d837da565e..07c3ed83f1 100644 --- a/volttron/platform/auth/auth.py +++ b/volttron/platform/auth/auth.py @@ -1,80 +1,52 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} - +import copy import logging import os -import copy import gevent import gevent.core from gevent.fileobject import FileObject -from volttron.platform.agent.known_identities import ( - CONTROL_CONNECTION, - PROCESS_IDENTITIES, -) -from volttron.platform.auth.auth_utils import load_user +from volttron.platform.agent.known_identities import CONTROL_CONNECTION, PROCESS_IDENTITIES +from volttron.platform.agent.utils import create_file_if_missing, get_messagebus, watch_file from volttron.platform.auth.auth_entry import AuthEntry from volttron.platform.auth.auth_file import AuthFile +from volttron.platform.auth.auth_utils import load_user from volttron.platform.jsonrpc import RemoteError +from volttron.platform.vip.agent import RPC, Agent, Core from volttron.platform.vip.agent.errors import Unreachable from volttron.platform.vip.pubsubservice import ProtectedPubSubTopics -from volttron.platform.agent.utils import ( - create_file_if_missing, - watch_file, - get_messagebus, -) -from volttron.platform.vip.agent import Agent, Core, RPC _log = logging.getLogger(__name__) class AuthService(Agent): - def __init__( - self, - auth_file, - protected_topics_file, - setup_mode, - aip, - *args, - **kwargs - ): + + def __init__(self, auth_file, protected_topics_file, setup_mode, aip, + *args, **kwargs): """Initializes AuthService, and prepares AuthFile.""" self.allow_any = kwargs.pop("allow_any", False) self.is_zap_required = kwargs.pop('zap_required', True) @@ -96,8 +68,7 @@ def __init__( self._is_connected = False self._protected_topics_file = protected_topics_file self._protected_topics_file_path = os.path.abspath( - protected_topics_file - ) + protected_topics_file) self._protected_topics = {} self._protected_topics_for_rmq = ProtectedPubSubTopics() self._setup_mode = setup_mode @@ -137,28 +108,23 @@ def auth_file_update_by_index(auth_entry, index, is_allow=True): :params: auth_entry, index, is_allow :return: None """ - self.auth_file.update_by_index( - AuthEntry(**auth_entry), index, is_allow - ) + self.auth_file.update_by_index(AuthEntry(**auth_entry), index, + is_allow) self.vip.rpc.export(auth_file_read, "auth_file.read") - self.vip.rpc.export( - self.auth_file.find_by_credentials, "auth_file.find_by_credentials" - ) + self.vip.rpc.export(self.auth_file.find_by_credentials, + "auth_file.find_by_credentials") self.vip.rpc.export(auth_file_add, "auth_file.add") - self.vip.rpc.export( - auth_file_update_by_index, "auth_file.update_by_index" - ) + self.vip.rpc.export(auth_file_update_by_index, + "auth_file.update_by_index") self.vip.rpc.export( self.auth_file.remove_by_credentials, "auth_file.remove_by_credentials", ) - self.vip.rpc.export( - self.auth_file.remove_by_index, "auth_file.remove_by_index" - ) - self.vip.rpc.export( - self.auth_file.remove_by_indices, "auth_file.remove_by_indices" - ) + self.vip.rpc.export(self.auth_file.remove_by_index, + "auth_file.remove_by_index") + self.vip.rpc.export(self.auth_file.remove_by_indices, + "auth_file.remove_by_indices") self.vip.rpc.export(self.auth_file.set_groups, "auth_file.set_groups") self.vip.rpc.export(self.auth_file.set_roles, "auth_file.set_roles") @@ -169,11 +135,13 @@ def setup_authentication_server(self, sender, **kwargs): self.read_auth_file() if get_messagebus() == "zmq": from volttron.platform.auth.auth_protocols.auth_zmq import ZMQAuthorization, ZMQServerAuthentication - self.authentication_server = ZMQServerAuthentication(auth_service=self) + self.authentication_server = ZMQServerAuthentication( + auth_service=self) self.authorization_server = ZMQAuthorization(auth_service=self) else: from volttron.platform.auth.auth_protocols.auth_rmq import RMQAuthorization, RMQServerAuthentication - self.authentication_server = RMQServerAuthentication(auth_service=self) + self.authentication_server = RMQServerAuthentication( + auth_service=self) self.authorization_server = RMQAuthorization(auth_service=self) self._read_protected_topics_file() self.core.spawn(watch_file, self.auth_file_path, self.read_auth_file) @@ -186,7 +154,8 @@ def setup_authentication_server(self, sender, **kwargs): @Core.receiver("onstart") def start_authentication_server(self, sender, **kwargs): - self.authentication_server.handle_authentication(self._protected_topics) + self.authentication_server.handle_authentication( + self._protected_topics) @Core.receiver("onstop") def stop_authentication_server(self, sender, **kwargs): @@ -220,27 +189,22 @@ def update_id_rpc_authorizations(self, identity, rpc_methods): # Create it and set it to have the provided # rpc capabilities entry.rpc_method_authorizations[method] = rpc_methods[ - method - ] + method] is_updated = True # Check if the rpc method does not have any # rpc capabilities if not entry.rpc_method_authorizations[method]: # Set it to have the provided rpc capabilities entry.rpc_method_authorizations[method] = rpc_methods[ - method - ] + method] is_updated = True # Check if the rpc method's capabilities match # what have been provided - if ( - entry.rpc_method_authorizations[method] - != rpc_methods[method] - ): + if (entry.rpc_method_authorizations[method] + != rpc_methods[method]): # Update rpc_methods based on auth entries updated_rpc_methods[ - method - ] = entry.rpc_method_authorizations[method] + method] = entry.rpc_method_authorizations[method] # Update auth file if changed and return rpc_methods if is_updated: self.auth_file.update_by_index(entry, entries.index(entry)) @@ -256,14 +220,11 @@ def get_entry_authorizations(self, identity): rpc_method_authorizations = {} try: rpc_method_authorizations = self.vip.rpc.call( - identity, "auth.get_all_rpc_authorizations" - ).get() + identity, "auth.get_all_rpc_authorizations").get() _log.debug(f"RPC Methods are: {rpc_method_authorizations}") except Unreachable: - _log.warning( - f"{identity} " - f"is unreachable while attempting to get rpc methods" - ) + _log.warning(f"{identity} " + f"is unreachable while attempting to get rpc methods") return rpc_method_authorizations @@ -276,11 +237,9 @@ def update_rpc_authorizations(self, entries): """ for entry in entries: # Skip if core agent - if ( - entry.identity is not None + if (entry.identity is not None and entry.identity not in PROCESS_IDENTITIES - and entry.identity != CONTROL_CONNECTION - ): + and entry.identity != CONTROL_CONNECTION): # Collect all modified methods modified_methods = {} for method in entry.rpc_method_authorizations: @@ -291,8 +250,7 @@ def update_rpc_authorizations(self, entries): # if no capabilities in auth file continue modified_methods[method] = entry.rpc_method_authorizations[ - method - ] + method] if modified_methods: method_error = True try: @@ -303,11 +261,9 @@ def update_rpc_authorizations(self, entries): ).wait(timeout=4) method_error = False except gevent.Timeout: - _log.error( - f"{entry.identity} " - f"has timed out while attempting " - f"to update rpc_method_authorizations" - ) + _log.error(f"{entry.identity} " + f"has timed out while attempting " + f"to update rpc_method_authorizations") method_error = False except RemoteError: method_error = True @@ -320,18 +276,14 @@ def update_rpc_authorizations(self, entries): entry.identity, "auth.set_rpc_authorizations", method_str=method, - capabilities= - entry.rpc_method_authorizations[ - method - ], + capabilities=entry. + rpc_method_authorizations[method], ) except gevent.Timeout: - _log.error( - f"{entry.identity} " - f"has timed out while attempting " - f"to update " - f"rpc_method_authorizations" - ) + _log.error(f"{entry.identity} " + f"has timed out while attempting " + f"to update " + f"rpc_method_authorizations") except RemoteError: _log.error(f"Method {method} does not exist.") @@ -357,27 +309,19 @@ def add_rpc_authorizations(self, identity, method, authorizations): elif not entry.rpc_method_authorizations[method]: entry.rpc_method_authorizations[method] = authorizations else: - entry.rpc_method_authorizations[method].extend( - [ - rpc_auth - for rpc_auth in authorizations - if rpc_auth in authorizations - and rpc_auth - not in entry.rpc_method_authorizations[method] - ] - ) + entry.rpc_method_authorizations[method].extend([ + rpc_auth for rpc_auth in authorizations + if rpc_auth in authorizations and rpc_auth not in + entry.rpc_method_authorizations[method] + ]) self.auth_file.update_by_index(entry, entries.index(entry)) return _log.error("Agent identity not found in auth file!") return @RPC.export - def delete_rpc_authorizations( - self, - identity, - method, - denied_authorizations - ): + def delete_rpc_authorizations(self, identity, method, + denied_authorizations): """ Removes authorizations to method in auth entry in auth file. @@ -396,44 +340,34 @@ def delete_rpc_authorizations( if method not in entry.rpc_method_authorizations: _log.error( f"{entry.identity} does not have a method called " - f"{method}" - ) + f"{method}") elif not entry.rpc_method_authorizations[method]: - _log.error( - f"{entry.identity}.{method} does not have any " - f"authorized capabilities." - ) + _log.error(f"{entry.identity}.{method} does not have any " + f"authorized capabilities.") else: any_match = False for rpc_auth in denied_authorizations: - if ( - rpc_auth - not in entry.rpc_method_authorizations[method] - ): + if (rpc_auth not in + entry.rpc_method_authorizations[method]): _log.error( f"{rpc_auth} is not an authorized capability " - f"for {method}" - ) + f"for {method}") else: any_match = True if any_match: entry.rpc_method_authorizations[method] = [ - rpc_auth - for rpc_auth in entry.rpc_method_authorizations[ - method - ] + rpc_auth for rpc_auth in + entry.rpc_method_authorizations[method] if rpc_auth not in denied_authorizations ] if not entry.rpc_method_authorizations[method]: entry.rpc_method_authorizations[method] = [""] - self.auth_file.update_by_index( - entry, entries.index(entry) - ) + self.auth_file.update_by_index(entry, + entries.index(entry)) else: _log.error( f"No matching authorized capabilities provided " - f"for {method}" - ) + f"for {method}") return _log.error("Agent identity not found in auth file!") return @@ -441,16 +375,14 @@ def delete_rpc_authorizations( def _update_auth_lists(self, entries, is_allow=True): auth_list = [] for entry in entries: - auth_list.append( - { - "domain": entry.domain, - "address": entry.address, - "mechanism": entry.mechanism, - "credentials": entry.credentials, - "user_id": entry.user_id, - "retries": 0, - } - ) + auth_list.append({ + "domain": entry.domain, + "address": entry.address, + "mechanism": entry.mechanism, + "credentials": entry.credentials, + "user_id": entry.user_id, + "retries": 0, + }) if is_allow: self._auth_approved = [ entry for entry in auth_list if entry["address"] is not None @@ -472,25 +404,21 @@ def _get_updated_entries(self, old_entries, new_entries): """ modified_entries = [] for entry in new_entries: - if ( - entry.identity is not None + if (entry.identity is not None and entry.identity not in PROCESS_IDENTITIES - and entry.identity != CONTROL_CONNECTION - ): + and entry.identity != CONTROL_CONNECTION): for old_entry in old_entries: if entry.identity == old_entry.identity: - if ( - entry.rpc_method_authorizations - != old_entry.rpc_method_authorizations - ): + if (entry.rpc_method_authorizations + != old_entry.rpc_method_authorizations): modified_entries.append(entry) else: pass else: pass if entry.identity not in [ - old_entry.identity for old_entry in old_entries + old_entry.identity for old_entry in old_entries ]: modified_entries.append(entry) else: @@ -498,7 +426,7 @@ def _get_updated_entries(self, old_entries, new_entries): return modified_entries def read_auth_file(self): - _log.info("loading auth file %s", self.auth_file_path) + _log.debug("loading auth file %s", self.auth_file_path) # Update from auth file into memory if self.auth_file.auth_data: old_entries = self.auth_file.read_allow_entries().copy() @@ -531,12 +459,9 @@ def read_auth_file(self): gevent.sleep(2) self._send_update(modified_entries) except BaseException as err: - _log.error( - "Exception sending auth updates to peer. %r", - err - ) + _log.error("Exception sending auth updates to peer. %r", err) raise err - _log.info("auth file %s loaded", self.auth_file_path) + _log.debug("auth file %s loaded", self.auth_file_path) def get_protected_topics(self): protected = self._protected_topics @@ -549,7 +474,8 @@ def _read_protected_topics_file(self): with open(self._protected_topics_file) as fil: # Use gevent FileObject to avoid blocking the thread data = FileObject(fil, close=False).read() - self._protected_topics = self.authorization_server.load_protected_topics(data) + self._protected_topics = self.authorization_server.load_protected_topics( + data) except Exception: _log.exception("error loading %s", self._protected_topics_file) @@ -576,7 +502,8 @@ def _send_update(self, modified_entries=None): peers = self.vip.peerlist().get(timeout=0.5) except BaseException as err: _log.warning( - "Attempt %i to get peerlist failed with " "exception %s", + "Attempt %i to get peerlist failed with " + "exception %s", i, err, ) @@ -596,12 +523,12 @@ def _send_update(self, modified_entries=None): # Update RPC method authorizations on agents if modified_entries: try: - gevent.spawn( - self.update_rpc_authorizations, modified_entries - ).join(timeout=15) + gevent.spawn(self.update_rpc_authorizations, + modified_entries).join(timeout=15) except gevent.Timeout: _log.error("Timed out updating methods from auth file!") - self.authorization_server.update_user_capabilites(self.get_user_to_capabilities()) + self.authorization_server.update_user_capabilites( + self.get_user_to_capabilities()) @RPC.export def get_user_to_capabilities(self): diff --git a/volttron/platform/auth/auth_entry.py b/volttron/platform/auth/auth_entry.py index 39c086d81e..76a5f8cfff 100644 --- a/volttron/platform/auth/auth_entry.py +++ b/volttron/platform/auth/auth_entry.py @@ -1,45 +1,31 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging import re -from typing import Optional +from typing import Optional, Union import uuid from volttron.platform.vip.socket import BASE64_ENCODED_CURVE_KEY_LEN @@ -114,7 +100,7 @@ def __init__( identity=None, groups=None, roles=None, - capabilities: Optional[dict] = None, + capabilities=None, rpc_method_authorizations=None, comments=None, enabled=True, @@ -127,13 +113,10 @@ def __init__( self.credentials = AuthEntry._build_field(credentials) self.groups = AuthEntry._build_field(groups) or [] self.roles = AuthEntry._build_field(roles) or [] - self.capabilities = ( - AuthEntry.build_capabilities_field(capabilities) or {} - ) - self.rpc_method_authorizations = ( - AuthEntry.build_rpc_authorizations_field(rpc_method_authorizations) - or {} - ) + self.capabilities = AuthEntry.build_capabilities_field(capabilities) or {} + + self.rpc_method_authorizations = AuthEntry.build_rpc_authorizations_field(rpc_method_authorizations) or {} + self.comments = AuthEntry._build_field(comments) if user_id is None: user_id = str(uuid.uuid4()) @@ -165,7 +148,7 @@ def _build_field(value): return List(String(elem) for elem in value) @staticmethod - def build_capabilities_field(value: Optional[dict]): + def build_capabilities_field(value): # _log.debug("_build_capabilities {}".format(value)) if not value: @@ -283,5 +266,3 @@ def valid_mechanism(mechanism): def _check_validity(self): """Raises AuthEntryInvalid if entry is invalid.""" AuthEntry.valid_credentials(self.credentials, self.mechanism) - - diff --git a/volttron/platform/auth/auth_exception.py b/volttron/platform/auth/auth_exception.py index 3e09a2c58f..3b6195244a 100644 --- a/volttron/platform/auth/auth_exception.py +++ b/volttron/platform/auth/auth_exception.py @@ -1,42 +1,28 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} class AuthException(Exception): """General exception for any auth error""" - pass \ No newline at end of file + pass diff --git a/volttron/platform/auth/auth_file.py b/volttron/platform/auth/auth_file.py index 2ac86f799d..76ee7b03be 100644 --- a/volttron/platform/auth/auth_file.py +++ b/volttron/platform/auth/auth_file.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -62,6 +48,7 @@ _log = logging.getLogger(__name__) + class AuthFile(object): def __init__(self, auth_file=None): self.auth_data = {} @@ -74,7 +61,7 @@ def __init__(self, auth_file=None): @property def version(self): - return {"major": 1, "minor": 3} + return {"major": 1, "minor": 4} def _check_for_upgrade(self): auth_data = self._read() @@ -268,6 +255,11 @@ def upgrade_1_2_to_1_3(allow_list): version["minor"] = 2 if version["major"] == 1 and version["minor"] == 2: allow_list = upgrade_1_2_to_1_3(allow_list) + version["minor"] = 3 + if version["major"] == 1 and version["minor"] == 3: + # on start a new entry for config.store should have got created automatically + # so just update version + version["minor"] = 4 allow_entries, deny_entries = self._get_entries(allow_list, deny_list) self._write(allow_entries, deny_entries, groups, roles) diff --git a/volttron/platform/auth/auth_protocols/__init__.py b/volttron/platform/auth/auth_protocols/__init__.py index 153ca84338..5b384a81bf 100644 --- a/volttron/platform/auth/auth_protocols/__init__.py +++ b/volttron/platform/auth/auth_protocols/__init__.py @@ -1,46 +1,32 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from .auth_protocol import ( - BaseAuthentication, - BaseClientAuthorization, - BaseServerAuthentication, + BaseAuthentication, + BaseClientAuthorization, + BaseServerAuthentication, BaseServerAuthorization, ) -__all__ = ["BaseAuthentication", "BaseClientAuthorization", "BaseServerAuthentication", "BaseServerAuthorization"] \ No newline at end of file +__all__ = ["BaseAuthentication", "BaseClientAuthorization", "BaseServerAuthentication", "BaseServerAuthorization"] diff --git a/volttron/platform/auth/auth_protocols/auth_protocol.py b/volttron/platform/auth/auth_protocols/auth_protocol.py index 7de07a7814..7b9ed38b5a 100644 --- a/volttron/platform/auth/auth_protocols/auth_protocol.py +++ b/volttron/platform/auth/auth_protocols/auth_protocol.py @@ -1,42 +1,27 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} -import os import volttron.platform from volttron.platform import jsonapi @@ -46,9 +31,9 @@ def __init__(self, auth_service=None ): self.auth_service = auth_service - + def approve_authorization(self, user_id): - pass + pass def deny_authorization(self, user_id): pass @@ -73,7 +58,7 @@ def get_denied_authorizations(self): def update_user_capabilites(self, user_to_caps): pass - + def load_protected_topics(self, protected_topics_data): return jsonapi.loads(protected_topics_data) if protected_topics_data else {} diff --git a/volttron/platform/auth/auth_protocols/auth_rmq.py b/volttron/platform/auth/auth_protocols/auth_rmq.py index c178c6ea39..17f4efd0ff 100644 --- a/volttron/platform/auth/auth_protocols/auth_rmq.py +++ b/volttron/platform/auth/auth_protocols/auth_rmq.py @@ -3,19 +3,16 @@ import ssl import re import logging -import grequests from collections import defaultdict from urllib.parse import urlparse, urlsplit from dataclasses import dataclass from volttron.platform.auth import certs -from volttron.platform.auth.auth_protocols import * +from volttron.platform.auth.auth_protocols import ( + BaseAuthentication, BaseClientAuthorization, BaseServerAuthentication, BaseServerAuthorization) from volttron.platform.parameters import Parameters -from volttron.utils.rmq_config_params import RMQConfig from volttron.utils.rmq_mgmt import RabbitMQMgmt from volttron.platform import jsonapi -from volttron.platform.agent.utils import get_fq_identity, get_platform_instance_name -from volttron.platform.messaging.health import STATUS_BAD -from volttron.platform import get_home +from volttron.platform.agent.utils import get_fq_identity from volttron.platform import is_rabbitmq_available @@ -119,9 +116,7 @@ def build_remote_connection_param(self, cert_dir=None, retry_attempt=30, retry_d :param retry_attempt: pika connection parameter - number of connection retry attempts :return: instance of pika.ConnectionParameters """ - from urllib import parse - - parsed_addr = parse.urlparse(self.params.url_address) + parsed_addr = urlparse(self.params.url_address) _, virtual_host = parsed_addr.path.split('/') try: diff --git a/volttron/platform/auth/auth_protocols/auth_zmq.py b/volttron/platform/auth/auth_protocols/auth_zmq.py index dda4edf067..3a303672f9 100644 --- a/volttron/platform/auth/auth_protocols/auth_zmq.py +++ b/volttron/platform/auth/auth_protocols/auth_zmq.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -42,29 +28,27 @@ import random import uuid import bisect -from urllib.parse import urlsplit, parse_qs, urlunsplit, urlparse +from urllib.parse import urlsplit, parse_qs, urlunsplit import gevent import gevent.time from zmq import green as zmq -from volttron.platform.auth.auth_protocols import * from volttron.platform import get_home from volttron.platform import jsonapi from volttron.platform.auth.auth_entry import AuthEntry from volttron.platform.auth.auth_exception import AuthException +from volttron.platform.auth.auth_protocols import ( + BaseAuthentication, BaseClientAuthorization, BaseServerAuthentication, BaseServerAuthorization) from volttron.platform.auth.auth_utils import dump_user from volttron.platform.keystore import KeyStore, KnownHostsStore from volttron.platform.parameters import Parameters from volttron.platform.vip.socket import encode_key -from volttron.platform.agent.utils import ( - get_platform_instance_name, - get_fq_identity, -) + _log = logging.getLogger(__name__) @dataclass class ZMQClientParameters(Parameters): - address: str = None + address: str = None identity: str = None publickey: str = None secretkey: str = None @@ -101,7 +85,7 @@ def create_authentication_parameters(self): if self.publickey and self.secretkey and self.serverkey: self._add_keys_to_addr() return self.address - + def _add_keys_to_addr(self): '''Adds public, secret, and server keys to query in VIP address if they are not already present''' @@ -120,7 +104,7 @@ def add_param(query_str, key, value): url[3] += add_param(url[3], 'secretkey', self.secretkey) url[3] += add_param(url[3], 'serverkey', self.serverkey) self.address = str(urlunsplit(url)) - + def _get_keys_from_keystore(self): '''Returns agent's public and secret key from keystore''' if self.agent_uuid: @@ -140,7 +124,7 @@ def _get_keys_from_keystore(self): keystore_path = os.path.join(keystore_dir, 'keystore.json') keystore = KeyStore(keystore_path) return keystore.public, keystore.secret - + def _set_public_and_secret_keys(self): if self.publickey is None or self.secretkey is None: self.publickey, self.secretkey, _ = self._get_keys_from_addr() @@ -179,7 +163,7 @@ def _get_keys_from_addr(self): class ZMQServerAuthentication(BaseServerAuthentication): """ - Implementation of the Zap Loop used by AuthService + Implementation of the Zap Loop used by AuthService for handling ZMQ Authentication on the VOLTTRON Server Instance """ def __init__(self, auth_service) -> None: @@ -187,7 +171,7 @@ def __init__(self, auth_service) -> None: self.zap_socket = None self._zap_greenlet = None self.authorization = ZMQAuthorization(self.auth_service) - + def setup_authentication(self): self.zap_socket = zmq.Socket(zmq.Context.instance(), zmq.ROUTER) self.zap_socket.bind("inproc://zeromq.zap.01") @@ -393,7 +377,7 @@ def _update_auth_pending( class ZMQAuthorization(BaseServerAuthorization): def __init__(self, auth_service): super().__init__(auth_service=auth_service) - + def create_authenticated_address(self): pass diff --git a/volttron/platform/auth/auth_utils.py b/volttron/platform/auth/auth_utils.py index ef1df3538c..56575ae9ec 100644 --- a/volttron/platform/auth/auth_utils.py +++ b/volttron/platform/auth/auth_utils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import re @@ -52,4 +38,4 @@ def load_user(string): def sub(match): return match.group(1) or "\x00" - return _load_re.sub(sub, string).split("\x00") \ No newline at end of file + return _load_re.sub(sub, string).split("\x00") diff --git a/volttron/platform/auth/certs.py b/volttron/platform/auth/certs.py index ce47416e68..5c252aab7b 100644 --- a/volttron/platform/auth/certs.py +++ b/volttron/platform/auth/certs.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from collections import namedtuple @@ -43,7 +29,7 @@ import six import time from shutil import copyfile -from socket import gethostname, getfqdn, getaddrinfo, AI_CANONNAME +from socket import gethostname, getfqdn import subprocess from cryptography import x509 @@ -58,7 +44,6 @@ from volttron.platform import jsonapi from volttron.platform import get_home from volttron.platform.agent.utils import (get_platform_instance_name, - get_fq_identity, execute_command) _log = logging.getLogger(__name__) diff --git a/volttron/platform/config.py b/volttron/platform/config.py index 61133d65aa..3367de4bc0 100644 --- a/volttron/platform/config.py +++ b/volttron/platform/config.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''Advanced argument parser. diff --git a/volttron/platform/control/control.py b/volttron/platform/control/control.py index 178b8aa185..c2769ca83f 100644 --- a/volttron/platform/control/control.py +++ b/volttron/platform/control/control.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import base64 @@ -547,7 +533,7 @@ def protocol_subscription(peer, sender, bus, topic, headers, message): def _install_wheel_to_platform( self, agent_uuid, vip_identity, path, agent_existed_before ): - + agent_data_dir = None backup_agent_file = None # Fix unbound variable. Only gets set if there is an existing agent diff --git a/volttron/platform/control/control_auth.py b/volttron/platform/control/control_auth.py index b90ecb889f..3147c4d7e0 100644 --- a/volttron/platform/control/control_auth.py +++ b/volttron/platform/control/control_auth.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/volttron/platform/control/control_certs.py b/volttron/platform/control/control_certs.py index d869fb8bfe..4eace8a703 100644 --- a/volttron/platform/control/control_certs.py +++ b/volttron/platform/control/control_certs.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from volttron.platform.agent import utils @@ -82,4 +68,4 @@ def add_certs_parser(add_parser_fn): help="identity of the agent to export") export_pkcs12.add_argument("outfile", help="file to write the PKCS12 file to") - export_pkcs12.set_defaults(func=export_pkcs12_from_identity) \ No newline at end of file + export_pkcs12.set_defaults(func=export_pkcs12_from_identity) diff --git a/volttron/platform/control/control_config.py b/volttron/platform/control/control_config.py index 5a8c028101..80de3c01e9 100644 --- a/volttron/platform/control/control_config.py +++ b/volttron/platform/control/control_config.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import argparse @@ -57,7 +43,7 @@ def add_config_to_store(opts): file_contents = opts.infile.read() call( - "manage_store", + "set_config", opts.identity, opts.name, file_contents, @@ -69,7 +55,7 @@ def delete_config_from_store(opts): opts.connection.peer = CONFIGURATION_STORE call = opts.connection.call if opts.delete_store: - call("manage_delete_store", opts.identity) + call("delete_store", opts.identity) return if opts.name is None: @@ -79,7 +65,7 @@ def delete_config_from_store(opts): ) return - call("manage_delete_config", opts.identity, opts.name) + call("delete_config", opts.identity, opts.name) def list_store(opts): @@ -87,9 +73,9 @@ def list_store(opts): call = opts.connection.call results = [] if opts.identity is None: - results = call("manage_list_stores") + results = call("list_stores") else: - results = call("manage_list_configs", opts.identity) + results = call("list_configs", opts.identity) for item in results: _stdout.write(item + "\n") @@ -98,7 +84,7 @@ def list_store(opts): def get_config(opts): opts.connection.peer = CONFIGURATION_STORE call = opts.connection.call - results = call("manage_get", opts.identity, opts.name, raw=opts.raw) + results = call("get_config", opts.identity, opts.name, raw=opts.raw) if opts.raw: _stdout.write(results) @@ -119,7 +105,7 @@ def edit_config(opts): raw_data = "" else: try: - results = call("manage_get_metadata", opts.identity, opts.name) + results = call("get_metadata", opts.identity, opts.name) config_type = results["type"] raw_data = results["data"] except RemoteError as e: @@ -159,7 +145,7 @@ def edit_config(opts): return call( - "manage_store", + "set_config", opts.identity, opts.name, new_raw_data, diff --git a/volttron/platform/control/control_connection.py b/volttron/platform/control/control_connection.py index 6539528b8f..0d53addaed 100644 --- a/volttron/platform/control/control_connection.py +++ b/volttron/platform/control/control_connection.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import gevent @@ -89,4 +75,3 @@ def kill(self, *args, **kwargs): self._greenlet.kill(*args, **kwargs) finally: self._greenlet = None - diff --git a/volttron/platform/control/control_parser.py b/volttron/platform/control/control_parser.py index aa3e34e280..5a256800d2 100644 --- a/volttron/platform/control/control_parser.py +++ b/volttron/platform/control/control_parser.py @@ -1,64 +1,49 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} # Monkeypatch for gevent from volttron.utils import monkey_patch + monkey_patch() import argparse import collections import logging -import logging.handlers import logging.config +import logging.handlers import os import sys - -from datetime import timedelta, datetime +from datetime import datetime, timedelta import gevent import gevent.event -# noinspection PyUnresolvedReferences - from volttron.platform import aip as aipmod -from volttron.platform import config -from volttron.platform import get_home, get_address -from volttron.platform import jsonapi +from volttron.platform import config, get_address, get_home, is_rabbitmq_available, jsonapi +from volttron.platform.agent import utils +from volttron.platform.agent.known_identities import PLATFORM_HEALTH +from volttron.platform.agent.utils import is_secure_mode, wait_for_volttron_shutdown from volttron.platform.control.control_auth import add_auth_parser from volttron.platform.control.control_certs import add_certs_parser from volttron.platform.control.control_config import add_config_store_parser @@ -66,25 +51,18 @@ from volttron.platform.control.control_rmq import add_rabbitmq_parser from volttron.platform.control.control_rpc import add_rpc_agent_parser from volttron.platform.control.control_utils import ( - _list_agents, - _show_filtered_agents, - _show_filtered_agents_status, - filter_agent, - filter_agents, - get_filtered_agents - ) -from volttron.platform.agent import utils -from volttron.platform.agent.known_identities import PLATFORM_HEALTH + _list_agents, _show_filtered_agents, _show_filtered_agents_status, + filter_agent, filter_agents, get_filtered_agents) +from volttron.platform.control.install_agents import InstallRuntimeError, add_install_agent_parser from volttron.platform.jsonrpc import RemoteError from volttron.platform.keystore import KeyStore, KnownHostsStore +from volttron.platform.vip.agent.errors import Unreachable, VIPError + +# noinspection PyUnresolvedReferences -from volttron.platform.vip.agent.errors import VIPError, Unreachable -from volttron.platform.agent.utils import is_secure_mode, wait_for_volttron_shutdown -from volttron.platform.control.install_agents import add_install_agent_parser, InstallRuntimeError -from volttron.platform import is_rabbitmq_available if is_rabbitmq_available(): - from volttron.utils.rmq_setup import check_rabbit_status from volttron.utils.rmq_config_params import RMQConfig + from volttron.utils.rmq_setup import check_rabbit_status try: import volttron.restricted @@ -100,8 +78,7 @@ # will be volttron.platform.main or main.py instead of __main__ _log = logging.getLogger( - os.path.basename(sys.argv[0]) if __name__ == "__main__" else __name__ -) + os.path.basename(sys.argv[0]) if __name__ == "__main__" else __name__) # Allows server side logging. # _log.setLevel(logging.DEBUG) @@ -110,16 +87,16 @@ CHUNK_SIZE = 4096 -def log_to_file(file, level=logging.WARNING, + +def log_to_file(file, + level=logging.WARNING, handler_class=logging.StreamHandler): """Direct log output to a file (or something like one).""" handler = handler_class(file) handler.setLevel(level) handler.setFormatter( utils.AgentFormatter( - "%(asctime)s %(composite_name)s %(levelname)s: %(message)s" - ) - ) + "%(asctime)s %(composite_name)s %(levelname)s: %(message)s")) root = logging.getLogger() root.setLevel(level) root.addHandler(handler) @@ -137,17 +114,17 @@ def tag_agent(opts): msg = "multiple agents selected" else: msg = "agent not found" - _stderr.write( - "{}: error: {}: {}\n".format(opts.command, msg, opts.agent)) + _stderr.write("{}: error: {}: {}\n".format(opts.command, msg, + opts.agent)) return 10 - (agent,) = agents + (agent, ) = agents if opts.tag: _stdout.write("Tagging {} {}\n".format(agent.uuid, agent.name)) opts.aip.tag_agent(agent.uuid, opts.tag) elif opts.remove: if agent.tag is not None: - _stdout.write( - "Removing tag for {} {}\n".format(agent.uuid, agent.name)) + _stdout.write("Removing tag for {} {}\n".format( + agent.uuid, agent.name)) opts.aip.tag_agent(agent.uuid, None) else: if agent.tag is not None: @@ -158,27 +135,25 @@ def remove_agent(opts, remove_auth=True): agents = _list_agents(opts.aip) for pattern, match in filter_agents(agents, opts.pattern, opts): if not match: - _stderr.write( - "{}: error: agent not found: {}\n".format(opts.command, - pattern) - ) + _stderr.write("{}: error: agent not found: {}\n".format( + opts.command, pattern)) elif len(match) > 1 and not opts.force: _stderr.write( "{}: error: pattern returned multiple agents: {}\n".format( - opts.command, pattern - ) - ) + opts.command, pattern)) _stderr.write( "Use -f or --force to force removal of multiple agents.\n") return 10 for agent in match: _stdout.write("Removing {} {}\n".format(agent.uuid, agent.name)) - opts.connection.call("remove_agent", agent.uuid, + opts.connection.call("remove_agent", + agent.uuid, remove_auth=remove_auth) # TODO: Remove AIP def list_agents(opts): + def get_priority(agent): return opts.aip.agent_priority(agent.uuid) or "" @@ -207,11 +182,8 @@ def update_health_cache(opts): do_update = True # Make sure we update if we don't have any health dicts, or if the cache # has timed out. - if ( - health_cache_timeout_date is not None - and t_now < health_cache_timeout_date - and health_cache - ): + if (health_cache_timeout_date is not None + and t_now < health_cache_timeout_date and health_cache): do_update = False if do_update: @@ -219,12 +191,10 @@ def update_health_cache(opts): if opts.connection.server: health_cache.update( opts.connection.server.vip.rpc.call( - PLATFORM_HEALTH, "get_platform_health" - ).get(timeout=4) - ) + PLATFORM_HEALTH, "get_platform_health").get(timeout=4)) health_cache_timeout_date = datetime.now() + timedelta( - seconds=health_cache_timeout - ) + seconds=health_cache_timeout) + # TODO: Remove AIP def status_agents(opts): @@ -243,12 +213,14 @@ def status_agents(opts): agent = agents[uuid] agents[uuid] = agent._replace(agent_user=agent_user) except KeyError: - Agent = collections.namedtuple("Agent", - "name tag uuid vip_identity " - "agent_user") - agents[uuid] = agent = Agent( - name, None, uuid, vip_identity=identity, agent_user=agent_user - ) + Agent = collections.namedtuple( + "Agent", "name tag uuid vip_identity " + "agent_user") + agents[uuid] = agent = Agent(name, + None, + uuid, + vip_identity=identity, + agent_user=agent_user) status[uuid] = stat agents = list(agents.values()) @@ -282,6 +254,7 @@ def get_health(agent): _show_filtered_agents_status(opts, get_status, get_health, agents) + #TODO: Remove AIP def agent_health(opts): agents = {agent.uuid: agent for agent in _list_agents(opts.aip)}.values() @@ -309,21 +282,17 @@ def agent_health(opts): def clear_status(opts): opts.connection.call("clear_status", opts.clear_all) + # TODO: Remove AIP def enable_agent(opts): agents = _list_agents(opts.aip) for pattern, match in filter_agents(agents, opts.pattern, opts): if not match: - _stderr.write( - "{}: error: agent not found: {}\n".format(opts.command, - pattern) - ) + _stderr.write("{}: error: agent not found: {}\n".format( + opts.command, pattern)) for agent in match: - _stdout.write( - "Enabling {} {} with priority {}\n".format( - agent.uuid, agent.name, opts.priority - ) - ) + _stdout.write("Enabling {} {} with priority {}\n".format( + agent.uuid, agent.name, opts.priority)) opts.aip.prioritize_agent(agent.uuid, opts.priority) @@ -331,15 +300,13 @@ def disable_agent(opts): agents = _list_agents(opts.aip) for pattern, match in filter_agents(agents, opts.pattern, opts): if not match: - _stderr.write( - "{}: error: agent not found: {}\n".format(opts.command, - pattern) - ) + _stderr.write("{}: error: agent not found: {}\n".format( + opts.command, pattern)) for agent in match: priority = opts.aip.agent_priority(agent.uuid) if priority is not None: - _stdout.write( - "Disabling {} {}\n".format(agent.uuid, agent.name)) + _stdout.write("Disabling {} {}\n".format( + agent.uuid, agent.name)) opts.aip.prioritize_agent(agent.uuid, None) @@ -363,21 +330,25 @@ def act_on_agent(action, opts): if not opts.by_all_tagged and not opts.pattern: raise ValueError("Missing search pattern.") - + if opts.by_all_tagged and not agents: return # when all-tagged option is used, prefilter agents that are tagged and set search pattern to * if opts.by_all_tagged and not opts.pattern: agents, pattern_to_use = [a for a in agents if a.tag is not None], '*' - + # filter agents and update regex pattern - for pattern, filtered_agents in filter_agents(agents, pattern_to_use, opts): + for pattern, filtered_agents in filter_agents(agents, pattern_to_use, + opts): if not filtered_agents: - _stderr.write(f"Agents NOT found using 'vctl {opts.command}' on pattern: {pattern}\n") + _stderr.write( + f"Agents NOT found using 'vctl {opts.command}' on pattern: {pattern}\n" + ) for agent in filtered_agents: pid, status = call("agent_status", agent.uuid) - _call_action_on_agent(agent, pid, status, call, action) + _call_action_on_agent(agent, pid, status, call, action) + def _call_action_on_agent(agent, pid, status, call, action): if action == "start_agent": @@ -403,23 +374,17 @@ def shutdown_agents(opts): if "rmq" == utils.get_messagebus(): if not check_rabbit_status(): rmq_cfg = RMQConfig() - wait_period = ( - rmq_cfg.reconnect_delay() if rmq_cfg.reconnect_delay() < 60 - else 60 - ) + wait_period = (rmq_cfg.reconnect_delay() + if rmq_cfg.reconnect_delay() < 60 else 60) _stderr.write( "RabbitMQ server is not running.\n" "Waiting for {} seconds for possible reconnection and to " - "perform normal shutdown\n".format( - wait_period - ) - ) + "perform normal shutdown\n".format(wait_period)) gevent.sleep(wait_period) if not check_rabbit_status(): _stderr.write( "RabbitMQ server is still not running.\nShutting down " - "the platform forcefully\n" - ) + "the platform forcefully\n") opts.aip.brute_force_platform_shutdown() return opts.connection.call("shutdown") @@ -456,9 +421,8 @@ def send(): wheel.close() channel.close(linger=0) - result = connection.vip.rpc.call( - peer, "install_agent", os.path.basename(path), channel.name - ) + result = connection.vip.rpc.call(peer, "install_agent", + os.path.basename(path), channel.name) task = gevent.spawn(send) result.rawlink(lambda glt: task.kill(block=False)) _log.debug(f"Result is {result}") @@ -472,9 +436,6 @@ def send_agent(opts): return uuid - - - def do_stats(opts): call = opts.connection.call if opts.op == "status": @@ -492,7 +453,6 @@ def do_stats(opts): _stdout.write("%sabled\n" % ("en" if call("stats.enabled") else "dis")) - def priority(value): n = int(value) if not 0 <= n < 100: @@ -507,17 +467,18 @@ def get_keys(opts): key_store = KeyStore() publickey = key_store.public secretkey = key_store.secret - return {"publickey": publickey, "secretkey": secretkey, - "serverkey": serverkey} + return { + "publickey": publickey, + "secretkey": secretkey, + "serverkey": serverkey + } def main(): # Refuse to run as root if not getattr(os, "getuid", lambda: -1)(): - sys.stderr.write( - "%s: error: refusing to run as root to prevent " - "potential damage.\n" % os.path.basename(sys.argv[0]) - ) + sys.stderr.write("%s: error: refusing to run as root to prevent " + "potential damage.\n" % os.path.basename(sys.argv[0])) sys.exit(77) volttron_home = get_home() @@ -548,8 +509,7 @@ def main(): help="timeout in seconds for remote calls (default: %(default)g)", ) global_args.add_argument( - "--msgdebug", help="route all messages to an agent while debugging" - ) + "--msgdebug", help="route all messages to an agent while debugging") global_args.add_argument( "--vip-address", metavar="ZMQADDR", @@ -568,21 +528,24 @@ def main(): action="store_true", help="filter/search by agent name", ) - filterable.add_argument( - "--tag", dest="by_tag", action="store_true", - help="filter/search by tag name" - ) - filterable.add_argument( - "--all-tagged", dest="by_all_tagged", action="store_true", - help="filter/search by all tagged agents" - ) + filterable.add_argument("--tag", + dest="by_tag", + action="store_true", + help="filter/search by tag name") + filterable.add_argument("--all-tagged", + dest="by_all_tagged", + action="store_true", + help="filter/search by all tagged agents") filterable.add_argument( "--uuid", dest="by_uuid", action="store_true", help="filter/search by UUID (default)", ) - filterable.set_defaults(by_name=False, by_tag=False, by_all_tagged=False, by_uuid=False) + filterable.set_defaults(by_name=False, + by_tag=False, + by_all_tagged=False, + by_uuid=False) parser = config.ArgumentParser( prog=os.path.basename(sys.argv[0]), @@ -628,12 +591,13 @@ def main(): default=logging.WARNING, help="set logger verboseness", ) - parser.add_argument("--show-config", action="store_true", + parser.add_argument("--show-config", + action="store_true", help=argparse.SUPPRESS) - parser.add_argument( - "--json", action="store_true", default=False, - help="format output to json" - ) + parser.add_argument("--json", + action="store_true", + default=False, + help="format output to json") parser.add_help_argument() parser.set_defaults( @@ -641,9 +605,9 @@ def main(): volttron_home=volttron_home, ) - top_level_subparsers = parser.add_subparsers( - title="commands", metavar="", dest="command" - ) + top_level_subparsers = parser.add_subparsers(title="commands", + metavar="", + dest="command") def add_parser(*args, **kwargs) -> argparse.ArgumentParser: parents = kwargs.get("parents", []) @@ -654,31 +618,35 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: # ==================================================== # install agent parser - # ==================================================== + # ==================================================== add_install_agent_parser(add_parser, HAVE_RESTRICTED) - tag = add_parser("tag", parents=[filterable], + tag = add_parser("tag", + parents=[filterable], help="set, show, or remove agent tag") tag.add_argument("agent", help="UUID or name of agent") group = tag.add_mutually_exclusive_group() group.add_argument("tag", nargs="?", const=None, help="tag to give agent") - group.add_argument("-r", "--remove", action="store_true", + group.add_argument("-r", + "--remove", + action="store_true", help="remove tag") tag.set_defaults(func=tag_agent, tag=None, remove=False) remove = add_parser("remove", parents=[filterable], help="remove agent") remove.add_argument("pattern", nargs="+", help="UUID or name of agent") - remove.add_argument( - "-f", "--force", action="store_true", - help="force removal of multiple agents" - ) + remove.add_argument("-f", + "--force", + action="store_true", + help="force removal of multiple agents") remove.set_defaults(func=remove_agent, force=False) peers = add_parser("peerlist", help="list the peers connected to the platform") peers.set_defaults(func=list_peers) - list_ = add_parser("list", parents=[filterable], + list_ = add_parser("list", + parents=[filterable], help="list installed agent") list_.add_argument("pattern", nargs="*", help="UUID or name of agent") list_.add_argument( @@ -690,7 +658,8 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: ) list_.set_defaults(func=list_agents, min_uuid_len=1) - status = add_parser("status", parents=[filterable], + status = add_parser("status", + parents=[filterable], help="show status of agents") status.add_argument("pattern", nargs="*", help="UUID or name of agent") status.add_argument( @@ -702,9 +671,9 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: ) status.set_defaults(func=status_agents, min_uuid_len=1) - health = add_parser( - "health", parents=[filterable], help="show agent health as JSON" - ) + health = add_parser("health", + parents=[filterable], + help="show agent health as JSON") health.add_argument("pattern", nargs=1, help="UUID or name of agent") health.set_defaults(func=agent_health, min_uuid_len=1) @@ -718,27 +687,29 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: ) clear.set_defaults(func=clear_status, clear_all=False) - enable = add_parser( - "enable", parents=[filterable], - help="enable agent to start automatically" - ) + enable = add_parser("enable", + parents=[filterable], + help="enable agent to start automatically") enable.add_argument("pattern", nargs="+", help="UUID or name of agent") - enable.add_argument( - "-p", "--priority", type=priority, - help="2-digit priority from 00 to 99" - ) + enable.add_argument("-p", + "--priority", + type=priority, + help="2-digit priority from 00 to 99") enable.set_defaults(func=enable_agent, priority="50") - disable = add_parser( - "disable", parents=[filterable], - help="prevent agent from start automatically" - ) + disable = add_parser("disable", + parents=[filterable], + help="prevent agent from start automatically") disable.add_argument("pattern", nargs="+", help="UUID or name of agent") disable.set_defaults(func=disable_agent) - start = add_parser("start", parents=[filterable], + start = add_parser("start", + parents=[filterable], help="start installed agent") - start.add_argument("pattern", nargs="*", help="UUID or name of agent", default='') + start.add_argument("pattern", + nargs="*", + help="UUID or name of agent", + default='') if HAVE_RESTRICTED: start.add_argument( "--verify", @@ -755,11 +726,17 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: start.set_defaults(func=start_agent) stop = add_parser("stop", parents=[filterable], help="stop agent") - stop.add_argument("pattern", nargs="*", help="UUID or name of agent", default='') + stop.add_argument("pattern", + nargs="*", + help="UUID or name of agent", + default='') stop.set_defaults(func=stop_agent) restart = add_parser("restart", parents=[filterable], help="restart agent") - restart.add_argument("pattern", nargs="*", help="UUID or name of agent", default='') + restart.add_argument("pattern", + nargs="*", + help="UUID or name of agent", + default='') restart.set_defaults(func=restart_agent) run = add_parser("run", help="start any agent by path") @@ -778,7 +755,6 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: help=argparse.SUPPRESS, ) run.set_defaults(func=run_agent) - # ==================================================== # rpc commands @@ -801,10 +777,9 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: add_config_store_parser(add_parser) shutdown = add_parser("shutdown", help="stop all agents") - shutdown.add_argument( - "--platform", action="store_true", - help="also stop the platform process" - ) + shutdown.add_argument("--platform", + action="store_true", + help="also stop the platform process") shutdown.set_defaults(func=shutdown_agents, platform=False) send = add_parser("send", help="send agent and start on a remote platform") @@ -814,9 +789,9 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: stats = add_parser("stats", help="manage router message statistics tracking") op = stats.add_argument( - "op", choices=["status", "enable", "disable", "dump", "pprint"], - nargs="?" - ) + "op", + choices=["status", "enable", "disable", "dump", "pprint"], + nargs="?") stats.set_defaults(func=do_stats, op="status") # ============================================================================== @@ -834,12 +809,14 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: "create-cgroups", help="setup VOLTTRON control group for restricted execution", ) - cgroup.add_argument( - "-u", "--user", metavar="USER", help="owning user name or ID" - ) - cgroup.add_argument( - "-g", "--group", metavar="GROUP", help="owning group name or ID" - ) + cgroup.add_argument("-u", + "--user", + metavar="USER", + help="owning user name or ID") + cgroup.add_argument("-g", + "--group", + metavar="GROUP", + help="owning group name or ID") cgroup.set_defaults(func=create_cgroups, user=None, group=None) # Parse and expand options @@ -854,10 +831,8 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: if args[0] not in ("list", "tag", "auth", "rabbitmq", "certs"): # check pid file if not utils.is_volttron_running(volttron_home): - _stderr.write( - "VOLTTRON is not running. This command " - "requires VOLTTRON platform to be running\n" - ) + _stderr.write("VOLTTRON is not running. This command " + "requires VOLTTRON platform to be running\n") return 10 conf = os.path.join(volttron_home, "config") @@ -882,13 +857,18 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: elif opts.log == "-": log_to_file(sys.stdout, level) elif opts.log: - log_to_file(opts.log, level, + log_to_file(opts.log, + level, handler_class=logging.handlers.WatchedFileHandler) else: log_to_file(None, 100, handler_class=lambda x: logging.NullHandler()) if opts.log_config: logging.config.fileConfig(opts.log_config) + if not hasattr(opts, "func"): + parser.print_help() + sys.exit(0) + opts.aip = aipmod.AIPplatform(opts) opts.aip.setup() diff --git a/volttron/platform/control/control_rmq.py b/volttron/platform/control/control_rmq.py index 16a50e1f1f..01a25b8911 100644 --- a/volttron/platform/control/control_rmq.py +++ b/volttron/platform/control/control_rmq.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys diff --git a/volttron/platform/control/control_rpc.py b/volttron/platform/control/control_rpc.py index 9dd81e9c94..9aa3c9f3da 100644 --- a/volttron/platform/control/control_rpc.py +++ b/volttron/platform/control/control_rpc.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import gevent @@ -213,7 +199,7 @@ def list_agent_rpc_code(opts): print(e) print_rpc_methods(opts, peer_method_metadata, code=True) -def add_rpc_agent_parser(add_parser_fn): +def add_rpc_agent_parser(add_parser_fn): rpc_ctl = add_parser_fn("rpc", help="rpc controls") rpc_subparsers = rpc_ctl.add_subparsers( @@ -262,4 +248,4 @@ def add_rpc_agent_parser(add_parser_fn): "method.", ) - rpc_list.set_defaults(func=list_agents_rpc, min_uuid_len=1) \ No newline at end of file + rpc_list.set_defaults(func=list_agents_rpc, min_uuid_len=1) diff --git a/volttron/platform/control/control_utils.py b/volttron/platform/control/control_utils.py index 232222ff5e..7dfa86f954 100644 --- a/volttron/platform/control/control_utils.py +++ b/volttron/platform/control/control_utils.py @@ -1,46 +1,32 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import collections -import os import sys import re from volttron.platform import jsonapi from volttron.platform.agent.utils import is_secure_mode +import os _stdout = sys.stdout _stderr = sys.stderr @@ -114,7 +100,7 @@ def filter_agents(agents, patterns, opts): for pattern in patterns: regex, _ = escape(pattern) filtered_agents = set() - + # if no option is selected, try matching based on uuid if not (by_uuid or by_name or by_tag or by_all_tagged): reobj = re.compile(regex) diff --git a/volttron/platform/control/install_agents.py b/volttron/platform/control/install_agents.py index 99359f0e12..5c8e953e95 100644 --- a/volttron/platform/control/install_agents.py +++ b/volttron/platform/control/install_agents.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import argparse @@ -140,43 +126,43 @@ def install_agent_directory(opts, publickey=None, secretkey=None): agent_uuid = _send_and_intialize_agent(opts, publickey, secretkey) return agent_uuid - + def _send_and_intialize_agent(opts, publickey, secretkey): - + agent_uuid = send_agent(opts.connection, opts.package, opts.vip_identity, publickey, secretkey, opts.force) if not agent_uuid: raise ValueError(f"Agent was not installed properly.") - + if isinstance(agent_uuid, AsyncResult): agent_uuid = agent_uuid.get() - + output_dict = dict(agent_uuid=agent_uuid) - + if opts.tag: _log.debug(f"Tagging agent {agent_uuid}, {opts.tag}") opts.connection.call('tag_agent', agent_uuid, opts.tag) output_dict['tag'] = opts.tag - if opts.enable or opts.priority != -1: + if opts.enable or opts.priority != -1: output_dict['enabling'] = True if opts.priority == -1: opts.priority = '50' _log.debug(f"Prioritinzing agent {agent_uuid},{opts.priority}") output_dict['priority'] = opts.priority - + opts.connection.call('prioritize_agent', agent_uuid, str(opts.priority)) - try: + try: if opts.start: gevent.sleep(2) _log.debug(f"Staring agent {agent_uuid}") opts.connection.call('start_agent', agent_uuid) output_dict['starting'] = True - + _log.debug(f"Getting agent status {agent_uuid}") gevent.sleep(opts.agent_start_time) status = opts.connection.call('agent_status', agent_uuid) @@ -260,7 +246,7 @@ def install_agent_local(opts, publickey=None, secretkey=None, callback=None): return agent_uuid -def send_agent(connection: "ControlConnection", wheel_file: str, vip_identity: str , publickey: str, +def send_agent(connection: "ControlConnection", wheel_file: str, vip_identity: str , publickey: str, secretkey: str, force: str): """ Send an agent wheel from the client to the server. @@ -271,7 +257,7 @@ def send_agent(connection: "ControlConnection", wheel_file: str, vip_identity: s peer = connection.peer server = connection.server _log.debug(f"server type is {type(server)} {type(server.core)}") - + wheel = open(path, 'rb') _log.debug(f"Connecting to {peer} to install {path}") channel = None @@ -288,7 +274,7 @@ def send_agent(connection: "ControlConnection", wheel_file: str, vip_identity: s def send_rmq(): nonlocal wheel, server - + sha512 = hashlib.sha512() protocol_message = None protocol_headers = None @@ -307,7 +293,7 @@ def protocol_requested(peer, sender, bus, topic, headers, message): op = None size = None _log.debug(f"Subscribing to {rmq_response_topic}") - server.vip.pubsub.subscribe(peer="pubsub", + server.vip.pubsub.subscribe(peer="pubsub", prefix=rmq_response_topic, callback=protocol_requested).get(timeout=5) gevent.sleep(5) @@ -319,7 +305,7 @@ def protocol_requested(peer, sender, bus, topic, headers, message): with gevent.Timeout(30): while not response_received: gevent.sleep(0.1) - + first = False resp = jsonapi.loads(protocol_message) _log.debug(f"Got first response {resp}") @@ -328,7 +314,7 @@ def protocol_requested(peer, sender, bus, topic, headers, message): op, size = resp else: op = resp[0] - + if op != 'fetch': raise ValueError(f'First channel response must be fetch but was {op}') response_received = False @@ -359,7 +345,7 @@ def protocol_requested(peer, sender, bus, topic, headers, message): _log.debug(f"Response received bottom of loop {protocol_message}") # wait for next response resp = jsonapi.loads(protocol_message) - + # [fetch, size] or checksum if len(resp) > 1: op, size = resp @@ -379,7 +365,7 @@ def send_zmq(): # Note sending and receiving through a channel all communication # is binary for zmq (RMQ may be different for this functionality) # - + first = True op = None size = None @@ -394,7 +380,7 @@ def send_zmq(): op, size = resp else: op = resp[0] - + if op != 'fetch': raise ValueError(f'First channel response must be fetch but was {op}') @@ -438,10 +424,10 @@ def send_zmq(): task = gevent.spawn(send_zmq) result = server.vip.rpc.call( peer, 'install_agent', os.path.basename(path), channel.name, vip_identity, publickey, secretkey, force) - + else: raise ValueError("Unknown messagebus detected!") - + result.rawlink(lambda glt: task.kill(block=False)) # Allows larger files to be sent across the message bus without # raising an error. @@ -455,7 +441,7 @@ def send_zmq(): # def send_agent(connection, wheel_file, vip_identity, publickey, secretkey, force): - + # #for wheel in opts.wheel: # #uuid = _send_agent(connection.server, connection.peer, wheel_file).get() # result = _send_agent(connection.server, connection.peer, wheel_file, @@ -463,14 +449,14 @@ def send_zmq(): # _log.debug(f"Returning {result} from send_agent") # return result - + def add_install_agent_parser(add_parser_fn, has_restricted): install = add_parser_fn('install', help='install agent from wheel', epilog='Optionally you may specify the --tag argument to tag the ' 'agent during install without requiring a separate call to ' 'the tag command. ') - install.add_argument("--skip-requirements", + install.add_argument("--skip-requirements", help="Skip installing requirements from a requirements.txt if present in the agent directory.") install.add_argument('install_path', help='path to agent wheel or directory for agent installation') install.add_argument('--tag', help='tag for the installed agent') diff --git a/volttron/platform/dbutils/basedb.py b/volttron/platform/dbutils/basedb.py index 7fe4f928fd..64f3f948b1 100644 --- a/volttron/platform/dbutils/basedb.py +++ b/volttron/platform/dbutils/basedb.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/dbutils/crateutils.py b/volttron/platform/dbutils/crateutils.py index cceddbe409..02cbc247b2 100644 --- a/volttron/platform/dbutils/crateutils.py +++ b/volttron/platform/dbutils/crateutils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} # without this we can get random batch process query failure with the error @@ -169,7 +155,7 @@ def create_schema(connection, schema="historian", table_names={}, num_replicas=' """ topic_table_query = """ - + CREATE TABLE IF NOT EXISTS {schema}.{topic_table}( topic string PRIMARY KEY, meta object diff --git a/volttron/platform/dbutils/influxdbutils.py b/volttron/platform/dbutils/influxdbutils.py index 739119de51..8d4c30d11f 100644 --- a/volttron/platform/dbutils/influxdbutils.py +++ b/volttron/platform/dbutils/influxdbutils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/volttron/platform/dbutils/mongoutils.py b/volttron/platform/dbutils/mongoutils.py index dabcab0a41..f49b0a3852 100644 --- a/volttron/platform/dbutils/mongoutils.py +++ b/volttron/platform/dbutils/mongoutils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import _sre diff --git a/volttron/platform/dbutils/mysqlfuncts.py b/volttron/platform/dbutils/mysqlfuncts.py index 3c5d761793..f6b560d8c2 100644 --- a/volttron/platform/dbutils/mysqlfuncts.py +++ b/volttron/platform/dbutils/mysqlfuncts.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import ast import contextlib @@ -108,9 +94,9 @@ def setup_historian_tables(self): if rows: _log.debug("Found table {}. Historian table exists".format( self.data_table)) - rows = self.select(f"""SELECT 1 FROM information_schema.COLUMNS - WHERE TABLE_SCHEMA = '{self.db_name}' AND - TABLE_NAME = '{self.topics_table}' AND + rows = self.select(f"""SELECT 1 FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = '{self.db_name}' AND + TABLE_NAME = '{self.topics_table}' AND COLUMN_NAME = 'metadata'""") _log.debug(f"Result of query to check columns of topic table {rows}") if rows: @@ -377,7 +363,7 @@ def update_topic_and_meta_query(self): :return: query string to update both metadata and topic_name field in self.topics_table. This is used from SQLHistorian version 4.0.0 """ - return '''UPDATE ''' + self.topics_table + ''' SET topic_name = %s , metadata = %s + return '''UPDATE ''' + self.topics_table + ''' SET topic_name = %s , metadata = %s WHERE topic_id = %s''' def update_meta_query(self): @@ -385,7 +371,7 @@ def update_meta_query(self): :return: query string to update metadata field in self.topics_table. This is used from SQLHistorian version 4.0.0 """ - return '''UPDATE ''' + self.meta_table + ''' SET metadata = %s + return '''UPDATE ''' + self.meta_table + ''' SET metadata = %s WHERE topic_id = %s''' def get_aggregation_list(self): diff --git a/volttron/platform/dbutils/postgresqlfuncts.py b/volttron/platform/dbutils/postgresqlfuncts.py index 55ceb74f35..8ce1ca2cca 100644 --- a/volttron/platform/dbutils/postgresqlfuncts.py +++ b/volttron/platform/dbutils/postgresqlfuncts.py @@ -45,6 +45,7 @@ """ class PostgreSqlFuncts(DbDriver): def __init__(self, connect_params, table_names): + self.db_name = connect_params.get('dbname') if table_names: self.data_table = table_names['data_table'] self.topics_table = table_names['topics_table'] @@ -147,7 +148,7 @@ def rollback(self): def setup_historian_tables(self): rows = self.select(f"""SELECT table_name FROM information_schema.tables - WHERE table_catalog = 'test_historian' and table_schema = 'public' + WHERE table_catalog = '{self.db_name}' and table_schema = 'public' AND table_name = '{self.data_table}'""") if rows: _log.debug("Found table {}. Historian table exists".format( @@ -350,7 +351,17 @@ def get_topic_meta_map(self): 'SELECT topic_id, metadata ' 'FROM {}').format(Identifier(self.meta_table)) rows = self.select(query) - meta_map = {tid: jsonapi.loads(meta) if meta else None for tid, meta in rows} + + meta_map = {} + for tid, meta in rows: + if meta: + if isinstance(meta, dict): + meta_map[tid] = meta + else: + meta_map[tid] = jsonapi.loads(meta) + else: + meta_map[tid] = None + return meta_map def get_agg_topics(self): diff --git a/volttron/platform/dbutils/sqlitefuncts.py b/volttron/platform/dbutils/sqlitefuncts.py index 5c525a63cd..e52a8b027e 100644 --- a/volttron/platform/dbutils/sqlitefuncts.py +++ b/volttron/platform/dbutils/sqlitefuncts.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import ast @@ -146,7 +132,7 @@ def setup_historian_tables(self): value_string TEXT NOT NULL, UNIQUE(topic_id, ts))''', commit=False) self.execute_stmt( - '''CREATE INDEX IF NOT EXISTS data_idx + '''CREATE INDEX IF NOT EXISTS data_idx ON ''' + self.data_table + ''' (ts ASC)''', commit=False) self.execute_stmt( '''CREATE TABLE IF NOT EXISTS ''' + self.topics_table + diff --git a/volttron/platform/dbutils/sqlutils.py b/volttron/platform/dbutils/sqlutils.py index 0c655d1553..9fa23a5a06 100644 --- a/volttron/platform/dbutils/sqlutils.py +++ b/volttron/platform/dbutils/sqlutils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import inspect import logging diff --git a/volttron/platform/instance_setup.py b/volttron/platform/instance_setup.py index 984e696023..56cbdb26a3 100644 --- a/volttron/platform/instance_setup.py +++ b/volttron/platform/instance_setup.py @@ -1,42 +1,29 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import argparse import hashlib +import json import os import sys import tempfile @@ -46,21 +33,24 @@ from shutil import copy from urllib.parse import urlparse import logging +from argparse import RawTextHelpFormatter from gevent import subprocess from gevent.subprocess import Popen from zmq import green as zmq -from requirements import extras_require from volttron.platform import is_rabbitmq_available from volttron.platform.auth import certs from volttron.platform import jsonapi from volttron.platform.agent.known_identities import PLATFORM_WEB, PLATFORM_DRIVER, VOLTTRON_CENTRAL from volttron.platform.agent.utils import get_platform_instance_name, wait_for_volttron_startup, \ - is_volttron_running, wait_for_volttron_shutdown, setup_logging + is_volttron_running, wait_for_volttron_shutdown, setup_logging, format_timestamp, get_aware_utc_now, \ + parse_json_config from volttron.utils import get_hostname from volttron.utils.prompt import prompt_response, y, n, y_or_n from . import get_home, get_services_core, set_home +from volttron.platform.agent.utils import load_config as load_yml_or_json +from volttron.platform.store import process_raw_config if is_rabbitmq_available(): from bootstrap import install_rabbit, default_rmq_dir @@ -79,6 +69,7 @@ # Determines if VOLTTRON instance can remain running with vcfg use_active = "N" + def _load_config(): """Loads the config file if the path exists.""" path = os.path.join(get_home(), 'config') @@ -155,24 +146,24 @@ def _is_bound_already(address): return already_bound -def fail_if_instance_running(): +def fail_if_instance_running(message, prompt=True): home = get_home() if os.path.exists(home) and\ is_volttron_running(home): - global use_active - use_active = prompt_response( - "The VOLTTRON Instance is currently running. " - "Installing agents to an active instance may overwrite currently installed " - "and active agents on the platform, causing undesirable behavior. " - "Would you like to continue?", - valid_answers=y_or_n, - default='Y') - if use_active in y: - return + if prompt: + global use_active + use_active = prompt_response( + message + + "Would you like to continue?", + valid_answers=y_or_n, + default='Y') + if use_active in y: + return else: - print(""" + print(message) + print(""" Please execute: volttron-ctl shutdown --platform @@ -180,7 +171,7 @@ def fail_if_instance_running(): to stop the instance. """) - sys.exit() + sys.exit(1) def fail_if_not_in_src_root(): @@ -189,7 +180,7 @@ def fail_if_not_in_src_root(): print(""" volttron-cfg needs to be run from the volttron top level source directory. """) - sys.exit() + sys.exit(1) def _start_platform(): @@ -261,13 +252,14 @@ def _is_agent_installed(tag): def installs(agent_dir, tag, identity=None, post_install_func=None): def wrap(config_func): global available_agents + def func(*args, **kwargs): global use_active print('Configuring {}.'.format(agent_dir)) config = config_func(*args, **kwargs) _update_config_file() - #TODO: Optimize long vcfg install times - #TODO: (potentially only starting the platform once per vcfg) + # TODO: Optimize long vcfg install times + # TODO: (potentially only starting the platform once per vcfg) if use_active in n: _start_platform() @@ -343,12 +335,7 @@ def _get_dependencies(): return dependencies -def _check_dependencies_met(requirement): - try: - dependencies_needed = extras_require[requirement] - except KeyError: - print(f"ERROR: Requirement {requirement} was not found in requirements.py") - return False +def _check_dependencies_met(dependencies_needed): current_dependencies = _get_dependencies() for dependency in dependencies_needed: if "==" in dependency: @@ -356,34 +343,31 @@ def _check_dependencies_met(requirement): pass else: return False + elif dependency.split("==")[0] in [r.split("==")[0] for r in current_dependencies]: + pass else: - if dependency.split("==")[0] in [r.split("==")[0] for r in current_dependencies]: - pass - else: - return False + return False return True def set_dependencies(requirement): try: + # go up two level above env/bin + sys.path.append(os.path.dirname(os.path.dirname(sys.path[0]))) + from requirements import extras_require dependencies_needed = extras_require[requirement] except KeyError: - print("ERROR: Incorrect requirement chosen") + print(f"ERROR: Incorrect requirement chosen: {requirement}") return - cmds = [sys.executable, "-m", "pip", "install"] - for dependency in dependencies_needed: - cmds.append(dependency) - subprocess.check_call(cmds) - return + if not _check_dependencies_met(dependencies_needed): + print(f"Installing {requirement} dependencies...") + cmds = [sys.executable, "-m", "pip", "install"] + for dependency in dependencies_needed: + cmds.append(dependency) + subprocess.check_call(cmds) + return -def set_dependencies_rmq(): - install_rabbit(default_rmq_dir) - prompt = 'What OS are you running?' - user_os = prompt_response(prompt, default='debian') - prompt = 'Which distribution are you running?' - user_dist = prompt_response(prompt, default='bionic') - _cmd(["./scripts/rabbit_dependencies.sh", user_os, user_dist]) def _create_web_certs(): global config_opts @@ -391,7 +375,7 @@ def _create_web_certs(): Utility to create web server certificates Designed to be used in conjecture with get_cert_and_key As such, it assumes that the program has already checked - for existing certs, and prompted the user to enter in + for existing certs, and prompted the user to enter in certificates that they have generated separately. """ crts = certs.Certs() @@ -413,7 +397,7 @@ def _create_web_certs(): prompt = '\tOrganization:' cert_data['organization'] = prompt_response(prompt, mandatory=True) prompt = '\tOrganization Unit:' - cert_data['organization-unit'] = prompt_response(prompt,mandatory=True) + cert_data['organization-unit'] = prompt_response(prompt, mandatory=True) cert_data['common-name'] = get_platform_instance_name() + '-root-ca' data = {'C': cert_data.get('country'), 'ST': cert_data.get('state'), @@ -422,12 +406,13 @@ def _create_web_certs(): 'OU': cert_data.get('organization-unit'), 'CN': cert_data.get('common-name')} crts.create_root_ca(overwrite=False, **data) - copy(crts.cert_file(crts.root_ca_name),crts.cert_file(crts.trusted_ca_name)) + copy(crts.cert_file(crts.root_ca_name), crts.cert_file(crts.trusted_ca_name)) else: return 1 - + print("Creating new web server certificate.") - crts.create_signed_cert_files(name=PLATFORM_WEB + "-server", cert_type='server', ca_name=crts.root_ca_name, fqdn=get_hostname()) + crts.create_signed_cert_files(name=PLATFORM_WEB + "-server", cert_type='server', ca_name=crts.root_ca_name, + fqdn=get_hostname()) return 0 @@ -454,12 +439,6 @@ def do_message_bus(): print("Message type is not valid. Valid entries are zmq or rmq.") if bus_type == 'rmq': - if not is_rabbitmq_available(): - print("RabbitMQ has not been set up!") - print("Setting up now...") - set_dependencies_rmq() - print("Done!") - try: check_rmq_setup() except AssertionError: @@ -488,8 +467,8 @@ def do_vip(): while not valid_address: if config_opts['message-bus'] == 'rmq': prompt = """ -The rmq message bus has a backward compatibility -layer with current zmq instances. What is the +The rmq message bus has a backward compatibility +layer with current zmq instances. What is the zmq bus's vip address?""" else: prompt = "What is the vip address?" @@ -543,13 +522,15 @@ def do_instance_name(): instance_name = new_instance_name config_opts['instance-name'] = '"{}"'.format(instance_name) + def do_web_enabled_rmq(vhome): global config_opts # Full implies that it will have a port on it as well. Though if it's # not in the address that means that we haven't set it up before. - full_bind_web_address = config_opts.get('bind-web-address', - 'https://' + get_hostname()) + full_bind_web_address = config_opts.get( + 'bind-web-address', + 'https://' + get_hostname()) parsed = urlparse(full_bind_web_address) @@ -591,11 +572,9 @@ def do_web_enabled_rmq(vhome): def do_web_enabled_zmq(vhome): global config_opts - # Full implies that it will have a port on it as well. Though if it's # not in the address that means that we haven't set it up before. - full_bind_web_address = config_opts.get('bind-web-address', - 'https://' + get_hostname()) + full_bind_web_address = config_opts.get('bind-web-address', 'https://' + get_hostname()) parsed = urlparse(full_bind_web_address) @@ -714,7 +693,7 @@ def get_cert_and_key(vhome): try: if certs.Certs.validate_key_pair(platform_web_cert, platform_web_key): print('\nThe following certificate and keyfile exists for web access over https: \n{}\n{}'.format( - platform_web_cert,platform_web_key)) + platform_web_cert, platform_web_key)) prompt = '\nDo you want to use these certificates for the web server?' if prompt_response(prompt, valid_answers=y_or_n, default='Y') in y: config_opts['web-ssl-cert'] = platform_web_cert @@ -729,8 +708,6 @@ def get_cert_and_key(vhome): print(e) pass - - # Either are there no valid existing certs or user decided to overwrite the existing file. # Prompt for new files while cert_error: @@ -769,10 +746,8 @@ def get_cert_and_key(vhome): else: cert_error = _create_web_certs() if not cert_error: - platform_web_cert = os.path.join(vhome, 'certificates/certs/', - PLATFORM_WEB+"-server.crt") - platform_web_key = os.path.join(vhome, 'certificates/private/', - PLATFORM_WEB + "-server.pem") + platform_web_cert = os.path.join(vhome, 'certificates/certs/', PLATFORM_WEB+"-server.crt") + platform_web_key = os.path.join(vhome, 'certificates/private/', PLATFORM_WEB + "-server.pem") config_opts['web-ssl-cert'] = platform_web_cert config_opts['web-ssl-key'] = platform_web_key @@ -806,11 +781,10 @@ def do_vcp(): vc_address = config_opts['bind-web-address'] if VOLTTRON_CENTRAL in vctl_list_output: is_vc = True - + except KeyError: vc_address = config_opts.get('volttron-central-address', - config_opts.get('bind-web-address', - 'https://' + get_hostname())) + config_opts.get('bind-web-address', 'https://' + get_hostname())) if not is_vc: parsed = urlparse(vc_address) address_only = vc_address @@ -908,7 +882,6 @@ def wizard(): # Start true configuration here. volttron_home = get_home() - confirm_volttron_home() _load_config() _update_config_file() if use_active in n: @@ -920,10 +893,7 @@ def wizard(): prompt = 'Is this instance web enabled?' response = prompt_response(prompt, valid_answers=y_or_n, default='N') if response in y: - if not _check_dependencies_met('web'): - print("Web dependencies not installed. Installing now...") - set_dependencies('web') - print("Done!") + set_dependencies('web') if config_opts['message-bus'] == 'rmq': do_web_enabled_rmq(volttron_home) elif config_opts['message-bus'] == 'zmq': @@ -943,13 +913,9 @@ def wizard(): prompt = 'Will this instance be controlled by volttron central?' response = prompt_response(prompt, valid_answers=y_or_n, default='Y') if response in y: - if not _check_dependencies_met("drivers") or not _check_dependencies_met("web"): - print("VCP dependencies not installed. Installing now...") - if not _check_dependencies_met("drivers"): - set_dependencies("drivers") - if not _check_dependencies_met("web"): - set_dependencies("web") - print("Done!") + print("Checking for VCP dependencies.....") + set_dependencies("drivers") + set_dependencies("web") do_vcp() prompt = 'Would you like to install a platform historian?' @@ -959,10 +925,8 @@ def wizard(): prompt = 'Would you like to install a platform driver?' response = prompt_response(prompt, valid_answers=y_or_n, default='N') if response in y: - if not _check_dependencies_met("drivers"): - print("Driver dependencies not installed. Installing now...") - set_dependencies("drivers") - print("Done!") + print("Checking Driver dependencies...") + set_dependencies("drivers") do_platform_driver() prompt = 'Would you like to install a listener agent?' @@ -981,14 +945,9 @@ def wizard(): prompt = 'Will this instance be controlled by volttron central?' response = prompt_response(prompt, valid_answers=y_or_n, default='Y') if response in y: - if not _check_dependencies_met( - "drivers") or not _check_dependencies_met("web"): - print("VCP dependencies not installed. Installing now...") - if not _check_dependencies_met("drivers"): - set_dependencies("drivers") - if not _check_dependencies_met("web"): - set_dependencies("web") - print("Done!") + print("Checking VCP dependencies...") + set_dependencies("drivers") + set_dependencies("web") do_vcp() prompt = 'Would you like to install a platform historian?' @@ -998,10 +957,8 @@ def wizard(): prompt = 'Would you like to install a platform driver?' response = prompt_response(prompt, valid_answers=y_or_n, default='N') if response in y: - if not _check_dependencies_met("drivers"): - print("Driver dependencies not installed. Installing now...") - set_dependencies("drivers") - print("Done!") + print("Checking Driver dependencies...") + set_dependencies("drivers") do_platform_driver() prompt = 'Would you like to install a listener agent?' @@ -1009,17 +966,142 @@ def wizard(): if response in y: do_listener() + +def read_agent_configs_from_store(store_source, path=True): + if path: + with open(store_source) as f: + store = parse_json_config(f.read()) + else: + store = store_source + return store + + +def update_configs_in_store(args_dict): + + vhome = get_home() + metadata_files = list() + + args_list = args_dict['metadata_file'] + # validate args + for item in args_list: + if os.path.isdir(item): + for f in os.listdir(item): + file_path = os.path.join(item, f) + if os.path.isfile(file_path): + metadata_files.append(file_path) + elif os.path.isfile(item): + metadata_files.append(item) + else: + print(f"Value is neither a file nor a directory: {args_dict['metadata_file']}: ") + print(f"The --metadata-file accepts one or more metadata files or directory containing metadata file") + _exit_with_metadata_error() + + # Validate each file content and load config + for metadata_file in metadata_files: + metadata_dict = dict() + try: + metadata_dict = load_yml_or_json(metadata_file) + except Exception as e: + print(f"Invalid metadata file: {metadata_file}: {e}") + exit(1) + + for vip_id in metadata_dict: + configs = metadata_dict[vip_id] + if isinstance(configs, dict): + # only single config for this vip id + configs = [configs] + if not isinstance(configs, list): + print( + f"Metadata for vip-identity {vip_id} in file {metadata_file} " + f"should be a dictionary or list of dictionary. " + f"Got type {type(configs)}") + _exit_with_metadata_error() + + configs_updated = False + agent_store_path = os.path.join(vhome, "configuration_store", vip_id+".store") + if os.path.isfile(agent_store_path): + # load current store configs as python object for comparison + store_configs = read_agent_configs_from_store(agent_store_path) + else: + store_configs = dict() + + for config_dict in configs: + if not isinstance(config_dict, dict): + print(f"Metadata for vip-identity {vip_id} in file {metadata_file} " + f"should be a dictionary or list of dictionary. " + f"Got type {type(config_dict)}") + _exit_with_metadata_error() + + config_name = config_dict.get("config-name", "config") + config_type = config_dict.get("config-type", "json") + config = config_dict.get("config") + if config is None: + print(f"No config entry found in file {metadata_file} for vip-id {vip_id} and " + f"config-name {config_name}") + _exit_with_metadata_error() + + # If there is config validate it + # Check if config is file path + if isinstance(config, str) and os.path.isfile(config): + raw_data = open(config).read() + # try loading it into appropriate python object to validate if file content and config-type match + processed_data = process_raw_config(raw_data, config_type) + elif isinstance(config, str) and config_type == 'raw': + raw_data = config + processed_data = config + else: + if not isinstance(config, (list, dict)): + processed_data = raw_data = None + print('Value for key "config" should be one of the following: \n' + '1. filepath \n' + '2. string with "config-type" set to "raw" \n' + '3. a dictionary \n' + '4. list ') + _exit_with_metadata_error() + else: + processed_data = config + raw_data = jsonapi.dumps(processed_data) + + current = store_configs.get(config_name) + + if not current or process_raw_config(current.get('data'), current.get('type')) != processed_data: + store_configs[config_name] = dict() + store_configs[config_name]['data'] = raw_data + store_configs[config_name]['type'] = config_type + store_configs[config_name]['modified'] = format_timestamp(get_aware_utc_now()) + configs_updated = True + + # All configs processed for current vip-id + # if there were updates write the new configs to file + if configs_updated: + os.makedirs(os.path.dirname(agent_store_path), exist_ok=True) + with open(agent_store_path, 'w+') as f: + json.dump(store_configs, f) + + +def _exit_with_metadata_error(): + print(""" +Metadata file format: +{ "vip-id": [ + { + "config-name": "optional. name. defaults to config + "config": "json config or string config or config file name", + "config-type": "optional. type of config - csv or json or raw. defaults to json" + }, ... + ],... +}""") + exit(1) + + def process_rmq_inputs(args_dict, instance_name=None): - #print(f"args_dict:{args_dict}, args") if not is_rabbitmq_available(): raise RuntimeError("Rabbitmq Dependencies not installed please run python bootstrap.py --rabbitmq") - confirm_volttron_home() + vhome = get_home() - if args_dict['installation-type'] in ['federation', 'shovel'] and not _check_dependencies_met('web'): - print("Web dependencies not installed. Installing now...") + if args_dict['installation-type'] in ['federation', 'shovel']: + print("Checking Web dependencies...") set_dependencies('web') - print("Done!") if args_dict['config'] is not None: if not os.path.exists(vhome): @@ -1058,9 +1140,11 @@ def process_rmq_inputs(args_dict, instance_name=None): else: print("Invalid installation type. Acceptable values single|federation|shovel") sys.exit(1) - setup_rabbitmq_volttron(args_dict['installation-type'], verbose, instance_name=instance_name, max_retries=args_dict['max_retries']) + setup_rabbitmq_volttron(args_dict['installation-type'], verbose, instance_name=instance_name, + max_retries=args_dict['max_retries']) else: - setup_rabbitmq_volttron(args_dict['installation-type'], verbose, prompt=True, instance_name=instance_name, max_retries=args_dict['max_retries']) + setup_rabbitmq_volttron(args_dict['installation-type'], verbose, prompt=True, instance_name=instance_name, + max_retries=args_dict['max_retries']) def main(): @@ -1071,34 +1155,60 @@ def main(): parser.add_argument('--vhome', help="Path to volttron home") parser.add_argument('--instance-name', dest='instance_name', help="Name of this volttron instance") parser.set_defaults(is_rabbitmq=False) + parser.set_defaults(config_update=False) group = parser.add_mutually_exclusive_group() agent_list = '\n\t' + '\n\t'.join(sorted(available_agents.keys())) group.add_argument('--list-agents', action='store_true', dest='list_agents', help='list configurable agents{}'.format(agent_list)) - rabbitmq_parser = parser.add_subparsers(title='rabbitmq', - metavar='', - dest='parser_name') - single_parser = rabbitmq_parser.add_parser('rabbitmq', help='Configure rabbitmq for single instance, ' - 'federation, or shovel either based on ' - 'configuration file in yml format or providing ' - 'details when prompted. \nUsage: vcfg rabbitmq ' - 'single|federation|shovel --config --max-retries ]') - single_parser.add_argument('installation-type', default='single', help='Rabbitmq option for installation. Installation type can be single|federation|shovel') + subparsers = parser.add_subparsers(dest="cmd") + single_parser = subparsers.add_parser('rabbitmq', help='Configure rabbitmq for single instance, ' + 'federation, or shovel either based on ' + 'configuration file in yml format or providing ' + 'details when prompted. \nUsage: vcfg rabbitmq ' + 'single|federation|shovel --config --max-retries ]') + single_parser.add_argument('installation-type', default='single', + help='Rabbitmq option for installation. ' + 'Installation type can be single|federation|shovel') single_parser.add_argument('--max-retries', help='Optional Max retry attempt', type=int, default=12) single_parser.add_argument('--config', help='Optional path to rabbitmq config yml', type=str) single_parser.set_defaults(is_rabbitmq=True) group.add_argument('--agent', nargs='+', - help='configure listed agents') + help='configure listed agents') group.add_argument('--agent-isolation-mode', action='store_true', dest='agent_isolation_mode', help='Require that agents run with their own users (this requires running ' 'scripts/secure_user_permissions.sh as sudo)') + config_store_parser = subparsers.add_parser("update-config-store", formatter_class=RawTextHelpFormatter, + help="Update one or more config entries for one more agents") + config_store_parser.set_defaults(config_update=True) + # start with just a metadata file support. + # todo - add support vip-id, directory + # vip-id, file with multiple configs etc. + # config_arg_group = config_store_parser.add_mutually_exclusive_group() + # meta_group = config_arg_group.add_mutually_exclusive_group() + config_store_parser.add_argument('--metadata-file', required=True, nargs='+', + help="""One or more metadata file or directory containing metadata file, +where each metadata file contain details of configs for one or more agent instance +Metadata file format: +{ "vip-id": [ + { + "config-name": "optional. name. defaults to config + "config": "json config or string config or config file name", + "config-type": "optional. type of config - csv or json or raw. defaults to json" + }, ... + ],... +}""") + + # single_agent_group = config_arg_group.add_mutually_exclusive_group() + # single_agent_group.add_argument("--vip-id", + # help='vip-identity of the agent for which config store should be updated') + # single_agent_group.add_argument("--config-path", + # help="json file containing configs or directory containing config files") args = parser.parse_args() - verbose = args.verbose # Protect against configuration of base logger when not the "main entry point" if verbose: @@ -1110,8 +1220,18 @@ def main(): if args.vhome: set_home(args.vhome) prompt_vhome = False + + confirm_volttron_home() # if not args.rabbitmq or args.rabbitmq[0] in ["single"]: - fail_if_instance_running() + if args.agent: + message = "The VOLTTRON Instance is currently running. " \ + "Installing agents to an active instance may overwrite currently installed "\ + "and active agents on the platform, causing undesirable behavior. " + fail_if_instance_running(message) + if args.config_update: + message = f"VOLTTRON is running using at {get_home()}, " \ + "you can add/update single configuration using vctl config command." + fail_if_instance_running(message, prompt=False) fail_if_not_in_src_root() if use_active in n: atexit.register(_cleanup_on_exit) @@ -1126,6 +1246,8 @@ def main(): _update_config_file() elif args.is_rabbitmq: process_rmq_inputs(vars(args)) + elif args.config_update: + update_configs_in_store(vars(args)) elif not args.agent: wizard() @@ -1137,8 +1259,6 @@ def main(): print('"{}" not configurable with this tool'.format(agent)) else: valid_agents = True - if valid_agents: - confirm_volttron_home() # Configure agents for agent in args.agent: diff --git a/volttron/platform/jsonapi.py b/volttron/platform/jsonapi.py index 59e35eaa9f..84cd77b485 100644 --- a/volttron/platform/jsonapi.py +++ b/volttron/platform/jsonapi.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from json import dump, dumps, load, loads diff --git a/volttron/platform/jsonrpc.py b/volttron/platform/jsonrpc.py index 8c753e753c..e45fe0655b 100644 --- a/volttron/platform/jsonrpc.py +++ b/volttron/platform/jsonrpc.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """Implementation of JSON-RPC 2.0 with support for bi-directional calls. diff --git a/volttron/platform/keystore.py b/volttron/platform/keystore.py index 0be8254239..6bf7ee9de7 100644 --- a/volttron/platform/keystore.py +++ b/volttron/platform/keystore.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} diff --git a/volttron/platform/lib/inotify/__init__.py b/volttron/platform/lib/inotify/__init__.py index c989514729..95f13899a9 100644 --- a/volttron/platform/lib/inotify/__init__.py +++ b/volttron/platform/lib/inotify/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''Interface to Linux inotify system calls.''' diff --git a/volttron/platform/lib/inotify/__main__.py b/volttron/platform/lib/inotify/__main__.py index 3a21617a63..dfff4a9346 100644 --- a/volttron/platform/lib/inotify/__main__.py +++ b/volttron/platform/lib/inotify/__main__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/lib/inotify/green.py b/volttron/platform/lib/inotify/green.py index 01047f6d57..fccd59ec3a 100644 --- a/volttron/platform/lib/inotify/green.py +++ b/volttron/platform/lib/inotify/green.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''gevent-safe interface to Linux inotify system calls.''' @@ -44,8 +30,7 @@ import gevent from gevent.select import select -from . import _inotify, __all__, _main -from . import * +from . import IN_NONBLOCK, _inotify, _main import logging _log = logging.getLogger(__name__) diff --git a/volttron/platform/lib/prctl.py b/volttron/platform/lib/prctl.py index 1a1bceabbe..937605be3a 100644 --- a/volttron/platform/lib/prctl.py +++ b/volttron/platform/lib/prctl.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''Python interface to Linux process control mechanism. diff --git a/volttron/platform/main.py b/volttron/platform/main.py index e3b8f13482..a0fdd7ecf4 100644 --- a/volttron/platform/main.py +++ b/volttron/platform/main.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from gevent import monkey @@ -53,74 +39,71 @@ fn() import argparse -import errno import logging -from logging import handlers import logging.config -from typing import Optional -from urllib.parse import urlparse - import os import resource import stat import struct +import subprocess import sys import threading import uuid +from logging import handlers +from typing import Optional +from urllib.parse import urlparse import gevent +import zmq +from zmq import ZMQError, green, NOBLOCK +from volttron.platform.agent.utils import get_platform_instance_name +# Create a context common to the green and non-green zmq modules. +from volttron.platform.instance_setup import _update_config_file from volttron.platform.vip.healthservice import HealthService from volttron.platform.vip.servicepeer import ServicePeerNotifier from volttron.utils import get_random_key from volttron.utils.frame_serialization import deserialize_frames, serialize_frames -import zmq -from zmq import ZMQError -from zmq import green -import subprocess - -# Create a context common to the green and non-green zmq modules. -from volttron.platform.instance_setup import _update_config_file -from volttron.platform.agent.utils import get_platform_instance_name -green.Context._instance = green.Context.shadow(zmq.Context.instance().underlying) -from volttron.platform import jsonapi - -from volttron.platform import aip -from volttron.platform import __version__ -from volttron.platform import config - -from volttron.platform.vip.router import * -from volttron.platform.vip.socket import decode_key, encode_key, Address -from volttron.platform.vip.tracking import Tracker +green.Context._instance = green.Context.shadow( + zmq.Context.instance().underlying) +from volttron.platform import __version__, aip, config, jsonapi from volttron.platform.auth.auth import AuthService -from volttron.platform.auth.auth_file import AuthFile from volttron.platform.auth.auth_entry import AuthEntry +from volttron.platform.auth.auth_file import AuthFile from volttron.platform.control.control import ControlService +from volttron.platform.vip.router import BaseRouter, ERROR, INCOMING, UNROUTABLE +from volttron.platform.vip.socket import Address, decode_key, encode_key +from volttron.platform.vip.tracking import Tracker + try: from .web import PlatformWebService HAS_WEB = True except ImportError: HAS_WEB = False -from .store import ConfigStoreService +from zmq import green as _green + +from volttron.platform import is_rabbitmq_available +from volttron.platform.agent.utils import store_message_bus_config +from volttron.platform.vip.proxy_zmq_router import ZMQProxyRouter + +from ..utils.persistance import load_create_store from .agent import utils -from .agent.known_identities import PLATFORM_WEB, CONFIGURATION_STORE, AUTH, CONTROL, CONTROL_CONNECTION, \ - PLATFORM_HEALTH, KEY_DISCOVERY, PROXY_ROUTER, PLATFORM -from .vip.agent.subsystems.pubsub import ProtectedPubSubTopics +from .agent.known_identities import (AUTH, CONFIGURATION_STORE, CONTROL, + CONTROL_CONNECTION, KEY_DISCOVERY, + PLATFORM, PLATFORM_HEALTH, PLATFORM_WEB, + PROXY_ROUTER) from .keystore import KeyStore, KnownHostsStore -from .vip.pubsubservice import PubSubService -from .vip.routingservice import RoutingService +from .store import ConfigStoreService from .vip.externalrpcservice import ExternalRPCService from .vip.keydiscovery import KeyDiscoveryAgent -from ..utils.persistance import load_create_store +from .vip.pubsubservice import PubSubService from .vip.rmq_router import RMQRouter -from volttron.platform.agent.utils import store_message_bus_config -from zmq import green as _green -from volttron.platform.vip.proxy_zmq_router import ZMQProxyRouter -from volttron.platform import is_rabbitmq_available +from .vip.routingservice import RoutingService + if is_rabbitmq_available(): - from volttron.utils.rmq_setup import start_rabbit from volttron.utils.rmq_config_params import RMQConfig + from volttron.utils.rmq_setup import start_rabbit try: import volttron.restricted @@ -131,14 +114,13 @@ HAVE_RESTRICTED = True -_log = logging.getLogger(os.path.basename(sys.argv[0]) - if __name__ == '__main__' else __name__) +_log = logging.getLogger( + os.path.basename(sys.argv[0]) if __name__ == '__main__' else __name__) # Only show debug on the platform when really necessary! log_level_info = ( #'volttron.platform.main', 'volttron.platform.vip.zmq_connection', - 'urllib3.connectionpool', 'watchdog.observers.inotify_buffer', 'volttron.platform.auth', 'volttron.platform.store', @@ -151,11 +133,13 @@ for log_name in log_level_info: logging.getLogger(log_name).setLevel(logging.INFO) +logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING) VOLTTRON_INSTANCES = '~/.volttron_instances' -def log_to_file(file_, level=logging.WARNING, +def log_to_file(file_, + level=logging.WARNING, handler_class=logging.StreamHandler): '''Direct log output to a file (or something like one).''' handler = handler_class(file_) @@ -232,9 +216,9 @@ def configure_logging(conf_path): import yaml except ImportError: return (conf_path, 'PyYAML must be installed before ' - 'loading logging configuration from a YAML file.') + 'loading logging configuration from a YAML file.') try: - conf_dict = yaml.load(conf_file) + conf_dict = yaml.safe_load(conf_file) except yaml.YAMLError as exc: return conf_path, exc try: @@ -276,8 +260,11 @@ def __init__(self, sock): self.sock = sock def run(self): - events = {value: name[6:] for name, value in vars(zmq).items() - if name.startswith('EVENT_') and name != 'EVENT_ALL'} + events = { + value: name[6:] + for name, value in vars(zmq).items() + if name.startswith('EVENT_') and name != 'EVENT_ALL' + } log = logging.getLogger('vip.monitor') if log.level == logging.NOTSET: log.setLevel(logging.INFO) @@ -290,6 +277,7 @@ def run(self): class FramesFormatter: + def __init__(self, frames): self.frames = frames @@ -301,18 +289,30 @@ def __repr__(self): class Router(BaseRouter): '''Concrete VIP router.''' + # Add ZMQClientAuthentication - for building address using public/secretkey ? - def __init__(self, local_address, addresses=(), - context=None, secretkey=None, publickey=None, - default_user_id=None, monitor=False, tracker=None, - volttron_central_address=None, instance_name=None, - bind_web_address=None, volttron_central_serverkey=None, - protected_topics={}, external_address_file='', - msgdebug=None, agent_monitor_frequency=600, + def __init__(self, + local_address, + addresses=(), + context=None, + secretkey=None, + publickey=None, + default_user_id=None, + monitor=False, + tracker=None, + volttron_central_address=None, + instance_name=None, + bind_web_address=None, + volttron_central_serverkey=None, + protected_topics={}, + external_address_file='', + msgdebug=None, + agent_monitor_frequency=600, service_notifier=Optional[ServicePeerNotifier]): - super(Router, self).__init__( - context=context, default_user_id=default_user_id, service_notifier=service_notifier) + super(Router, self).__init__(context=context, + default_user_id=default_user_id, + service_notifier=service_notifier) self.local_address = Address(local_address) self._addr = addresses self.addresses = addresses = [Address(addr) for addr in set(addresses)] @@ -370,9 +370,9 @@ def setup(self): for address in self.addresses: if not address.identity: address.identity = identity - if (address.secretkey is None and - address.server not in ['NULL', 'PLAIN'] and - self._secretkey): + if (address.secretkey is None + and address.server not in ['NULL', 'PLAIN'] + and self._secretkey): address.server = 'CURVE' address.secretkey = self._secretkey if not address.domain: @@ -385,11 +385,9 @@ def setup(self): self._socket_class, self._poller, self._addr, self._instance_name) - self.pubsub = PubSubService(self.socket, - self._protected_topics, + self.pubsub = PubSubService(self.socket, self._protected_topics, self._ext_routing) - self.ext_rpc = ExternalRPCService(self.socket, - self._ext_routing) + self.ext_rpc = ExternalRPCService(self.socket, self._ext_routing) self._poller.register(sock, zmq.POLLIN) _log.debug("ZMQ version: {}".format(zmq.zmq_version())) @@ -402,25 +400,30 @@ def issue(self, topic, frames, extra=None): elif topic == UNROUTABLE: log('unroutable: %s: %s', extra, formatter) else: - log('%s: %s', - ('incoming' if topic == INCOMING else 'outgoing'), formatter) + log('%s: %s', ('incoming' if topic == INCOMING else 'outgoing'), + formatter) if self._tracker: self._tracker.hit(topic, frames, extra) if self._msgdebug: if not self._message_debugger_socket: # Initialize a ZMQ IPC socket on which to publish all messages to MessageDebuggerAgent. - socket_path = os.path.expandvars('$VOLTTRON_HOME/run/messagedebug') + socket_path = os.path.expandvars( + '$VOLTTRON_HOME/run/messagedebug') socket_path = os.path.expanduser(socket_path) - socket_path = 'ipc://{}'.format('@' if sys.platform.startswith('linux') else '') + socket_path + socket_path = 'ipc://{}'.format('@' if sys.platform.startswith( + 'linux') else '') + socket_path self._message_debugger_socket = zmq.Context().socket(zmq.PUB) self._message_debugger_socket.connect(socket_path) # Publish the routed message, including the "topic" (status/direction), for use by MessageDebuggerAgent. frame_bytes = [topic] - frame_bytes.extend(frames) # [frame if type(frame) is bytes else frame.bytes for frame in frames]) + frame_bytes.extend( + frames + ) # [frame if type(frame) is bytes else frame.bytes for frame in frames]) frame_bytes = serialize_frames(frames) # TODO we need to fix the msgdebugger socket if we need it to be connected #frame_bytes = [f.bytes for f in frame_bytes] #self._message_debugger_socket.send_pyobj(frame_bytes) + # This is currently not being used e.g once fixed we won't use it. #def extract_bytes(self, frame_bytes): # result = [] @@ -432,7 +435,8 @@ def issue(self, topic, frames, extra=None): # return result def handle_subsystem(self, frames, user_id): - _log.debug(f"Handling subsystem with frames: {frames} user_id: {user_id}") + _log.debug( + f"Handling subsystem with frames: {frames} user_id: {user_id}") subsystem = frames[5] if subsystem == 'quit': @@ -446,8 +450,9 @@ def handle_subsystem(self, frames, user_id): self.stop() raise KeyboardInterrupt() else: - _log.error(f"Sender {sender} not authorized to shutdown platform") - elif subsystem =='agentstop': + _log.error( + f"Sender {sender} not authorized to shutdown platform") + elif subsystem == 'agentstop': try: drop = frames[6] self._drop_peer(drop) @@ -455,9 +460,13 @@ def handle_subsystem(self, frames, user_id): if self._service_notifier: self._service_notifier.peer_dropped(drop) - _log.debug("ROUTER received agent stop message. dropping peer: {}".format(drop)) + _log.debug( + "ROUTER received agent stop message. dropping peer: {}". + format(drop)) except IndexError: - _log.error(f"agentstop called but unable to determine agent from frames sent {frames}") + _log.error( + f"agentstop called but unable to determine agent from frames sent {frames}" + ) return False elif subsystem == 'query': try: @@ -494,7 +503,7 @@ def handle_subsystem(self, frames, user_id): value = None frames[6:] = ['', value] frames[3] = '' - + return frames elif subsystem == 'pubsub': result = self.pubsub.handle_subsystem(frames, user_id) @@ -564,7 +573,9 @@ def ext_route(self, socket): peer = msg_data['to_peer'] # Send to destionation agent/peer # Form new frame for local - frames[:9] = [peer, sender, proto, usr_id, msg_id, 'external_rpc', msg] + frames[:9] = [ + peer, sender, proto, usr_id, msg_id, 'external_rpc', msg + ] try: self.socket.send_multipart(frames, flags=NOBLOCK, copy=False) except ZMQError as ex: @@ -594,25 +605,44 @@ class GreenRouter(Router): Greenlet friendly Router """ - def __init__(self, local_address, addresses=(), - context=None, secretkey=None, publickey=None, - default_user_id=None, monitor=False, tracker=None, - volttron_central_address=None, instance_name=None, - bind_web_address=None, volttron_central_serverkey=None, - protected_topics={}, external_address_file='', - msgdebug=None, volttron_central_rmq_address=None, + def __init__(self, + local_address, + addresses=(), + context=None, + secretkey=None, + publickey=None, + default_user_id=None, + monitor=False, + tracker=None, + volttron_central_address=None, + instance_name=None, + bind_web_address=None, + volttron_central_serverkey=None, + protected_topics={}, + external_address_file='', + msgdebug=None, + volttron_central_rmq_address=None, service_notifier=Optional[ServicePeerNotifier]): self._context_class = _green.Context self._socket_class = _green.Socket self._poller_class = _green.Poller super(GreenRouter, self).__init__( - local_address, addresses=addresses, - context=context, secretkey=secretkey, publickey=publickey, - default_user_id=default_user_id, monitor=monitor, tracker=tracker, - volttron_central_address=volttron_central_address, instance_name=instance_name, - bind_web_address=bind_web_address, volttron_central_serverkey=volttron_central_address, - protected_topics=protected_topics, external_address_file=external_address_file, - msgdebug=msgdebug, service_notifier=service_notifier) + local_address, + addresses=addresses, + context=context, + secretkey=secretkey, + publickey=publickey, + default_user_id=default_user_id, + monitor=monitor, + tracker=tracker, + volttron_central_address=volttron_central_address, + instance_name=instance_name, + bind_web_address=bind_web_address, + volttron_central_serverkey=volttron_central_address, + protected_topics=protected_topics, + external_address_file=external_address_file, + msgdebug=msgdebug, + service_notifier=service_notifier) def start(self): '''Create the socket and call setup(). @@ -690,9 +720,11 @@ def start_volttron_process(opts): opts.web_ssl_cert = config.expandall(opts.web_ssl_cert) if opts.web_ssl_key and not opts.web_ssl_cert: - raise Exception("If web-ssl-key is specified web-ssl-cert MUST be specified.") + raise Exception( + "If web-ssl-key is specified web-ssl-cert MUST be specified.") if opts.web_ssl_cert and not opts.web_ssl_key: - raise Exception("If web-ssl-cert is specified web-ssl-key MUST be specified.") + raise Exception( + "If web-ssl-cert is specified web-ssl-key MUST be specified.") if opts.web_ca_cert: assert os.path.isfile(opts.web_ca_cert), "web_ca_cert does not exist!" @@ -721,26 +753,31 @@ def start_volttron_process(opts): os.environ['BIND_WEB_ADDRESS'] = opts.bind_web_address parsed = urlparse(opts.bind_web_address) if parsed.scheme not in ('http', 'https'): - raise Exception( - 'bind-web-address must begin with http or https.') + raise Exception('bind-web-address must begin with http or https.') opts.bind_web_address = config.expandall(opts.bind_web_address) # zmq with tls is supported if opts.message_bus == 'zmq' and parsed.scheme == 'https': if not opts.web_ssl_key or not opts.web_ssl_cert: - raise Exception("zmq https requires a web-ssl-key and a web-ssl-cert file.") - if not os.path.isfile(opts.web_ssl_key) or not os.path.isfile(opts.web_ssl_cert): - raise Exception("zmq https requires a web-ssl-key and a web-ssl-cert file.") + raise Exception( + "zmq https requires a web-ssl-key and a web-ssl-cert file." + ) + if not os.path.isfile(opts.web_ssl_key) or not os.path.isfile( + opts.web_ssl_cert): + raise Exception( + "zmq https requires a web-ssl-key and a web-ssl-cert file." + ) # zmq without tls is supported through the use of a secret key, if it's None then # we want to generate a secret key and set it in the config file. elif opts.message_bus == 'zmq' and opts.web_secret_key is None: opts.web_secret_key = get_random_key() - _update_config_file(web_secret_key = opts.web_secret_key) + _update_config_file(web_secret_key=opts.web_secret_key) if opts.volttron_central_address: parsed = urlparse(opts.volttron_central_address) if parsed.scheme not in ('http', 'https', 'tcp', 'amqp', 'amqps'): raise Exception( - 'volttron-central-address must begin with tcp, amqp, amqps, http or https.') + 'volttron-central-address must begin with tcp, amqp, amqps, http or https.' + ) opts.volttron_central_address = config.expandall( opts.volttron_central_address) opts.volttron_central_serverkey = opts.volttron_central_serverkey @@ -767,8 +804,7 @@ def start_volttron_process(opts): else: _log.debug('open file resource limit increased from %d to %d', soft, limit) - _log.debug('open file resource limit %d to %d', - soft, hard) + _log.debug('open file resource limit %d to %d', soft, hard) # Set configuration if HAVE_RESTRICTED: if opts.verify_agents: @@ -782,13 +818,15 @@ def start_volttron_process(opts): # Check for agent isolation mode/permissions on VOLTTRON_HOME directory mode = os.stat(opts.volttron_home).st_mode if mode & (stat.S_IWGRP | stat.S_IWOTH): - _log.warning('insecure access control on directory: %s', opts.volttron_home) - + _log.warning('insecure access control on directory: %s', + opts.volttron_home) + # Initialize public and secret keys for Non-auth. publickey = None secretkey = None # auth entries for agents if opts.allow_auth: + _log.info("Loading auth entries from auth.json") # Get or generate encryption key keystore = KeyStore() _log.debug('using key-store file %s', keystore.filename) @@ -800,10 +838,15 @@ def start_volttron_process(opts): publickey = decode_key(keystore.public) if publickey: # Authorize the platform key: - entry = AuthEntry(credentials=encode_key(publickey), - user_id=PLATFORM, - capabilities=[{'edit_config_store': {'identity': '/.*/'}}], - comments='Automatically added by platform on start') + entry = AuthEntry( + credentials=encode_key(publickey), + user_id=PLATFORM, + capabilities=[{ + 'edit_config_store': { + 'identity': '/.*/' + } + }], + comments='Automatically added by platform on start') AuthFile().add(entry, overwrite=True) # Add platform key to known-hosts file: known_hosts = KnownHostsStore() @@ -813,14 +856,20 @@ def start_volttron_process(opts): secretkey = decode_key(keystore.secret) # Add the control.connection so that volttron-ctl can access the bus - control_conn_path = KeyStore.get_agent_keystore_path(CONTROL_CONNECTION) + control_conn_path = KeyStore.get_agent_keystore_path( + CONTROL_CONNECTION) os.makedirs(os.path.dirname(control_conn_path), exist_ok=True) - ks_control_conn = KeyStore(KeyStore.get_agent_keystore_path(CONTROL_CONNECTION)) - entry = AuthEntry(credentials=encode_key(decode_key(ks_control_conn.public)), + ks_control_conn = KeyStore( + KeyStore.get_agent_keystore_path(CONTROL_CONNECTION)) + entry = AuthEntry(credentials=encode_key( + decode_key(ks_control_conn.public)), user_id=CONTROL_CONNECTION, identity=CONTROL_CONNECTION, - capabilities=[{'edit_config_store': {'identity': '/.*/'}}, - 'modify_rpc_method_allowance', + capabilities=[{ + 'edit_config_store': { + 'identity': '/.*/' + } + }, 'modify_rpc_method_allowance', 'allow_auth_modifications'], comments='Automatically added by platform on start') AuthFile().add(entry, overwrite=True) @@ -831,9 +880,11 @@ def start_volttron_process(opts): # zmq.Context.instance().set(zmq.MAX_SOCKETS, 2046) tracker = Tracker() - protected_topics_file = os.path.join(opts.volttron_home, 'protected_topics.json') + protected_topics_file = os.path.join(opts.volttron_home, + 'protected_topics.json') _log.debug('protected topics file %s', protected_topics_file) - external_address_file = os.path.join(opts.volttron_home, 'external_address.json') + external_address_file = os.path.join(opts.volttron_home, + 'external_address.json') _log.debug('external_address_file file %s', external_address_file) protected_topics = {} if opts.agent_monitor_frequency: @@ -852,9 +903,12 @@ def start_volttron_process(opts): def zmq_router(stop): try: _log.debug("Running zmq router") - Router(opts.vip_local_address, opts.vip_address, - secretkey=secretkey, publickey=publickey, - default_user_id='vip.service', monitor=opts.monitor, + Router(opts.vip_local_address, + opts.vip_address, + secretkey=secretkey, + publickey=publickey, + default_user_id='vip.service', + monitor=opts.monitor, tracker=tracker, volttron_central_address=opts.volttron_central_address, volttron_central_serverkey=opts.volttron_central_serverkey, @@ -876,12 +930,14 @@ def zmq_router(stop): # RMQ router def rmq_router(stop): try: - RMQRouter(opts.vip_address, opts.vip_local_address, opts.instance_name, opts.vip_address, + RMQRouter(opts.vip_address, + opts.vip_local_address, + opts.instance_name, + opts.vip_address, volttron_central_address=opts.volttron_central_address, bind_web_address=opts.bind_web_address, enable_auth=opts.allow_auth, - service_notifier=notifier - ).run() + service_notifier=notifier).run() except Exception: _log.exception('Unhandled exception in rmq router loop') except KeyboardInterrupt: @@ -902,26 +958,44 @@ def rmq_router(stop): proxy_router = None proxy_router_task = None - _log.debug("********************************************************************") - _log.debug("VOLTTRON PLATFORM RUNNING ON {} MESSAGEBUS".format(opts.message_bus)) - _log.debug("********************************************************************") + _log.debug( + "********************************************************************" + ) + _log.debug("VOLTTRON PLATFORM RUNNING ON {} MESSAGEBUS".format( + opts.message_bus)) + _log.debug( + "********************************************************************" + ) # Start the config store before auth so we may one day have auth use it. config_store = ConfigStoreService(address=address, - identity=CONFIGURATION_STORE, - message_bus=opts.message_bus, - enable_auth=opts.allow_auth) + identity=CONFIGURATION_STORE, + message_bus=opts.message_bus, + enable_auth=opts.allow_auth, + enable_store=False) + + if opts.allow_auth: + entry = AuthEntry(credentials=config_store.core.publickey, + user_id=CONFIGURATION_STORE, + identity=CONFIGURATION_STORE, + capabilities='sync_agent_config', + comments='Automatically added by platform on start') + AuthFile().add(entry, overwrite=True) # Launch additional services and wait for them to start before # auto-starting agents services = [ - ControlService(opts.aip, address=address, identity=CONTROL, - tracker=tracker, heartbeat_autostart=True, - enable_store=False, enable_channel=True, - message_bus=opts.message_bus, - agent_monitor_frequency=opts.agent_monitor_frequency, - enable_auth=opts.allow_auth), - + ControlService( + opts.aip, + address=address, + identity=CONTROL, + tracker=tracker, + heartbeat_autostart=True, + enable_store=False, + enable_channel=True, + message_bus=opts.message_bus, + agent_monitor_frequency=opts.agent_monitor_frequency, + enable_auth=opts.allow_auth), KeyDiscoveryAgent(address=address, identity=KEY_DISCOVERY, external_address_config=external_address_file, @@ -933,19 +1007,27 @@ def rmq_router(stop): ] health_service = HealthService(address=address, - identity=PLATFORM_HEALTH, heartbeat_autostart=True, + identity=PLATFORM_HEALTH, + heartbeat_autostart=True, enable_store=False, message_bus=opts.message_bus, enable_auth=opts.allow_auth) - notifier.register_peer_callback(health_service.peer_added, health_service.peer_dropped) + notifier.register_peer_callback(health_service.peer_added, + health_service.peer_dropped) services.append(health_service) # Begin the webserver based options here. if opts.bind_web_address is not None: if not HAS_WEB: - _log.info(f"Web libraries not installed, but bind web address specified\n") - sys.stderr.write("Web libraries not installed, but bind web address specified\n") - sys.stderr.write("Please install web libraries using python3 bootstrap.py --web\n") + _log.info( + f"Web libraries not installed, but bind web address specified\n" + ) + sys.stderr.write( + "Web libraries not installed, but bind web address specified\n" + ) + sys.stderr.write( + "Please install web libraries using python3 bootstrap.py --web\n" + ) sys.exit(-1) if opts.instance_name is None: @@ -960,25 +1042,28 @@ def rmq_router(stop): base_webserver_name = PLATFORM_WEB + "-server" from volttron.platform.auth.certs import Certs certs = Certs() - certs.create_signed_cert_files(base_webserver_name, cert_type='server') - opts.web_ssl_key = certs.private_key_file(base_webserver_name) + certs.create_signed_cert_files(base_webserver_name, + cert_type='server') + opts.web_ssl_key = certs.private_key_file( + base_webserver_name) opts.web_ssl_cert = certs.cert_file(base_webserver_name) - + _log.info("Starting platform web service") - services.append(PlatformWebService( - serverkey=publickey, - identity=PLATFORM_WEB, - address=address, - bind_web_address=opts.bind_web_address, - volttron_central_address=opts.volttron_central_address, - enable_store=False, - message_bus=opts.message_bus, - volttron_central_rmq_address=opts.volttron_central_rmq_address, - web_ssl_key=opts.web_ssl_key, - web_ssl_cert=opts.web_ssl_cert, - web_secret_key=opts.web_secret_key, - enable_auth=opts.allow_auth - )) + services.append( + PlatformWebService( + serverkey=publickey, + identity=PLATFORM_WEB, + address=address, + bind_web_address=opts.bind_web_address, + volttron_central_address=opts.volttron_central_address, + enable_store=False, + message_bus=opts.message_bus, + volttron_central_rmq_address=opts. + volttron_central_rmq_address, + web_ssl_key=opts.web_ssl_key, + web_ssl_cert=opts.web_ssl_cert, + web_secret_key=opts.web_secret_key, + enable_auth=opts.allow_auth)) if opts.message_bus == 'zmq': # starting sequence is different for zmq and rmq @@ -993,7 +1078,8 @@ def rmq_router(stop): del event # Start ZMQ router in separate thread to remain responsive - thread = threading.Thread(target=zmq_router, args=(config_store.core.stop,)) + thread = threading.Thread(target=zmq_router, + args=(config_store.core.stop, )) thread.daemon = True thread.start() @@ -1004,7 +1090,9 @@ def rmq_router(stop): # Start RabbitMQ server if not running rmq_config = RMQConfig() if rmq_config is None: - _log.error("DEBUG: Exiting due to error in rabbitmq config file. Please check.") + _log.error( + "DEBUG: Exiting due to error in rabbitmq config file. Please check." + ) sys.exit() # If RabbitMQ is started as service, don't start it through the code @@ -1012,14 +1100,17 @@ def rmq_router(stop): try: start_rabbit(rmq_config.rmq_home) except AttributeError as exc: - _log.error("Exception while starting RabbitMQ. Check the path in the config file.") + _log.error( + "Exception while starting RabbitMQ. Check the path in the config file." + ) sys.exit() except subprocess.CalledProcessError as exc: _log.error("Unable to start rabbitmq server. " "Check rabbitmq log for errors") sys.exit() - thread = threading.Thread(target=rmq_router, args=(config_store.core.stop,)) + thread = threading.Thread(target=rmq_router, + args=(config_store.core.stop, )) thread.daemon = True thread.start() @@ -1039,17 +1130,21 @@ def rmq_router(stop): # Spawn Greenlet friendly ZMQ router # Necessary for backward compatibility with ZMQ message bus - green_router = GreenRouter(opts.vip_local_address, opts.vip_address, - secretkey=secretkey, publickey=publickey, - default_user_id='vip.service', monitor=opts.monitor, - tracker=tracker, - volttron_central_address=opts.volttron_central_address, - instance_name=opts.instance_name, - bind_web_address=opts.bind_web_address, - protected_topics=protected_topics, - external_address_file=external_address_file, - msgdebug=opts.msgdebug, - service_notifier=notifier) + green_router = GreenRouter( + opts.vip_local_address, + opts.vip_address, + secretkey=secretkey, + publickey=publickey, + default_user_id='vip.service', + monitor=opts.monitor, + tracker=tracker, + volttron_central_address=opts.volttron_central_address, + instance_name=opts.instance_name, + bind_web_address=opts.bind_web_address, + protected_topics=protected_topics, + external_address_file=external_address_file, + msgdebug=opts.msgdebug, + service_notifier=notifier) proxy_router = ZMQProxyRouter(address=address, identity=PROXY_ROUTER, @@ -1079,10 +1174,11 @@ def rmq_router(stop): instances[opts.volttron_home] = this_instance instances.async_sync() - events = [gevent.event.Event() for service in services] - tasks = [gevent.spawn(service.core.run, event) - for service, event in zip(services, events)] + tasks = [ + gevent.spawn(service.core.run, event) + for service, event in zip(services, events) + ] tasks.append(config_store_task) tasks.append(auth_task) tasks = [task for task in tasks if task] @@ -1130,19 +1226,28 @@ def rmq_router(stop): os.remove(pid_file) except Exception: _log.warning("Unable to load {}".format(VOLTTRON_INSTANCES)) - _log.debug("********************************************************************") + _log.debug( + "********************************************************************" + ) _log.debug("VOLTTRON PLATFORM HAS SHUTDOWN") - _log.debug("********************************************************************") + _log.debug( + "********************************************************************" + ) def setup_auth_service(opts, address, services): - protected_topics_file = os.path.join(opts.volttron_home, 'protected_topics.json') + protected_topics_file = os.path.join(opts.volttron_home, + 'protected_topics.json') _log.debug('protected topics file %s', protected_topics_file) auth_file = os.path.join(opts.volttron_home, 'auth.json') - auth = AuthService(auth_file, protected_topics_file, - opts.setup_mode, opts.aip, - address=address, identity=AUTH, - enable_store=False, message_bus=opts.message_bus, + auth = AuthService(auth_file, + protected_topics_file, + opts.setup_mode, + opts.aip, + address=address, + identity=AUTH, + enable_store=False, + message_bus=opts.message_bus, enable_auth=opts.allow_auth) event = gevent.event.Event() @@ -1154,24 +1259,27 @@ def setup_auth_service(opts, address, services): _log.debug("MAIN: protected topics content {}".format(protected_topics)) ks_auth = KeyStore(KeyStore.get_agent_keystore_path(AUTH)) - entry = AuthEntry( - credentials=encode_key(decode_key(ks_auth.public)), - user_id=AUTH, - identity=AUTH, - capabilities=['modify_rpc_method_allowance'], - comments='Automatically added by platform on start') + entry = AuthEntry(credentials=encode_key(decode_key(ks_auth.public)), + user_id=AUTH, + identity=AUTH, + capabilities=['modify_rpc_method_allowance'], + comments='Automatically added by platform on start') AuthFile().add(entry, overwrite=True) - - external_address_file = os.path.join(opts.volttron_home, 'external_address.json') + external_address_file = os.path.join(opts.volttron_home, + 'external_address.json') _log.debug('external_address_file file %s', external_address_file) entry = AuthEntry(credentials=services[0].core.publickey, user_id=CONTROL, identity=CONTROL, - capabilities=[{'edit_config_store': {'identity': '/.*/'}}, - 'modify_rpc_method_allowance', - 'allow_auth_modifications'], + capabilities=[ + { + 'edit_config_store': { + 'identity': '/.*/'} + }, + 'modify_rpc_method_allowance', + 'allow_auth_modifications'], comments='Automatically added by platform on start') AuthFile().add(entry, overwrite=True) @@ -1197,126 +1305,168 @@ def main(argv=sys.argv): 'potential damage.\n' % os.path.basename(argv[0])) sys.exit(77) - volttron_home = os.path.normpath(config.expandall( - os.environ.get('VOLTTRON_HOME', '~/.volttron'))) + volttron_home = os.path.normpath( + config.expandall(os.environ.get('VOLTTRON_HOME', '~/.volttron'))) os.environ['VOLTTRON_HOME'] = volttron_home # Setup option parser parser = config.ArgumentParser( - prog=os.path.basename(argv[0]), add_help=False, + prog=os.path.basename(argv[0]), + add_help=False, description='VOLTTRON platform service', usage='%(prog)s [OPTION]...', argument_default=argparse.SUPPRESS, epilog='Boolean options, which take no argument, may be inversed by ' - 'prefixing the option with no- (e.g. --autostart may be ' - 'inversed using --no-autostart).' - ) + 'prefixing the option with no- (e.g. --autostart may be ' + 'inversed using --no-autostart).') + parser.add_argument('-c', + '--config', + metavar='FILE', + action='parse_config', + ignore_unknown=False, + sections=[None, 'volttron'], + help='read configuration from FILE') + parser.add_argument('-l', + '--log', + metavar='FILE', + default=None, + help='send log output to FILE instead of stderr') + parser.add_argument('-L', + '--log-config', + metavar='FILE', + help='read logging configuration from FILE') + parser.add_argument('--log-level', + metavar='LOGGER:LEVEL', + action=LogLevelAction, + help='override default logger logging level') + parser.add_argument('--monitor', + action='store_true', + help='monitor and log connections (implies -v)') parser.add_argument( - '-c', '--config', metavar='FILE', action='parse_config', - ignore_unknown=False, sections=[None, 'volttron'], - help='read configuration from FILE') - parser.add_argument( - '-l', '--log', metavar='FILE', default=None, - help='send log output to FILE instead of stderr') - parser.add_argument( - '-L', '--log-config', metavar='FILE', - help='read logging configuration from FILE') - parser.add_argument( - '--log-level', metavar='LOGGER:LEVEL', action=LogLevelAction, - help='override default logger logging level') - parser.add_argument( - '--monitor', action='store_true', - help='monitor and log connections (implies -v)') - parser.add_argument( - '-q', '--quiet', action='add_const', const=10, dest='verboseness', + '-q', + '--quiet', + action='add_const', + const=10, + dest='verboseness', help='decrease logger verboseness; may be used multiple times') parser.add_argument( - '-v', '--verbose', action='add_const', const=-10, dest='verboseness', + '-v', + '--verbose', + action='add_const', + const=-10, + dest='verboseness', help='increase logger verboseness; may be used multiple times') - parser.add_argument( - '--verboseness', type=int, metavar='LEVEL', default=logging.WARNING, - help='set logger verboseness') + parser.add_argument('--verboseness', + type=int, + metavar='LEVEL', + default=logging.WARNING, + help='set logger verboseness') # parser.add_argument( # '--volttron-home', env_var='VOLTTRON_HOME', metavar='PATH', # help='VOLTTRON configuration directory') - parser.add_argument( - '--show-config', action='store_true', - help=argparse.SUPPRESS) + parser.add_argument('--show-config', + action='store_true', + help=argparse.SUPPRESS) parser.add_help_argument() parser.add_version_argument(version='%(prog)s ' + __version__) agents = parser.add_argument_group('agent options') + agents.add_argument('--autostart', + action='store_true', + inverse='--no-autostart', + help='automatically start enabled agents and services') + agents.add_argument('--no-autostart', + action='store_false', + dest='autostart', + help=argparse.SUPPRESS) agents.add_argument( - '--autostart', action='store_true', inverse='--no-autostart', - help='automatically start enabled agents and services') - agents.add_argument( - '--no-autostart', action='store_false', dest='autostart', - help=argparse.SUPPRESS) - agents.add_argument( - '--publish-address', metavar='ZMQADDR', + '--publish-address', + metavar='ZMQADDR', help='ZeroMQ URL used for pre-3.x agent publishing (deprecated)') agents.add_argument( - '--subscribe-address', metavar='ZMQADDR', + '--subscribe-address', + metavar='ZMQADDR', help='ZeroMQ URL used for pre-3.x agent subscriptions (deprecated)') + agents.add_argument('--vip-address', + metavar='ZMQADDR', + action='append', + default=[], + help='ZeroMQ URL to bind for VIP connections') agents.add_argument( - '--vip-address', metavar='ZMQADDR', action='append', default=[], - help='ZeroMQ URL to bind for VIP connections') - agents.add_argument( - '--vip-local-address', metavar='ZMQADDR', + '--vip-local-address', + metavar='ZMQADDR', help='ZeroMQ URL to bind for local agent VIP connections') agents.add_argument( - '--bind-web-address', metavar='BINDWEBADDR', default=None, + '--bind-web-address', + metavar='BINDWEBADDR', + default=None, help='Bind a web server to the specified ip:port passed') agents.add_argument( - '--web-ca-cert', metavar='CAFILE', default=None, - help='If using self-signed certificates, this variable will be set globally to allow requests' - 'to be able to correctly reach the webserver without having to specify verify in all calls.' + '--web-ca-cert', + metavar='CAFILE', + default=None, + help= + 'If using self-signed certificates, this variable will be set globally to allow requests' + 'to be able to correctly reach the webserver without having to specify verify in all calls.' ) agents.add_argument( - "--web-secret-key", default=None, - help="Secret key to be used instead of https based authentication." - ) + "--web-secret-key", + default=None, + help="Secret key to be used instead of https based authentication.") agents.add_argument( - '--web-ssl-key', metavar='KEYFILE', default=None, - help='ssl key file for using https with the volttron server' - ) + '--web-ssl-key', + metavar='KEYFILE', + default=None, + help='ssl key file for using https with the volttron server') agents.add_argument( - '--web-ssl-cert', metavar='CERTFILE', default=None, - help='ssl certficate file for using https with the volttron server' - ) + '--web-ssl-cert', + metavar='CERTFILE', + default=None, + help='ssl certficate file for using https with the volttron server') agents.add_argument( - '--volttron-central-address', default=None, + '--volttron-central-address', + default=None, help='The web address of a volttron central install instance.') + agents.add_argument('--volttron-central-serverkey', + default=None, + help='The serverkey of volttron central.') agents.add_argument( - '--volttron-central-serverkey', default=None, - help='The serverkey of volttron central.') - agents.add_argument( - '--allow-auth', default='True', - help='Require authentication and authorization in VOLTTRON. Default=True' - ) + '--allow-auth', + default='True', + help= + 'Require authentication and authorization in VOLTTRON. Default=True') agents.add_argument( - '--instance-name', default=None, + '--instance-name', + default=None, help='The name of the instance that will be reported to ' - 'VOLTTRON central.') + 'VOLTTRON central.') + agents.add_argument('--msgdebug', + action='store_true', + help='Route all messages to an agent while debugging.') agents.add_argument( - '--msgdebug', action='store_true', - help='Route all messages to an agent while debugging.') - agents.add_argument( - '--setup-mode', action='store_true', - help='Setup mode flag for setting up authorization of external platforms.') + '--setup-mode', + action='store_true', + help= + 'Setup mode flag for setting up authorization of external platforms.') parser.add_argument( - '--message-bus', action='store', default='zmq', dest='message_bus', + '--message-bus', + action='store', + default='zmq', + dest='message_bus', help='set message to be used. valid values are zmq and rmq') agents.add_argument( - '--volttron-central-rmq-address', default=None, + '--volttron-central-rmq-address', + default=None, help='The AMQP address of a volttron central install instance') agents.add_argument( - '--agent-monitor-frequency', default=600, + '--agent-monitor-frequency', + default=600, help='How often should the platform check for crashed agents and ' - 'attempt to restart. Units=seconds. Default=600') + 'attempt to restart. Units=seconds. Default=600') agents.add_argument( - '--agent-isolation-mode', default=False, + '--agent-isolation-mode', + default=False, help='Require that agents run with their own users (this requires ' - 'running scripts/secure_user_permissions.sh as sudo)') + 'running scripts/secure_user_permissions.sh as sudo)') # XXX: re-implement control options # on @@ -1334,12 +1484,20 @@ def main(argv=sys.argv): # help='user groups allowed to connect to control socket') if HAVE_RESTRICTED: + class RestrictedAction(argparse.Action): - def __init__(self, option_strings, dest, - const=True, help=None, **kwargs): - super(RestrictedAction, self).__init__( - option_strings, dest=argparse.SUPPRESS, nargs=0, - const=const, help=help) + + def __init__(self, + option_strings, + dest, + const=True, + help=None, + **kwargs): + super(RestrictedAction, self).__init__(option_strings, + dest=argparse.SUPPRESS, + nargs=0, + const=const, + help=help) def __call__(self, parser, namespace, values, option_string=None): namespace.verify_agents = self.const @@ -1348,24 +1506,30 @@ def __call__(self, parser, namespace, values, option_string=None): restrict = parser.add_argument_group('restricted options') restrict.add_argument( - '--restricted', action=RestrictedAction, inverse='--no-restricted', + '--restricted', + action=RestrictedAction, + inverse='--no-restricted', help='shortcut to enable all restricted features') - restrict.add_argument( - '--no-restricted', action=RestrictedAction, const=False, - help=argparse.SUPPRESS) - restrict.add_argument( - '--verify', action='store_true', inverse='--no-verify', - help='verify agent integrity before execution') - restrict.add_argument( - '--no-verify', action='store_false', dest='verify_agents', - help=argparse.SUPPRESS) - restrict.add_argument( - '--resource-monitor', action='store_true', - inverse='--no-resource-monitor', - help='enable agent resource management') - restrict.add_argument( - '--no-resource-monitor', action='store_false', - dest='resource_monitor', help=argparse.SUPPRESS) + restrict.add_argument('--no-restricted', + action=RestrictedAction, + const=False, + help=argparse.SUPPRESS) + restrict.add_argument('--verify', + action='store_true', + inverse='--no-verify', + help='verify agent integrity before execution') + restrict.add_argument('--no-verify', + action='store_false', + dest='verify_agents', + help=argparse.SUPPRESS) + restrict.add_argument('--resource-monitor', + action='store_true', + inverse='--no-resource-monitor', + help='enable agent resource management') + restrict.add_argument('--no-resource-monitor', + action='store_false', + dest='resource_monitor', + help=argparse.SUPPRESS) # restrict.add_argument( # '--mobility', action='store_true', inverse='--no-mobility', # help='enable agent mobility') @@ -1410,8 +1574,7 @@ def __call__(self, parser, namespace, values, option_string=None): web_ca_cert=None, # If we aren't using ssl then we need a secret key available for us to use. web_secret_key=None, - allow_auth='True' - ) + allow_auth='True') # Parse and expand options args = argv[1:] diff --git a/volttron/platform/messaging/__init__.py b/volttron/platform/messaging/__init__.py index 582fd7adbd..8153685948 100644 --- a/volttron/platform/messaging/__init__.py +++ b/volttron/platform/messaging/__init__.py @@ -1,40 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from .socket import * - diff --git a/volttron/platform/messaging/headers.py b/volttron/platform/messaging/headers.py index ab8548b5f2..b17c81909d 100644 --- a/volttron/platform/messaging/headers.py +++ b/volttron/platform/messaging/headers.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ messaging header name constants.''' diff --git a/volttron/platform/messaging/health.py b/volttron/platform/messaging/health.py index 29988d15ef..a0e2824250 100644 --- a/volttron/platform/messaging/health.py +++ b/volttron/platform/messaging/health.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -182,4 +168,3 @@ def build(status, context=None, status_changed_callback=None): statusobj.update_status(status, context) statusobj._status_changed_callback = status_changed_callback return statusobj - diff --git a/volttron/platform/messaging/socket.py b/volttron/platform/messaging/socket.py index 18b2b0d46a..1afc93e0b0 100644 --- a/volttron/platform/messaging/socket.py +++ b/volttron/platform/messaging/socket.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ messaging classes.''' @@ -80,7 +66,7 @@ def recv_message(self, flags=0): def recv_message_ex(self, flags=0): '''Receive a message as (content type, message) tuples. - + Like recv_message(), returns a three tuple. However, the final message component contains a list of 2-tuples instead of a list of messages. These 2-tuples contain the content- type and the @@ -121,4 +107,3 @@ def send_message_ex(self, topic, headers, *msg_tuples, **kwargs): headers = Headers(headers) if headers else Headers() headers['Content-Type'], msg_parts = list(zip(*msg_tuples)) self.send_message(topic, headers.dict, *msg_parts, **kwargs) - diff --git a/volttron/platform/messaging/topics.py b/volttron/platform/messaging/topics.py index 079013ea18..c264670433 100644 --- a/volttron/platform/messaging/topics.py +++ b/volttron/platform/messaging/topics.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ topic templates. @@ -147,7 +133,7 @@ ACTUATOR_VALUE = _(_DEVICES_VALUE.replace('{node}', 'actuators/value')) -#Ragardless of the interface used (RPC vs pubsub) when an agent +#Ragardless of the interface used (RPC vs pubsub) when an agent # attempts to set a point it is announced on this topic. #This is intended to inable a historian to capture all attempted writes. ACTUATOR_WRITE = _(_DEVICES_VALUE.replace('{node}', 'actuators/write')) diff --git a/volttron/platform/messaging/utils.py b/volttron/platform/messaging/utils.py index 66bc9a55c0..6b069df801 100644 --- a/volttron/platform/messaging/utils.py +++ b/volttron/platform/messaging/utils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VOLTTRON platform™ messaging utilities.''' @@ -174,4 +160,3 @@ def __repr__(self): class Header(str): pass - diff --git a/volttron/platform/packages.py b/volttron/platform/packages.py index 2011059371..5f646c400c 100644 --- a/volttron/platform/packages.py +++ b/volttron/platform/packages.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import base64 @@ -67,7 +53,7 @@ class VolttronPackageWheelFileNoSign(WheelFile): def __init__(self, filename,**kwargs): - super(VolttronPackageWheelFileNoSign, self).__init__(filename, + super(VolttronPackageWheelFileNoSign, self).__init__(filename, **kwargs) def contains(self, path): @@ -90,13 +76,13 @@ def add_files(self, files_to_add=None, basedir='.'): last_record_name = records[0] # new_record_name = "RECORD.{}".format(len(records)) -# +# tmp_dir = tempfile.mkdtemp() try: record_path = '/'.join((self.distinfo_name, last_record_name)) - tmp_new_record_file = '/'.join((tmp_dir, self.distinfo_name, + tmp_new_record_file = '/'.join((tmp_dir, self.distinfo_name, last_record_name)) - self.zipfile.extract('/'.join((self.distinfo_name, last_record_name)), + self.zipfile.extract('/'.join((self.distinfo_name, last_record_name)), path = tmp_dir) self.remove_files('/'.join((self.distinfo_name, 'config'))) @@ -338,7 +324,7 @@ def get_records(self): raise ValueError('missing RECORD file(s) in .dist-info directory') return records - + class ZipPackageVerifier(BasePackageVerifier): '''Verify files of a Zip file.''' @@ -423,7 +409,7 @@ def package_name(self): def version(self): metadata = self.metadata return metadata['version'] - + @property def wheel_name(self): metadata = self.metadata diff --git a/volttron/platform/packaging.py b/volttron/platform/packaging.py index 459b4e6760..2a82f2246c 100644 --- a/volttron/platform/packaging.py +++ b/volttron/platform/packaging.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """Agent packaging and signing support. @@ -50,9 +36,9 @@ import errno from wheel.install import WheelFile -from volttron.platform.packages import * from volttron.platform.agent import utils from volttron.platform import get_volttron_data, get_home +from volttron.platform.packages import UnpackedPackage, VolttronPackageWheelFileNoSign from volttron.utils.prompt import prompt_response from volttron.platform.auth import certs from volttron.platform import config @@ -467,7 +453,7 @@ def _create_ca(override=True, data=None): if override: msg = '''Creating a new root ca will overwrite the current ca and invalidate any signed certs. - + Are you sure you want to do this? type 'yes' to continue: ''' continue_yes = input(msg) @@ -692,33 +678,32 @@ def main(argv=sys.argv): init_agent(opts.directory, opts.module_name, opts.template, opts.silent, opts.identity) elif opts.subparser_name == 'create_ca': _create_ca() - else: - if auth is not None: - try: - if opts.subparser_name == 'verify': - if not os.path.exists(opts.package): - print(f'Invalid package name {opts.package}') - verifier = auth.SignedZipPackageVerifier(opts.package) - verifier.verify() - print("Package is verified") - else: - user_type = {'admin': opts.admin, - 'creator': opts.creator, - 'initiator': opts.initiator, - 'platform': opts.platform} - if opts.subparser_name == 'sign': - in_args = { - 'config_file': opts.config_file, - 'user_type': user_type, - 'contract': opts.contract, - 'certs_dir': opts.certs_dir - } - _sign_agent_package(opts.package, **in_args) - - elif opts.subparser_name == 'create_cert': - _create_cert(name=opts.name, **user_type) - except auth.AuthError as e: - _log.error(e.message) + elif auth is not None: + try: + if opts.subparser_name == 'verify': + if not os.path.exists(opts.package): + print(f'Invalid package name {opts.package}') + verifier = auth.SignedZipPackageVerifier(opts.package) + verifier.verify() + print("Package is verified") + else: + user_type = {'admin': opts.admin, + 'creator': opts.creator, + 'initiator': opts.initiator, + 'platform': opts.platform} + if opts.subparser_name == 'sign': + in_args = { + 'config_file': opts.config_file, + 'user_type': user_type, + 'contract': opts.contract, + 'certs_dir': opts.certs_dir + } + _sign_agent_package(opts.package, **in_args) + + elif opts.subparser_name == 'create_cert': + _create_cert(name=opts.name, **user_type) + except auth.AuthError as e: + _log.error(e.message) except AgentPackageError as e: print(e) diff --git a/volttron/platform/parameters.py b/volttron/platform/parameters.py index d7f0dead66..8adb94ebb0 100644 --- a/volttron/platform/parameters.py +++ b/volttron/platform/parameters.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from dataclasses import dataclass @@ -43,4 +29,4 @@ class Parameters(object): """ Base class for use by Authentication and Authorization parameters. """ - pass \ No newline at end of file + pass diff --git a/volttron/platform/resmon.py b/volttron/platform/resmon.py index fca3be8585..c26ca2ece0 100644 --- a/volttron/platform/resmon.py +++ b/volttron/platform/resmon.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -154,7 +140,7 @@ def get_static_resources(self, query_items=None): The returned dictionary contains the requested items that are available and their associated values and/or limits. - + Examples of static resources: architecture kernel version @@ -179,7 +165,7 @@ def get_static_resources(self, query_items=None): def check_hard_resources(self, contract): '''Test contract against hard resources and return failed terms. - + contract should be a dictionary of terms and conditions that are being requested. If all terms can be met, None is returned. Otherwise, a dictionary is returned with the terms that failed @@ -211,4 +197,3 @@ def check_hard_resources(self, contract): # ''' # execenv = ExecutionEnvironment() # return execenv, None - diff --git a/volttron/platform/scheduling.py b/volttron/platform/scheduling.py index 625da649e7..33b23190d6 100644 --- a/volttron/platform/scheduling.py +++ b/volttron/platform/scheduling.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """Schedule generators.""" diff --git a/volttron/platform/store.py b/volttron/platform/store.py index 95a2580abb..2417af35bd 100644 --- a/volttron/platform/store.py +++ b/volttron/platform/store.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -44,8 +30,8 @@ import errno from csv import DictReader from io import StringIO - import gevent +from deprecated import deprecated from volttron.platform import jsonapi from gevent.lock import Semaphore @@ -54,7 +40,7 @@ from volttron.platform.agent.utils import parse_json_config from volttron.platform.vip.agent import errors from volttron.platform.jsonrpc import RemoteError, MethodNotFound -from volttron.platform.agent.utils import parse_timestamp_string, format_timestamp, get_aware_utc_now +from volttron.platform.agent.utils import format_timestamp, get_aware_utc_now from volttron.platform.storeutils import check_for_recursion, strip_config_name, store_ext from .vip.agent import Agent, Core, RPC @@ -162,19 +148,50 @@ def _onstart(self, sender, **kwargs): @RPC.export @RPC.allow('edit_config_store') - def manage_store(self, identity, config_name, raw_contents, config_type="raw"): + @deprecated(reason="Use set_config") + def manage_store(self, identity, config_name, raw_contents, config_type="raw", trigger_callback=True, + send_update=True): + """ + This method is deprecated and will be removed in VOLTTRON 10. Please use set_config instead + """ + contents = process_raw_config(raw_contents, config_type) + self._add_config_to_store(identity, config_name, raw_contents, contents, config_type, + trigger_callback=trigger_callback, send_update=send_update) + + @RPC.export + @RPC.allow('edit_config_store') + def set_config(self, identity, config_name, raw_contents, config_type="raw", trigger_callback=True, + send_update=True): contents = process_raw_config(raw_contents, config_type) self._add_config_to_store(identity, config_name, raw_contents, contents, config_type, - trigger_callback=True) + trigger_callback=trigger_callback, send_update=send_update) @RPC.export @RPC.allow('edit_config_store') - def manage_delete_config(self, identity, config_name): - self.delete(identity, config_name, trigger_callback=True) + @deprecated(reason="Use delete_config") + def manage_delete_config(self, identity, config_name, trigger_callback=True, send_update=True): + """ + This method is deprecated and will be removed in VOLTTRON 10. Please use delete_config instead + """ + self.delete(identity, config_name, trigger_callback=trigger_callback, send_update=send_update) + + @RPC.export + @RPC.allow('edit_config_store') + def delete_config(self, identity, config_name, trigger_callback=True, send_update=True): + self.delete(identity, config_name, trigger_callback=trigger_callback, send_update=send_update) @RPC.export @RPC.allow('edit_config_store') + @deprecated(reason="Use delete_store") def manage_delete_store(self, identity): + """ + This method is deprecated and will be removed in VOLTTRON 10. Please use delete_store instead + """ + self.delete_store(identity) + + @RPC.export + @RPC.allow('edit_config_store') + def delete_store(self, identity): agent_store = self.store.get(identity) if agent_store is None: return @@ -211,19 +228,43 @@ def manage_delete_store(self, identity): self.store.pop(identity, None) @RPC.export + @deprecated(reason="Use list_configs") def manage_list_configs(self, identity): + """ + This method is deprecated and will be removed in VOLTTRON 10. Use list_configs instead + """ + return self.list_configs(identity) + + @RPC.export + def list_configs(self, identity): result = list(self.store.get(identity, {}).get("store", {}).keys()) result.sort() return result @RPC.export + @deprecated(reason="Use list_stores") def manage_list_stores(self): + """ + This method is deprecated and will be removed in VOLTTRON 10. Use list_stores instead + """ + return self.list_stores() + + @RPC.export + def list_stores(self): result = list(self.store.keys()) result.sort() return result @RPC.export + @deprecated(reason="Use get_config") def manage_get(self, identity, config_name, raw=True): + """ + This method is deprecated and will be removed in VOLTTRON 10. Use get_config instead + """ + return self.get_config(identity, config_name, raw) + + @RPC.export + def get_config(self, identity, config_name, raw=True): agent_store = self.store.get(identity) if agent_store is None: raise KeyError('No configuration file "{}" for VIP IDENTIY {}'.format(config_name, identity)) @@ -246,7 +287,15 @@ def manage_get(self, identity, config_name, raw=True): return agent_configs[real_config_name] @RPC.export + @deprecated(reason="Use get_metadata") def manage_get_metadata(self, identity, config_name): + """ + This method is deprecated and will be removed in VOLTTRON 10. Please use get_metadata instead + """ + return self.get_metadata(identity, config_name) + + @RPC.export + def get_metadata(self, identity, config_name): agent_store = self.store.get(identity) if agent_store is None: raise KeyError('No configuration file "{}" for VIP IDENTIY {}'.format(config_name, identity)) @@ -264,27 +313,21 @@ def manage_get_metadata(self, identity, config_name): real_config = agent_disk_store[real_config_name] - #Set modified to none if we predate the modified flag. + # Set modified to none if we predate the modified flag. if real_config.get("modified") is None: real_config["modified"] = None return real_config + @RPC.allow('edit_config_store') @RPC.export - def set_config(self, config_name, contents, trigger_callback=False, send_update=True): - identity = self.vip.rpc.context.vip_message.peer - self.store_config(identity, config_name, contents, trigger_callback=trigger_callback, send_update=send_update) - - - @RPC.export - def get_configs(self): + def initialize_configs(self, identity): """ Called by an Agent at startup to trigger initial configuration state push. """ - identity = self.vip.rpc.context.vip_message.peer - #We need to create store and lock if it doesn't exist in case someone + # We need to create store and lock if it doesn't exist in case someone # tries to add a configuration while we are sending the initial state. agent_store = self.store.get(identity) @@ -321,13 +364,6 @@ def get_configs(self): if not agent_disk_store: self.store.pop(identity, None) - @RPC.export - def delete_config(self, config_name, trigger_callback=False, send_update=True): - """Called by an Agent to delete a configuration.""" - identity = self.vip.rpc.context.vip_message.peer - self.delete(identity, config_name, trigger_callback=trigger_callback, - send_update=send_update) - # Helper method to allow the local services to delete configs before message # bus in online. def delete(self, identity, config_name, trigger_callback=False, send_update=True): diff --git a/volttron/platform/storeutils.py b/volttron/platform/storeutils.py index ca4be85255..01da7a0acf 100644 --- a/volttron/platform/storeutils.py +++ b/volttron/platform/storeutils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/upgrade/move_sqlite_files.py b/volttron/platform/upgrade/move_sqlite_files.py index ac43b0ef66..292ba00c89 100644 --- a/volttron/platform/upgrade/move_sqlite_files.py +++ b/volttron/platform/upgrade/move_sqlite_files.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys import shutil diff --git a/volttron/platform/upgrade/rename_config_for_agent_isolation.py b/volttron/platform/upgrade/rename_config_for_agent_isolation.py index 8ec9c18649..0892e1a4ba 100644 --- a/volttron/platform/upgrade/rename_config_for_agent_isolation.py +++ b/volttron/platform/upgrade/rename_config_for_agent_isolation.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os.path import sys diff --git a/volttron/platform/upgrade/update_auth_file.py b/volttron/platform/upgrade/update_auth_file.py index a9caea7266..517ad641eb 100644 --- a/volttron/platform/upgrade/update_auth_file.py +++ b/volttron/platform/upgrade/update_auth_file.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys import shutil diff --git a/volttron/platform/upgrade/upgrade_volttron.py b/volttron/platform/upgrade/upgrade_volttron.py index a60e7c283f..fdcbf4bf80 100644 --- a/volttron/platform/upgrade/upgrade_volttron.py +++ b/volttron/platform/upgrade/upgrade_volttron.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys diff --git a/volttron/platform/vip/__init__.py b/volttron/platform/vip/__init__.py index 07c284d6ed..dc5d9ef286 100644 --- a/volttron/platform/vip/__init__.py +++ b/volttron/platform/vip/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#green -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """VIP - VOLTTRON™ Interconnect Protocol implementation diff --git a/volttron/platform/vip/agent/__init__.py b/volttron/platform/vip/agent/__init__.py index 9a07f18f13..1ba524d70e 100644 --- a/volttron/platform/vip/agent/__init__.py +++ b/volttron/platform/vip/agent/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -91,7 +77,7 @@ def __init__(self, identity=None, address=None, context=None, if volttron_home is None: volttron_home = os.path.abspath(platform.get_home()) - + try: self._version = version @@ -111,7 +97,7 @@ def __init__(self, identity=None, address=None, context=None, reconnect_interval=reconnect_interval, version=version, volttron_central_address=volttron_central_address, - volttron_central_instance_name=volttron_central_instance_name, + volttron_central_instance_name=volttron_central_instance_name, enable_auth=enable_auth) else: _log.debug("Creating ZMQ Core {}".format(identity)) @@ -121,7 +107,7 @@ def __init__(self, identity=None, address=None, context=None, instance_name=instance_name, volttron_home=volttron_home, agent_uuid=agent_uuid, reconnect_interval=reconnect_interval, - version=version, enable_fncs=enable_fncs, + version=version, enable_fncs=enable_fncs, enable_auth=enable_auth) self.vip = Agent.Subsystems(self, self.core, heartbeat_autostart, heartbeat_period, enable_store, enable_web, diff --git a/volttron/platform/vip/agent/compat.py b/volttron/platform/vip/agent/compat.py index 4d7c2af8b5..76519d71fe 100644 --- a/volttron/platform/vip/agent/compat.py +++ b/volttron/platform/vip/agent/compat.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/agent/connection.py b/volttron/platform/vip/agent/connection.py index aa87675a31..eb4499c82d 100644 --- a/volttron/platform/vip/agent/connection.py +++ b/volttron/platform/vip/agent/connection.py @@ -1,44 +1,29 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging import urllib.parse -import uuid import os import gevent @@ -226,5 +211,5 @@ def notify(self, method, *args, **kwargs): def kill(self, *args, **kwargs): if self._greenlet is not None: self._greenlet.kill(*args, **kwargs) - del(self._greenlet) + del self._greenlet self._greenlet = None diff --git a/volttron/platform/vip/agent/core.py b/volttron/platform/vip/agent/core.py index 3cbd38a5ae..36acb7eaab 100644 --- a/volttron/platform/vip/agent/core.py +++ b/volttron/platform/vip/agent/core.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import heapq @@ -55,26 +41,29 @@ import gevent.event import grequests from gevent.queue import Queue -from volttron.platform.keystore import KnownHostsStore from zmq import green as zmq -from zmq.green import ZMQError, EAGAIN, ENOTSOCK +from zmq.green import EAGAIN, ENOTSOCK, ZMQError from zmq.utils.monitor import recv_monitor_message -from volttron.platform import get_address, get_home, jsonapi -from volttron.platform import is_rabbitmq_available +from volttron.platform import get_address, get_home, is_rabbitmq_available, jsonapi from volttron.platform.agent import utils -from volttron.platform.agent.utils import get_fq_identity, load_platform_config, get_platform_instance_name, is_auth_enabled +from volttron.platform.agent.utils import (get_fq_identity, + get_platform_instance_name, + is_auth_enabled, + load_platform_config) +from volttron.platform.keystore import KnownHostsStore from volttron.platform.messaging.health import STATUS_BAD from volttron.utils.rmq_config_params import RMQConfig from volttron.utils.rmq_mgmt import RabbitMQMgmt -from .decorators import annotate, annotations, dualmethod -from .dispatch import Signal -from .errors import VIPError + +from .... import platform from .. import router from ..rmq_connection import RMQConnection from ..socket import Message from ..zmq_connection import ZMQConnection -from .... import platform +from .decorators import annotate, annotations, dualmethod +from .dispatch import Signal +from .errors import VIPError if is_rabbitmq_available(): import pika @@ -160,7 +149,7 @@ def findsignal(obj, owner, name): signal = owner for part in parts: signal = getattr(signal, part) - assert isinstance(signal, Signal), 'bad signal name %r' % (name,) + assert isinstance(signal, Signal), 'bad signal name %r' % (name, ) return signal @@ -190,8 +179,8 @@ def __init__(self, owner): prev_int_signal = gevent.signal.getsignal(signal.SIGINT) # To avoid a child agent handler overwriting the parent agent handler if prev_int_signal in [None, signal.SIG_IGN, signal.SIG_DFL]: - self.oninterrupt = gevent.signal.signal(signal.SIGINT, - self._on_sigint_handler) + self.oninterrupt = gevent.signal.signal( + signal.SIGINT, self._on_sigint_handler) self._owner = owner def setup(self): @@ -206,9 +195,10 @@ def setup(self): def setup(member): # pylint: disable=redefined-outer-name periodics.extend( - periodic.get(member) for periodic in annotations( - member, list, 'core.periodics')) - for deadline, args, kwargs in annotations(member, list, 'core.schedule'): + periodic.get(member) + for periodic in annotations(member, list, 'core.periodics')) + for deadline, args, kwargs in annotations(member, list, + 'core.schedule'): self.schedule(deadline, member, *args, **kwargs) for name in annotations(member, set, 'core.signals'): findsignal(self, owner, name).connect(member, owner) @@ -397,8 +387,7 @@ def periodic(self, period, func, args=None, kwargs=None, wait=0): warnings.warn( 'Use of the periodic() method is deprecated in favor of the ' 'schedule() method with the periodic() generator. This ' - 'method will be removed in a future version.', - DeprecationWarning) + 'method will be removed in a future version.', DeprecationWarning) greenlet = Periodic(period, args, kwargs, wait).get(func) self.spawned_greenlets.add(greenlet) greenlet.start() @@ -415,6 +404,7 @@ def periodic(cls, period, args=None, kwargs=None, wait=0): # pylint: disable=no @classmethod def receiver(cls, signal): + def decorate(method): annotate(method, set, 'core.signals', signal) return method @@ -438,11 +428,13 @@ def get_tie_breaker(self): def _schedule_callback(self, deadline, callback): deadline = utils.get_utc_seconds_from_epoch(deadline) - heapq.heappush(self._schedule, (deadline, self.get_tie_breaker(), callback)) + heapq.heappush(self._schedule, + (deadline, self.get_tie_breaker(), callback)) if self._schedule_event: self._schedule_event.set() def _schedule_iter(self, it, event): + def wrapper(): if event.canceled: event.finished = True @@ -485,11 +477,20 @@ class Core(BasicCore): # to false to keep from blocking. AuthService does this. delay_running_event_set = True - def __init__(self, owner, address=None, identity=None, context=None, - publickey=None, secretkey=None, serverkey=None, + def __init__(self, + owner, + address=None, + identity=None, + context=None, + publickey=None, + secretkey=None, + serverkey=None, volttron_home=os.path.abspath(platform.get_home()), - agent_uuid=None, reconnect_interval=None, - version='0.1', instance_name=None, messagebus=None): + agent_uuid=None, + reconnect_interval=None, + version='0.1', + instance_name=None, + messagebus=None): self.volttron_home = volttron_home # These signals need to exist before calling super().__init__() @@ -500,7 +501,8 @@ def __init__(self, owner, address=None, identity=None, context=None, self.configuration = Signal() super(Core, self).__init__(owner) self.address = address if address is not None else get_address() - self.identity = str(identity) if identity is not None else str(uuid.uuid4()) + self.identity = str(identity) if identity is not None else str( + uuid.uuid4()) self.agent_uuid = agent_uuid self.publickey = publickey self.secretkey = secretkey @@ -530,8 +532,7 @@ def set_connected(self, value): self.__connected = value connected = property(fget=lambda self: self.get_connected(), - fset=lambda self, v: self.set_connected(v) - ) + fset=lambda self, v: self.set_connected(v)) def stop(self, timeout=None, platform_shutdown=False): # Send message to router that this agent is stopping @@ -584,7 +585,9 @@ def handle_error(self, message): error = VIPError.from_errno(*args) self.onviperror.send(self, error=error, message=message) - def create_event_handlers(self, state, hello_response_event, running_event): + def create_event_handlers(self, state, hello_response_event, + running_event): + def connection_failed_check(): # If we don't have a verified connection after 10.0 seconds # shut down. @@ -592,13 +595,13 @@ def connection_failed_check(): return _log.error("No response to hello message after 10 seconds.") _log.error("Type of message bus used {}".format(self.messagebus)) - _log.error("A common reason for this is a conflicting VIP IDENTITY.") + _log.error( + "A common reason for this is a conflicting VIP IDENTITY.") _log.error("Another common reason is not having an auth entry on" "the target instance.") _log.error("Shutting down agent.") _log.error("Possible conflicting identity is: {}".format( - self.identity - )) + self.identity)) self.stop(timeout=10.0) @@ -608,15 +611,16 @@ def hello(): state.ident = ident = 'connect.hello.%d' % state.count state.count += 1 self.spawn(connection_failed_check) - message = Message(peer='', subsystem='hello', - id=ident, args=['hello']) + message = Message(peer='', + subsystem='hello', + id=ident, + args=['hello']) self.connection.send_vip_object(message) - def hello_response(sender, version='', - router='', identity=''): + def hello_response(sender, version='', router='', identity=''): _log.info("Connected to platform: " "router: {} version: {} identity: {}".format( - router, version, identity)) + router, version, identity)) _log.debug("Running onstart methods.") hello_response_event.set() self.onstart.sendby(self.link_receiver, self) @@ -632,36 +636,50 @@ class ZMQCore(Core): Concrete Core class for ZeroMQ message bus """ - def __init__(self, owner, address=None, identity=None, context=None, - publickey=None, secretkey=None, serverkey=None, + def __init__(self, + owner, + address=None, + identity=None, + context=None, + publickey=None, + secretkey=None, + serverkey=None, volttron_home=os.path.abspath(platform.get_home()), - agent_uuid=None, reconnect_interval=None, - version='0.1', enable_fncs=False, - instance_name=None, messagebus='zmq', enable_auth=True): - super(ZMQCore, self).__init__(owner, address=address, identity=identity, - context=context, publickey=publickey, secretkey=secretkey, - serverkey=serverkey, volttron_home=volttron_home, - agent_uuid=agent_uuid, reconnect_interval=reconnect_interval, + agent_uuid=None, + reconnect_interval=None, + version='0.1', + enable_fncs=False, + instance_name=None, + messagebus='zmq', + enable_auth=True): + super(ZMQCore, self).__init__(owner, + address=address, + identity=identity, + context=context, + publickey=publickey, + secretkey=secretkey, + serverkey=serverkey, + volttron_home=volttron_home, + agent_uuid=agent_uuid, + reconnect_interval=reconnect_interval, version=version, - instance_name=instance_name, messagebus=messagebus) + instance_name=instance_name, + messagebus=messagebus) self.context = context or zmq.Context.instance() self._fncs_enabled = enable_fncs self.messagebus = messagebus self.enable_auth = enable_auth zmq_auth = None - if self.enable_auth: + if self.enable_auth: from volttron.platform.auth.auth_protocols.auth_zmq import ZMQClientAuthentication, ZMQClientParameters zmq_auth = ZMQClientAuthentication( - ZMQClientParameters( - address=self.address, - identity=self.identity, - agent_uuid=self.agent_uuid, - publickey=self.publickey, - secretkey=self.secretkey, - serverkey=self.serverkey, - volttron_home=self.volttron_home - ) - ) + ZMQClientParameters(address=self.address, + identity=self.identity, + agent_uuid=self.agent_uuid, + publickey=self.publickey, + secretkey=self.secretkey, + serverkey=self.serverkey, + volttron_home=self.volttron_home)) self.address = zmq_auth.create_authentication_parameters() self.publickey = zmq_auth.publickey self.secretkey = zmq_auth.secretkey @@ -681,7 +699,8 @@ def set_connected(self, value): def loop(self, running_event): # pre-setup # self.context.set(zmq.MAX_SOCKETS, 30690) - _log.info(f"CORE address:{self.address}") + _log.info( + f"Identity: {self.identity} connecting to address:{self.address}") self.connection = ZMQConnection(self.address, self.identity, self.instance_name, @@ -713,7 +732,7 @@ def monitor(): # get_monitor_socket() so we can use green sockets with # regular contexts (get_monitor_socket() uses # self.context.socket()). - addr = 'inproc://monitor.v-%d' % (id(self.socket),) + addr = 'inproc://monitor.v-%d' % (id(self.socket), ) sock = None if self.socket is not None: try: @@ -755,7 +774,8 @@ def monitor(): if self.socket is not None: self.socket.monitor(None, 0) except Exception as exc: - _log.debug("Error in closing the socket: {}".format(exc)) + _log.debug( + "Error in closing the socket: {}".format(exc)) self.onconnected.connect(hello_response) self.ondisconnected.connect(close_socket) @@ -789,14 +809,15 @@ def vip_loop(): # subsystem, message.id, len(message.args), message.args[0])) # Handle hellos sent by CONNECTED event - if (str(subsystem) == 'hello' and - message.id == state.ident and - len(message.args) > 3 and - message.args[0] == 'welcome'): + if (str(subsystem) == 'hello' and message.id == state.ident + and len(message.args) > 3 + and message.args[0] == 'welcome'): version, server, identity = message.args[1:4] self.connected = True - self.onconnected.send(self, version=version, - router=server, identity=identity) + self.onconnected.send(self, + version=version, + router=server, + identity=identity) continue try: @@ -829,13 +850,10 @@ def vip_loop(): self.socket = None yield - - def connect_remote_platform( - self, - address: str, - serverkey: typing.Optional[str]=None, - agent_class=None - ): + def connect_remote_platform(self, + address: str, + serverkey: typing.Optional[str] = None, + agent_class=None): """ Agent attempts to connect to a remote platform to exchange data. @@ -861,8 +879,8 @@ def connect_remote_platform( function. """ - from volttron.platform.vip.agent.utils import build_agent from volttron.platform.vip.agent import Agent + from volttron.platform.vip.agent.utils import build_agent if agent_class is None: agent_class = Agent @@ -879,8 +897,7 @@ def connect_remote_platform( if not temp_serverkey: _log.info( "Destination serverkey not found in known hosts file, " - "using config" - ) + "using config") destination_serverkey = serverkey elif not serverkey: destination_serverkey = temp_serverkey @@ -889,13 +906,10 @@ def connect_remote_platform( raise ValueError( "server_key passed and known hosts serverkey do not " "" - "match!" - ) + "match!") destination_serverkey = serverkey - _log.debug( - "Connecting using: %s", get_fq_identity(self.identity) - ) + _log.debug("Connecting using: %s", get_fq_identity(self.identity)) value = build_agent( agent_class=agent_class, @@ -907,8 +921,7 @@ def connect_remote_platform( address=address, ) elif parsed_address.scheme in ("https", "http"): - from volttron.platform.web import DiscoveryInfo - from volttron.platform.web import DiscoveryError + from volttron.platform.web import DiscoveryError, DiscoveryInfo try: # TODO: Use known host instead of looking up for discovery @@ -928,14 +941,12 @@ def connect_remote_platform( # version of the identity because there will be conflicts if # volttron central has more than one platform.agent connecting if not info.vip_address: - err = ( - "Discovery from {} did not return vip_address".format(address) - ) + err = ("Discovery from {} did not return vip_address". + format(address)) raise ValueError(err) if self.enable_auth and not info.serverkey: - err = ( - "Discovery from {} did not return serverkey".format(address) - ) + err = ("Discovery from {} did not return serverkey".format( + address)) raise ValueError(err) _log.debug( "Connecting using: %s", @@ -963,8 +974,7 @@ def connect_remote_platform( else: raise ValueError( "Invalid configuration found the address: {} has an invalid " - "scheme".format(address) - ) + "scheme".format(address)) return value @@ -990,18 +1000,36 @@ class RMQCore(Core): Concrete Core class for RabbitMQ message bus """ - def __init__(self, owner, address=None, identity=None, context=None, - publickey=None, secretkey=None, serverkey=None, + def __init__(self, + owner, + address=None, + identity=None, + context=None, + publickey=None, + secretkey=None, + serverkey=None, volttron_home=os.path.abspath(platform.get_home()), - agent_uuid=None, reconnect_interval=None, - version='0.1', instance_name=None, messagebus='rmq', + agent_uuid=None, + reconnect_interval=None, + version='0.1', + instance_name=None, + messagebus='rmq', volttron_central_address=None, - volttron_central_instance_name=None, enable_auth=True): - super(RMQCore, self).__init__(owner, address=address, identity=identity, - context=context, publickey=publickey, secretkey=secretkey, - serverkey=serverkey, volttron_home=volttron_home, - agent_uuid=agent_uuid, reconnect_interval=reconnect_interval, - version=version, instance_name=instance_name, messagebus=messagebus) + volttron_central_instance_name=None, + enable_auth=True): + super(RMQCore, self).__init__(owner, + address=address, + identity=identity, + context=context, + publickey=publickey, + secretkey=secretkey, + serverkey=serverkey, + volttron_home=volttron_home, + agent_uuid=agent_uuid, + reconnect_interval=reconnect_interval, + version=version, + instance_name=instance_name, + messagebus=messagebus) self.volttron_central_address = volttron_central_address self.enable_auth = enable_auth self.remote_certs_dir = None @@ -1033,16 +1061,13 @@ def __init__(self, owner, address=None, identity=None, context=None, if self.publickey is None or self.secretkey is None and self.enable_auth: from volttron.platform.auth.auth_protocols.auth_zmq import ZMQClientAuthentication, ZMQClientParameters zmq_auth = ZMQClientAuthentication( - ZMQClientParameters( - address=self.address, - identity=self.identity, - agent_uuid=self.agent_uuid, - publickey=self.publickey, - secretkey=self.secretkey, - serverkey=self.serverkey, - volttron_home=self.volttron_home - ) - ) + ZMQClientParameters(address=self.address, + identity=self.identity, + agent_uuid=self.agent_uuid, + publickey=self.publickey, + secretkey=self.secretkey, + serverkey=self.serverkey, + volttron_home=self.volttron_home)) zmq_auth._set_public_and_secret_keys() self.publickey = zmq_auth.publickey @@ -1058,6 +1083,7 @@ def set_connected(self, value): super(RMQCore, self).set_connected(value) connected = property(get_connected, set_connected) + # Replace with RMQConnectionParam (wraps around pika.Connection) # Passed into RMQClientConnection() def _build_connection_parameters(self): @@ -1072,24 +1098,28 @@ def _build_connection_parameters(self): try: if self.instance_name == get_platform_instance_name(): - param = connection_api.build_agent_connection(self.identity, self.instance_name) + param = connection_api.build_agent_connection( + self.identity, self.instance_name) else: param = connection_api.build_remote_connection_param() except AttributeError: - _log.error("RabbitMQ broker may not be running. Restart the broker first") + _log.error( + "RabbitMQ broker may not be running. Restart the broker first" + ) param = None return param def loop(self, running_event): - if not isinstance(self.rmq_address, pika.ConnectionParameters): + if not isinstance(self.rmq_address, pika.ConnectionParameters): self.rmq_address = self._build_connection_parameters() # pre-setup - self.connection = RMQConnection(self.rmq_address, - self.identity, - self.instance_name, - reconnect_delay=self.rmq_mgmt.rmq_config.reconnect_delay(), - vc_url=self.volttron_central_address) + self.connection = RMQConnection( + self.rmq_address, + self.identity, + self.instance_name, + reconnect_delay=self.rmq_mgmt.rmq_config.reconnect_delay(), + vc_url=self.volttron_central_address) yield # pre-start @@ -1115,8 +1145,8 @@ def connect_callback(): bindings = self.rmq_mgmt.get_bindings('volttron') except AttributeError: bindings = None - router_user = router_key = "{inst}.{ident}".format(inst=self.instance_name, - ident='router') + router_user = router_key = "{inst}.{ident}".format( + inst=self.instance_name, ident='router') if bindings: for binding in bindings: if binding['destination'] == router_user and \ @@ -1130,8 +1160,9 @@ def connect_callback(): if router_connected: hello() else: - _log.debug("Router not bound to RabbitMQ yet, waiting for 2 seconds before sending hello {}". - format(self.identity)) + _log.debug( + "Router not bound to RabbitMQ yet, waiting for 2 seconds before sending hello {}" + .format(self.identity)) self.spawn_later(2, hello) # Connect to RMQ broker. Register a callback to get notified when @@ -1158,21 +1189,23 @@ def vip_loop(): subsystem = message.subsystem if subsystem == 'hello': - if (subsystem == 'hello' and - message.id == state.ident and - len(message.args) > 3 and - message.args[0] == 'welcome'): + if (subsystem == 'hello' + and message.id == state.ident + and len(message.args) > 3 + and message.args[0] == 'welcome'): version, server, identity = message.args[1:4] self.connected = True - self.onconnected.send(self, version=version, + self.onconnected.send(self, + version=version, router=server, identity=identity) continue try: handle = self.subsystems[subsystem] except KeyError: - _log.error('peer %r requested unknown subsystem %r', - message.peer, subsystem) + _log.error( + 'peer %r requested unknown subsystem %r', + message.peer, subsystem) message.user = '' message.args = list(router._INVALID_SUBSYSTEM) message.args.append(message.subsystem) @@ -1193,13 +1226,10 @@ def vip_message_handler(self, message): # _log.debug("RMQ VIP Core {}".format(message)) self._event_queue.put(message) - - def connect_remote_platform( - self, - address, - serverkey=None, - agent_class=None - ): + def connect_remote_platform(self, + address, + serverkey=None, + agent_class=None): """ Agent attempts to connect to a remote platform to exchange data. @@ -1225,8 +1255,8 @@ def connect_remote_platform( function. """ - from volttron.platform.vip.agent.utils import build_agent from volttron.platform.vip.agent import Agent + from volttron.platform.vip.agent.utils import build_agent if agent_class is None: agent_class = Agent @@ -1237,15 +1267,16 @@ def connect_remote_platform( if parsed_address.scheme == "tcp": # ZMQ connection destination_serverkey = None - _log.debug(f"parsed address scheme is tcp. auth enabled = {self.enable_auth}") + _log.debug( + f"parsed address scheme is tcp. auth enabled = {self.enable_auth}" + ) if self.enable_auth: hosts = KnownHostsStore() temp_serverkey = hosts.serverkey(address) if not temp_serverkey: _log.info( "Destination serverkey not found in known hosts file, " - "using config" - ) + "using config") destination_serverkey = serverkey elif not serverkey: destination_serverkey = temp_serverkey @@ -1254,13 +1285,10 @@ def connect_remote_platform( raise ValueError( "server_key passed and known hosts serverkey do not " "" - "match!" - ) + "match!") destination_serverkey = serverkey - _log.debug( - "Connecting using: %s", get_fq_identity(self.identity) - ) + _log.debug("Connecting using: %s", get_fq_identity(self.identity)) value = build_agent( agent_class=agent_class, @@ -1272,9 +1300,8 @@ def connect_remote_platform( address=address, ) elif parsed_address.scheme in ("https", "http"): - from volttron.platform.web import DiscoveryInfo - from volttron.platform.web import DiscoveryError from volttron.platform.auth.auth_protocols.auth_rmq import RMQConnectionAPI + from volttron.platform.web import DiscoveryError, DiscoveryInfo try: # TODO: Use known host instead of looking up for discovery @@ -1294,28 +1321,22 @@ def connect_remote_platform( # Check if we already have the cert, if so use it # instead of requesting cert again remote_certs_dir = self.get_remote_certs_dir() - remote_cert_name = "{}.{}".format( - info.instance_name, fqid_local - ) - certfile = os.path.join( - remote_certs_dir, remote_cert_name + ".crt" - ) + remote_cert_name = "{}.{}".format(info.instance_name, + fqid_local) + certfile = os.path.join(remote_certs_dir, + remote_cert_name + ".crt") if os.path.exists(certfile): response = certfile else: - response = self.request_cert( - address, fqid_local, info - ) + response = self.request_cert(address, fqid_local, info) if response is None: _log.error("there was no response from the server") value = None elif isinstance(response, tuple): if response[0] == "PENDING": - _log.info( - "Waiting for administrator to accept a " - "CSR request." - ) + _log.info("Waiting for administrator to accept a " + "CSR request.") value = None # elif isinstance(response, dict): # response @@ -1329,14 +1350,13 @@ def connect_remote_platform( # pass to the build_remote_connection_params # for a successful - remote_rmq_user = get_fq_identity( - fqid_local, info.instance_name - ) - _log.debug( - "REMOTE RMQ USER IS: %s", remote_rmq_user - ) - connection_api = RMQConnectionAPI(rmq_user=remote_rmq_user, - url_address=info.rmq_address, ssl_auth=True) + remote_rmq_user = get_fq_identity(fqid_local, + info.instance_name) + _log.debug("REMOTE RMQ USER IS: %s", remote_rmq_user) + connection_api = RMQConnectionAPI( + rmq_user=remote_rmq_user, + url_address=info.rmq_address, + ssl_auth=True) remote_rmq_address = connection_api.build_remote_connection_param( cert_dir=self.get_remote_certs_dir()) @@ -1351,9 +1371,7 @@ def connect_remote_platform( agent_class=agent_class, ) else: - raise ValueError( - "Unknown path through discovery process!" - ) + raise ValueError("Unknown path through discovery process!") except DiscoveryError: _log.error( @@ -1366,17 +1384,12 @@ def connect_remote_platform( else: raise ValueError( "Invalid configuration found the address: {} has an invalid " - "scheme".format(address) - ) + "scheme".format(address)) return value - def request_cert( - self, - csr_server, - fully_qualified_local_identity, - discovery_info - ): + def request_cert(self, csr_server, fully_qualified_local_identity, + discovery_info): """ Get a signed csr from the csr_server endpoint @@ -1391,25 +1404,22 @@ def request_cert( if not config.is_ssl: raise ValueError( - "Only can create csr for rabbitmq based platform in ssl mode." - ) + "Only can create csr for rabbitmq based platform in ssl mode.") # info = discovery_info # if info is None: # info = DiscoveryInfo.request_discovery_info(csr_server) csr_request = self.rmq_mgmt.certs.create_csr( - fully_qualified_local_identity, discovery_info.instance_name - ) + fully_qualified_local_identity, discovery_info.instance_name) # The csr request requires the fully qualified identity that is # going to be connected to the external instance. # # The remote instance id is the instance name of the remote platform # concatenated with the identity of the local fully quallified # identity. - remote_cert_name = "{}.{}".format( - discovery_info.instance_name, fully_qualified_local_identity - ) + remote_cert_name = "{}.{}".format(discovery_info.instance_name, + fully_qualified_local_identity) remote_ca_name = discovery_info.instance_name + "_ca" # if certs.cert_exists(remote_cert_name, True): @@ -1452,8 +1462,7 @@ def request_cert( discovery_info.rmq_ca_cert.encode("utf-8"), ) os.environ["REQUESTS_CA_BUNDLE"] = os.path.join( - remote_certs_dir, "requests_ca_bundle" - ) + remote_certs_dir, "requests_ca_bundle") _log.debug( "Set os.environ requests ca bundle to %s", os.environ["REQUESTS_CA_BUNDLE"], @@ -1470,15 +1479,13 @@ def request_cert( "Shutting down", ) self._owner.vip.health.set_status(status.status, status.context) - self._owner.vip.health.send_alert( - self.identity + "_DENIED", status - ) + self._owner.vip.health.send_alert(self.identity + "_DENIED", + status) self.stop() return None elif status == "ERROR": err = "Error retrieving certificate from {}\n".format( - config.hostname - ) + config.hostname) err += "{}".format(message) raise ValueError(err) else: # No resposne @@ -1492,9 +1499,7 @@ def request_cert( def get_remote_certs_dir(self): if not self.remote_certs_dir: - install_dir = os.path.join( - get_home(), "agents", self.agent_uuid - ) + install_dir = os.path.join(get_home(), "agents", self.agent_uuid) files = os.listdir(install_dir) for f in files: agent_dir = os.path.join(install_dir, f) diff --git a/volttron/platform/vip/agent/decorators.py b/volttron/platform/vip/agent/decorators.py index 28e2d969b8..e39c723c07 100644 --- a/volttron/platform/vip/agent/decorators.py +++ b/volttron/platform/vip/agent/decorators.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/agent/dispatch.py b/volttron/platform/vip/agent/dispatch.py index c6e5639244..3d1ea9f5a8 100644 --- a/volttron/platform/vip/agent/dispatch.py +++ b/volttron/platform/vip/agent/dispatch.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -65,7 +51,7 @@ def send(self, sender, **kwargs): def sendby(self, executor, sender, **kwargs): return [executor(receiver, sender, **kwargs) for receiver in self._receivers] - + def receiver(self, func): self.connect(func) return func diff --git a/volttron/platform/vip/agent/errors.py b/volttron/platform/vip/agent/errors.py index 4a1d9912e6..1f48b9fed9 100644 --- a/volttron/platform/vip/agent/errors.py +++ b/volttron/platform/vip/agent/errors.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/agent/example.py b/volttron/platform/vip/agent/example.py index 297d14a8be..337c881807 100644 --- a/volttron/platform/vip/agent/example.py +++ b/volttron/platform/vip/agent/example.py @@ -1,9 +1,9 @@ - - - import gevent -from volttron.platform.vip.agent import * +from volttron.platform.vip.agent import Agent +from volttron.platform.vip.agent.core import Core +from volttron.platform.vip.agent.errors import Unreachable +from volttron.platform.vip.agent.subsystems import RPC from volttron.platform.scheduling import periodic diff --git a/volttron/platform/vip/agent/results.py b/volttron/platform/vip/agent/results.py index f1740a5c1e..45bd5ff310 100644 --- a/volttron/platform/vip/agent/results.py +++ b/volttron/platform/vip/agent/results.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/agent/subsystems/__init__.py b/volttron/platform/vip/agent/subsystems/__init__.py index b9a25954c0..dc51e77890 100644 --- a/volttron/platform/vip/agent/subsystems/__init__.py +++ b/volttron/platform/vip/agent/subsystems/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -53,4 +39,3 @@ __all__ = ['PeerList', 'Ping', 'RPC', 'Hello', 'PubSub', 'RMQPubSub','Channel', 'Heartbeat', 'Health', 'ConfigStore', 'Auth', 'FNCS'] - diff --git a/volttron/platform/vip/agent/subsystems/auth.py b/volttron/platform/vip/agent/subsystems/auth.py index f4df2d41b1..8ba4e2dcba 100644 --- a/volttron/platform/vip/agent/subsystems/auth.py +++ b/volttron/platform/vip/agent/subsystems/auth.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/volttron/platform/vip/agent/subsystems/base.py b/volttron/platform/vip/agent/subsystems/base.py index 1d4c6ee172..4c346fff54 100644 --- a/volttron/platform/vip/agent/subsystems/base.py +++ b/volttron/platform/vip/agent/subsystems/base.py @@ -1,42 +1,27 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} class SubsystemBase: pass - diff --git a/volttron/platform/vip/agent/subsystems/channel.py b/volttron/platform/vip/agent/subsystems/channel.py index 36f903753f..1d4cb090b1 100644 --- a/volttron/platform/vip/agent/subsystems/channel.py +++ b/volttron/platform/vip/agent/subsystems/channel.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -134,7 +120,7 @@ def _handle_subsystem(self, message): except TypeError: _log.debug("Serializing frames necessary") frames = serialize_frames(frames) - + _log.debug(f"frames are before send_multipart: {frames}") self.socket.send_multipart(frames, copy=False) diff --git a/volttron/platform/vip/agent/subsystems/configstore.py b/volttron/platform/vip/agent/subsystems/configstore.py index 4ba08ed72c..8aeec97ff9 100644 --- a/volttron/platform/vip/agent/subsystems/configstore.py +++ b/volttron/platform/vip/agent/subsystems/configstore.py @@ -1,52 +1,40 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging import traceback import os import weakref import fnmatch -import greenlet import inspect from .base import SubsystemBase from volttron.platform.storeutils import list_unique_links, check_for_config_link from volttron.platform.vip.agent import errors from volttron.platform.agent.known_identities import CONFIGURATION_STORE +from volttron.platform import jsonapi +from volttron.platform.agent.utils import is_auth_enabled + from collections import defaultdict from copy import deepcopy @@ -61,14 +49,15 @@ _log = logging.getLogger(__name__) -VALID_ACTIONS = set(["NEW", "UPDATE", "DELETE"]) +VALID_ACTIONS = ("NEW", "UPDATE", "DELETE") + class ConfigStore(SubsystemBase): def __init__(self, owner, core, rpc): self._core = weakref.ref(core) self._rpc = weakref.ref(rpc) - self._ref_map = {} #For triggering callbacks. + self._ref_map = {} # For triggering callbacks. self._reverse_ref_map = defaultdict(set) # For triggering callbacks. self._store = {} self._default_store = {} @@ -80,6 +69,7 @@ def __init__(self, owner, core, rpc): self._initial_callbacks_called = False self._process_callbacks_code_object = self._process_callbacks.__code__ + self.vip_identity = self._core().identity def sub_factory(): return defaultdict(set) @@ -89,6 +79,9 @@ def sub_factory(): def onsetup(sender, **kwargs): rpc.export(self._update_config, 'config.update') rpc.export(self._initial_update, 'config.initial_update') + if is_auth_enabled(): + rpc.allow('config.update', 'sync_agent_config') + rpc.allow('config.initial_update', 'sync_agent_config') core.onsetup.connect(onsetup, self) core.configuration.connect(self._onconfig, self) @@ -96,7 +89,7 @@ def onsetup(sender, **kwargs): def _onconfig(self, sender, **kwargs): if not self._initialized: try: - self._rpc().call(CONFIGURATION_STORE, "get_configs").get() + self._rpc().call(CONFIGURATION_STORE, "initialize_configs", self.vip_identity).get() except errors.Unreachable as e: _log.error("Connected platform does not support the Configuration Store feature.") return @@ -104,7 +97,6 @@ def _onconfig(self, sender, **kwargs): _log.error("Error retrieving agent configurations: {}".format(e)) return - affected_configs = {} for config_name in self._store: affected_configs[config_name] = "NEW" @@ -126,9 +118,8 @@ def _update_refs(self, config_name, contents): self._add_refs(config_name, contents) - def _delete_refs(self, config_name): - #Delete refs if they exist. + # Delete refs if they exist. old_refs = self._ref_map.pop(config_name, set()) for ref in old_refs: @@ -137,7 +128,6 @@ def _delete_refs(self, config_name): if not reverse_ref_set: del self._reverse_ref_map[ref] - def _initial_update(self, configs, reset_name_map=True): self._initialized = True self._store = {key.lower(): value for (key, value) in configs.items()} @@ -151,7 +141,6 @@ def _initial_update(self, configs, reset_name_map=True): if config_name not in self._store: self._add_refs(config_name, config_contents) - def _process_links(self, config_contents, already_gathered): if isinstance(config_contents, dict): for key, value in config_contents.items(): @@ -185,7 +174,6 @@ def _gather_child_configs(self, config_name, already_gathered): return config_contents - def _gather_config(self, config_name): config_contents = self._store.get(config_name) if config_contents is None: @@ -198,8 +186,6 @@ def _gather_config(self, config_name): return self._gather_child_configs(config_name, already_configured) - - def _gather_affected(self, config_name, seen_dict): reverse_refs = self._reverse_ref_map[config_name] for ref in reverse_refs: @@ -207,16 +193,15 @@ def _gather_affected(self, config_name, seen_dict): seen_dict[ref] = "UPDATE" self._gather_affected(ref, seen_dict) - def _update_config(self, action, config_name, contents=None, trigger_callback=False): """Called by the platform to push out configuration changes.""" - #If we haven't yet grabbed the initial callback state we just bail. + # If we haven't yet grabbed the initial callback state we just bail. if not self._initialized: return affected_configs = {} - #Update local store. + # Update local store. if action == "DELETE": config_name_lower = config_name.lower() if config_name_lower in self._store: @@ -234,7 +219,7 @@ def _update_config(self, action, config_name, contents=None, trigger_callback=Fa if action == "DELETE_ALL": for name in self._store: affected_configs[name] = "DELETE" - #Just assume all default stores updated. + # Just assume all default stores updated. for name in self._default_store: affected_configs[name] = "UPDATE" self._ref_map = {} @@ -251,7 +236,6 @@ def _update_config(self, action, config_name, contents=None, trigger_callback=Fa self._update_refs(config_name_lower, self._store[config_name_lower]) self._gather_affected(config_name_lower, affected_configs) - if trigger_callback and self._initial_callbacks_called: self._process_callbacks(affected_configs) @@ -261,13 +245,11 @@ def _update_config(self, action, config_name, contents=None, trigger_callback=Fa if action == "DELETE_ALL": self._name_map.clear() - - def _process_callbacks(self, affected_configs): _log.debug("Processing callbacks for affected files: {}".format(affected_configs)) all_map = self._default_name_map.copy() all_map.update(self._name_map) - #Always process "config" first. + # Always process "config" first. if "config" in affected_configs: self._process_callbacks_one_config("config", affected_configs["config"], all_map) @@ -276,7 +258,6 @@ def _process_callbacks(self, affected_configs): continue self._process_callbacks_one_config(config_name, action, all_map) - def _process_callbacks_one_config(self, config_name, action, name_map): callbacks = set() for pattern, actions in self._subscriptions.items(): @@ -307,7 +288,7 @@ def list(self): # Handle case were we are called during "onstart". if not self._initialized: try: - self._rpc().call(CONFIGURATION_STORE, "get_configs").get() + self._rpc().call(CONFIGURATION_STORE, "initialize_configs", self.vip_identity).get() except errors.Unreachable as e: _log.error("Connected platform does not support the Configuration Store feature.") except errors.VIPError as e: @@ -333,13 +314,13 @@ def get(self, config_name="config"): :Return Values: The contents of the configuration specified. """ - #Handle case were we are called during "onstart". + # Handle case were we are called during "onstart". - #If we fail to initialize we don't raise an exception as there still - #may be a default configuration to grab. + # If we fail to initialize we don't raise an exception as there still + # may be a default configuration to grab. if not self._initialized: try: - self._rpc().call(CONFIGURATION_STORE, "get_configs").get() + self._rpc().call(CONFIGURATION_STORE, "initialize_configs", self.vip_identity).get() except errors.Unreachable as e: _log.error("Connected platform does not support the Configuration Store feature.") except errors.VIPError as e: @@ -352,14 +333,13 @@ def get(self, config_name="config"): def _check_call_from_process_callbacks(self): frame_records = inspect.stack() try: - #Don't create any unneeded references to frame objects. + # Don't create any unneeded references to frame objects. for frame, *_ in frame_records: if self._process_callbacks_code_object is frame.f_code: raise RuntimeError("Cannot request changes to the config store from a configuration callback.") finally: del frame_records - def set(self, config_name, contents, trigger_callback=False, send_update=True): """Called to set the contents of a configuration. @@ -370,6 +350,8 @@ def set(self, config_name, contents, trigger_callback=False, send_update=True): :param config_name: Name of configuration to add to store. :param contents: Contents of the configuration. May be a string, dictionary, or list. :param trigger_callback: Tell the platform to trigger callbacks on the agent for this change. + :param send_update: Boolean flag to tell the server if it should call config.update on this agent + after server side update is done :type config_name: str :type contents: str, dict, list @@ -377,9 +359,17 @@ def set(self, config_name, contents, trigger_callback=False, send_update=True): """ self._check_call_from_process_callbacks() - self._rpc().call(CONFIGURATION_STORE, "set_config", config_name, contents, - trigger_callback=trigger_callback, - send_update=send_update).get(timeout=10.0) + if isinstance(contents, (dict, list)): + config_type = 'json' + raw_data = jsonapi.dumps(contents) + elif isinstance(contents, str): + config_type = 'raw' + raw_data = contents + else: + raise ValueError("Unsupported configuration content type: {}".format(str(type(contents)))) + + self._rpc().call(CONFIGURATION_STORE, "set_config", self.vip_identity, config_name, raw_data, + config_type, trigger_callback=trigger_callback, send_update=send_update).get(timeout=10.0) def set_default(self, config_name, contents): """Called to set the contents of a default configuration file. Default configurations are used if the @@ -427,7 +417,6 @@ def delete_default(self, config_name): self._update_refs(config_name_lower, self._store[config_name_lower]) - def delete(self, config_name, trigger_callback=False, send_update=True): """Delete a configuration by name. May not be called from a callback as this will cause deadlock with the platform. Will produce a runtime error if done so. @@ -439,7 +428,7 @@ def delete(self, config_name, trigger_callback=False, send_update=True): """ self._check_call_from_process_callbacks() - self._rpc().call(CONFIGURATION_STORE, "delete_config", config_name, + self._rpc().call(CONFIGURATION_STORE, "delete_config", self.vip_identity, config_name, trigger_callback=trigger_callback, send_update=send_update).get(timeout=10.0) @@ -447,7 +436,8 @@ def subscribe(self, callback, actions=VALID_ACTIONS, pattern="*"): """Subscribe to changes to a configuration. :param callback: Function to call in response to changes to a configuration. - :param actions: Change actions to respond to. Valid values are "NEW", "UPDATE", and "DELETE". May be a single action or a list of actions. + :param actions: Change actions to respond to. Valid values are "NEW", "UPDATE", and "DELETE". + May be a single action or a list of actions. :param pattern: Configuration name pattern to match to. Uses Unix style filename pattern matching. :type callback: str @@ -459,9 +449,9 @@ def subscribe(self, callback, actions=VALID_ACTIONS, pattern="*"): actions = set(action.upper() for action in actions) - invalid_actions = actions - VALID_ACTIONS - if (invalid_actions): - raise ValueError("Invalid actions: " + list(invalid_actions)) + invalid_actions = actions - set(VALID_ACTIONS) + if invalid_actions: + raise ValueError(f"Invalid actions: {invalid_actions}") pattern = pattern.lower() @@ -471,12 +461,3 @@ def subscribe(self, callback, actions=VALID_ACTIONS, pattern="*"): def unsubscribe_all(self): """Remove all subscriptions.""" self._subscriptions.clear() - - - - - - - - - diff --git a/volttron/platform/vip/agent/subsystems/health.py b/volttron/platform/vip/agent/subsystems/health.py index 37dadf96f0..2bc4aeffe9 100644 --- a/volttron/platform/vip/agent/subsystems/health.py +++ b/volttron/platform/vip/agent/subsystems/health.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/volttron/platform/vip/agent/subsystems/heartbeat.py b/volttron/platform/vip/agent/subsystems/heartbeat.py index c8d9688fea..473a0e1284 100644 --- a/volttron/platform/vip/agent/subsystems/heartbeat.py +++ b/volttron/platform/vip/agent/subsystems/heartbeat.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -45,7 +31,7 @@ from volttron.platform.agent.utils import (get_aware_utc_now, format_timestamp) from volttron.platform.scheduling import periodic -from ..errors import Unreachable, VIPError +from ..errors import Unreachable """The heartbeat subsystem adds an optional periodic publish to all agents. Heartbeats can be started with agents and toggled on and off at runtime. @@ -152,4 +138,3 @@ def publish(self): except Unreachable as exc: self.connect_error = True self.stop() - diff --git a/volttron/platform/vip/agent/subsystems/hello.py b/volttron/platform/vip/agent/subsystems/hello.py index d515c7b7c9..0a377cdda1 100644 --- a/volttron/platform/vip/agent/subsystems/hello.py +++ b/volttron/platform/vip/agent/subsystems/hello.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -42,7 +28,6 @@ import weakref from .base import SubsystemBase -from ..errors import VIPError from ..results import ResultsDictionary from zmq import ZMQError from zmq.green import ENOTSOCK diff --git a/volttron/platform/vip/agent/subsystems/peerlist.py b/volttron/platform/vip/agent/subsystems/peerlist.py index 384569875f..59fee14111 100644 --- a/volttron/platform/vip/agent/subsystems/peerlist.py +++ b/volttron/platform/vip/agent/subsystems/peerlist.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/agent/subsystems/ping.py b/volttron/platform/vip/agent/subsystems/ping.py index 2b9bbea512..ad31f6acb0 100644 --- a/volttron/platform/vip/agent/subsystems/ping.py +++ b/volttron/platform/vip/agent/subsystems/ping.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/agent/subsystems/pubsub.py b/volttron/platform/vip/agent/subsystems/pubsub.py index 186b7fe776..320afde189 100644 --- a/volttron/platform/vip/agent/subsystems/pubsub.py +++ b/volttron/platform/vip/agent/subsystems/pubsub.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -44,22 +30,19 @@ import random import re import weakref -import sys import gevent from zmq import green as zmq from zmq import SNDMORE from volttron.platform import jsonapi -from volttron.utils.frame_serialization import serialize_frames from .base import SubsystemBase from ..decorators import annotate, annotations, dualmethod, spawn -from ..errors import Unreachable, VIPError, UnknownSubsystem +from ..errors import Unreachable from .... import jsonrpc -from volttron.platform.agent import utils + from ..results import ResultsDictionary -from gevent.queue import Queue, Empty +from gevent.queue import Queue from collections import defaultdict -from datetime import timedelta __all__ = ['PubSub'] diff --git a/volttron/platform/vip/agent/subsystems/query.py b/volttron/platform/vip/agent/subsystems/query.py index cd5971a05d..9103e22317 100644 --- a/volttron/platform/vip/agent/subsystems/query.py +++ b/volttron/platform/vip/agent/subsystems/query.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/agent/subsystems/rmq_pubsub.py b/volttron/platform/vip/agent/subsystems/rmq_pubsub.py index 21480d0e06..64c335d709 100644 --- a/volttron/platform/vip/agent/subsystems/rmq_pubsub.py +++ b/volttron/platform/vip/agent/subsystems/rmq_pubsub.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import errno diff --git a/volttron/platform/vip/agent/subsystems/rpc.py b/volttron/platform/vip/agent/subsystems/rpc.py index 00ec7314af..510ce9d099 100644 --- a/volttron/platform/vip/agent/subsystems/rpc.py +++ b/volttron/platform/vip/agent/subsystems/rpc.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -48,16 +34,13 @@ import gevent.local from gevent.event import AsyncResult from volttron.platform import jsonapi -from volttron.platform.agent.utils import get_messagebus from .base import SubsystemBase -from ..errors import VIPError from ..results import counter, ResultsDictionary from ..decorators import annotate, annotations, dualmethod, spawn from .... import jsonrpc -from volttron.platform.vip.socket import Message -from zmq import Frame, NOBLOCK, ZMQError, EINVAL, EHOSTUNREACH +from zmq import ZMQError from zmq.green import ENOTSOCK @@ -307,9 +290,9 @@ def _add_auth_check(self, method, required_caps): def checked_method(*args, **kwargs): user = str(self.context.vip_message.user) if self._message_bus == "rmq": - # When we address issue #2107 external platform user should - # have instance name also included in username. - user = user.split(".")[1] + # remove platform instance name. rmq user names are of the format . + user = user[user.index(".")+1:] + user_capabilites = self._owner.vip.auth.get_capabilities(user) _log.debug("**user caps is: {}".format(user_capabilites)) if user_capabilites: diff --git a/volttron/platform/vip/agent/subsystems/volttronfncs.py b/volttron/platform/vip/agent/subsystems/volttronfncs.py index 6f6044d1e7..a019bd3c05 100644 --- a/volttron/platform/vip/agent/subsystems/volttronfncs.py +++ b/volttron/platform/vip/agent/subsystems/volttronfncs.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -358,7 +344,3 @@ def simulation_complete(self): @property def current_values(self): return self._current_values.copy() - - - - diff --git a/volttron/platform/vip/agent/subsystems/web.py b/volttron/platform/vip/agent/subsystems/web.py index 98ec30d764..dd8bdd9c86 100644 --- a/volttron/platform/vip/agent/subsystems/web.py +++ b/volttron/platform/vip/agent/subsystems/web.py @@ -1,42 +1,27 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} -from collections import defaultdict import logging import weakref from enum import Enum @@ -223,9 +208,8 @@ def _opened(self, fromip, endpoint): if callbacks is None: _log.error('Websocket endpoint {} is not available'.format( endpoint)) - else: - if callbacks[0]: - return callbacks[0](fromip, endpoint) + elif callbacks[0]: + return callbacks[0](fromip, endpoint) return False @@ -236,9 +220,8 @@ def _closed(self, endpoint): if callbacks is None: _log.error('Websocket endpoint {} is not available'.format( endpoint)) - else: - if callbacks[1]: - callbacks[1](endpoint) + elif callbacks[1]: + callbacks[1](endpoint) def _message(self, endpoint, message): @@ -246,6 +229,5 @@ def _message(self, endpoint, message): if callbacks is None: _log.error('Websocket endpoint {} is not available'.format( endpoint)) - else: - if callbacks[2]: - callbacks[2](endpoint, message) + elif callbacks[2]: + callbacks[2](endpoint, message) diff --git a/volttron/platform/vip/agent/utils.py b/volttron/platform/vip/agent/utils.py index 84a4ce87fa..e099debd50 100644 --- a/volttron/platform/vip/agent/utils.py +++ b/volttron/platform/vip/agent/utils.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/externalrpcservice.py b/volttron/platform/vip/externalrpcservice.py index be4f068b52..d81530ee94 100644 --- a/volttron/platform/vip/externalrpcservice.py +++ b/volttron/platform/vip/externalrpcservice.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/green.py b/volttron/platform/vip/green.py index cb7b4f6e15..81795245e3 100644 --- a/volttron/platform/vip/green.py +++ b/volttron/platform/vip/green.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VIP - VOLTTRON™ Interconnect Protocol implementation @@ -58,7 +44,6 @@ from zmq.green import NOBLOCK, POLLOUT from zmq import green as _green -from . import * from .router import BaseRouter as _BaseRouter from .socket import _Socket diff --git a/volttron/platform/vip/healthservice.py b/volttron/platform/vip/healthservice.py index 07bc1c3f53..c79cb9aee2 100644 --- a/volttron/platform/vip/healthservice.py +++ b/volttron/platform/vip/healthservice.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from collections import defaultdict @@ -130,6 +116,3 @@ def _heartbeat_updates(self, peer, sender, bus, topic, headers, message): def onstart(self, sender, **kwargs): # Start subscribing to heartbeat topic to get updates from the health subsystem. self.vip.pubsub.subscribe('pubsub', 'heartbeat', callback=self._heartbeat_updates) - - - diff --git a/volttron/platform/vip/keydiscovery.py b/volttron/platform/vip/keydiscovery.py index 971c9f27f9..4ca0e7b790 100644 --- a/volttron/platform/vip/keydiscovery.py +++ b/volttron/platform/vip/keydiscovery.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -47,7 +33,7 @@ from requests.exceptions import HTTPError, Timeout from volttron.platform.agent import utils -from .agent import Agent, Core, RPC +from .agent import Agent, Core from requests.packages.urllib3.connection import (ConnectionError, NewConnectionError) from urllib.parse import urlparse, urljoin @@ -261,4 +247,3 @@ def _get_platform_discovery(self, web_address): raise DiscoveryError( "Unknown Exception: {}".format(e) ) - diff --git a/volttron/platform/vip/proxy_zmq_router.py b/volttron/platform/vip/proxy_zmq_router.py index 9655a56c74..f7222fd5a8 100644 --- a/volttron/platform/vip/proxy_zmq_router.py +++ b/volttron/platform/vip/proxy_zmq_router.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/volttron/platform/vip/pubsubservice.py b/volttron/platform/vip/pubsubservice.py index 7902c9b7d2..d416251c61 100644 --- a/volttron/platform/vip/pubsubservice.py +++ b/volttron/platform/vip/pubsubservice.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} @@ -53,7 +39,6 @@ from volttron.utils.frame_serialization import serialize_frames green.Context._instance = green.Context.shadow(zmq.Context.instance().underlying) -from volttron.platform import get_home from .agent.subsystems.pubsub import ProtectedPubSubTopics from volttron.platform.jsonrpc import (INVALID_REQUEST, UNAUTHORIZED) from volttron.platform import jsonapi @@ -598,7 +583,7 @@ def _load_protected_topics(self, topics_data): self._logger.exception('invalid format for protected topics ') else: self._protected_topics = topics - self._logger.info('protected-topics loaded') + self._logger.debug('protected-topics loaded') def handle_subsystem(self, frames, user_id=''): """ diff --git a/volttron/platform/vip/rmq_connection.py b/volttron/platform/vip/rmq_connection.py index 9f63b098f9..a9f696a518 100644 --- a/volttron/platform/vip/rmq_connection.py +++ b/volttron/platform/vip/rmq_connection.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import errno @@ -583,7 +569,7 @@ def _handle_error(self, channel, method, props, body): # The below try/except protects the platform from someone who is not communicating # via vip protocol. If sender is not a string then the channel publish will throw - # an AssertionError and it will kill the platform. + # an AssertionError and it will kill the platform. try: self.channel.basic_publish(self.exchange, sender, @@ -591,7 +577,7 @@ def _handle_error(self, channel, method, props, body): props) except AssertionError: pass - + def loop(self): """ Connect to RabbiMQ broker and run infinite loop to listen to incoming messages diff --git a/volttron/platform/vip/rmq_router.py b/volttron/platform/vip/rmq_router.py index dc741e71a3..a7ab1d752e 100644 --- a/volttron/platform/vip/rmq_router.py +++ b/volttron/platform/vip/rmq_router.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import errno diff --git a/volttron/platform/vip/router.py b/volttron/platform/vip/router.py index add4f77fb1..4b0d562996 100644 --- a/volttron/platform/vip/router.py +++ b/volttron/platform/vip/router.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/routingservice.py b/volttron/platform/vip/routingservice.py index 8e2db105ba..ca71430a2b 100644 --- a/volttron/platform/vip/routingservice.py +++ b/volttron/platform/vip/routingservice.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/platform/vip/servicepeer.py b/volttron/platform/vip/servicepeer.py index d5cbcc72ad..65a5f18188 100644 --- a/volttron/platform/vip/servicepeer.py +++ b/volttron/platform/vip/servicepeer.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/volttron/platform/vip/socket.py b/volttron/platform/vip/socket.py index 8d41402ed8..6266801803 100644 --- a/volttron/platform/vip/socket.py +++ b/volttron/platform/vip/socket.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} '''VIP - VOLTTRON™ Interconnect Protocol implementation diff --git a/volttron/platform/vip/tracking.py b/volttron/platform/vip/tracking.py index cdac2cf110..cc94b19941 100644 --- a/volttron/platform/vip/tracking.py +++ b/volttron/platform/vip/tracking.py @@ -2,41 +2,27 @@ # vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} #}}} diff --git a/volttron/platform/vip/zmq_connection.py b/volttron/platform/vip/zmq_connection.py index 09e5b04af9..1547724b29 100644 --- a/volttron/platform/vip/zmq_connection.py +++ b/volttron/platform/vip/zmq_connection.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufactufrer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import zmq @@ -106,4 +92,3 @@ def close_connection(self, linger=5): _log.debug("********************************************************************") _log.debug("Closing connection to ZMQ: {}".format(self._identity)) _log.debug("********************************************************************") - diff --git a/volttron/platform/web/__init__.py b/volttron/platform/web/__init__.py index c9bffba28a..5fb0a54c71 100644 --- a/volttron/platform/web/__init__.py +++ b/volttron/platform/web/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from http.cookies import SimpleCookie diff --git a/volttron/platform/web/admin_endpoints.py b/volttron/platform/web/admin_endpoints.py index 9a387eab8f..9de8d05a5c 100644 --- a/volttron/platform/web/admin_endpoints.py +++ b/volttron/platform/web/admin_endpoints.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging @@ -198,7 +184,7 @@ def verify_and_dispatch(self, env, data): self._denied_auths = [] self._approved_auths = [] except Exception as err: - _log.error(f"Error message is: {err}") + _log.error(f"Error message is: {err}") # # When messagebus is rmq, include pending csrs in the output pending_auth_reqs.html page # if self._rmq_mgmt is not None: # html = template.render(csrs=self._rpc_caller.call(AUTH, 'get_pending_csrs').get(timeout=4), diff --git a/volttron/platform/web/platform_web_service.py b/volttron/platform/web/platform_web_service.py index 50fe254ed9..56b49ce7c9 100644 --- a/volttron/platform/web/platform_web_service.py +++ b/volttron/platform/web/platform_web_service.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import base64 @@ -491,7 +477,7 @@ def app_routing(self, env, start_response): retvalue = v(env, start_response, data) except TypeError: response = v(env, data) - _log.debug(f'VUI: Response at app_routing is: {response.response}') + #_log.debug(f'VUI: Response at app_routing is: {response.response}') return response(env, start_response) # retvalue = self.process_response(start_response, v(env, data)) @@ -806,7 +792,7 @@ def startupagent(self, sender, **kwargs): # Register VUI endpoints: self._vui_endpoints = VUIEndpoints(self) - _log.debug(f'VUI: adding routes - {self._vui_endpoints.get_routes()}') + #_log.debug(f'VUI: adding routes - {self._vui_endpoints.get_routes()}') self.registeredroutes.extend(self._vui_endpoints.get_routes()) # Allow authentication endpoint from any https connection diff --git a/volttron/platform/web/topic_tree.py b/volttron/platform/web/topic_tree.py index 26a1c940a0..fedc0e6820 100644 --- a/volttron/platform/web/topic_tree.py +++ b/volttron/platform/web/topic_tree.py @@ -151,17 +151,17 @@ def devices(self, nid=None): def from_store(cls, platform, rpc_caller): # TODO: Duplicate logic for external_platform check from VUIEndpoints to remove reference to it from here. kwargs = {'external_platform': platform} if 'VUIEndpoints' in rpc_caller.__repr__() else {} - devices = rpc_caller(CONFIGURATION_STORE, 'manage_list_configs', 'platform.driver', **kwargs) + devices = rpc_caller(CONFIGURATION_STORE, 'list_configs', 'platform.driver', **kwargs) devices = devices if kwargs else devices.get(timeout=5) devices = [d for d in devices if re.match('^devices/.*', d)] device_tree = cls(devices) for d in devices: - dev_config = rpc_caller(CONFIGURATION_STORE, 'manage_get', 'platform.driver', d, raw=False, **kwargs) + dev_config = rpc_caller(CONFIGURATION_STORE, 'get_config', 'platform.driver', d, raw=False, **kwargs) # TODO: If not AsyncResponse instead of if kwargs dev_config = dev_config if kwargs else dev_config.get(timeout=5) reg_cfg_name = dev_config.pop('registry_config')[len('config://'):] device_tree.update_node(d, data=dev_config, segment_type='DEVICE') - registry_config = rpc_caller('config.store', 'manage_get', 'platform.driver', + registry_config = rpc_caller('config.store', 'get_config', 'platform.driver', f'{reg_cfg_name}', raw=False, **kwargs) registry_config = registry_config if kwargs else registry_config.get(timeout=5) for pnt in registry_config: diff --git a/volttron/platform/web/vui_endpoints.py b/volttron/platform/web/vui_endpoints.py index 50e1676c86..f27fbca646 100644 --- a/volttron/platform/web/vui_endpoints.py +++ b/volttron/platform/web/vui_endpoints.py @@ -331,15 +331,15 @@ def handle_platforms_agents_configs(self, env: dict, data: dict) -> Response: try: if no_config_name: if vip_identity != '-': - setting_list = self._rpc('config.store', 'manage_list_configs', vip_identity, + setting_list = self._rpc('config.store', 'list_configs', vip_identity, external_platform=platform) route_dict = self._links(path_info, setting_list) return Response(json.dumps(route_dict), 200, content_type='application/json') else: - list_of_agents = self._rpc('config.store', 'manage_list_stores', external_platform=platform) + list_of_agents = self._rpc('config.store', 'list_stores', external_platform=platform) return Response(json.dumps(list_of_agents), 200, content_type='application/json') elif not no_config_name: - setting_dict = self._rpc('config.store', 'manage_get', vip_identity, config_name, + setting_dict = self._rpc('config.store', 'get_config', vip_identity, config_name, external_platform=platform) return Response(json.dumps(setting_dict), 200, content_type='application/json') except RemoteError as e: @@ -356,7 +356,7 @@ def handle_platforms_agents_configs(self, env: dict, data: dict) -> Response: elif request_method == 'POST' and no_config_name: if config_type in ['application/json', 'text/csv', 'text/plain']: - setting_list = self._rpc('config.store', 'manage_list_configs', vip_identity, + setting_list = self._rpc('config.store', 'list_configs', vip_identity, external_platform=platform) if config_name in setting_list: e = {'Error': f'Configuration: "{config_name}" already exists for agent: "{vip_identity}"'} @@ -373,13 +373,13 @@ def handle_platforms_agents_configs(self, env: dict, data: dict) -> Response: elif request_method == 'DELETE': if no_config_name: try: - self._rpc('config.store', 'manage_delete_store', vip_identity, external_platform=platform) + self._rpc('config.store', 'delete_store', vip_identity, external_platform=platform) return Response(None, 204, content_type='application/json') except RemoteError as e: return Response(json.dumps({"Error": f"{e}"}), 400, content_type='application/json') else: try: - self._rpc('config.store', 'manage_delete_config', vip_identity, config_name, + self._rpc('config.store', 'delete_config', vip_identity, config_name, external_platform=platform) return Response(None, 204, content_type='application/json') except RemoteError as e: @@ -998,7 +998,7 @@ def _insert_config(self, config_type, data, vip_identity, config_name, platform) 'text/csv'] else 'raw' if config_type == 'json': data = json.dumps(data) - self._rpc('config.store', 'manage_store', vip_identity, config_name, data, config_type, + self._rpc('config.store', 'set_config', vip_identity, config_name, data, config_type, external_platform=platform) return None diff --git a/volttron/utils/__init__.py b/volttron/utils/__init__.py index e4d1a23299..daa1e1aaa7 100644 --- a/volttron/utils/__init__.py +++ b/volttron/utils/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import inspect import os diff --git a/volttron/utils/frame_serialization.py b/volttron/utils/frame_serialization.py index 45c1e79e8c..5d06ef5727 100644 --- a/volttron/utils/frame_serialization.py +++ b/volttron/utils/frame_serialization.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from json import JSONDecodeError @@ -111,5 +97,3 @@ def serialize_frames(data: List[Any]) -> List[Frame]: import sys sys.exit(0) return frames - - diff --git a/volttron/utils/frozendict.py b/volttron/utils/frozendict.py index 0ecbd918e5..ce250c7e49 100644 --- a/volttron/utils/frozendict.py +++ b/volttron/utils/frozendict.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/utils/prompt.py b/volttron/utils/prompt.py index 25c010ea9c..455d00bf7e 100644 --- a/volttron/utils/prompt.py +++ b/volttron/utils/prompt.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttron/utils/rmq_config_params.py b/volttron/utils/rmq_config_params.py index 2e8c247e64..17672afc60 100644 --- a/volttron/utils/rmq_config_params.py +++ b/volttron/utils/rmq_config_params.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os @@ -88,7 +74,7 @@ def __init__(self): with open(os.path.expanduser("~/.volttron_rmq_home")) as f: self.rabbitmq_server = f.read().strip() else: - self.rabbitmq_server = os.path.expanduser("~/rabbitmq_server/rabbitmq_server-3.9.7/") + self.rabbitmq_server = os.path.expanduser("~/rabbitmq_server/rabbitmq_server-3.9.29/") assert os.path.isdir(self.rabbitmq_server), "Missing rabbitmq server directory{}".format(self.rabbitmq_server) from volttron.platform.auth import certs @@ -118,7 +104,7 @@ def _set_default_config(self): self.config_opts.setdefault('reconnect-delay', 30) self.config_opts.setdefault('user', self.instance_name + '-admin') rmq_home = os.path.join(os.path.expanduser("~"), - "rabbitmq_server/rabbitmq_server-3.9.7") + "rabbitmq_server/rabbitmq_server-3.9.29") self.config_opts.setdefault('rabbitmq-service', False) self.config_opts.setdefault("rmq-home", rmq_home) @@ -281,7 +267,3 @@ def node_name(self, name): @rabbitmq_as_service.setter def rabbitmq_as_service(self, service_flag): self.config_opts['rabbitmq-service'] = service_flag - - - - diff --git a/volttron/utils/rmq_mgmt.py b/volttron/utils/rmq_mgmt.py index ea0d74bf94..20c3ce1192 100644 --- a/volttron/utils/rmq_mgmt.py +++ b/volttron/utils/rmq_mgmt.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import logging diff --git a/volttron/utils/rmq_setup.py b/volttron/utils/rmq_setup.py index 66fbb7e530..65e9be6fde 100644 --- a/volttron/utils/rmq_setup.py +++ b/volttron/utils/rmq_setup.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -59,7 +45,7 @@ from volttron.platform import get_home from volttron.platform.agent.utils import (store_message_bus_config, execute_command) -from volttron.utils.prompt import prompt_response, y, n, y_or_n +from volttron.utils.prompt import prompt_response, y, y_or_n from volttron.platform import jsonapi from urllib.parse import urlparse from volttron.platform.agent.utils import get_platform_instance_name, get_fq_identity @@ -90,13 +76,13 @@ def _start_rabbitmq_without_ssl(rmq_config, conf_file, env=None): rmq_home = rmq_config.rmq_home if not rmq_home: rmq_home = os.path.join(os.path.expanduser("~"), - "rabbitmq_server/rabbitmq_server-3.9.7") + "rabbitmq_server/rabbitmq_server-3.9.29") if os.path.exists(rmq_home): os.environ['RABBITMQ_HOME'] = rmq_home else: _log.error("\nMissing key 'rmq_home' in RabbitMQ config and RabbitMQ is " "not installed in default path: \n" - "~/rabbitmq_server/rabbitmq_server-3.9.7 \n" + "~/rabbitmq_server/rabbitmq_server-3.9.29 \n" "Please set the correct RabbitMQ installation path in " "rabbitmq_config.yml") exit(1) @@ -1543,7 +1529,7 @@ def start_rabbit(rmq_home, env=None): execute_command(status_cmd, env=env) if not start: # if we have attempted started already - gevent.sleep(1) # give a second just to be sure + gevent.sleep(2) # give couple of seconds just to be sure started = True _log.info("Rmq server at {} is running at ".format(rmq_home)) except RuntimeError as e: diff --git a/volttrontesting/README.md b/volttrontesting/README.md index 0659841aca..dcb5eaabea 100644 --- a/volttrontesting/README.md +++ b/volttrontesting/README.md @@ -13,20 +13,20 @@ the VOLTTRON repository. ``` # Execute all tests throughout the repository -py.test +pytest # Execute a specific directory of tests recursively from the # specified directory. -py.test examples/ListenerAgent +pytest examples/ListenerAgent # Execute only tests that are marked as slow -py.test -m slow +pytest -m slow # Execute tests that are not marked as slow -py.test -m "not slow" +pytest -m "not slow" # Execute only zmq tests -py.test -m zmq +pytest -m zmq ``` ## Notes diff --git a/volttrontesting/fixtures/rmq_test_setup.py b/volttrontesting/fixtures/rmq_test_setup.py index 464179dfb8..a69a6373b1 100644 --- a/volttrontesting/fixtures/rmq_test_setup.py +++ b/volttrontesting/fixtures/rmq_test_setup.py @@ -34,7 +34,7 @@ def __init__(self): # This is overwritten in the class below during # the create_rmq_volttron_setup function, but is # left here for completeness of the configuration. - 'rmq-home': '~/rabbitmq_server-3.9.7', + 'rmq-home': '~/rabbitmq_server-3.9.29', 'reconnect-delay': 5 } diff --git a/volttrontesting/fixtures/volttron_platform_fixtures.py b/volttrontesting/fixtures/volttron_platform_fixtures.py index 1b905f9963..a568f190e6 100644 --- a/volttrontesting/fixtures/volttron_platform_fixtures.py +++ b/volttrontesting/fixtures/volttron_platform_fixtures.py @@ -49,10 +49,8 @@ def build_wrapper(vip_address: str, should_start: bool = True, messagebus: str = auth_enabled=kwargs.pop('auth_enabled', True)) if should_start: wrapper.startup_platform(vip_address=vip_address, **kwargs) - if wrapper.messagebus == 'rmq': - gevent.sleep(5) - else: - gevent.sleep(2) + if not wrapper.dynamic_agent: + raise ValueError(f"Couldn't start platform successfully for {wrapper.messagebus}") assert wrapper.is_running() return wrapper @@ -62,14 +60,22 @@ def cleanup_wrapper(wrapper): # if wrapper.is_running(): # wrapper.remove_all_agents() # Shutdown handles case where the platform hasn't started. + if not wrapper.is_running(): + return + wrapper_pid = wrapper.p_process.pid wrapper.shutdown_platform() if wrapper.p_process is not None: - if psutil.pid_exists(wrapper.p_process.pid): - proc = psutil.Process(wrapper.p_process.pid) + if psutil.pid_exists(wrapper_pid): + proc = psutil.Process(wrapper_pid) proc.terminate() if not wrapper.debug_mode: assert not Path(wrapper.volttron_home).parent.exists(), \ f"{str(Path(wrapper.volttron_home).parent)} wasn't cleaned!" + if not wrapper.debug_mode: + assert not Path(wrapper.volttron_home).exists() + # Final way to kill off the platform wrapper for the tests. + if psutil.pid_exists(wrapper_pid): + psutil.Process(wrapper_pid).kill() def cleanup_wrappers(platforms): @@ -117,7 +123,7 @@ def volttron_instance_module_web(request): params=[ dict(messagebus='zmq'), pytest.param(dict(messagebus='rmq', ssl_auth=True), marks=rmq_skipif), - dict(messagebus='zmq', auth_enabled=False), + dict(messagebus='zmq', auth_enabled=False) ]) def volttron_instance(request, **kwargs): """Fixture that returns a single instance of volttron platform for testing @@ -126,12 +132,14 @@ def volttron_instance(request, **kwargs): @return: volttron platform instance """ address = kwargs.pop("vip_address", get_rand_vip()) + if request.param['messagebus'] == 'rmq': + kwargs['timeout'] = 240 + wrapper = build_wrapper(address, - messagebus=request.param.pop('messagebus', 'zmq'), - ssl_auth=request.param.pop('ssl_auth', False), - auth_enabled=request.param.pop('auth_enabled', True), + messagebus=request.param.get('messagebus', 'zmq'), + ssl_auth=request.param.get('ssl_auth', False), + auth_enabled=request.param.get('auth_enabled', True), **kwargs) - wrapper_pid = wrapper.p_process.pid try: yield wrapper @@ -139,11 +147,6 @@ def volttron_instance(request, **kwargs): print(ex.args) finally: cleanup_wrapper(wrapper) - if not wrapper.debug_mode: - assert not Path(wrapper.volttron_home).exists() - # Final way to kill off the platform wrapper for the tests. - if psutil.pid_exists(wrapper_pid): - psutil.Process(wrapper_pid).kill() # Use this fixture to get more than 1 volttron instance for test. @@ -182,8 +185,9 @@ def get_n_volttron_instances(n, should_start=True, **kwargs): address = kwargs.pop("vip_address", get_rand_vip()) wrapper = build_wrapper(address, should_start=should_start, - messagebus=request.param.pop('messagebus', 'zmq'), - ssl_auth=request.param.pop('ssl_auth', False), + messagebus=request.param.get('messagebus', 'zmq'), + ssl_auth=request.param.get('ssl_auth', False), + auth_enabled=request.param.get('auth_enabled', True), **kwargs) instances.append(wrapper) if should_start: @@ -196,17 +200,10 @@ def get_n_volttron_instances(n, should_start=True, **kwargs): def cleanup(): nonlocal instances - print(f"My instances: {get_n_volttron_instances.count}") - if isinstance(get_n_volttron_instances.instances, PlatformWrapper): - print('Shutting down instance: {}'.format( - get_n_volttron_instances.instances)) - cleanup_wrapper(get_n_volttron_instances.instances) - return - - for i in range(0, get_n_volttron_instances.count): + for i in range(0, len(instances)): print('Shutting down instance: {}'.format( - get_n_volttron_instances.instances[i].volttron_home)) - cleanup_wrapper(get_n_volttron_instances.instances[i]) + instances[i].volttron_home)) + cleanup_wrapper(instances[i]) try: yield get_n_volttron_instances @@ -216,20 +213,31 @@ def cleanup(): # Use this fixture when you want a single instance of volttron platform for zmq message bus # test -@pytest.fixture(scope="module") -def volttron_instance_zmq(): +@pytest.fixture(scope="module", + params=[ + dict(messagebus='zmq'), + dict(messagebus='zmq', auth_enabled=False) + ]) +def volttron_instance_zmq(request, **kwargs): """Fixture that returns a single instance of volttron platform for testing @param request: pytest request object @return: volttron platform instance """ - address = get_rand_vip() - - wrapper = build_wrapper(address) + address = kwargs.pop("vip_address", get_rand_vip()) - yield wrapper + wrapper = build_wrapper(address, + messagebus=request.param.get('messagebus', 'zmq'), + ssl_auth=request.param.get('ssl_auth', False), + auth_enabled=request.param.get('auth_enabled', True), + **kwargs) - cleanup_wrapper(wrapper) + try: + yield wrapper + except Exception as ex: + print(ex.args) + finally: + cleanup_wrapper(wrapper) # Use this fixture when you want a single instance of volttron platform for rmq message bus diff --git a/volttrontesting/multiplatform/test_federation.py b/volttrontesting/multiplatform/test_federation.py index 46243aa25f..a04c475303 100644 --- a/volttrontesting/multiplatform/test_federation.py +++ b/volttrontesting/multiplatform/test_federation.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ pytest test cases base historian to test all_platform configuration. @@ -51,6 +37,8 @@ if not is_rabbitmq_available(): pytest.skip("Pika is not installed", allow_module_level=True) + +@pytest.mark.timeout(600) @pytest.mark.federation def test_federation_pubsub(federated_rmq_instances): upstream, downstream = federated_rmq_instances @@ -127,4 +115,3 @@ def test_federation_rpc(two_way_federated_rmq_instances): finally: if instance_2.is_running: instance_2.remove_agent(auuid) - diff --git a/volttrontesting/multiplatform/test_multiplatform_pubsub.py b/volttrontesting/multiplatform/test_multiplatform_pubsub.py index a9a86cee18..88c35d9d4a 100644 --- a/volttrontesting/multiplatform/test_multiplatform_pubsub.py +++ b/volttrontesting/multiplatform/test_multiplatform_pubsub.py @@ -247,6 +247,7 @@ def test_multiplatform_pubsub(request, multi_platform_connection): assert message == [{'point': 'value'}] +@pytest.mark.timeout(600) @pytest.mark.multiplatform def test_multiplatform_2_publishers(request, five_platform_connection): subscription_results2 = {} @@ -544,14 +545,14 @@ def test_multiplatform_configstore_rpc(request, get_volttron_instances): test_agent = p2.build_agent() kwargs = {"external_platform": p1.instance_name} test_agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_store', + 'set_config', 'platform.thresholddetection', 'config', jsonapi.dumps(updated_config), 'json', **kwargs).get(timeout=10) config = test_agent.vip.rpc.call(CONFIGURATION_STORE, - 'manage_get', + 'get_config', 'platform.thresholddetection', 'config', raw=True, diff --git a/volttrontesting/multiplatform/test_shovel.py b/volttrontesting/multiplatform/test_shovel.py index 76afbefe58..1d1351db30 100644 --- a/volttrontesting/multiplatform/test_shovel.py +++ b/volttrontesting/multiplatform/test_shovel.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ pytest test cases base historian to test all_platform configuration. @@ -259,6 +245,7 @@ def two_way_shovel_connection(request, **kwargs): sink.shutdown_platform() +@pytest.mark.timeout(800) @pytest.mark.shovel def test_shovel_pubsub(shovel_pubsub_rmq_instances): source, sink = shovel_pubsub_rmq_instances @@ -286,6 +273,7 @@ def callback2(peer, sender, bus, topic, headers, message): assert message == [{'point': 'value'}] +@pytest.mark.timeout(600) @pytest.mark.shovel def test_shovel_rpc(two_way_shovel_connection): instance_1, instance_2 = two_way_shovel_connection diff --git a/volttrontesting/platform/auth_tests/test_auth_file.py b/volttrontesting/platform/auth_tests/test_auth_file.py index f7d8c65e05..320accc2e3 100644 --- a/volttrontesting/platform/auth_tests/test_auth_file.py +++ b/volttrontesting/platform/auth_tests/test_auth_file.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import os diff --git a/volttrontesting/platform/base_market_agent/test_market_registration.py b/volttrontesting/platform/base_market_agent/test_market_registration.py index ff813f13a9..62ec49b0ff 100644 --- a/volttrontesting/platform/base_market_agent/test_market_registration.py +++ b/volttrontesting/platform/base_market_agent/test_market_registration.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest diff --git a/volttrontesting/platform/base_market_agent/test_point.py b/volttrontesting/platform/base_market_agent/test_point.py index d2b79bfafe..9050075d70 100644 --- a/volttrontesting/platform/base_market_agent/test_point.py +++ b/volttrontesting/platform/base_market_agent/test_point.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest @@ -72,4 +58,3 @@ def test_point_y_negative(): def test_point_tuppleize(): p = Point(4,8) assert p == (4.0,8.0) - diff --git a/volttrontesting/platform/base_market_agent/test_poly_line.py b/volttrontesting/platform/base_market_agent/test_poly_line.py index e711093162..b09fcb6084 100644 --- a/volttrontesting/platform/base_market_agent/test_poly_line.py +++ b/volttrontesting/platform/base_market_agent/test_poly_line.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest @@ -47,55 +33,55 @@ @pytest.mark.market def test_poly_line_min(): - min = PolyLine.min(1,2) + min = PolyLine.min(1, 2) assert min == 1 @pytest.mark.market def test_poly_line_min_first_none(): - min = PolyLine.min(None,2) + min = PolyLine.min(None, 2) assert min == 2 @pytest.mark.market def test_poly_line_min_second_none(): - min = PolyLine.min(1,None) + min = PolyLine.min(1, None) assert min == 1 @pytest.mark.market def test_poly_line_max(): - max = PolyLine.max(1,2) + max = PolyLine.max(1, 2) assert max == 2 @pytest.mark.market def test_poly_line_max_first_none(): - max = PolyLine.max(None,2) + max = PolyLine.max(None, 2) assert max == 2 @pytest.mark.market def test_poly_line_max_second_none(): - max = PolyLine.max(1,None) + max = PolyLine.max(1, None) assert max == 1 @pytest.mark.market def test_poly_line_sum(): - sum = PolyLine.sum(1,2) + sum = PolyLine.sum(1, 2) assert sum == 3 @pytest.mark.market def test_poly_line_sum_first_none(): - sum = PolyLine.sum(None,2) + sum = PolyLine.sum(None, 2) assert sum == 2 @pytest.mark.market def test_poly_line_sum_second_none(): - sum = PolyLine.sum(1,None) + sum = PolyLine.sum(1, None) assert sum == 1 @@ -108,23 +94,23 @@ def test_poly_line_init_points_none(): @pytest.mark.market def test_poly_line_add_one_point(): line = PolyLine() - line.add(Point(4,8)) + line.add(Point(4, 8)) assert len(line.points) == 1 @pytest.mark.market def test_poly_line_add_two_points(): line = PolyLine() - line.add(Point(4,8)) - line.add(Point(2,4)) + line.add(Point(4, 8)) + line.add(Point(2, 4)) assert len(line.points) == 2 @pytest.mark.market def test_poly_line_add_points_is_sorted(): line = PolyLine() - line.add(Point(4,8)) - line.add(Point(2,4)) + line.add(Point(4, 8)) + line.add(Point(2, 4)) assert line.points[0].x == 2 @@ -156,10 +142,10 @@ def create_supply_curve(): supply_curve = PolyLine() price = 0 quantity = 0 - supply_curve.add(Point(price,quantity)) + supply_curve.add(Point(price, quantity)) price = 1000 quantity = 1000 - supply_curve.add(Point(price,quantity)) + supply_curve.add(Point(price, quantity)) return supply_curve @@ -167,8 +153,8 @@ def create_demand_curve(): demand_curve = PolyLine() price = 0 quantity = 1000 - demand_curve.add(Point(price,quantity)) + demand_curve.add(Point(price, quantity)) price = 1000 quantity = 0 - demand_curve.add(Point(price,quantity)) + demand_curve.add(Point(price, quantity)) return demand_curve diff --git a/volttrontesting/platform/base_market_agent/test_poly_line_factory.py b/volttrontesting/platform/base_market_agent/test_poly_line_factory.py index 075bcb1270..b55fd0fd6b 100644 --- a/volttrontesting/platform/base_market_agent/test_poly_line_factory.py +++ b/volttrontesting/platform/base_market_agent/test_poly_line_factory.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest diff --git a/volttrontesting/platform/control_tests/test_control.py b/volttrontesting/platform/control_tests/test_control.py index 987c33a0ac..5477b92df3 100644 --- a/volttrontesting/platform/control_tests/test_control.py +++ b/volttrontesting/platform/control_tests/test_control.py @@ -9,7 +9,7 @@ from volttron.platform.jsonrpc import RemoteError import sys - +@pytest.mark.timeout(600) @pytest.mark.control def test_agent_versions(volttron_instance): auuid = volttron_instance.install_agent( @@ -111,13 +111,14 @@ def test_prioritize_agent_valid_input(volttron_instance): assert cn.vip.rpc.call('control', 'prioritize_agent', auuid, '99').get(timeout=2) is None -@pytest.mark.xfail(reason="bytes() calls (control.py:390|398) raise: TypeError('string argument without an encoding').") @pytest.mark.parametrize('uuid, priority, expected', [ - (34, '50', "expected a string for 'uuid'"), + pytest.param(34, '50', "expected a string for 'uuid'", + marks=pytest.mark.xfail(reason="bytes() calls raise: TypeError(string argument without an encoding)")), ('34/7', '50', 'invalid agent'), ('.', '50', 'invalid agent'), ('..', '50', 'invalid agent'), - ('foo', 2, "expected a string or null for 'priority'"), + pytest.param('foo', 2, "expected a string or null for 'priority'", + marks=pytest.mark.xfail(reason="bytes() calls raise: TypeError(string argument without an encoding)")), ('foo', '-1', 'Priority must be an integer from 0 - 99.'), ('foo', '4.5', 'Priority must be an integer from 0 - 99.'), ('foo', '100', 'Priority must be an integer from 0 - 99.'), @@ -130,15 +131,16 @@ def test_prioritize_agent_invalid_input(volttron_instance, uuid, priority, expec assert expected in e.value.message +@pytest.mark.timeout(600) @pytest.mark.control -def test_recover_from_crash(get_volttron_instances): +def test_recover_from_crash(volttron_instance): """ Test if control agent periodically monitors and restarts any crashed agents :param volttron_instance: :return: """ - - volttron_instance = get_volttron_instances(1, True, agent_monitor_frequency=10) + volttron_instance.stop_platform() + volttron_instance.startup_platform(volttron_instance.vip_address, agent_monitor_frequency=20) tmpdir = tempfile.mkdtemp() os.chdir(tmpdir) @@ -158,9 +160,9 @@ def __init__(self, config_path, **kwargs): super(CrashTestAgent, self).__init__(**kwargs) @Core.receiver('onstart') - def crash_after_five_seconds(self, sender, **kwargs): + def crash_after_test_seconds(self, sender, **kwargs): print("crash test agent on start") - gevent.sleep(5) + gevent.sleep(15) print("crash test agent quitting") sys.exit(5) @@ -204,8 +206,10 @@ def main(argv=sys.argv): wheel = os.path.join(tmpdir, "dist", "crashtest-0.1-py3-none-any.whl") assert os.path.exists(wheel) - agent_uuid = volttron_instance.install_agent(agent_wheel=wheel, start=True) + agent_uuid = volttron_instance.install_agent(agent_wheel=wheel) assert agent_uuid + gevent.sleep(1) + volttron_instance.start_agent(agent_uuid) query_agent = volttron_instance.dynamic_agent status = query_agent.vip.rpc.call("control", "agent_status", agent_uuid).get( timeout=2 @@ -216,9 +220,9 @@ def main(argv=sys.argv): wait_time = 0 # wait till it has not crashed and once crashed # wait till we detect a restart or 20 seconds. - # have to do this since the test agent is hardcoded to crash 5 + # have to do this since the test agent is hardcoded to crash 15 # seconds after start - while not crashed or (not restarted and wait_time < 30): + while not crashed or (not restarted and wait_time < 50): status = query_agent.vip.rpc.call("control", "agent_status", agent_uuid).get( timeout=2 ) diff --git a/volttrontesting/platform/control_tests/test_vctl_commands.py b/volttrontesting/platform/control_tests/test_vctl_commands.py index f8f6c55701..4ac7f164f8 100644 --- a/volttrontesting/platform/control_tests/test_vctl_commands.py +++ b/volttrontesting/platform/control_tests/test_vctl_commands.py @@ -30,6 +30,7 @@ def test_needs_connection(): except AssertionError: assert not stderr.decode("utf-8") +@pytest.mark.timeout(600) @pytest.mark.control def test_needs_connection_with_connection(volttron_instance: PlatformWrapper): # Verify peerlist command works when instance is running @@ -592,4 +593,3 @@ def test_vctl_start_stop_restart_should_not_fail_on_when_no_agents_are_installed with with_os_environ(volttron_instance.env): execute_command(["vctl", subcommand, valid_option], volttron_instance.env) assert not jsonapi.loads(execute_command(["vctl", "--json", "status"], volttron_instance.env)) - \ No newline at end of file diff --git a/volttrontesting/platform/dbutils/test_mysqlfuncts.py b/volttrontesting/platform/dbutils/test_mysqlfuncts.py index 67c78bb978..78759d9606 100644 --- a/volttrontesting/platform/dbutils/test_mysqlfuncts.py +++ b/volttrontesting/platform/dbutils/test_mysqlfuncts.py @@ -23,9 +23,7 @@ IMAGES = [ - "mysql:8.0", - "mysql:5.7.35", - "mysql:5.6" + "mysql:8.0" ] CONNECTION_HOST = "localhost" @@ -105,7 +103,7 @@ def test_query_should_return_data(get_container_func, topic_ids, id_name_map, ex value_string TEXT NOT NULL, UNIQUE(topic_id, ts)); REPLACE INTO {DATA_TABLE} - VALUES ('2020-06-01 12:30:59', 43, '[2,3]') + VALUES ('2020-06-01 12:30:59', 43, '[2,3]') """ seed_database(container, query) actual_values = sqlfuncts.query(topic_ids, id_name_map) @@ -250,7 +248,7 @@ def test_get_topic_map_should_succeed(get_container_func): INSERT INTO topics (topic_name) VALUES ('football'); INSERT INTO topics (topic_name) - VALUES ('baseball'); + VALUES ('baseball'); """ seed_database(container, query) expected = ( @@ -272,7 +270,7 @@ def test_get_topic_meta_map_should_succeed(get_container_func): INSERT INTO topics (topic_name) VALUES ('football'); INSERT INTO topics (topic_name, metadata) - VALUES ('baseball', '{\\"metadata\\":\\"value\\"}'); + VALUES ('baseball', '{\\"metadata\\":\\"value\\"}'); """ seed_database(container, query) expected = {1: None, 2: {"metadata": "value"}} @@ -305,7 +303,7 @@ def test_query_topics_by_pattern_should_succeed(get_container_func): INSERT INTO {TOPICS_TABLE} (topic_name) VALUES ('foobar'); INSERT INTO {TOPICS_TABLE} (topic_name) - VALUES ('xyzzzzzzzz'); + VALUES ('xyzzzzzzzz'); """ seed_database(container, query) expected = {"football": 1, "foobar": 2} @@ -335,8 +333,8 @@ def test_insert_aggregate_stmt_should_succeed(get_container_func): container, sqlfuncts, connection_port, historian_version = get_container_func query = """ CREATE TABLE IF NOT EXISTS AVG_1776 - (ts timestamp NOT NULL, topic_id INTEGER NOT NULL, - value_string TEXT NOT NULL, topics_list TEXT, + (ts timestamp NOT NULL, topic_id INTEGER NOT NULL, + value_string TEXT NOT NULL, topics_list TEXT, UNIQUE(topic_id, ts), INDEX (ts ASC)) """ seed_database(container, query) @@ -437,7 +435,7 @@ def get_container_func(request): create_all_tables(container, historian_version) mysqlfuncts = get_mysqlfuncts(connection_port) - sleep(5) + sleep(25) # So that sqlfuncts class can check if metadata is in topics table and sets its variables accordingly mysqlfuncts.setup_historian_tables() yield container, mysqlfuncts, connection_port, historian_version @@ -510,28 +508,28 @@ def create_aggregate_tables(container, historian_version): if historian_version == "<4.0.0": query = f""" CREATE TABLE IF NOT EXISTS {AGG_TOPICS_TABLE} - (agg_topic_id INTEGER NOT NULL AUTO_INCREMENT, - agg_topic_name varchar(512) NOT NULL, - agg_type varchar(512) NOT NULL, - agg_time_period varchar(512) NOT NULL, - PRIMARY KEY (agg_topic_id), + (agg_topic_id INTEGER NOT NULL AUTO_INCREMENT, + agg_topic_name varchar(512) NOT NULL, + agg_type varchar(512) NOT NULL, + agg_time_period varchar(512) NOT NULL, + PRIMARY KEY (agg_topic_id), UNIQUE(agg_topic_name, agg_type, agg_time_period)); CREATE TABLE IF NOT EXISTS {AGG_META_TABLE} - (agg_topic_id INTEGER NOT NULL, + (agg_topic_id INTEGER NOT NULL, metadata TEXT NOT NULL, PRIMARY KEY(agg_topic_id)); """ else: query = f""" CREATE TABLE IF NOT EXISTS {AGG_TOPICS_TABLE} - (agg_topic_id INTEGER NOT NULL AUTO_INCREMENT, - agg_topic_name varchar(512) NOT NULL, - agg_type varchar(20) NOT NULL, - agg_time_period varchar(20) NOT NULL, - PRIMARY KEY (agg_topic_id), + (agg_topic_id INTEGER NOT NULL AUTO_INCREMENT, + agg_topic_name varchar(512) NOT NULL, + agg_type varchar(20) NOT NULL, + agg_time_period varchar(20) NOT NULL, + PRIMARY KEY (agg_topic_id), UNIQUE(agg_topic_name, agg_type, agg_time_period)); CREATE TABLE IF NOT EXISTS {AGG_META_TABLE} - (agg_topic_id INTEGER NOT NULL, + (agg_topic_id INTEGER NOT NULL, metadata TEXT NOT NULL, PRIMARY KEY(agg_topic_id)); """ diff --git a/volttrontesting/platform/security/SecurityAgent/security/agent.py b/volttrontesting/platform/security/SecurityAgent/security/agent.py index fd251b2bfa..404924c937 100644 --- a/volttrontesting/platform/security/SecurityAgent/security/agent.py +++ b/volttrontesting/platform/security/SecurityAgent/security/agent.py @@ -244,7 +244,7 @@ def verify_config_store_access(self, agent2_identity): """ error = None try: - self.vip.rpc.call('config.store', 'manage_store', "security_agent", 'config', + self.vip.rpc.call('config.store', 'set_config', "security_agent", 'config', json.dumps({"name": "value"}), config_type='json').get(timeout=2) except Exception as e: error = str(e) @@ -253,12 +253,12 @@ def verify_config_store_access(self, agent2_identity): return error try: - self.vip.rpc.call('config.store', 'manage_store', agent2_identity, 'config', + self.vip.rpc.call('config.store', 'set_config', agent2_identity, 'config', json.dumps({"test": "value"}), config_type='json').get(timeout=10) error = "Security agent is able to edit config store entry of security_agent2" except Exception as e: error = e.message - if error == "User can call method manage_store only with identity=security_agent " \ + if error == "User can call method set_config only with identity=security_agent " \ "but called with identity={}".format(agent2_identity): error = None diff --git a/volttrontesting/platform/security/test_aip_security.py b/volttrontesting/platform/security/test_aip_security.py index 0a45c2740e..baa1981cf1 100644 --- a/volttrontesting/platform/security/test_aip_security.py +++ b/volttrontesting/platform/security/test_aip_security.py @@ -1,13 +1,12 @@ import pwd import gevent import pytest - +import os from mock import MagicMock from volttron.platform import is_rabbitmq_available from volttron.platform import get_services_core from volttron.platform.agent.utils import execute_command -from volttron.platform.vip.agent import * from volttrontesting.fixtures.volttron_platform_fixtures import build_wrapper, cleanup_wrapper, rmq_skipif from volttrontesting.utils.utils import get_rand_vip @@ -19,9 +18,14 @@ reason="Can't run on travis as this test needs root to run " "setup script before running test case") -# Run as root or sudo scripts/secure_user_permissions.sh for both the below instance names before running these tests -INSTANCE_NAME1 = "volttron1" -INSTANCE_NAME2 = "volttron2" +# IMPORTANT steps for running this test +# 1. Make sure your test environment has acl installed (sudo apt-get install acl) +# 2. Make sure the python executable is accessible by any user. This would mean read and execute access to all +# directories in the path. For example if python is in /user/home/env/bin/python, then do chmod r+x to /user, +# and /user/home, and /user/home/env/, and /user/home/env/bin and /user/home/env/bin/python. +# 3. Run as root or sudo scripts/secure_user_permissions.sh for both the below instance names before running these +INSTANCE_NAME1 = "svolttron1" +INSTANCE_NAME2 = "svolttron2" def get_agent_user_from_dir(agent_uuid, home): diff --git a/volttrontesting/platform/test_basehistorian.py b/volttrontesting/platform/test_basehistorian.py index 1b99f8ca00..19a8fafb3b 100644 --- a/volttrontesting/platform/test_basehistorian.py +++ b/volttrontesting/platform/test_basehistorian.py @@ -16,6 +16,7 @@ from volttrontesting.platform.test_instance_setup import create_vcfg_vhome + class QueryHelper: """ Query helper allows us to mock out the Query subsystem and return default diff --git a/volttrontesting/platform/test_connection.py b/volttrontesting/platform/test_connection.py index b257c7d342..b5e69a4f47 100644 --- a/volttrontesting/platform/test_connection.py +++ b/volttrontesting/platform/test_connection.py @@ -8,12 +8,12 @@ @pytest.fixture(scope="module") -def setup_control_connection(request, get_volttron_instances): +def setup_control_connection(request, volttron_instance): """ Creates a single instance of VOLTTRON for testing purposes """ global wrapper, control_connection - wrapper = get_volttron_instances(1) + wrapper = volttron_instance request.addfinalizer(wrapper.shutdown_platform) @@ -27,14 +27,14 @@ def setup_control_connection(request, get_volttron_instances): ks = KeyStore() ks.generate() - control_connection = build_connection(identity="foo", - address=wrapper.vip_address, - peer=CONTROL, - serverkey=wrapper.serverkey, - publickey=ks.public, - secretkey=ks.secret, - instance_name=wrapper.instance_name, - message_bus=wrapper.messagebus) + control_connection = wrapper.build_connection(identity="foo", + address=wrapper.vip_address, + peer=CONTROL, + serverkey=wrapper.serverkey, + publickey=ks.public, + secretkey=ks.secret, + instance_name=wrapper.instance_name, + message_bus=wrapper.messagebus) # Sleep a couple seconds to wait for things to startup gevent.sleep(2) @@ -49,11 +49,12 @@ def test_can_connect_to_control(setup_control_connection): @pytest.mark.control -def test_can_get_peers(setup_control_connection): +def test_can_get_peers(setup_control_connection, volttron_instance): wrapper, connection = setup_control_connection peers = connection.peers() assert CONTROL in peers - assert AUTH in peers + if volttron_instance.auth_enabled: + assert AUTH in peers assert CONFIGURATION_STORE in peers diff --git a/volttrontesting/platform/test_core_agent.py b/volttrontesting/platform/test_core_agent.py index 45e265b308..548d814142 100644 --- a/volttrontesting/platform/test_core_agent.py +++ b/volttrontesting/platform/test_core_agent.py @@ -174,7 +174,9 @@ def setup_channel(self, channel_name): channel.close(linger=0) del channel - +# marking the first test with extra time out as starting RMQ instance for the first time takes longer and +# pytest.timeout applies not just for the test run alone but include fixture and clean up time +@pytest.mark.timeout(600) @pytest.mark.agent def test_channel_send_data(volttron_instance: PlatformWrapper): diff --git a/volttrontesting/platform/test_instance_setup.py b/volttrontesting/platform/test_instance_setup.py index 959864a576..d4a6961b1f 100644 --- a/volttrontesting/platform/test_instance_setup.py +++ b/volttrontesting/platform/test_instance_setup.py @@ -8,12 +8,15 @@ from volttron.platform.instance_setup import _is_agent_installed from volttron.utils import get_hostname from volttron.platform.agent.utils import is_volttron_running -from volttrontesting.fixtures.rmq_test_setup import create_rmq_volttron_setup from volttrontesting.utils.platformwrapper import create_volttron_home +from volttrontesting.utils.utils import get_rand_port HAS_RMQ = is_rabbitmq_available() RMQ_TIMEOUT = 600 +if HAS_RMQ: + from volttrontesting.fixtures.rmq_test_setup import create_rmq_volttron_setup + ''' Example variables to be used during each of the tests, depending on the prompts that will be asked @@ -40,7 +43,7 @@ is_vcp = "N" instance_name = "" vc_hostname = "" -vc_port = "8443" +vc_port = "" install_historian = "N" install_driver = "N" install_fake_device = "N" @@ -80,8 +83,9 @@ def test_zmq_case_no_agents(monkeypatch): config_path = os.path.join(vhome, "config") message_bus = "zmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = "127.0.0.15" + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) instance_name = "test_zmq" is_web_enabled = "N" is_vcp = "N" @@ -116,7 +120,7 @@ def test_zmq_case_no_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "zmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_zmq" assert not _is_agent_installed("listener") assert not _is_agent_installed("platform_driver") @@ -126,19 +130,21 @@ def test_zmq_case_no_agents(monkeypatch): assert not is_volttron_running(vhome) +@pytest.mark.timeout(400) def test_zmq_case_with_agents(monkeypatch): with create_vcfg_vhome() as vhome: monkeypatch.setenv("VOLTTRON_HOME", vhome) config_path = os.path.join(vhome, "config") message_bus = "zmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) is_web_enabled = "N" is_vcp = "Y" instance_name = "test_zmq" vc_hostname = "{}{}".format("https://", get_hostname()) - vc_port = "8443" + vc_port = str(get_rand_port(ip)) install_historian = "Y" install_driver = "Y" install_fake_device = "Y" @@ -177,7 +183,7 @@ def test_zmq_case_with_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "zmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_zmq" assert _is_agent_installed("listener") assert _is_agent_installed("platform_driver") @@ -194,12 +200,13 @@ def test_zmq_case_web_no_agents(monkeypatch): config_path = os.path.join(vhome, "config") message_bus = "zmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) instance_name = "test_zmq" is_web_enabled = "Y" web_protocol = "https" - web_port = "8443" + web_port = str(get_rand_port(ip, 8000, 9000)) gen_web_cert = "Y" new_root_ca = "Y" ca_country = "US" @@ -248,11 +255,14 @@ def test_zmq_case_web_no_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "zmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_zmq" - assert config.get('volttron', 'bind-web-address') == "{}{}{}".format("https://", get_hostname().lower(), ":8443") - assert config.get('volttron', 'web-ssl-cert') == os.path.join(vhome, "certificates", "certs", "platform_web-server.crt") - assert config.get('volttron', 'web-ssl-key') == os.path.join(vhome, "certificates", "private", "platform_web-server.pem") + assert config.get('volttron', 'bind-web-address') ==\ + "{}{}:{}".format("https://", get_hostname().lower(), web_port) + assert config.get('volttron', 'web-ssl-cert') == \ + os.path.join(vhome, "certificates", "certs", "platform_web-server.crt") + assert config.get('volttron', 'web-ssl-key') == \ + os.path.join(vhome, "certificates", "private", "platform_web-server.pem") assert not _is_agent_installed("listener") assert not _is_agent_installed("platform_driver") assert not _is_agent_installed("platform_historian") @@ -261,18 +271,20 @@ def test_zmq_case_web_no_agents(monkeypatch): assert not is_volttron_running(vhome) +@pytest.mark.timeout(400) def test_zmq_case_web_with_agents(monkeypatch): with create_vcfg_vhome() as vhome: monkeypatch.setenv("VOLTTRON_HOME", vhome) config_path = os.path.join(vhome, "config") message_bus = "zmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) instance_name = "test_zmq" is_web_enabled = "Y" web_protocol = "https" - web_port = "8443" + web_port = str(get_rand_port(ip, 8000, 9000)) gen_web_cert = "Y" new_root_ca = "Y" ca_country = "US" @@ -283,7 +295,7 @@ def test_zmq_case_web_with_agents(monkeypatch): is_vc = "N" is_vcp = "Y" vc_hostname = "{}{}".format("https://", get_hostname()) - vc_port = "8443" + vc_port = str(get_rand_port(ip)) install_historian = "Y" install_driver = "Y" install_fake_device = "Y" @@ -331,11 +343,14 @@ def test_zmq_case_web_with_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "zmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_zmq" - assert config.get('volttron', 'bind-web-address') == "{}{}{}".format("https://", get_hostname().lower(), ":8443") - assert config.get('volttron', 'web-ssl-cert') == os.path.join(vhome, "certificates", "certs", "platform_web-server.crt") - assert config.get('volttron', 'web-ssl-key') == os.path.join(vhome, "certificates", "private", "platform_web-server.pem") + assert config.get('volttron', 'bind-web-address') == \ + "{}{}:{}".format("https://", get_hostname().lower(), web_port) + assert config.get('volttron', 'web-ssl-cert') == \ + os.path.join(vhome, "certificates", "certs", "platform_web-server.crt") + assert config.get('volttron', 'web-ssl-key') == \ + os.path.join(vhome, "certificates", "private", "platform_web-server.pem") assert _is_agent_installed("listener") assert _is_agent_installed("platform_driver") assert _is_agent_installed("platform_historian") @@ -350,12 +365,13 @@ def test_zmq_case_web_vc(monkeypatch): config_path = os.path.join(vhome, "config") message_bus = "zmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) instance_name = "test_zmq" is_web_enabled = "Y" web_protocol = "https" - web_port = "8443" + web_port = str(get_rand_port(ip, 8000, 9000)) gen_web_cert = "Y" new_root_ca = "Y" ca_country = "US" @@ -406,12 +422,16 @@ def test_zmq_case_web_vc(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "zmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_zmq" - assert config.get('volttron', 'volttron-central-address') == "{}{}{}".format("https://", get_hostname().lower(), ":8443") - assert config.get('volttron', 'bind-web-address') == "{}{}{}".format("https://", get_hostname().lower(), ":8443") - assert config.get('volttron', 'web-ssl-cert') == os.path.join(vhome, "certificates", "certs", "platform_web-server.crt") - assert config.get('volttron', 'web-ssl-key') == os.path.join(vhome, "certificates", "private", "platform_web-server.pem") + assert config.get('volttron', 'volttron-central-address') == \ + "{}{}:{}".format("https://", get_hostname().lower(), web_port) + assert config.get('volttron', 'bind-web-address') == \ + "{}{}:{}".format("https://", get_hostname().lower(), web_port) + assert config.get('volttron', 'web-ssl-cert') == \ + os.path.join(vhome, "certificates", "certs", "platform_web-server.crt") + assert config.get('volttron', 'web-ssl-key') == \ + os.path.join(vhome, "certificates", "private", "platform_web-server.pem") assert not _is_agent_installed("listener") assert not _is_agent_installed("platform_driver") assert not _is_agent_installed("platform_historian") @@ -426,12 +446,13 @@ def test_zmq_case_web_vc_with_agents(monkeypatch): config_path = os.path.join(vhome, "config") message_bus = "zmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) instance_name = "test_zmq" is_web_enabled = "Y" web_protocol = "https" - web_port = "8443" + web_port = str(get_rand_port(ip, 8000, 9000)) gen_web_cert = "Y" new_root_ca = "Y" ca_country = "US" @@ -487,12 +508,16 @@ def test_zmq_case_web_vc_with_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "zmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_zmq" - assert config.get('volttron', 'volttron-central-address') == "{}{}{}".format("https://", get_hostname().lower(), ":8443") - assert config.get('volttron', 'bind-web-address') == "{}{}{}".format("https://", get_hostname().lower(), ":8443") - assert config.get('volttron', 'web-ssl-cert') == os.path.join(vhome, "certificates", "certs", "platform_web-server.crt") - assert config.get('volttron', 'web-ssl-key') == os.path.join(vhome, "certificates", "private", "platform_web-server.pem") + assert config.get('volttron', 'volttron-central-address') == \ + "{}{}:{}".format("https://", get_hostname().lower(), web_port) + assert config.get('volttron', 'bind-web-address') == \ + "{}{}:{}".format("https://", get_hostname().lower(), web_port) + assert config.get('volttron', 'web-ssl-cert') == \ + os.path.join(vhome, "certificates", "certs", "platform_web-server.crt") + assert config.get('volttron', 'web-ssl-key') == \ + os.path.join(vhome, "certificates", "private", "platform_web-server.pem") assert _is_agent_installed("listener") assert _is_agent_installed("platform_driver") assert _is_agent_installed("platform_historian") @@ -511,8 +536,9 @@ def test_rmq_case_no_agents(monkeypatch): message_bus = "rmq" instance_name = "test_rmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) is_web_enabled = "N" is_vcp = "N" install_historian = "N" @@ -546,7 +572,7 @@ def test_rmq_case_no_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "rmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_rmq" assert not _is_agent_installed("listener") assert not _is_agent_installed("platform_driver") @@ -566,12 +592,13 @@ def test_rmq_case_with_agents(monkeypatch): message_bus = "rmq" instance_name = "test_rmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) is_web_enabled = "N" is_vcp = "Y" vc_hostname = "{}{}".format("https://", get_hostname()) - vc_port = "8443" + vc_port = str(get_rand_port(ip)) install_historian = "Y" install_driver = "Y" install_fake_device = "Y" @@ -612,7 +639,7 @@ def test_rmq_case_with_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "rmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_rmq" assert _is_agent_installed("listener") assert _is_agent_installed("platform_driver") @@ -634,11 +661,12 @@ def test_rmq_case_web_no_agents(monkeypatch): message_bus = "rmq" instance_name = "test_rmq" is_web_enabled = "Y" - web_port = "8443" is_vc = "N" is_vcp = "N" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + web_port = str(get_rand_port(ip, 8000, 9000)) + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) install_historian = "N" install_driver = "N" install_listener = "N" @@ -672,9 +700,9 @@ def test_rmq_case_web_no_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "rmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_rmq" - assert config.get('volttron', 'bind-web-address') == "{}{}{}".format("https://", get_hostname(), ":8443") + assert config.get('volttron', 'bind-web-address') == "{}{}:{}".format("https://", get_hostname(), web_port) assert not _is_agent_installed("listener") assert not _is_agent_installed("platform_driver") assert not _is_agent_installed("platform_historian") @@ -694,13 +722,14 @@ def test_rmq_case_web_with_agents(monkeypatch): message_bus = "rmq" instance_name = "test_rmq" is_web_enabled = "Y" - web_port = "8443" is_vc = "N" is_vcp = "Y" vc_hostname = "{}{}".format("https://", get_hostname()) - vc_port = "8443" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + web_port = str(get_rand_port(ip, 8000, 9000)) + vc_port = str(get_rand_port(ip)) + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) install_historian = "Y" install_driver = "Y" install_fake_device = "Y" @@ -742,9 +771,9 @@ def test_rmq_case_web_with_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "rmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_rmq" - assert config.get('volttron', 'bind-web-address') == "{}{}{}".format("https://", get_hostname(), ":8443") + assert config.get('volttron', 'bind-web-address') == "{}{}:{}".format("https://", get_hostname(), web_port) assert _is_agent_installed("listener") assert _is_agent_installed("platform_driver") assert _is_agent_installed("platform_historian") @@ -764,10 +793,11 @@ def test_rmq_case_web_vc(monkeypatch): message_bus = "rmq" instance_name = "test_rmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) is_web_enabled = "Y" - web_port = "8443" + web_port = str(get_rand_port(ip, 8000, 9000)) is_vc = "Y" is_vcp = "Y" install_historian = "N" @@ -806,10 +836,12 @@ def test_rmq_case_web_vc(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "rmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address assert config.get('volttron', 'instance-name').strip('"') == "test_rmq" - assert config.get('volttron', 'volttron-central-address') == "{}{}{}".format("https://", get_hostname(), ":8443") - assert config.get('volttron', 'bind-web-address') == "{}{}{}".format("https://", get_hostname(), ":8443") + assert config.get('volttron', 'volttron-central-address') == "{}{}:{}".format( + "https://", get_hostname(), web_port) + assert config.get('volttron', 'bind-web-address') == "{}{}:{}".format( + "https://", get_hostname(), web_port) assert not _is_agent_installed("listener") assert not _is_agent_installed("platform_driver") assert not _is_agent_installed("platform_historian") @@ -829,10 +861,11 @@ def test_rmq_case_web_vc_with_agents(monkeypatch): message_bus = "rmq" instance_name = "test_rmq" - vip_address = "tcp://127.0.0.15" - vip_port = "22916" + ip = '127.0.0.15' + vip_address = "tcp://" + ip + vip_port = str(get_rand_port(ip)) is_web_enabled = "Y" - web_port = "8443" + web_port = str(get_rand_port(ip, 8000, 9000)) is_vc = "Y" is_vcp = "Y" install_historian = "Y" @@ -876,10 +909,12 @@ def test_rmq_case_web_vc_with_agents(monkeypatch): config = ConfigParser() config.read(config_path) assert config.get('volttron', 'message-bus') == "rmq" - assert config.get('volttron', 'vip-address') == "tcp://127.0.0.15:22916" + assert config.get('volttron', 'vip-address') == vip_address + ":" + vip_port assert config.get('volttron', 'instance-name').strip('"') == "test_rmq" - assert config.get('volttron', 'volttron-central-address') == "{}{}{}".format("https://", get_hostname(), ":8443") - assert config.get('volttron', 'bind-web-address') == "{}{}{}".format("https://", get_hostname(), ":8443") + assert config.get('volttron', 'volttron-central-address') == "{}{}:{}".format( + "https://", get_hostname(), web_port) + assert config.get('volttron', 'bind-web-address') == "{}{}:{}".format( + "https://", get_hostname(), web_port) assert _is_agent_installed("listener") assert _is_agent_installed("platform_driver") assert _is_agent_installed("platform_historian") @@ -930,12 +965,13 @@ def test_web_with_agents_volttron_running(monkeypatch, volttron_instance_web): assert os.path.exists(config_path) config = ConfigParser() config.read(config_path) - assert config.get('volttron', 'message-bus') == "zmq" - if volttron_instance_web.ssl_auth is True: + assert config.get('volttron', 'message-bus') == volttron_instance_web.messagebus + if volttron_instance_web.ssl_auth is True and volttron_instance_web.messagebus == 'zmq': assert config.get('volttron', 'web-ssl-cert') == os.path.join(vhome, "certificates", "certs", "server0.crt") assert config.get('volttron', 'web-ssl-key') == os.path.join(vhome, "certificates", "private", "server0.pem") - assert _is_agent_installed("listener") - assert _is_agent_installed("platform_driver") - assert _is_agent_installed("platform_historian") - assert _is_agent_installed("vcp") + # if instance is running + assert not _is_agent_installed("listener") + # assert _is_agent_installed("platform_driver") + # assert _is_agent_installed("platform_historian") + # assert _is_agent_installed("vcp") assert is_volttron_running(vhome) diff --git a/volttrontesting/platform/test_packaging.py b/volttrontesting/platform/test_packaging.py index 4465b30182..4de2f006ee 100644 --- a/volttrontesting/platform/test_packaging.py +++ b/volttrontesting/platform/test_packaging.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/volttrontesting/platform/test_platform_init.py b/volttrontesting/platform/test_platform_init.py index bb61e5e76b..98c17e6623 100644 --- a/volttrontesting/platform/test_platform_init.py +++ b/volttrontesting/platform/test_platform_init.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import pytest diff --git a/volttrontesting/platform/test_platform_rmq.py b/volttrontesting/platform/test_platform_rmq.py index 08c47aa528..b4aaa6199e 100644 --- a/volttrontesting/platform/test_platform_rmq.py +++ b/volttrontesting/platform/test_platform_rmq.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ Test cases to test volttron platform with rmq and ssl auth. diff --git a/volttrontesting/platform/test_platform_web.py b/volttrontesting/platform/test_platform_web.py index 1bf18481bf..9fbcbd9d19 100644 --- a/volttrontesting/platform/test_platform_web.py +++ b/volttrontesting/platform/test_platform_web.py @@ -229,8 +229,8 @@ def test_test_web_agent(volttron_instance_web): @pytest.mark.web -def test_register_path_route(web_instance): - vi = web_instance +def test_register_path_route(volttron_instance_web): + vi = volttron_instance_web with with_os_environ(vi.env): assert vi.is_running() diff --git a/volttrontesting/platform/test_rmq_platform_shutdown.py b/volttrontesting/platform/test_rmq_platform_shutdown.py index ad81d43dcc..71d46a524d 100644 --- a/volttrontesting/platform/test_rmq_platform_shutdown.py +++ b/volttrontesting/platform/test_rmq_platform_shutdown.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import psutil @@ -52,6 +38,9 @@ pytestmark = [pytest.mark.xfail] +pytestmark = [pytest.mark.xfail] + + @pytest.mark.rmq_shutdown def test_vctl_shutdown_on_rmq_stop(request): """ diff --git a/volttrontesting/platform/test_rmq_reconnect.py b/volttrontesting/platform/test_rmq_reconnect.py index f03090223f..726bf8d593 100644 --- a/volttrontesting/platform/test_rmq_reconnect.py +++ b/volttrontesting/platform/test_rmq_reconnect.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ diff --git a/volttrontesting/platform/test_sqlite3_fix.py b/volttrontesting/platform/test_sqlite3_fix.py index 81983029e5..b6018c1ac3 100644 --- a/volttrontesting/platform/test_sqlite3_fix.py +++ b/volttrontesting/platform/test_sqlite3_fix.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from dateutil.parser import parse @@ -43,29 +29,29 @@ def test_sqlite_fix_current(): now_string = '2015-12-17 00:00:00.000005Z' now = parse(now_string) - + now_string_tz = '2015-12-17 00:00:00Z' now_tz = parse(now_string_tz) - + # Patch the global sqlite3 fix_sqlite3_datetime() - + conn = sql.connect(':memory:', detect_types=sql.PARSE_DECLTYPES|sql.PARSE_COLNAMES) - + cur = conn.cursor() cur.execute("create table test(ts timestamp)") - - cur.execute("delete from test") + + cur.execute("delete from test") cur.execute("insert into test(ts) values (?)", (now,)) - + cur.execute("select * from test") test_now = cur.fetchone()[0] - - cur.execute("delete from test") + + cur.execute("delete from test") cur.execute("insert into test(ts) values (?)", (now_tz,)) - + cur.execute("select * from test") test_now_tz = cur.fetchone()[0] - + assert test_now == now assert test_now_tz == now_tz diff --git a/volttrontesting/platform/test_vcfg_config_update.py b/volttrontesting/platform/test_vcfg_config_update.py new file mode 100644 index 0000000000..c34fdfa652 --- /dev/null +++ b/volttrontesting/platform/test_vcfg_config_update.py @@ -0,0 +1,467 @@ +import json + +import pytest +import os +import shutil +import subprocess +from csv import DictReader +from io import StringIO + +from volttrontesting.utils.platformwrapper import create_volttron_home +from volttron.platform.agent.utils import parse_json_config +from volttrontesting.fixtures.volttron_platform_fixtures import build_wrapper, cleanup_wrapper +from volttrontesting.utils.utils import get_rand_vip + +METATADATA_FILE_FORMAT = """Metadata file format: +{ "vip-id": [ + { + "config-name": "optional. name. defaults to config + "config": "json config or string config or config file name", + "config-type": "optional. type of config - csv or json or raw. defaults to json" + }, ... + ],... +}""" + + +@pytest.fixture(scope="module") +def shared_vhome(): + debug_flag = os.environ.get('DEBUG', False) + vhome = create_volttron_home() + yield vhome + if not debug_flag: + shutil.rmtree(vhome, ignore_errors=True) + + +@pytest.fixture() +def vhome(): + debug_flag = os.environ.get('DEBUG', False) + vhome = create_volttron_home() + yield vhome + if not debug_flag: + shutil.rmtree(vhome, ignore_errors=True) + + +@pytest.fixture(scope="module") +def single_vinstance(): + address = get_rand_vip() + wrapper = build_wrapper(address, + messagebus='zmq', + ssl_auth=False, + auth_enabled=False) + yield wrapper + cleanup_wrapper(wrapper) + + +# Only integration test. Rest are unit tests +def test_fail_if_volttron_is_running(single_vinstance, monkeypatch): + monkeypatch.setenv("VOLTTRON_HOME", single_vinstance.volttron_home) + process = subprocess.run(["vcfg", "--vhome", single_vinstance.volttron_home, + "update-config-store", "--metadata-file", "test"], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + assert process.stdout.decode("utf-8").startswith( + f"VOLTTRON is running using at {single_vinstance.volttron_home}, " + f"you can add/update single configuration using vctl config command.") + assert process.returncode == 1 + + +def test_help(monkeypatch, shared_vhome): + monkeypatch.setenv("VOLTTRON_HOME", shared_vhome) + process = subprocess.run(["vcfg", "--vhome", shared_vhome, "update-config-store", "--help"], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + assert process.stdout.startswith(b"usage: vcfg update-config-store [-h] --metadata-file METADATA_FILE") + + +def test_no_arg(monkeypatch, shared_vhome): + monkeypatch.setenv("VOLTTRON_HOME", shared_vhome) + process = subprocess.run(["vcfg", "--vhome", shared_vhome, "update-config-store"], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + assert process.stderr.startswith(b"usage: vcfg update-config-store [-h] --metadata-file METADATA_FILE") + + +def test_no_args_value(monkeypatch, shared_vhome): + monkeypatch.setenv("VOLTTRON_HOME", shared_vhome) + process = subprocess.run(["vcfg", "--vhome", shared_vhome, "update-config-store", "--metadata-file"], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + assert process.stderr.startswith(b"usage: vcfg update-config-store [-h] --metadata-file METADATA_FILE") + + +def test_invalid_file_path(monkeypatch, shared_vhome): + monkeypatch.setenv("VOLTTRON_HOME", shared_vhome) + process = subprocess.run(["vcfg", "--vhome", shared_vhome, "update-config-store", "--metadata-file", "invalid"], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + expected_message = "Value is neither a file nor a directory: ['invalid']: \n" \ + "The --metadata-file accepts one or more metadata " \ + "files or directory containing metadata file\n\n" + METATADATA_FILE_FORMAT + + assert process.stdout.decode('utf-8').strip() == expected_message + assert process.returncode == 1 + + +@pytest.mark.parametrize('json_metadata, json_file, config_name', [ + ({"vip-id-1": {}}, "no_config_json1", "config"), + ({"vip-id-1": [{"config-name": "config"}]}, "no_config_json2", "config"), + ({"vip-id-1": [{"config-name": "new_config", "config_type": "json"}]}, "no_config_json2", "new_config") +]) +def test_no_config_metadata(monkeypatch, vhome, json_metadata, json_file, config_name): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + file_path = os.path.join(vhome, json_file) + with open(file_path, "w") as f: + f.write(json.dumps(json_metadata)) + expected_message = f"No config entry found in file {file_path} for vip-id vip-id-1 and " \ + f"config-name {config_name}\n\n" + METATADATA_FILE_FORMAT + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == expected_message + assert process.returncode == 1 + + +def test_invalid_config_class(monkeypatch, vhome): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + file_path = os.path.join(vhome, "invalid_config_class.json") + with open(file_path, "w") as f: + f.write(json.dumps({"vip-id-1": "string config"})) + expected_message = f"Metadata for vip-identity vip-id-1 in file {file_path} should be a dictionary or " \ + f"list of dictionary. Got type \n\n" + METATADATA_FILE_FORMAT + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == expected_message + assert process.returncode == 1 + + +def test_incorrect_config_type(monkeypatch, vhome): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + file_path = os.path.join(vhome, "invalid_config_type.json") + with open(file_path, "w") as f: + f.write(json.dumps({"vip-id-1": {"config": "string config for json config-type", + "config-type": "json"}})) + expected_message = 'Value for key "config" should be one of the following: \n' \ + '1. filepath \n'\ + '2. string with "config-type" set to "raw" \n'\ + '3. a dictionary \n'\ + '4. list \n\n' + METATADATA_FILE_FORMAT + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == expected_message + assert process.returncode == 1 + + +def test_raw_config_in_single_metafile(monkeypatch, vhome): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + file_path = os.path.join(vhome, "single_config.json") + with open(file_path, "w") as f: + f.write(json.dumps({"agent1": {"config": "string config", + "config-type": "raw"}})) + + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == '' + assert process.stderr.decode('utf-8').strip() == '' + assert process.returncode == 0 + store_path = os.path.join(vhome, "configuration_store/agent1.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert store["config"]["data"] == "string config" + assert store["config"]["type"] == "raw" + initial_modified_time = store["config"]["modified"] + + # now try list of raw config with 1 new and 1 existing + file_path = os.path.join(vhome, "two_config.json") + with open(file_path, "w") as f: + f.write(json.dumps( + {"agent1": [ + {"config": "string config", "config-type": "raw"}, + {"config-name": "new_config", "config-type": "raw", "config": "another string config"} + ] + } + )) + + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == '' + assert process.stderr.decode('utf-8').strip() == '' + assert process.returncode == 0 + store_path = os.path.join(vhome, "configuration_store/agent1.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert store["config"]["data"] == "string config" + assert store["config"]["type"] == "raw" + assert initial_modified_time == store["config"]["modified"] + + assert store["new_config"] + assert store["new_config"]["data"] == "another string config" + assert store["new_config"]["type"] == "raw" + assert store["new_config"]["modified"] + assert store["new_config"]["modified"] != initial_modified_time + + +def test_json_config_in_single_metafile(monkeypatch, vhome): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + json_data = {"config_key1": "config_value1"} + file_path = os.path.join(vhome, "single_config.json") + with open(file_path, "w") as f: + f.write(json.dumps({"agent2": {"config": json_data, + "config-type": "json"}})) + + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == '' + assert process.stderr.decode('utf-8').strip() == '' + assert process.returncode == 0 + store_path = os.path.join(vhome, "configuration_store/agent2.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert parse_json_config(store["config"]["data"]) == json_data + assert store["config"]["type"] == "json" + initial_modified_time = store["config"]["modified"] + + +def test_csv_configfile_in_single_metafile(monkeypatch, vhome): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + csv_file = os.path.join(vhome, "config.csv") + csv_str = "point_name,type\npoint1,boolean\npoint2,int" + csv_list = [{"point_name": "point1", "type": "boolean"}, {"point_name": "point2", "type": "int"}] + with open(csv_file, "w") as f: + f.write(csv_str) + file_path = os.path.join(vhome, "single_config.json") + with open(file_path, "w") as f: + f.write(json.dumps({"agent3": {"config": csv_file, + "config-type": "csv"}})) + + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == '' + assert process.stderr.decode('utf-8').strip() == '' + assert process.returncode == 0 + store_path = os.path.join(vhome, "configuration_store/agent3.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + f = StringIO(store["config"]["data"]) + csv_list_in_store = [x for x in DictReader(f)] + assert csv_list_in_store == csv_list + assert store["config"]["type"] == "csv" + initial_modified_time = store["config"]["modified"] + + +def test_single_metafile_two_agent(monkeypatch, vhome): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + file_path = os.path.join(vhome, "single_config.json") + with open(file_path, "w") as f: + f.write(json.dumps( + {"agent1": {"config": "string config", "config-type": "raw"}, + "agent2": [ + {"config": "string config", "config-type": "raw"}, + {"config-name": "new_config", "config-type": "raw", "config": "another string config"} + ] + })) + + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == '' + assert process.stderr.decode('utf-8').strip() == '' + assert process.returncode == 0 + store_path = os.path.join(vhome, "configuration_store/agent1.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert store["config"]["data"] == "string config" + assert store["config"]["type"] == "raw" + assert store["config"]["modified"] + + store_path = os.path.join(vhome, "configuration_store/agent2.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert store["config"]["data"] == "string config" + assert store["config"]["type"] == "raw" + assert store["config"]["modified"] + + assert store["new_config"] + assert store["new_config"]["data"] == "another string config" + assert store["new_config"]["type"] == "raw" + assert store["new_config"]["modified"] + + +def test_two_metafile(monkeypatch, vhome): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + file_path1 = os.path.join(vhome, "meta1.json") + with open(file_path1, "w") as f: + f.write(json.dumps({"agent1": {"config": "string config", "config-type": "raw"}})) + file_path2 = os.path.join(vhome, "meta2.json") + with open(file_path2, "w") as f: + f.write(json.dumps( + {"agent2": [ + {"config": "string config", "config-type": "raw"}, + {"config-name": "new_config", "config-type": "raw", "config": "another string config"} + ] + })) + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", file_path1, file_path2], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == '' + assert process.stderr.decode('utf-8').strip() == '' + assert process.returncode == 0 + store_path = os.path.join(vhome, "configuration_store/agent1.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert store["config"]["data"] == "string config" + assert store["config"]["type"] == "raw" + assert store["config"]["modified"] + + store_path = os.path.join(vhome, "configuration_store/agent2.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert store["config"]["data"] == "string config" + assert store["config"]["type"] == "raw" + assert store["config"]["modified"] + + assert store["new_config"] + assert store["new_config"]["data"] == "another string config" + assert store["new_config"]["type"] == "raw" + assert store["new_config"]["modified"] + + +def test_meta_dir(monkeypatch, vhome): + monkeypatch.setenv("VOLTTRON_HOME", vhome) + meta_dir = os.path.join(vhome, "meta_dir") + os.mkdir(meta_dir) + file_path1 = os.path.join(meta_dir, "meta1.json") + with open(file_path1, "w") as f: + f.write(json.dumps({"agent1": {"config": "string config", "config-type": "raw"}})) + file_path2 = os.path.join(meta_dir, "meta2.json") + with open(file_path2, "w") as f: + f.write(json.dumps( + {"agent2": [ + {"config": "string config", "config-type": "raw"}, + {"config-name": "new_config", "config-type": "raw", "config": "another string config"} + ] + })) + process = subprocess.run(["vcfg", "--vhome", vhome, + "update-config-store", "--metadata-file", meta_dir], + env=os.environ, + cwd=os.environ.get("VOLTTRON_ROOT"), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + + assert process.stdout.decode('utf-8').strip() == '' + assert process.stderr.decode('utf-8').strip() == '' + assert process.returncode == 0 + store_path = os.path.join(vhome, "configuration_store/agent1.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert store["config"]["data"] == "string config" + assert store["config"]["type"] == "raw" + assert store["config"]["modified"] + + store_path = os.path.join(vhome, "configuration_store/agent2.store") + assert os.path.isfile(store_path) + with open(store_path) as f: + store = parse_json_config(f.read()) + + assert store["config"] + assert store["config"]["data"] == "string config" + assert store["config"]["type"] == "raw" + assert store["config"]["modified"] + + assert store["new_config"] + assert store["new_config"]["data"] == "another string config" + assert store["new_config"]["type"] == "raw" + assert store["new_config"]["modified"] diff --git a/volttrontesting/platform/web/test_admin_endpoints.py b/volttrontesting/platform/web/test_admin_endpoints.py index ffd7ba2a54..4efbd02d4c 100644 --- a/volttrontesting/platform/web/test_admin_endpoints.py +++ b/volttrontesting/platform/web/test_admin_endpoints.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttrontesting/platform/web/test_certs.py b/volttrontesting/platform/web/test_certs.py index 08e79788a5..f56d91ccf1 100644 --- a/volttrontesting/platform/web/test_certs.py +++ b/volttrontesting/platform/web/test_certs.py @@ -60,8 +60,8 @@ # defaults to true ssl: 'true' -# defaults to ~/rabbitmq_server/rabbbitmq_server-3.9.7 -rmq-home: "~/rabbitmq_server/rabbitmq_server-3.9.7" +# defaults to ~/rabbitmq_server/rabbbitmq_server-3.9.29 +rmq-home: "~/rabbitmq_server/rabbitmq_server-3.9.29" """ diff --git a/volttrontesting/platform/web/test_discovery.py b/volttrontesting/platform/web/test_discovery.py index 184138a2b7..5b2ab40641 100644 --- a/volttrontesting/platform/web/test_discovery.py +++ b/volttrontesting/platform/web/test_discovery.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} diff --git a/volttrontesting/platform/web/test_topic_tree.py b/volttrontesting/platform/web/test_topic_tree.py index c411495e85..f9606d25a9 100644 --- a/volttrontesting/platform/web/test_topic_tree.py +++ b/volttrontesting/platform/web/test_topic_tree.py @@ -241,17 +241,17 @@ def test_devices(nid, expected): def _mock_rpc_caller(peer, method, agent, file_name=None, raw=False, external_platform=None): - if method == 'manage_list_configs': + if method == 'list_configs': return ['config', 'devices/Campus/Building1/Fake1', 'devices/Campus/Building2/Fake1', 'devices/Campus/Building3/Fake1', 'registry_configs/fake.csv'] - elif method == 'manage_get' and '.csv' in file_name: + elif method == 'get_config' and '.csv' in file_name: return [{'Point Name': 'SampleBool1', 'Volttron Point Name': 'SampleBool1', 'Units': 'On / Off', 'Units Details': 'on/off', 'Writable': 'FALSE', 'Starting Value': 'TRUE', 'Type': 'boolean', 'Notes': 'Status indidcator of cooling stage 1'}, {'Point Name': 'SampleWritableFloat1', 'Volttron Point Name': 'SampleWritableFloat1', 'Units': 'PPM', 'Units Details': '1000.00 (default)', 'Writable': 'TRUE', 'Starting Value': '10', 'Type': 'float', 'Notes': 'Setpoint to enable demand control ventilation'}] - elif method == 'manage_get' and '.csv' not in file_name: + elif method == 'get_config' and '.csv' not in file_name: return {'driver_config': {}, 'registry_config': 'config://registry_configs/fake.csv', 'interval': 60, 'timezone': 'US/Pacific', 'driver_type': 'fakedriver', 'publish_breadth_first_all': False, 'publish_depth_first': False, 'publish_breadth_first': False, 'campus': 'campus', diff --git a/volttrontesting/platform/web/test_vui_endpoints.py b/volttrontesting/platform/web/test_vui_endpoints.py index fc47becc94..fccc475f41 100644 --- a/volttrontesting/platform/web/test_vui_endpoints.py +++ b/volttrontesting/platform/web/test_vui_endpoints.py @@ -277,16 +277,16 @@ def _mock_agents_rpc(peer, meth, *args, external_platform=None, **kwargs): 'config2': {'setting1': 3, 'setting2': 4}}}, {'identity': 'run2', 'configs': {'config1': {'setting1': 5, 'setting2': 6}, 'config2': {'setting1': 7, 'setting2': 8}}}] - if peer == 'config.store' and meth == 'manage_get': + if peer == 'config.store' and meth == 'get_config': config_list = [a['configs'].get(args[1]) for a in config_definition_list if a['identity'] == args[0]] if not config_list or config_list == [None]: raise RemoteError(f'''builtins.KeyError('No configuration file \"{args[1]}\" for VIP IDENTIY {args[0]}')''', exc_info={"exc_type": '', "exc_args": []}) return config_list[0] if config_list else [] - elif peer == 'config.store' and meth == 'manage_list_configs': + elif peer == 'config.store' and meth == 'list_configs': config_list = [a['configs'].keys() for a in config_definition_list if a['identity'] == args[0]] return config_list[0] if config_list else [] - elif peer == 'config.store' and meth == 'manage_list_stores': + elif peer == 'config.store' and meth == 'list_stores': return [a['identity'] for a in config_definition_list] elif peer == 'control' and meth == 'list_agents': return list_of_agents @@ -458,7 +458,7 @@ def test_handle_platforms_agents_configs_config_put_response(mock_platform_web_s config_type = re.search(r'([^\/]+$)', config_type).group() if config_type in ['application/json', 'text/csv'] else 'raw' if status == '204': - vui_endpoints._rpc.assert_has_calls([mock.call('config.store', 'manage_store', vip_identity, config_name, + vui_endpoints._rpc.assert_has_calls([mock.call('config.store', 'set_config', vip_identity, config_name, data_passed, config_type, external_platform='my_instance_name')]) elif status == '400': assert json.loads(response.response[0]) == \ @@ -488,7 +488,7 @@ def test_handle_platforms_agents_configs_post_response(mock_platform_web_service response = vui_endpoints.handle_platforms_agents_configs(env, data_given) check_response_codes(response, status) if status == '204': - vui_endpoints._rpc.assert_has_calls([mock.call('config.store', 'manage_store', vip_identity, config_name, + vui_endpoints._rpc.assert_has_calls([mock.call('config.store', 'set_config', vip_identity, config_name, data_passed, config_type, external_platform='my_instance_name')]) elif status == '400': assert json.loads(response.response[0]) == \ @@ -510,7 +510,7 @@ def test_handle_platforms_agents_configs_delete_response(mock_platform_web_servi response = vui_endpoints.handle_platforms_agents_configs(env, {}) check_response_codes(response, status) if status == '204': - vui_endpoints._rpc.assert_has_calls([mock.call('config.store', 'manage_delete_store', vip_identity_passed, + vui_endpoints._rpc.assert_has_calls([mock.call('config.store', 'delete_store', vip_identity_passed, external_platform='my_instance_name')]) @@ -526,7 +526,7 @@ def test_handle_platforms_agents_configs_config_delete_response(mock_platform_we response = vui_endpoints.handle_platforms_agents_configs(env, {}) check_response_codes(response, status) if status == '204': - vui_endpoints._rpc.assert_has_calls([mock.call('config.store', 'manage_delete_config', vip_identity, + vui_endpoints._rpc.assert_has_calls([mock.call('config.store', 'delete_config', vip_identity, config_name_passed, external_platform='my_instance_name')]) diff --git a/volttrontesting/services/aggregate_historian/copy_test_data.py b/volttrontesting/services/aggregate_historian/copy_test_data.py index ac019e4542..2e43ca65a4 100644 --- a/volttrontesting/services/aggregate_historian/copy_test_data.py +++ b/volttrontesting/services/aggregate_historian/copy_test_data.py @@ -36,13 +36,13 @@ def connect_mongodb(connection_params): - print ("setup mongodb") + print("setup mongodb") mongo_conn_str = 'mongodb://{user}:{passwd}@{host}:{port}/{database}' if connection_params.get('authSource'): mongo_conn_str = mongo_conn_str+ '?authSource={authSource}' params = connection_params mongo_conn_str = mongo_conn_str.format(**params) - print (mongo_conn_str) + print(mongo_conn_str) mongo_client = pymongo.MongoClient(mongo_conn_str) db = mongo_client[connection_params['database']] return db @@ -118,7 +118,7 @@ def copy(source_params, dest_params, start_date, end_date): {'$and': [{'_id': {'$gte': ObjectId.from_datetime(start_date)}}, {'_id': {'$lte': ObjectId.from_datetime(end_date)}}]}) - print ("Record count from cursor {}".format(cursor.count())) + print("Record count from cursor {}".format(cursor.count())) for record in cursor: i += 1 records.append( diff --git a/volttrontesting/services/aggregate_historian/test_aggregate_historian.py b/volttrontesting/services/aggregate_historian/test_aggregate_historian.py index 7d7107b63b..642b77ad5a 100644 --- a/volttrontesting/services/aggregate_historian/test_aggregate_historian.py +++ b/volttrontesting/services/aggregate_historian/test_aggregate_historian.py @@ -192,7 +192,7 @@ def setup_mysql(connection_params, table_names): - print ("setup mysql") + print("setup mysql") db_connection = mysql.connect(**connection_params) # clean up any rows from older runs cleanup_mysql(db_connection, None, drop_tables=True) @@ -200,11 +200,11 @@ def setup_mysql(connection_params, table_names): def setup_sqlite(connection_params, table_names): - print ("setup sqlite") + print("setup sqlite") database_path = connection_params['database'] - print ("connecting to sqlite path " + database_path) + print("connecting to sqlite path " + database_path) db_connection = sqlite3.connect(database_path) - print ("successfully connected to sqlite") + print("successfully connected to sqlite") cleanup_sqlite(db_connection, None, drop_tables=True) db_connection.commit() return db_connection @@ -328,9 +328,9 @@ def get_table_names(config): def publish_test_data(publish_agent, start_time, start_reading, count): reading = start_reading time = start_time - print ("publishing test data starttime is {} utcnow is {}".format( + print("publishing test data starttime is {} utcnow is {}".format( start_time, datetime.utcnow())) - print ("publishing test data value string {} at {}".format(reading, + print("publishing test data value string {} at {}".format(reading, datetime.now())) float_meta = {'units': 'F', 'tz': 'UTC', 'type': 'float'} @@ -426,7 +426,7 @@ def aggregate_agent(request, volttron_instance): # Set this hear so that we can create these table after connecting to db table_names = get_table_names(request.param) - print ("request.param -- {}".format(request.param)) + print("request.param -- {}".format(request.param)) # 2: Open db connection that can be used for row deletes after # each test method. Clean up old tables if any @@ -490,7 +490,7 @@ def test_get_supported_aggregations(aggregate_agent, query_agent): :param query_agent: fake agent used to query historian :return: """ - query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", + query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", AGG_AGENT_VIP, "config", aggregate_agent).get() gevent.sleep(1) @@ -502,7 +502,7 @@ def test_get_supported_aggregations(aggregate_agent, query_agent): 'get_supported_aggregations').get(timeout=10) assert result - print (result) + print(result) conn = aggregate_agent.get("connection") if conn: if conn.get("type") == "mysql": @@ -565,7 +565,7 @@ def test_single_topic_pattern(aggregate_agent, query_agent): ] } ] - query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", + query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", AGG_AGENT_VIP, "config", new_config).get() gevent.sleep(1) @@ -668,7 +668,7 @@ def test_single_topic(aggregate_agent, query_agent): ] } ] - query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", + query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", AGG_AGENT_VIP, "config", new_config).get() gevent.sleep(3 * 60) # sleep till we see two rows in aggregate table @@ -841,7 +841,7 @@ def test_multiple_topic_pattern(aggregate_agent, query_agent): } ] - query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", + query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", AGG_AGENT_VIP, "config", new_config).get() gevent.sleep(1) @@ -914,7 +914,7 @@ def test_multiple_topic_list(aggregate_agent, query_agent): } ] - query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", + query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", AGG_AGENT_VIP, "config", new_config).get() gevent.sleep(1) @@ -991,7 +991,7 @@ def test_topic_reconfiguration(aggregate_agent, query_agent): } ] - query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", + query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", AGG_AGENT_VIP, "config", new_config).get() gevent.sleep(2) @@ -1037,11 +1037,11 @@ def test_topic_reconfiguration(aggregate_agent, query_agent): print("Before reinstall current time is {}".format(datetime.utcnow())) - query_agent.vip.rpc.call(CONFIGURATION_STORE, "manage_store", + query_agent.vip.rpc.call(CONFIGURATION_STORE, "set_config", AGG_AGENT_VIP, "config", new_config).get() - print ("After configure\n\n") + print("After configure\n\n") gevent.sleep(3) result1 = query_agent.vip.rpc.call( diff --git a/volttrontesting/services/aggregate_historian/test_base_aggregate_historian.py b/volttrontesting/services/aggregate_historian/test_base_aggregate_historian.py index c3931725cf..ede35b0ca5 100644 --- a/volttrontesting/services/aggregate_historian/test_base_aggregate_historian.py +++ b/volttrontesting/services/aggregate_historian/test_base_aggregate_historian.py @@ -124,7 +124,7 @@ def test_time_slice_calculation_realtime(): # month aggregation period start, end = AggregateHistorian.compute_aggregation_time_slice( utc_collection_start_time, '2M', False) - print (start, end) + print(start, end) assert end == utc_collection_start_time assert start == utc_collection_start_time - timedelta(days=60) try: diff --git a/volttrontesting/services/historian/test_base_historian.py b/volttrontesting/services/historian/test_base_historian.py index 4771e257a5..04df3ee4be 100644 --- a/volttrontesting/services/historian/test_base_historian.py +++ b/volttrontesting/services/historian/test_base_historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from time import sleep @@ -54,7 +40,7 @@ STATUS_KEY_TIME_ERROR) from volttron.platform.agent import utils from volttron.platform.messaging import headers as headers_mod -from volttron.platform.messaging.health import * +from volttron.platform.messaging.health import STATUS_BAD, STATUS_GOOD, Status from volttron.platform.messaging import topics from volttron.platform.agent.known_identities import CONFIGURATION_STORE @@ -388,7 +374,7 @@ def test_time_tolerance_check(request, volttron_instance, client_agent): # Change config to modify topic for time tolerance check historian.publish_sleep = 0 json_config = """{"time_tolerance_topics":["record"]}""" - historian.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + historian.vip.rpc.call(CONFIGURATION_STORE, 'set_config', identity, "config", json_config, config_type="json").get() gevent.sleep(2) diff --git a/volttrontesting/services/historian/test_historian.py b/volttrontesting/services/historian/test_historian.py index eb4b02fce5..352cbfea6a 100644 --- a/volttrontesting/services/historian/test_historian.py +++ b/volttrontesting/services/historian/test_historian.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ pytest test cases for SQLHistorian and MongodbHistorian @@ -405,7 +391,7 @@ def setup_sqlite(connection_params, table_names, historian_version): UNIQUE(topic_id, ts))''' ) cursor.execute( - '''CREATE INDEX IF NOT EXISTS data_idx + '''CREATE INDEX IF NOT EXISTS data_idx ON ''' + table_names['data_table'] + ''' (ts ASC)''' ) db_connection.commit() @@ -1457,6 +1443,8 @@ def test_invalid_query(request, historian, publish_agent, query_agent, start=now, count=20, order="LAST_TO_FIRST").get(timeout=10) + except gevent.timeout.Timeout: + assert True except Exception as error: print("exception: {}".format(error)) assert "No route to host:" in str(error) diff --git a/volttrontesting/services/historian/test_multiplatform.py b/volttrontesting/services/historian/test_multiplatform.py index 94c4b76385..d7e8ba7fe2 100644 --- a/volttrontesting/services/historian/test_multiplatform.py +++ b/volttrontesting/services/historian/test_multiplatform.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ pytest test cases base historian to test all_platform configuration. @@ -49,16 +35,19 @@ import gevent import pytest -from volttron.platform import get_services_core, jsonapi +from volttron.platform import get_services_core, jsonapi, is_rabbitmq_available from volttron.platform.agent import utils from volttron.platform.messaging import headers as headers_mod from volttrontesting.fixtures.volttron_platform_fixtures import build_wrapper +from volttrontesting.skip_if_handlers import rmq_skipif from volttrontesting.utils.utils import get_rand_vip, get_hostname_and_random_port from volttrontesting.utils.platformwrapper import PlatformWrapper from volttrontesting.fixtures.volttron_platform_fixtures import get_rand_vip, \ get_rand_ip_and_port -from volttron.utils.rmq_setup import start_rabbit, stop_rabbit from volttron.platform.agent.utils import execute_command +HAS_RMQ = is_rabbitmq_available() +if HAS_RMQ: + from volttron.utils.rmq_setup import start_rabbit, stop_rabbit @pytest.fixture(scope="module") @@ -239,6 +228,7 @@ def test_all_platform_subscription_zmq(request, get_zmq_volttron_instances): @pytest.mark.historian @pytest.mark.multiplatform +@pytest.mark.skipif(rmq_skipif, reason="RMQ not installed.") def test_all_platform_subscription_rmq(request, federated_rmq_instances): try: upstream, downstream = federated_rmq_instances @@ -313,4 +303,3 @@ def test_all_platform_subscription_rmq(request, federated_rmq_instances): finally: if downstream: downstream.remove_agent(hist_id) - diff --git a/volttrontesting/services/market_service/test_market_service.py b/volttrontesting/services/market_service/test_market_service.py index 41758a06ac..5ddeb9b71f 100644 --- a/volttrontesting/services/market_service/test_market_service.py +++ b/volttrontesting/services/market_service/test_market_service.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -103,10 +89,10 @@ def create_supply_curve(self): supply_curve = PolyLine() price = 100 quantity = 0 - supply_curve.add(Point(price,quantity)) + supply_curve.add(Point(price, quantity)) price = 100 quantity = 1000 - supply_curve.add(Point(price,quantity)) + supply_curve.add(Point(price, quantity)) return supply_curve def create_demand_curve(self): @@ -223,4 +209,3 @@ def test_simple_market_errors(_function_config_test_seller, _function_config_tes gevent.sleep(LONG_DELAY) assert len(seller_agent.error_callback_results) == 0, "expected that the seller got no error callbacks" assert len(buyer_agent.error_callback_results) == 0, "expected that the buyer got no error callbacks" - diff --git a/volttrontesting/services/tagging/test_tagging.py b/volttrontesting/services/tagging/test_tagging.py index 8164372354..8c1dab0db0 100644 --- a/volttrontesting/services/tagging/test_tagging.py +++ b/volttrontesting/services/tagging/test_tagging.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ pytest test cases for tagging service @@ -161,7 +147,7 @@ def cleanup_mysql(db_connection, truncate_tables): def cleanup_mongodb(db_connection, truncate_tables): for collection in truncate_tables: - db_connection[collection].remove() + db_connection[collection].drop() print("Finished removing {}".format(truncate_tables)) @@ -245,7 +231,7 @@ def test_init_failure(volttron_instance, tagging_service, query_agent): callback=query_agent.callback).get() new_config = copy.copy(tagging_service) new_config['connection'] = {"params": - {"host": "localhost", + {"host": "localhost2", "port": 27017, "database": "mongo_test", "user": "invalid_user", @@ -259,8 +245,8 @@ def test_init_failure(volttron_instance, tagging_service, query_agent): volttron_instance.start_agent(agent_id) except: pass - gevent.sleep(1) - print ("Call back count {}".format(query_agent.callback.call_count)) + gevent.sleep(3) + print("Call back count {}".format(query_agent.callback.call_count)) assert query_agent.callback.call_count == 1 print("Call args {}".format(query_agent.callback.call_args)) assert query_agent.callback.call_args[0][1] == 'test.tagging.init' diff --git a/volttrontesting/services/weather/test_base_weather.py b/volttrontesting/services/weather/test_base_weather.py index 2a11f1ca39..2d9d02d773 100644 --- a/volttrontesting/services/weather/test_base_weather.py +++ b/volttrontesting/services/weather/test_base_weather.py @@ -1,46 +1,32 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import csv import datetime import os import sqlite3 - +import logging import gevent import pytest from mock import MagicMock @@ -48,7 +34,9 @@ from volttron.platform.agent import utils from volttron.platform.agent.base_weather import BaseWeatherAgent from volttron.platform.agent.utils import get_fq_identity -from volttron.platform.messaging.health import * +from volttron.platform.messaging.health import STATUS_BAD, STATUS_GOOD +from volttron.platform import jsonapi +from volttron.platform.agent.utils import format_timestamp utils.setup_logging() _log = logging.getLogger(__name__) @@ -524,6 +512,7 @@ def test_manage_unit_conversion_fail(weather, from_units, start, to_units, [{"location": "fake_location1"}, {"location": "fake_location2"}] ]) def test_get_current_valid_locations(weather, fake_locations): + clear_api_calls(weather) conn = weather._cache._sqlite_conn cursor = conn.cursor() weather.set_update_interval("get_current_weather", diff --git a/volttrontesting/subsystems/test_config_store.py b/volttrontesting/subsystems/test_config_store.py index 003cc17707..a9d3a8af2e 100644 --- a/volttrontesting/subsystems/test_config_store.py +++ b/volttrontesting/subsystems/test_config_store.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} """ @@ -66,6 +52,14 @@ def _module_config_test_agent(request, volttron_instance): agent = volttron_instance.build_agent(identity='config_test_agent', agent_class=_config_test_agent, enable_store=True) + # wait for config store's onconnect method to complete. onconnect calls handle_callback we don't want this + # to interfere with tests that test the trigger_callback mechanism + # Quote from config store documentation: + # + # As the configuration subsystem calls all callbacks in the onconfig phase and none are called beforehand + # the trigger_callback setting is effectively ignored if an agent sets a configuration or default configuration + # before the end of the onstart phase. + gevent.sleep(3) def cleanup(): agent.core.stop() @@ -78,7 +72,7 @@ def cleanup(): def config_test_agent(request, _module_config_test_agent, volttron_instance): def cleanup(): - _module_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_delete_store', 'config_test_agent').get() + _module_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'delete_store', 'config_test_agent').get() request.addfinalizer(cleanup) return _module_config_test_agent @@ -100,6 +94,18 @@ def cleanup(): return config_test_agent +@pytest.mark.config_store +def test_set_config_json(default_config_test_agent): + json_config = """{"value":1}""" + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config", json_config, config_type="json").get() + + results = default_config_test_agent.callback_results + assert len(results) == 1 + first = results[0] + assert first == ("config", "NEW", {"value": 1}) + + @pytest.mark.config_store def test_manage_store_json(default_config_test_agent): json_config = """{"value":1}""" @@ -113,9 +119,9 @@ def test_manage_store_json(default_config_test_agent): @pytest.mark.config_store -def test_manage_store_csv(default_config_test_agent): +def test_set_config_csv(default_config_test_agent): csv_config = "value\n1" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", csv_config, config_type="csv").get() results = default_config_test_agent.callback_results @@ -125,9 +131,9 @@ def test_manage_store_csv(default_config_test_agent): @pytest.mark.config_store -def test_manage_store_raw(default_config_test_agent): +def test_set_config_raw(default_config_test_agent): raw_config = "test_config_stuff" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", raw_config, config_type="raw").get() results = default_config_test_agent.callback_results @@ -137,9 +143,9 @@ def test_manage_store_raw(default_config_test_agent): @pytest.mark.config_store -def test_manage_update_config(default_config_test_agent): +def test_update_config(default_config_test_agent): json_config = """{"value":1}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() results = default_config_test_agent.callback_results @@ -148,7 +154,7 @@ def test_manage_update_config(default_config_test_agent): assert first == ("config", "NEW", {"value": 1}) json_config = """{"value":2}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() assert len(results) == 2 @@ -156,10 +162,27 @@ def test_manage_update_config(default_config_test_agent): assert second == ("config", "UPDATE", {"value": 2}) +@pytest.mark.config_store +def test_delete_config(default_config_test_agent): + json_config = """{"value":1}""" + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config", json_config, config_type="json").get() + + results = default_config_test_agent.callback_results + assert len(results) == 1 + first = results[0] + assert first == ("config", "NEW", {"value": 1}) + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'delete_config', + "config_test_agent", "config").get() + assert len(results) == 2 + second = results[1] + assert second == ("config", "DELETE", None) + + @pytest.mark.config_store def test_manage_delete_config(default_config_test_agent): json_config = """{"value":1}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() results = default_config_test_agent.callback_results @@ -173,13 +196,31 @@ def test_manage_delete_config(default_config_test_agent): assert second == ("config", "DELETE", None) +@pytest.mark.config_store +def test_delete_store(default_config_test_agent): + json_config = """{"value":1}""" + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config", json_config, config_type="json").get() + + results = default_config_test_agent.callback_results + print(f"callback results is {results}") + assert len(results) == 1 + first = results[0] + assert first == ("config", "NEW", {"value": 1}) + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'delete_store', "config_test_agent").get() + assert len(results) == 2 + second = results[1] + assert second == ("config", "DELETE", None) + + @pytest.mark.config_store def test_manage_delete_store(default_config_test_agent): json_config = """{"value":1}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() results = default_config_test_agent.callback_results + print(f"callback results is {results}") assert len(results) == 1 first = results[0] assert first == ("config", "NEW", {"value": 1}) @@ -189,10 +230,22 @@ def test_manage_delete_store(default_config_test_agent): assert second == ("config", "DELETE", None) +@pytest.mark.config_store +def test_get_config(config_test_agent): + json_config = """{"value":1}""" + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config", json_config, config_type="json").get() + + config = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'get_config', + "config_test_agent", "config", raw=False).get() + + assert config == {"value": 1} + + @pytest.mark.config_store def test_manage_get_config(config_test_agent): json_config = """{"value":1}""" - config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() config = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_get', @@ -201,10 +254,60 @@ def test_manage_get_config(config_test_agent): assert config == {"value": 1} +@pytest.mark.config_store +def test_get_metadata(config_test_agent): + json_config = """{"value":1}""" + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config", json_config, config_type="json").get() + + config = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'get_config', + "config_test_agent", "config", raw=False).get() + + assert config == {"value": 1} + + metadata = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'get_metadata', + "config_test_agent", "config").get() + print(f"Metadata {metadata}") + assert metadata["type"] == "json" + assert metadata["modified"] + assert metadata["data"] == '{"value":1}' + + +@pytest.mark.config_store +def test_manage_get_metadata(config_test_agent): + json_config = """{"value":1}""" + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config", json_config, config_type="json").get() + + config = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_get', + "config_test_agent", "config", raw=False).get() + + assert config == {"value": 1} + + metadata = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_get_metadata', + "config_test_agent", "config").get() + print(f"Metadata {metadata}") + assert metadata["type"] == "json" + assert metadata["modified"] + assert metadata["data"] == '{"value":1}' + + +@pytest.mark.config_store +def test_get_raw_config(config_test_agent): + json_config = """{"value":1}""" + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config", json_config, config_type="json").get() + + config = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'get_config', + "config_test_agent", "config", raw=True).get() + + assert config == json_config + + @pytest.mark.config_store def test_manage_get_raw_config(config_test_agent): json_config = """{"value":1}""" - config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() config = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_get', @@ -213,16 +316,34 @@ def test_manage_get_raw_config(config_test_agent): assert config == json_config +@pytest.mark.config_store +def test_list_config(config_test_agent): + json_config = """{"value":1}""" + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config1", json_config, config_type="json").get() + json_config = """{"value":2}""" + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config2", json_config, config_type="json").get() + json_config = """{"value":3}""" + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config3", json_config, config_type="json").get() + + config_list = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'list_configs', + "config_test_agent").get() + + assert config_list == ['config1', 'config2', 'config3'] + + @pytest.mark.config_store def test_manage_list_config(config_test_agent): json_config = """{"value":1}""" - config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config1", json_config, config_type="json").get() json_config = """{"value":2}""" - config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config2", json_config, config_type="json").get() json_config = """{"value":3}""" - config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config3", json_config, config_type="json").get() config_list = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_list_configs', @@ -231,10 +352,21 @@ def test_manage_list_config(config_test_agent): assert config_list == ['config1', 'config2', 'config3'] +@pytest.mark.config_store +def test_list_store(config_test_agent): + json_config = """{"value":1}""" + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', + "config_test_agent", "config1", json_config, config_type="json").get() + + config_list = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'list_stores').get() + + assert "config_test_agent" in config_list + + @pytest.mark.config_store def test_manage_list_store(config_test_agent): json_config = """{"value":1}""" - config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config1", json_config, config_type="json").get() config_list = config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_list_stores').get() @@ -245,13 +377,13 @@ def test_manage_list_store(config_test_agent): @pytest.mark.config_store def test_agent_list_config(default_config_test_agent): json_config = """{"value":1}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config1", json_config, config_type="json").get() json_config = """{"value":2}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config2", json_config, config_type="json").get() json_config = """{"value":3}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config3", json_config, config_type="json").get() config_list = default_config_test_agent.vip.config.list() @@ -262,7 +394,7 @@ def test_agent_list_config(default_config_test_agent): @pytest.mark.config_store def test_agent_get_config(default_config_test_agent): json_config = """{"value":1}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() config = default_config_test_agent.vip.config.get("config") @@ -273,7 +405,7 @@ def test_agent_get_config(default_config_test_agent): @pytest.mark.config_store def test_agent_reference_config_and_callback_order(default_config_test_agent): json_config = """{"config2":"config://config2", "config3":"config://config3"}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() config = default_config_test_agent.vip.config.get("config") @@ -281,7 +413,7 @@ def test_agent_reference_config_and_callback_order(default_config_test_agent): assert config == {"config2":None, "config3":None} json_config = """{"value":2}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config2", json_config, config_type="json").get() # Also use th to verify that the callback for "config" is called first. @@ -289,7 +421,7 @@ def test_agent_reference_config_and_callback_order(default_config_test_agent): default_config_test_agent.reset_results() json_config = """{"value":3}""" - default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + default_config_test_agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config3", json_config, config_type="json").get() config = default_config_test_agent.vip.config.get("config") @@ -304,12 +436,13 @@ def test_agent_reference_config_and_callback_order(default_config_test_agent): second = results[1] assert second == ("config3", "NEW", {"value": 3}) + @pytest.mark.config_store -def test_agent_set_config(default_config_test_agent): - json_config = {"value":1} +def test_agent_set_config(default_config_test_agent, volttron_instance): + json_config = {"value": 1} default_config_test_agent.vip.config.set("config", json_config) - + gevent.sleep(5) # wait to avoid case where we are simply missing the callback results = default_config_test_agent.callback_results assert len(results) == 0 @@ -318,7 +451,7 @@ def test_agent_set_config(default_config_test_agent): assert config == {"value": 1} default_config_test_agent.vip.config.set("config", json_config, trigger_callback=True) - + gevent.sleep(5) results = default_config_test_agent.callback_results assert len(results) == 1 first = results[0] @@ -360,7 +493,7 @@ def test_agent_default_config(request, volttron_instance): def cleanup(): if agent: - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_delete_store', 'test_default_agent').get() + agent.vip.rpc.call(CONFIGURATION_STORE, 'delete_store', 'test_default_agent').get() agent.core.stop() request.addfinalizer(cleanup) @@ -383,14 +516,14 @@ def __init__(self, **kwargs): result = results[0] assert result == ("config", "NEW", {"value": 2}) - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "test_default_agent", "config", '{"value": 1}', config_type="json").get() assert len(results) == 2 result = results[-1] assert result == ("config", "UPDATE", {"value": 1}) - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_delete_config', "test_default_agent", "config").get() + agent.vip.rpc.call(CONFIGURATION_STORE, 'delete_config', "test_default_agent", "config").get() assert len(results) == 3 result = results[-1] @@ -401,7 +534,7 @@ def __init__(self, **kwargs): def test_agent_sub_options(request, volttron_instance): def cleanup(): - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_delete_store', 'test_agent_sub_options').get() + agent.vip.rpc.call(CONFIGURATION_STORE, 'delete_store', 'test_agent_sub_options').get() agent.core.stop() request.addfinalizer(cleanup) @@ -424,13 +557,13 @@ def __init__(self, **kwargs): update_json = """{"value": 2}""" for name in ("new/config", "update/config", "delete/config"): - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "test_agent_sub_options", name, new_json, config_type="json").get() - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', + agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "test_agent_sub_options", name, update_json, config_type="json").get() - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_delete_config', + agent.vip.rpc.call(CONFIGURATION_STORE, 'delete_config', "test_agent_sub_options", name).get() results = agent.callback_results @@ -456,9 +589,9 @@ def test_config_store_security(volttron_instance, default_config_test_agent): # By default agents should have access to edit their own config store json_config = """{"value":1}""" - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', "rpc_agent", "config", json_config, + agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "rpc_agent", "config", json_config, config_type="json").get() - config = agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_get', "rpc_agent", "config", raw=False).get() + config = agent.vip.rpc.call(CONFIGURATION_STORE, 'get_config', "rpc_agent", "config", raw=False).get() assert config == {"value": 1} @@ -466,25 +599,21 @@ def test_config_store_security(volttron_instance, default_config_test_agent): # default_config_test_agent unless explicitly granted permissions try: json_config = """{"value":1}""" - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_store', "config_test_agent", "config", + agent.vip.rpc.call(CONFIGURATION_STORE, 'set_config', "config_test_agent", "config", json_config, config_type="json").get() except jsonrpc.RemoteError as e: - assert e.message == "User rpc_agent can call method manage_store only with " \ + assert e.message == "User rpc_agent can call method set_config only with " \ "identity=rpc_agent but called with identity=config_test_agent" try: - agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_delete_store', 'config_test_agent').get() + agent.vip.rpc.call(CONFIGURATION_STORE, 'delete_store', 'config_test_agent').get() except jsonrpc.RemoteError as e: - assert e.message == "User rpc_agent can call method manage_delete_store only with " \ + assert e.message == "User rpc_agent can call method delete_store only with " \ "identity=rpc_agent but called with identity=config_test_agent" # Should be able to view - result = agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_list_configs', "config_test_agent").get() + result = agent.vip.rpc.call(CONFIGURATION_STORE, 'list_configs', "config_test_agent").get() print(result) finally: agent.core.stop() - - - - diff --git a/volttrontesting/subsystems/test_health_subsystem.py b/volttrontesting/subsystems/test_health_subsystem.py index 9bb415458b..d0c2a4290b 100644 --- a/volttrontesting/subsystems/test_health_subsystem.py +++ b/volttrontesting/subsystems/test_health_subsystem.py @@ -5,7 +5,7 @@ from volttron.platform.messaging import topics from volttron.platform.messaging.headers import DATE -from volttron.platform.messaging.health import * +from volttron.platform.messaging.health import STATUS_BAD, STATUS_GOOD, Status from volttron.platform.agent.utils import parse_timestamp_string from volttrontesting.utils.utils import (poll_gevent_sleep, messages_contains_prefix) diff --git a/volttrontesting/subsystems/test_pubsub.py b/volttrontesting/subsystems/test_pubsub.py index ce8421698a..814aa6c6d4 100644 --- a/volttrontesting/subsystems/test_pubsub.py +++ b/volttrontesting/subsystems/test_pubsub.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import gevent diff --git a/volttrontesting/testutils/test_getinstance_1.py b/volttrontesting/testutils/test_getinstance_1.py index a445d0fc2a..eaaca45102 100644 --- a/volttrontesting/testutils/test_getinstance_1.py +++ b/volttrontesting/testutils/test_getinstance_1.py @@ -5,11 +5,9 @@ @pytest.mark.wrapper def test_fixture_returns_correct_number_of_instances(get_volttron_instances): - num_instances = 4 + num_instances = 2 wrappers = get_volttron_instances(num_instances, should_start=False) - assert num_instances == len(wrappers) for w in wrappers: assert isinstance(w, PlatformWrapper) - assert not w.is_running() diff --git a/volttrontesting/testutils/test_platformwrapper.py b/volttrontesting/testutils/test_platformwrapper.py index ed91f2031f..df69202a71 100644 --- a/volttrontesting/testutils/test_platformwrapper.py +++ b/volttrontesting/testutils/test_platformwrapper.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from configparser import ConfigParser import time diff --git a/volttrontesting/utils/__init__.py b/volttrontesting/utils/__init__.py index 16e0b81948..bc56c260df 100644 --- a/volttrontesting/utils/__init__.py +++ b/volttrontesting/utils/__init__.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} from . utils import is_running_in_container diff --git a/volttrontesting/utils/build_agent.py b/volttrontesting/utils/build_agent.py index 7020e0610b..0f5b0af6f3 100644 --- a/volttrontesting/utils/build_agent.py +++ b/volttrontesting/utils/build_agent.py @@ -6,14 +6,19 @@ from volttrontesting.utils.platformwrapper import PlatformWrapper -def build_agent(platform: PlatformWrapper, identity=None): +def build_agent(platform: PlatformWrapper, identity=None, agent_class=None): """Builds an agent instance with the passed platform as its bus. The agent identity will be set. If the identity is set to None then a random identity will be created. """ + from volttron.platform.vip.agent import Agent + + if agent_class is None: + agent_class = Agent + os.environ['VOLTTRON_HOME'] = platform.volttron_home - agent = platform.build_agent(identity) + agent = platform.build_agent(identity, agent_class=agent_class) gevent.sleep(0.1) # switch context for a bit os.environ.pop('VOLTTRON_HOME') return agent diff --git a/volttrontesting/utils/platformwrapper.py b/volttrontesting/utils/platformwrapper.py index 17e6817149..5fc82bf4b0 100644 --- a/volttrontesting/utils/platformwrapper.py +++ b/volttrontesting/utils/platformwrapper.py @@ -2,7 +2,7 @@ import logging import os from pathlib import Path -from typing import Optional, Union +from typing import Literal, Optional, Union import uuid from urllib.parse import urlencode @@ -170,7 +170,8 @@ def start_wrapper_platform(wrapper, with_http=False, with_tcp=True, wrapper.startup_platform(vip_address=vc_tcp, bind_web_address=bind_address, volttron_central_address=volttron_central_address, - volttron_central_serverkey=volttron_central_serverkey) + volttron_central_serverkey=volttron_central_serverkey, + timeout=100) if with_http: discovery = "{}/discovery/".format(vc_http) response = grequests.get(discovery).send().response @@ -305,9 +306,6 @@ def __init__(self, messagebus=None, ssl_auth=False, instance_name=None, # with older 2.0 agents. self.opts = None - keystorefile = os.path.join(self.volttron_home, 'keystore') - self.keystore = KeyStore(keystorefile) - self.keystore.generate() self.messagebus = messagebus if messagebus else 'zmq' # Regardless of what is passed in if using rmq we need auth and ssl. if self.messagebus == 'rmq': @@ -330,9 +328,12 @@ def __init__(self, messagebus=None, ssl_auth=False, instance_name=None, # Writes the main volttron config file for this instance. store_message_bus_config(self.messagebus, self.instance_name) - - # Update volttron config file with non-auth setting if auth_enabled is False - if not self.auth_enabled: + if self.auth_enabled: + keystorefile = os.path.join(self.volttron_home, 'keystore') + self.keystore = KeyStore(keystorefile) + self.keystore.generate() + else: + # Update volttron config file with non-auth setting if auth_enabled is False config_path = os.path.join(self.volttron_home, "config") if os.path.exists(config_path): config = configparser.ConfigParser() @@ -358,7 +359,6 @@ def __init__(self, messagebus=None, ssl_auth=False, instance_name=None, if not self.debug_mode: self.debug_mode = self.env.get('DEBUG', False) self.skip_cleanup = self.env.get('SKIP_CLEANUP', False) - self._web_admin_api = None @property @@ -419,10 +419,11 @@ def build_connection(self, peer=None, address=None, identity=None, self.logit( 'Default address was None so setting to current instances') address = self.vip_address + if self.auth_enabled: - if address is None: - serverkey = self.serverkey if serverkey is None: + serverkey = self.serverkey + if serverkey is None and address is not None: self.logit("serverkey wasn't set but the address was.") raise Exception("Invalid state.") if publickey is None or secretkey is None: @@ -479,31 +480,32 @@ def build_agent(self, address=None, should_spawn=True, identity=None, print(f"Publickey is: {publickey}\nServerkey is: {serverkey}") if serverkey is None: serverkey = self.serverkey - if publickey is None: - self.logit(f'generating new public secret key pair {KeyStore.get_agent_keystore_path(identity=identity)}') - ks = KeyStore(KeyStore.get_agent_keystore_path(identity=identity)) - publickey = ks.public - secretkey = ks.secret if address is None: self.logit('Using vip-address {address}'.format( address=self.vip_address)) address = self.vip_address + if self.auth_enabled: + if publickey is None: + self.logit( + f'generating new public secret key pair {KeyStore.get_agent_keystore_path(identity=identity)}') + ks = KeyStore(KeyStore.get_agent_keystore_path(identity=identity)) + publickey = ks.public + secretkey = ks.secret + if publickey and not serverkey: + self.logit('using instance serverkey: {}'.format(publickey)) + serverkey = publickey + self.logit("BUILD agent VOLTTRON HOME: {}".format(self.volttron_home)) + if self.bind_web_address: + kwargs['enable_web'] = True - if publickey and not serverkey: - self.logit('using instance serverkey: {}'.format(publickey)) - serverkey = publickey - self.logit("BUILD agent VOLTTRON HOME: {}".format(self.volttron_home)) - if self.bind_web_address: - kwargs['enable_web'] = True + if 'enable_store' not in kwargs: + kwargs['enable_store'] = False - if 'enable_store' not in kwargs: - kwargs['enable_store'] = False + if capabilities is None: + capabilities = dict(edit_config_store=dict(identity=identity)) + print(f"Publickey is: {publickey}\nServerkey is: {serverkey}") - if capabilities is None: - capabilities = dict(edit_config_store=dict(identity=identity)) - print(f"Publickey is: {publickey}\nServerkey is: {serverkey}") - if self.auth_enabled: entry = AuthEntry(user_id=identity, identity=identity, credentials=publickey, capabilities=capabilities, comments="Added by platform wrapper") @@ -529,6 +531,9 @@ def build_agent(self, address=None, should_spawn=True, identity=None, event.wait(timeout=4) has_control = False times = 0 + if self.messagebus == 'rmq': + # agent seem to need a extra second for agent to establish connection + gevent.sleep(1) while not has_control and times < 10: times += 1 try: @@ -599,6 +604,9 @@ def disable_auto_csr(self): assert not self.is_auto_csr_enabled() def add_capabilities(self, publickey, capabilities): + if not self.auth_enabled: + self.logit("Auth is not enabled, so ignore and return False") + return False with with_os_environ(self.env): if isinstance(capabilities, str) or isinstance(capabilities, dict): capabilities = [capabilities] @@ -619,17 +627,52 @@ def add_capabilities(self, publickey, capabilities): # when invoked in quick succession. add_capabilities updates auth.json, gets the peerlist and calls all peers' # auth.update rpc call. So sleeping here instead expecting individual test cases to sleep for long gevent.sleep(2) + return True + + file_types = Union[Literal["raw"], Literal["json"], Literal["csv"]] + + def config_store_get(self, vip_identity: str, name: str, file_type: Optional[Literal["raw"]] = None) -> str: + with with_os_environ(self.env): + self.__wait_for_control_connection_to_exit__() + env = self.env.copy() + file_type = None if file_type is None else "--raw" + + cmd = ['volttron-ctl', '--json', 'config', 'get', vip_identity, name] + + if file_type: + cmd.append(file_type) - @staticmethod - def add_capability(entry, capabilites): + res = execute_command(cmd, env=env, logger=_log) + + print(res) + return res + + def config_store_store(self, identity: str, name: str, infile: Path, file_type: file_types = "json"): + with with_os_environ(self.env): + self.__wait_for_control_connection_to_exit__() + env = self.env.copy() + file_type = "--" + file_type + + cmd = ['volttron-ctl', '--json', 'config', 'store', identity, name, infile.absolute().as_posix(), file_type] + + res = execute_command(cmd, env=env, logger=_log) + + print(res) + + + def add_capability(self, entry, capabilities): + if not self.auth_enabled: + self.logit("Auth is not enabled, so ignore and return False") + return False if isinstance(entry, str): - if entry not in capabilites: - capabilites[entry] = None + if entry not in capabilities: + capabilities[entry] = None elif isinstance(entry, dict): - capabilites.update(entry) + capabilities.update(entry) else: raise ValueError("Invalid capability {}. Capability should be string or dictionary or list of string" "and dictionary.") + return True def set_auth_dict(self, auth_dict): if auth_dict: @@ -845,12 +888,13 @@ def startup_platform(self, vip_address, auth_dict=None, pconfig = os.path.join(self.volttron_home, 'config') config = {} - # Add platform's public key to known hosts file - publickey = self.keystore.public - known_hosts_file = os.path.join(self.volttron_home, 'known_hosts') - known_hosts = KnownHostsStore(known_hosts_file) - known_hosts.add(self.opts['vip_local_address'], publickey) - known_hosts.add(self.opts['vip_address'], publickey) + if self.auth_enabled: + # Add platform's public key to known hosts file + publickey = self.keystore.public + known_hosts_file = os.path.join(self.volttron_home, 'known_hosts') + known_hosts = KnownHostsStore(known_hosts_file) + known_hosts.add(self.opts['vip_local_address'], publickey) + known_hosts.add(self.opts['vip_address'], publickey) # Set up the configuration file based upon the passed parameters. parser = configparser.ConfigParser() @@ -900,7 +944,7 @@ def startup_platform(self, vip_address, auth_dict=None, # if msgdebug: # cmd.append('--msgdebug') if enable_logging: - cmd.append('-vv') + cmd.append('-v') cmd.append('-l{}'.format(self.log_path)) if setupmode: cmd.append('--setup-mode') @@ -918,8 +962,9 @@ def startup_platform(self, vip_address, auth_dict=None, utils.wait_for_volttron_startup(self.volttron_home, timeout) - self.serverkey = self.keystore.public - assert self.serverkey + if self.auth_enabled: + self.serverkey = self.keystore.public + assert self.serverkey # Use dynamic_agent so we can look and see the agent with peerlist. if not setupmode: @@ -1223,7 +1268,12 @@ def __wait_for_control_connection_to_exit__(self, timeout: int = 10): disconnected = False timer_start = time.time() while not disconnected: - peers = self.dynamic_agent.vip.peerlist().get(timeout=20) + try: + peers = self.dynamic_agent.vip.peerlist().get(timeout=10) + except gevent.Timeout: + self.logit("peerlist call timed out. Exiting loop. " + "Not waiting for control connection to exit.") + break disconnected = CONTROL_CONNECTION not in peers if disconnected: break @@ -1602,10 +1652,9 @@ def mergetree(src, dst, symlinks=False, ignore=None): d = os.path.join(dst, item) if os.path.isdir(s): mergetree(s, d, symlinks, ignore) - else: - if not os.path.exists(d) or os.stat(src).st_mtime - os.stat( + elif not os.path.exists(d) or os.stat(src).st_mtime - os.stat( dst).st_mtime > 1: - shutil.copy2(s, d) + shutil.copy2(s, d) class WebAdminApi: diff --git a/volttrontesting/utils/utils.py b/volttrontesting/utils/utils.py index cfd2a81df2..3ff7076d23 100644 --- a/volttrontesting/utils/utils.py +++ b/volttrontesting/utils/utils.py @@ -134,7 +134,7 @@ def build_devices_header_and_message(points=['abc', 'def']): for point in points: data[point] = random() * 10 - meta_data[point] = meta_templates[randint(0,len(meta_templates)-1)] + meta_data[point] = meta_templates[randint(0, len(meta_templates)-1)] time1 = utils.format_timestamp( datetime.utcnow()) headers = { diff --git a/volttrontesting/zmq/test_zmq.py b/volttrontesting/zmq/test_zmq.py index 789c3fe707..c4ff6f47b9 100644 --- a/volttrontesting/zmq/test_zmq.py +++ b/volttrontesting/zmq/test_zmq.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys @@ -81,13 +67,13 @@ def subscriber(): print(sub.recv_multipart()) @pytest.mark.slow -@pytest.mark.zmq +@pytest.mark.zmq def test_broker(): #broker_test(): pub = zmq.Socket(ctx, zmq.PUB) pull = zmq.Socket(ctx, zmq.PULL) pub.bind('ipc:///tmp/volttron-platform-agent-subscribe') pull.bind('ipc:///tmp/volttron-platform-agent-publish') - + time.sleep(2) # pub.send_multipart(['topic1', 'Hello world1']) pub.send_multipart([b'topic1', b'Hello world1']) diff --git a/volttrontesting/zmq/test_zmqsub.py b/volttrontesting/zmq/test_zmqsub.py index abd49cb3a4..991fe37ba4 100644 --- a/volttrontesting/zmq/test_zmqsub.py +++ b/volttrontesting/zmq/test_zmqsub.py @@ -1,39 +1,25 @@ # -*- coding: utf-8 -*- {{{ -# vim: set fenc=utf-8 ft=python sw=4 ts=4 sts=4 et: +# ===----------------------------------------------------------------------=== # -# Copyright 2020, Battelle Memorial Institute. +# Component of Eclipse VOLTTRON # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# ===----------------------------------------------------------------------=== # -# http://www.apache.org/licenses/LICENSE-2.0 +# Copyright 2023 Battelle Memorial Institute # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # -# This material was prepared as an account of work sponsored by an agency of -# the United States Government. Neither the United States Government nor the -# United States Department of Energy, nor Battelle, nor any of their -# employees, nor any jurisdiction or organization that has cooperated in the -# development of these materials, makes any warranty, express or -# implied, or assumes any legal liability or responsibility for the accuracy, -# completeness, or usefulness or any information, apparatus, product, -# software, or process disclosed, or represents that its use would not infringe -# privately owned rights. Reference herein to any specific commercial product, -# process, or service by trade name, trademark, manufacturer, or otherwise -# does not necessarily constitute or imply its endorsement, recommendation, or -# favoring by the United States Government or any agency thereof, or -# Battelle Memorial Institute. The views and opinions of authors expressed -# herein do not necessarily state or reflect those of the -# United States Government or any agency thereof. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. # -# PACIFIC NORTHWEST NATIONAL LABORATORY operated by -# BATTELLE for the UNITED STATES DEPARTMENT OF ENERGY -# under Contract DE-AC05-76RL01830 +# ===----------------------------------------------------------------------=== # }}} import sys @@ -79,14 +65,14 @@ def subscriber(): while True: print(sub.recv_multipart()) -@pytest.mark.slow +@pytest.mark.slow @pytest.mark.zmq def test_broker(): pub = zmq.Socket(ctx, zmq.PUB) pull = zmq.Socket(ctx, zmq.PULL) pub.bind('ipc:///tmp/volttron-platform-agent-subscribe') pull.bind('ipc:///tmp/volttron-platform-agent-publish') - + pub.send_multipart([b'topic1', b'Hello world1']) time.sleep(2) pub.send_multipart([b'foo', b'bar'])