Grid substation
A 110/20 kV distribution substation with two transformers and six feeders, on IEC 60870-5-104. Nine devices and 69 points.
Operator view | port 4016 |
|---|---|
Protocol server | port 5026 |
Devices and tags | 9 devices, 69 points |
Litmus Edge driver | IEC 60870-5-104 |
Image | grid-substation-demo |
Scenarios
- Thermal margin as a forecast. A transformer's hot spot is not a threshold to alarm on but a curve to project. The useful question is how long the current loading can continue, not whether it is over a limit right now.
- The tap changer wear counter. Operations accumulate towards maintenance. A counter that adds up over months is worth more than an alarm that fires after the fact.
- A recloser sequence, end to end, on the wire. A feeder fault produces a burst of protection events in under a second. The demonstration is what an Edge does with a burst: capture it at the resolution it happened rather than at the rate someone chose to poll.
Overview
Most of the solutions here poll steadily. A substation does not. The data that matters arrives in bursts around an event, and the value of an Edge is that it is close enough to catch the whole sequence.
IEC 60870-5-104 is report by exception for exactly this reason, and the solution uses it that way.
What it creates on Litmus Edge
Nine DeviceHub devices covering the two transformers, six feeders and the station itself, with 69 points over IEC 60870-5-104. A Digital Twin model and instance for each transformer and feeder. Analytics groups behind the thermal margin, tap changer wear and event figures.
Requirements
- Litmus Edge 4.0.x, reachable over HTTPS from the host running the solution
- An API token for that Edge, or a username and password, or a client id and secret
- Docker, and Docker Compose for the compose deployment
- A network path in both directions: the solution reaches the Edge's API, and the Edge reaches this host on the protocol port
Deploy
The solution ships two ways. Use the registry if the host can reach Google Artifact Registry, and the downloaded archive if it cannot.
Option 1: pull from the registry
Requires a read-only registry credential, supplied by Litmus separately.
cat key.json | docker login -u _json_key --password-stdin https://us-docker.pkg.devSave this as docker-compose.yml:
services:
grid-substation:
image: us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/grid-substation-demo:0.6.1
container_name: grid-substation-demo
restart: unless-stopped
ports:
- target: 4016
published: 4016
protocol: tcp
- target: 5026
published: 5026
protocol: tcp
environment:
# Fill these in.
EDGE_URL: "${EDGE_URL:-}"
EDGE_API_TOKEN: "${EDGE_API_TOKEN:-}"
SIM_HOST: "${SIM_HOST:-auto}"
APPLY_ON_START: "${APPLY_ON_START:-1}"
EDGE_VERIFY_TLS: "${EDGE_VERIFY_TLS:-0}"
# Optional: publish the twins into Litmus Unify.
UNIFY_URL: "${UNIFY_URL:-}"
UNIFY_USERNAME: "${UNIFY_USERNAME:-}"
UNIFY_PASSWORD: "${UNIFY_PASSWORD:-}"
UNIFY_CONNECTOR: "${UNIFY_CONNECTOR:-}"
HTTP_PORT: "4016"
IEC104_PORT: "5026"
AUTOSTART: "1"
TIME_SCALE: "120"
SEED: "7"
LOG_LEVEL: "INFO"EDGE_URL=https://10.0.0.5
EDGE_API_TOKEN=your-token
SIM_HOST=10.0.0.9docker compose up -dOr, without Docker Compose, run the same image with the same .env:
docker run -d \
--name grid-substation-demo \
--restart unless-stopped \
-p 4016:4016 \
-p 5026:5026 \
--env-file .env \
-e APPLY_ON_START=1 \
-e EDGE_VERIFY_TLS=0 \
-e HTTP_PORT=4016 \
-e IEC104_PORT=5026 \
-e AUTOSTART=1 \
-e TIME_SCALE=120 \
-e SEED=7 \
-e LOG_LEVEL=INFO \
us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/grid-substation-demo:0.6.1Flags given with -e take precedence over .env, so change APPLY_ON_START or EDGE_VERIFY_TLS on the command line rather than in the file.
Open http://localhost:4016.
The page stays on its waiting panel until the Edge carries this solution's devices. That is deliberate: the simulation does not tick and no value is shown until Litmus Edge is verified to hold the devices and poll them, so nothing on screen can be mistaken for data that never made the trip. With APPLY_ON_START at its default of 1 the solution configures the Edge itself on startup, which takes 30 to 60 seconds. If you set it to 0, or the apply failed, press Apply to Edge in the page header.
Option 2: load the downloaded archive
Download grid-substation-demo-0.6.1-amd64.tar.gz from the solution's page on portal.litmus.io. The archive is the container image, not a source bundle, and needs no registry access.
docker load -i grid-substation-demo-0.6.1-amd64.tar.gzdocker load prints the image it added:
Loaded image: us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/grid-substation-demo:0.6.1That reference is the one the compose file above already names, so the same docker-compose.yml and .env, or the docker run command above, now work offline with no docker login:
docker compose up -dTo run it without Compose, pass the same three values on the command line:
docker run -d \
--name grid-substation-demo \
--restart unless-stopped \
-p 4016:4016 \
-p 5026:5026 \
-e EDGE_URL=https://10.0.0.5 \
-e EDGE_API_TOKEN=your-token \
-e SIM_HOST=10.0.0.9 \
us-docker.pkg.dev/litmus-customer-facing/litmus-solutions/grid-substation-demo:0.6.1Configuration
Variable | Default | What it does |
|---|---|---|
EDGE_URL | the Docker host | Litmus Edge to configure |
EDGE_API_TOKEN | unset | token for that Edge. Or a username and password, or a client id and secret |
SIM_HOST | auto | address the Edge polls to reach this solution |
APPLY_ON_START | 1 | configure the Edge on startup |
EDGE_VERIFY_TLS | 0 | 1 checks the Edge's certificate |
UNIFY_URL | unset | optional: Litmus Unify to publish the twins into |
UNIFY_USERNAME | unset | optional: a Unify user |
UNIFY_PASSWORD | unset | optional: that user's password |
UNIFY_CONNECTOR | the Edge's only one | optional: which Litmus UNS connector on the Edge to publish through |
TIME_SCALE | 120 | the station clock runs 120x, so a daily load curve passes in twelve minutes |
SEED | 7 | makes a run repeatable |
Litmus Unify (optional)
This solution can also publish its 9 Digital Twins into Litmus Unify, one message per asset under litmus-solutions/northside-110-20-kv/.... It stays off until two things are true: the UNIFY_ values above are set, and the Litmus Edge has a Litmus UNS connector, which the Solutions provisioner can pair in one click. The next apply then publishes the twins, the page header shows how many are arriving, and removing the solution from the Edge removes its branch from Unify as well. Leave the values empty to keep Unify out of it.
Operator view
The station single line: the 110 kV bus, both transformers with their loading, hot spot temperature and tap position, the 20 kV bus, and the six feeders with their currents.
Above it, station load, worst transformer, bus voltage and frequency, feeders open, and ambient temperature, since the thermal margin depends on it.
Every value on the page is read back from Litmus Edge rather than from the simulator, and the page says how many reads it has made and how old the newest is.
Faults include a feeder fault with a recloser sequence, a transformer cooling fan failure, tap changer hunting and a load surge.
Apply and remove
docker compose downUse Clean up in the Solutions provisioner to remove what it created on the Edge.