GridWorks SpaceHeat SCADA

Intended for running a heat pump thermal storage space heating system in a house, and doing this transactively.
https://github.com/thegridelectric/gridworks-scada

Category: Consumption
Sub Category: Buildings and Heating

Last synced: about 19 hours ago
JSON representation

Repository metadata

GridWorks SCADA for space heating

README.md

GridWorks SCADA

Tests
Codecov

========

This code is intended for running a heat pump thermal storage space heating system in a house, and doing this transactively. That means the heating system is capable of dynamically responding to local electric grid conditions and buying energy at the lowest cost times, while keeping the house warm. We believe this repo may be instrumental in effectively and efficiently reaching a low-carbon future. For an architectural overview of the code, and why it has something to do with a low-carbon future, please go here.

This code is part of a larger framework. In particular it assumes there is a cloud-based actor which it refers to as the AtomicTNode (short for Atomic Transactive Node) that is calling the shots on its control decisions most of the time. In addition, the code is structured in an
actor-based way, with a collection of actors each responsible for an important but limited set
of functionality communicating to each other via messages. For a more specific description of both how these internal actors work with each other and how
this repo fits into the larger transactive energy framework please go here; this page describes typical sequences of messages between relevant actors in the system.

We are indebted to Efficiency Maine, who spearheaded and funded the initial pilot using this code. As per the requirements of the initial pilot, the code is intended to:

  1. run on a raspberry Pi 4; and
  2. to be able to use a variety of off-the-shelf actuating and sensing devices.

For information on setting up an SD card that will run this code on a Pi 4 with the correct
configuration and attached devices, please go here

Creating a Dev environment for macos or Pi

Use python 3.11

Create the development environment with:

tools/mkenv.sh

On a Pi run:

tools/mkenv-pi.sh

To activate the environment, add 'gw_spaceheat' to your PYTHONPATH and then
source the environment's activation file. This is most easily accomplished
with a shell alias, for example on a Mac by fixing to following to contain the
actual the path to this repo on your machine and then adding the result to
$HOME/.zprofile:

export SCADA_REPO=actual/path/to/your/repo
export GW_SPACEHEAT=$SCADA_REPO/gw_spaceheat
alias gw="source $GW_SPACEHEAT/venv/bin/activate && export PYTHONPATH=$GW_SPACEHEAT && cd $SCADA_REPO"

You will then be able to activate the development environment in a new terminal
with:

gw

Run the tests from the root directory of the repo with:

pytest

A hardware layout file is necessary to run the scada locally. Find the default path the layout file with:

python -c "from gwproactor.config.paths import Paths; print(Paths().hardware_layout)"

For initial experiments the test layout file can be used. The test layout file is located at:

tests/config/hardware-layout.json

Display the hardware layout with:

gws layout show

Display current settings with:

gws config

There are some scratch notes on Pi-related setup (like enabling interfaces) in docs/pi_setup.md

Adding libraries

Add libraries by adding the library spec to the appropriate ".in" file in the
requirements directory. Use:

  • dev.in for requirements only needed for
    development or CI.
  • drivers.in for requirements only
    needed on a Pi.
  • base.in for requirements used used
    in all contexts.

Once you have added your requirement run:

tools/pipc.sh

Then manually modify the modified .txt files to remove the absolute paths
that pip-tools adds to comments inside the .txt files. This allow someone looking
at the commit to see only the dependency you changed. Otherwise they will see a
change in the comment many dependencies. For example, in a text editor or IDE
do a search/replace in *.txt files in the project, searching for the text

path/to/scada/repo/on/your/machine/gw_spaceheat

and replacing it with

gw_spaceheat

Handling secrets and config variables

SETTING UP SECRETS.
Configuration variables (secret or otherwise) use dotenv module in a gitignored .env file, copied over from .env-template. These are accessed via config.ScadaSettings.

Setting up MQTT

See instructions here to set up a local MQTT broker
using Mosquitto.

Static analsyis with ruff

Ruff is installed via the test and dev requirements.
You can run it with:

ruff check

Ruff is not run in CI or in pre-commit, since the code will not currently pass.
Ruff is provided primarily for visual feedback in the IDE. Ruff is configured
in pyproject.toml.

Static analysis in Visual Studio Code

Visual Studio Code will provide visual feedback on code that does not pass ruff.

To use this functionality, the ruff plugin
for Visual Studio code must be installed. We recommend:

  1. Installing the ruff extension.
  2. Disabling it.
  3. Enabling for workspaces in which you want to use it, such as this one.

More static analysis

More rigid ruff rules can be applied by modifying pyproject.toml. Gwproto, for
example, uses many more rules.

Typechecking feedback can be applied in the IDE by enabling Pylance type checking
inside vscode. Change that
in user not workspace settings since much of the code will currently fail.

TLS

TLS is used by default. Follow these instructions to set up
a local self-signed Certificate Authority to create test certificates and to create certificates for the Mosquitto
broker. Note that this section
is relevant if you will connect to the Mosquitto broker from a Raspberry PI.

Create a certificate for the test ATN
gwcert key add --certs-dir $HOME/.config/gridworks/atn/certs scada_mqtt
cp $HOME/.local/share/gridworks/ca/ca.crt $HOME/.config/gridworks/atn/certs/scada_mqtt
Create a certificate for test Scada
gwcert key add --certs-dir $HOME/.config/gridworks/scada/certs gridworks_mqtt
cp $HOME/.local/share/gridworks/ca/ca.crt $HOME/.config/gridworks/scada/certs/gridworks_mqtt                    
Test generated certificates

In one terminal run:


mosquitto_sub -h localhost -p 8883 -t foo \
     --cafile $HOME/.config/gridworks/atn/certs/scada_mqtt/ca.crt \
     --cert $HOME/.config/gridworks/atn/certs/scada_mqtt/scada_mqtt.crt \
     --key $HOME/.config/gridworks/atn/certs/scada_mqtt/private/scada_mqtt.pem

In another terminal run:

mosquitto_pub -h localhost -p 8883 -t foo -m '{"bar":1}' \
     --cafile $HOME/.config/gridworks/scada/certs/gridworks_mqtt/ca.crt \
     --cert $HOME/.config/gridworks/scada/certs/gridworks_mqtt/gridworks_mqtt.crt \
     --key $HOME/.config/gridworks/scada/certs/gridworks_mqtt/private/gridworks_mqtt.pem

Verify you see {"bar":1} in the first window.

Configuring a Scada with keys that can be used with the GridWorks MQTT broker.

Use getkeys.py to
create and copy TLS to keys to a scada such that it can communicate with the actual GridWorks MQTT broker. For details
run:

python gw_spaceheat/getkeys.py --help

The overview of this process is that you need:

  1. The ssh key for certbot.
  2. rclone installed.
  3. An rclone remote configured for your scada.
  4. To construct the getkeys.py command line per its help.

Running the code

This command will show information about what scada would do if started locally:

gws run --dry-run  

This command will will start the scada locally:

gws run

These commands will start the local test ATN:

gws atn run

Development flow

Default branch is dev. Make PRs to this branch for review from your code branch. Make bug changes directly to this branch.
The first 5 homes in Millinocket are designed for beta testing. The idea here is that they run on dev, and the larger
group of houses run on main.

The main branch is protected - requires a pull request. Default pattern is PRs from dev to main.
This will also publish a new gridworks-scada-protcol package and a new grdiworks-admin package.

Packages

Motivated by the need to make gridworks-admin installable without setting up the
scada development environment, this repository contains a packages
directory for code published on PyPI as separate distribution packages. The
separate distribution packages are managed as separate by python projects, with
their own subdirectory, each containing its own pyproject.toml. Subproject
development is done using uv and publication to PyPI happens in CI after
merging to the main branch.

There are two packages:

  1. gridworks-admin, the admin user interface.
  2. gridworks-scada-protocol, which contains protocol messages shared by both
    Scada and admin.

See the packages directory README.md for more information.

Admin

To install admin as a tool separate from development environment:

uv tool install gridworks-admin

or

pipx install gridworks-admin

To run admin from the development environment:

gwa

To publish a new version admin to PyPI install uv, if necessary, and then:

  1. Update the version field in the admin pyproject.toml, either using
    the uv version command, for example:
    cd packages/gridworks-admin
    uv version --bump patch
    
    or by manually modifying the pyproject.toml and then running uv lock.
  2. Merge to main.

See the packages directory README.md for more information.

License

Distributed under the terms of the MIT license,
this repository is free and open source software.

Contributing

Contributions are very welcome.
To learn more, see the [Contributor Guide].


Owner metadata


GitHub Events

Total
Last Year

Committers metadata

Last synced: about 22 hours ago

Total Commits: 2,108
Total Committers: 6
Avg Commits per committer: 351.333
Development Distribution Score (DDS): 0.54

Commits in past year: 658
Committers in past year: 3
Avg Commits per committer in past year: 219.333
Development Distribution Score (DDS) in past year: 0.555

Name Email Commits
Jessica Millar j****r@g****m 970
thdfw t****w@g****m 543
Andrew Schweitzer s****2@g****m 516
stickler-ci s****t@s****m 63
Preethi Vaidyanathan p****i@g****m 15
Jessica Millar j****a@j****l 1

Committer domains:


Issue and Pull Request metadata

Last synced: 9 days ago

Total issues: 7
Total pull requests: 114
Average time to close issues: 1 day
Average time to close pull requests: 2 days
Total issue authors: 2
Total pull request authors: 3
Average comments per issue: 0.57
Average comments per pull request: 0.16
Merged pull request: 79
Bot issues: 0
Bot pull requests: 0

Past year issues: 7
Past year pull requests: 90
Past year average time to close issues: 1 day
Past year average time to close pull requests: 3 days
Past year issue authors: 2
Past year pull request authors: 3
Past year average comments per issue: 0.57
Past year average comments per pull request: 0.18
Past year merged pull request: 60
Past year bot issues: 0
Past year bot pull requests: 0

More stats: https://issues.ecosyste.ms/repositories/lookup?url=https://github.com/thegridelectric/gridworks-scada

Top Issue Authors

  • anschweitzer (6)
  • jessicamillar (1)

Top Pull Request Authors

  • jessicamillar (49)
  • anschweitzer (39)
  • thdfw (26)

Top Issue Labels

  • ops (3)
  • admin (3)

Top Pull Request Labels

  • ops (2)
  • admin (2)
  • DRAFT PR (2)

Dependencies

gw_spaceheat/requirements/base.in pypi
  • numpy *
  • paho-mqtt *
  • pendulum *
  • pika ==1.1.0
  • python-dotenv *
  • pytz *
gw_spaceheat/requirements/base.txt pypi
  • numpy ==1.22.4
  • paho-mqtt ==1.6.1
  • pendulum ==2.1.2
  • pika ==1.1.0
  • python-dateutil ==2.8.2
  • python-dotenv ==0.20.0
  • pytz ==2022.1
  • pytzdata ==2020.1
  • six ==1.16.0
gw_spaceheat/requirements/dev.in pypi
  • ipython ==8.0.0
  • isort *
  • pip-tools *
gw_spaceheat/requirements/drivers.in pypi
  • pymodbus *
  • pyserial *
  • smbus2 *
gw_spaceheat/requirements/drivers.txt pypi
  • numpy ==1.22.4
  • paho-mqtt ==1.6.1
  • pendulum ==2.1.2
  • pika ==1.1.0
  • pymodbus ==2.5.3
  • pyserial ==3.5
  • python-dateutil ==2.8.2
  • python-dotenv ==0.20.0
  • pytz ==2022.1
  • pytzdata ==2020.1
  • six ==1.16.0
  • smbus2 ==0.4.1
gw_spaceheat/requirements/test.in pypi
  • black *
  • coverage *
  • mypy *
  • nose *
  • pytest *
.github/workflows/ci.yaml actions
  • actions/checkout v2 composite
  • actions/download-artifact v2 composite
  • actions/setup-python v2 composite
  • actions/upload-artifact v3 composite
  • canastro/copy-file-action master composite
  • codecov/codecov-action v3.1.0 composite
  • namoshek/mosquitto-github-action v1 composite
gw_spaceheat/requirements/dev.txt pypi
  • appnope ==0.1.3 development
  • asttokens ==2.0.5 development
  • attrs ==21.4.0 development
  • backcall ==0.2.0 development
  • black ==22.3.0 development
  • build ==0.8.0 development
  • certifi ==2022.9.14 development
  • charset-normalizer ==2.1.1 development
  • click ==8.1.3 development
  • commonmark ==0.9.1 development
  • coverage ==6.4.1 development
  • decorator ==5.1.1 development
  • docutils ==0.19 development
  • executing ==0.8.3 development
  • gridworks-protocol ==0.2.2 development
  • idna ==3.4 development
  • iniconfig ==1.1.1 development
  • ipython ==8.0.0 development
  • isort ==5.10.1 development
  • jedi ==0.18.1 development
  • matplotlib-inline ==0.1.3 development
  • mypy ==0.961 development
  • mypy-extensions ==0.4.3 development
  • nose ==1.3.7 development
  • numpy ==1.22.4 development
  • packaging ==21.3 development
  • paho-mqtt ==1.6.1 development
  • parso ==0.8.3 development
  • pathspec ==0.9.0 development
  • pendulum ==2.1.2 development
  • pep517 ==0.12.0 development
  • pexpect ==4.8.0 development
  • pickleshare ==0.7.5 development
  • pika ==1.1.0 development
  • pip-tools ==6.9.0 development
  • platformdirs ==2.5.2 development
  • pluggy ==1.0.0 development
  • prompt-toolkit ==3.0.29 development
  • ptyprocess ==0.7.0 development
  • pure-eval ==0.2.2 development
  • py ==1.11.0 development
  • pydantic ==1.10.2 development
  • pygments ==2.12.0 development
  • pymodbus ==2.5.3 development
  • pyparsing ==3.0.9 development
  • pyserial ==3.5 development
  • pytest ==7.1.2 development
  • pytest-asyncio ==0.19.0 development
  • pytest-sugar ==0.9.5 development
  • python-dateutil ==2.8.2 development
  • python-dotenv ==0.20.0 development
  • pytz ==2022.1 development
  • pytzdata ==2020.1 development
  • requests ==2.28.1 development
  • result ==0.8.0 development
  • rich ==12.5.1 development
  • rich-cli ==1.8.0 development
  • rich-rst ==1.1.7 development
  • six ==1.16.0 development
  • smbus2 ==0.4.1 development
  • stack-data ==0.2.0 development
  • termcolor ==1.1.0 development
  • textual ==0.1.18 development
  • tomli ==2.0.1 development
  • traitlets ==5.1.1 development
  • typing-extensions ==4.2.0 development
  • urllib3 ==1.26.12 development
  • wcwidth ==0.2.5 development
  • wheel ==0.37.1 development
  • xdg ==5.1.1 development
gw_spaceheat/requirements/test.txt pypi
  • attrs ==21.4.0 test
  • black ==22.3.0 test
  • click ==8.1.3 test
  • coverage ==6.4.1 test
  • iniconfig ==1.1.1 test
  • mypy ==0.961 test
  • mypy-extensions ==0.4.3 test
  • nose ==1.3.7 test
  • packaging ==21.3 test
  • pathspec ==0.9.0 test
  • platformdirs ==2.5.2 test
  • pluggy ==1.0.0 test
  • py ==1.11.0 test
  • pyparsing ==3.0.9 test
  • pytest ==7.1.2 test
  • pytest-asyncio ==0.19.0 test
  • tomli ==2.0.1 test
  • typing-extensions ==4.2.0 test
pyproject.toml pypi

Score: 5.7430031878094825