Understanding energy data
This tutorial applies the query techniques from tutorial 2 to a real domain: a renewable energy community, in which members share the electricity they produce. You explore the master data of a community, find the time series of a metering point, learn what the metering registers mean and compute the key figures that describe how well the community works.
You need a tenant in which the EnergyCommunity solution is installed
(blueprint EnergyCommunity.Base) and that contains data, for example a
simulated demo community. The background is described in the use case
Energy Communities; this
tutorial links to the relevant sections as you go.
Time: about 60 minutes.
The questions behind the data
An energy community has to answer a few questions every day:
- Who are the members, and which metering points do they bring in?
- How much did each member consume and produce, in every quarter hour?
- How much of the consumption could be covered by the community's own generation, and how much was left over?
- How reliable are these numbers: measured, interpolated or estimated?
Each question maps onto one part of the OctoMesh model.
Step 1: Members, facilities, metering points
The master data form a tree: customer → operating facility → metering point (consumer or producer). Read the data model first, then query it:
query Members {
runtime {
energyCommunityCustomer(first: 20) {
totalCount
items {
customerNumber
contact { firstName lastName companyName }
facilities(ckTypeIds: ["Basic.Energy/OperatingFacility"]) {
items {
... on BasicEnergyOperatingFacility {
name
children(ckTypeIds: ["EnergyCommunity/Consumer", "EnergyCommunity/Producer"]) {
items {
... on EnergyCommunityConsumer {
rtId ckTypeId meteringPointNumber partitionFactor meteringDataSource
}
... on EnergyCommunityProducer {
rtId ckTypeId meteringPointNumber partitionFactor productionType
}
}
}
}
}
}
}
}
}
}
Things to notice:
partitionFactoris a percentage.100means the metering point takes part in this community completely.meteringDataSourcesays where the values come from:EDA(the grid operator),SIMULATEDorSELF_REPORTED.- Count consumers and producers. The ratio of consumption to installed generation largely decides how a community behaves.
Exercise: Write down the rtId of one consumer and one producer.
Step 2: From a metering point to its time series
A metering point does not store values itself. For every register it has a
child entity of type Basic.Energy/EnergyMeasurement, the anchor of one time
series. Its rtId is what you pass to stream-data queries:
query Anchors($meteringPoint: OctoObjectId!) {
runtime {
energyCommunityConsumer(rtId: $meteringPoint) {
items {
meteringPointNumber
children(ckTypeIds: ["Basic.Energy/EnergyMeasurement"]) {
items {
... on BasicEnergyEnergyMeasurement { rtId rtWellKnownName obisCode }
}
}
}
}
}
}
A consumer typically has two anchors, 1-1:1.9.0 G.01 and 1-1:2.9.0 G.03; a
producer has three, 1-1:2.9.0 G.01, 1-1:2.9.0 G.01T and 1-1:2.9.0 P.01T.
The table in metering registers
explains each of them.
You can also go the other way and list all anchors of one register in the tenant:
query SelfCoverageAnchors {
runtime {
basicEnergyEnergyMeasurement(
first: 500
fieldFilter: [{ attributePath: "obisCode", operator: EQUALS, comparisonValue: "1-1:2.9.0 G.03" }]
) {
totalCount
items { rtId rtWellKnownName }
}
}
}
Step 3: One day in 15-minute slots
Electricity is settled in 15-minute slots: 96 per day, 92 or 100 on the days the clocks change. Query one day of the consumption anchor of your consumer from the raw archive (see tutorial 2, raw values for the full query):
archiveRtId: the raw archive of the community (in the Studio under Archives, usually namedenergy-measurements)rtIds: the anchor of1-1:1.9.0 G.01from/to: local midnight to local midnight in UTC, for example2026-10-05T22:00:00Zto2026-10-06T22:00:00Zfor 6 October (summer time)
Then run the same query for the producer's 1-1:2.9.0 G.01 anchor.
Exercise: Plot both series over the day (any tool will do). When does the producer feed in, when does the consumer draw the most? In which slots could the producer's generation cover the consumer's demand?
Each row also carries a dataQuality. Read
data quality to see why
an estimated value (L3) never overwrites a measured one (L1).
Step 4: The daily allocation
The registers G.03, G.01T and P.01T are the result of the allocation:
for every slot the community distributes what its producers offer among the
consumers who need energy in that slot, and the rest is surplus. The allocation
runs once a day for the previous day (D+1). Read
daily allocation
for the rules.
Check the balance yourself. Sum one day per register with a grouping aggregation over the raw archive (query in tutorial 2). A sample result:
| Register | kWh | Meaning |
|---|---|---|
1-1:1.9.0 G.01 | 431.36 | consumption of all consumers |
1-1:2.9.0 G.01 | 474.27 | generation of all producers |
1-1:2.9.0 G.01T | 474.01 | generation offered to the community |
1-1:2.9.0 G.03 | 207.63 | consumption covered from within the community |
1-1:2.9.0 P.01T | 266.38 | offered generation not distributed |
The balance holds: G.01T − P.01T = 474.01 − 266.38 = 207.63 = G.03. Notice
that the community produced more than it consumed over the day and still only
covered about half of its consumption: generation and consumption happen at
different times of day, and only energy in the same slot can be shared.
Exercise: Repeat the aggregation for a single slot at noon and a single slot in the evening. How do the shares change?
Step 5: Key figures
Two ratios describe a community over a period (see key figures):
- Coverage ratio = Σ
2.9.0 G.03/ Σ1.9.0 G.01 - Surplus ratio = Σ
P.01T/ ΣG.01T
For the sample day above: coverage ratio = 207.63 / 431.36 = 48 %, surplus ratio = 266.38 / 474.01 = 56 %.
For longer periods, use the rollup archives instead of the raw archive: the monthly rollup already holds the monthly sum per anchor. The Python script in tutorial 2, step 6 computes both ratios per month:
month consumption self-cov. coverage surplus %
2026-06 12940.8 7950.0 61.4% 61.7%
2026-07 13372.1 8093.9 60.5% 61.4%
2026-08 13372.1 7623.0 57.0% 60.2%
2026-09 12737.3 6720.7 52.8% 58.1%
Exercises:
- Extend the script to a full year. How do the ratios change between summer and winter, and why?
- Compute the ratios per consumer instead of for the whole community. Which members benefit most?
- The surplus is energy the community could sell. In which hours of the day is the surplus largest? Use the hourly rollup.
Things to keep in mind
- Units and signs: all values are kWh per slot and positive; the direction is in the OBIS code.
- Time zone: the community's day is the local day in
Europe/Vienna. The archives store UTC. - Grid alignment: query on full quarter hours (raw archive) or local midnights (daily and coarser rollups), otherwise partially covered windows are counted in full.
- Quality: a period that contains
L3values contains estimates. Check thedataquality_maxcolumn of the rollups before you trust a sum. - Provisional vs. final: the allocation for day D is final only after the reporting cut-off on day D+1.
Summary
- Master data form the tree customer → facility → metering point; each metering point has one anchor entity per register.
- Raw values are 15-minute windows in a time-range archive; rollups provide hourly to yearly sums.
1.9.0 G.01and2.9.0 G.01are what was measured;G.03,G.01TandP.01Tare what the allocation made of it.- Coverage ratio and surplus ratio summarise how well a community uses its own generation.
Next: Building solutions with AI via the MCP server lets an AI assistant do this exploration with you.