Add ESPI-native Meter Data and Billing Summary Verifiable Credential schemas#186
Add ESPI-native Meter Data and Billing Summary Verifiable Credential schemas#186
Conversation
Anusree-J
left a comment
There was a problem hiding this comment.
Some comments:
- Seems like https://naesb.org/espi/ is not an open URL; schema validation will fail
- Terms like serviceKind, intervalBlocks, intervalBlock are mapped to class IRIs (espi:ServiceKind, espi:IntervalBlock) instead of property IRIs. In JSON-LD, context terms must map to properties, not
classes. Fix mappings to use the correct property IRIs (e.g., meter:serviceKind, meter:intervalBlocks). - Fix coveragePeriod structure mismatch
- attributes.yaml defines coveragePeriod with start + end
- vocab.jsonld declares its range as meter:DateTimeInterval
- But DateTimeInterval (from Green Button) uses start + duration, not start + end
- credential subject id is seperate from DID - i think we used customer id in other VCs
intervalBlockscan be moved underreadingTypeinstead ofcredentialSubject- do we need interval length since we have interval blocks?
- Little confused about the reasoning behind keeping value as int and having powerOfTenMultiplier property
replaced this by
fixed this.
fixed.
Interval blocks now use start + duration
Can you check if this resolves it? I did not understand this fully.
Per Green button examples that Vish shared of his actual bills,intervalBlocks and readingType are in parallel, and not nested.
https://utilityapi.com/docs/greenbutton/xml#ReadingType If intervalLength is not provided in interval blcoks, one from ReadingType seems to be the default one.
Now keeping both float & int values, at slight deviation from GB schema, but making it backward compatible. Thanks for suggesting. |
| - logicallyDisconnected | ||
| - physicallyDisconnected | ||
|
|
||
| AmiBillingReadyKind: |
There was a problem hiding this comment.
Hi @Anusree-J this was the closest to the smart meter type I found.
See AMR vs. AMI difference here.
… EnergyCredentials
…nergy: prefix to deg: - Wrap the 5 JSON Schema attributes.yaml files (EnergyCustomerProfile, EnergyMeterDataGB, EnergyBillingSummary, EnergyMeterDataCredential, EnergyBillingSummaryCredential) as OpenAPI 3.1.1 documents with components.schemas so they render in Swagger UI and serve as canonical schema-validation inputs. Canonical identity preserved via $id on each schema object; jsonSchemaDialect pins JSON Schema 2020-12. - Bump espiGreenButton and espiGreenButtonWithCIM from OpenAPI 3.0.0 to 3.1.1 and add jsonSchemaDialect. - Switch in-PR cross-refs from absolute schema.beckn.io URIs to relative file refs with #/components/schemas/<Name> JSON Pointers so they resolve locally in Swagger and validators. - Rename JSON-LD prefix energy: to deg: across all vocab.jsonld, context.jsonld, x-jsonld annotations and README references. Namespace base updated from https://schema.beckn.io/energy/ to https://schema.beckn.io/deg/ to align with the deg: convention used in schema.beckn.io/P2PTrade/2.0/vocab.jsonld. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
attributes.yaml (OpenAPI 3.1.1 with JSON Schema 2020-12 dialect) is the canonical schema. The standalone schema.json files duplicated that content with envelope fields inlined locally, and the pytest harness existed only to validate examples against schema.json. Remove both, plus the __pycache__ artifacts, and update the Files section of each credential README to point at attributes.yaml. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ributes.yaml
Bundles attributes.yaml with @redocly/cli (dereferencing cross-schema
$refs into a self-contained document), then validates each example
JSON/NDJSON file against the chosen components.schemas entry with
jsonschema Draft 2020-12. Remote $refs that Redocly does not resolve
(e.g. upstream schema.beckn.io docs) are fetched lazily via a
referencing.Registry retrieve callable.
Usage:
python3 scripts/validate_vc_examples.py \\
specification/schema/EnergyMeterDataCredential/v1.0/attributes.yaml
Examples auto-discovered from <attributes-dir>/examples/; schema name
defaults to the single entry in components.schemas or the one matching
info.title. Add a Validation section to each credential README.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…le drift
Validation harness surfaced drift in two shapes:
1. espiGreenButton/attributes.yaml, mechanically generated from the
NAESB ESPI XSD, declares every code field as integer-only and every
timestamp as integer (Unix epoch). DEG credentials use ESPI-native
values but also accept the human-readable camelCase aliases
documented in the PR, and ISO-8601 timestamps. The old standalone
schema.json inlined loosened `oneOf: [integer, string]` unions for
those fields; removing schema.json dropped the loosening.
Loosen in espiGreenButton directly:
- ReadingType: commodity, flowDirection, uom, accumulationBehaviour,
currency, kind, phase -> oneOf [integer-enum, string-enum]
- UsageSummary: commodity, currency, qualityOfReading -> same
- ReadingQuality.quality, SummaryMeasurement.uom, LineItem.itemKind
-> same
- DateTimeInterval.start, UsageSummary.statusTimeStamp,
SummaryMeasurement.timeStamp, LineItem.dateTime
-> oneOf [integer epoch, ISO-8601 date-time string]
- IntervalReading.value/cost, SummaryMeasurement.value
-> type number (accept both integer and decimal)
- IntervalBlock.IntervalReading,
UsageSummary.costAdditionalDetailLastPeriod
-> array wrappers (fix XSD maxOccurs=unbounded that the generator
emitted as a single $ref)
String enums mirror the DEG mapping from the removed schema.json.
Existing descriptions and x-enum-descriptions preserved.
2. Example envelope drift vs upstream EnergyCredential/v2.0:
- issuer.licenseNumber is required upstream; populated from the
existing subjectId regulatory ID value.
- credentialStatus.type must be the literal "dediregistry" (not
"dedi") per the upstream const.
- UsageSummary.statusTimeStamp is required per ESPI; populated per
entry from billingPeriod.start.
All 6 examples (EnergyMeterDataCredential: example.json,
example-decimal.json, example.ndjson x3; EnergyBillingSummaryCredential:
example.json) now pass validation via
`scripts/validate_vc_examples.py`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Closes #185
Adds two energy Verifiable Credentials — Meter Data and Billing Summary — that use ESPI/Green Button types natively, plus the full ESPI reference schema and CIM meter telemetry extension. All schemas are published-ready for
schema.beckn.io.Credentials
meterDataVC/v1.0/) — historical interval meter readings (15-min, hourly) using ESPIIntervalBlock,ReadingType,IntervalReadingwith native numeric/string enum codesbillingSummaryVC/v1.0/) — aggregated monthly billing data using ESPIUsageSummary,SummaryMeasurement,LineItemwith hundred-thousandths (1e-5) cost encodingBoth import shared identity from
EnergyCustomerProfile(aligned with PR #208'sCustomerCredential) and ESPI types fromespiGreenButton.ESPI Reference Schemas
espiGreenButton/— full OpenAPI 3.1.1 representation of NAESB ESPI XSD (~30 types), JSON-LD context mapping tohttp://naesb.org/espi#IRIs withskos:exactMatchlinks, and comprehensive README with enum lookup tables. Code fields (commodity,flowDirection,uom,accumulationBehaviour,currency,kind,phase,qualityOfReading,itemKind) accept both ESPI integer codes and human-readable camelCase string aliases viaoneOfunions; timestamp fields accept both Unix epoch integers and ISO-8601 date-time strings.espiGreenButtonWithCIM/— optional CIM (IEC 61968/61970) extension: device models, SCADA telemetry, instrument transformers, events (38 classes)Publishable Schema Packs (beckn/schemas format)
Under
specification/schema/:EnergyCustomerProfile/v1.0/—customerNumber,meterNumber,meterType(enum: AMR, AMI, Electromechanical, ...),idRef— shared with PR Unify energy VCs into Electricity Credentials #208EnergyMeterDataGB/v1.0/—ServiceCategory,timeZone,ReadingType,IntervalBlock,qualityOfReadingEnergyBillingSummary/v1.0/—ServiceCategory,timeZone,currency,UsageSummary[]Each pack has:
attributes.yaml,context.jsonld,vocab.jsonld,README.md— ready forschema.beckn.iodeployment.Key design decisions
attributes.yaml, single source of truth — all schema packs and the ESPI reference schemas are OpenAPI 3.1.1 documents (withjsonSchemaDialect: https://json-schema.org/draft/2020-12/schema) so they render in Swagger UI and serve as the canonical input for schema validation. No parallel standaloneschema.jsonfiles; cross-refs use relative-file$refs with#/components/schemas/<Name>JSON Pointer fragments so they resolve locally in both Swagger and validators. Canonical identity preserved via$idon each schema object.oneOfunions live inespiGreenButton/attributes.yamlitself so DEG credentials referencing the base ESPI types inherit the relaxation without needing overlay schemas. Integer codes remain ESPI-faithful; string aliases follow ESPI camelCase naming.type: number— integer = hundred-thousandths (1e-5) of currency (ESPI native); float (decimal point) = exact currency amount. Convention documented, not schema-enforceable (JSON has onenumbertype)+05:30) accepted alongside ESPI Unix epoch integers viaoneOfEnergyCustomerProfile/context.jsonldusing thedeg:namespace (https://schema.beckn.io/deg/), aligning with the prefix convention used inschema.beckn.io/P2PTrade/2.0/vocab.jsonldcustomerProfile,customerNumber,meterNumber,meterType,idRefterms resolve to same namespace.maskedIdType/maskedIdNumberremoved (replaced byidRef).meterTypeenum matches PR Unify energy VCs into Electricity Credentials #208meterDataVC/andbillingSummaryVC/usev1.0/subdirectories, with all schema URLs updated to include/v1.0/(e.g.,https://schema.beckn.io/EnergyMeterDataGB/v1.0/context.jsonld)Files added/modified
meterDataVC/v1.0/billingSummaryVC/v1.0/energy-credentials/external/schema/espiGreenButton/external/schema/espiGreenButtonWithCIM/specification/schema/EnergyCustomerProfile/specification/schema/EnergyMeterDataGB/specification/schema/EnergyBillingSummary/scripts/validate_vc_examples.pyredocly bundle --dereferenced+ jsonschema Draft 2020-12Validation harness
scripts/validate_vc_examples.pyreplaces the old standaloneschema.json+ pytest harness. It bundles anyattributes.yamlvia@redocly/cli bundle --dereferenced(inlining cross-schema$refs into one self-contained document) and validates each example withjsonschema. Any residual remote$refs Redocly leaves unresolved are fetched lazily via areferencing.Registryretrieve callable.Examples auto-discovered from
<attributes-dir>/examples/; schema picked as the single entry incomponents.schemasor the one matchinginfo.title(override with--schema).Test plan
espi:IRIs, identity terms todeg:IRIs$idand@contextURLs use versioned/v1.0/pathsattributes.yamlvalidates as OpenAPI 3.1.1 via@redocly/cli lint(in-PR refs resolve; residual errors in the 2 VC envelopes are transitive through upstreamschema.beckn.io/Credential/v2.0, unrelated to this PR)scripts/validate_vc_examples.pywired up end-to-end against both credentialsespiGreenButton/attributes.yamlcode fields tooneOf: [integer, string]unions (commodity, uom, currency, flowDirection, accumulationBehaviour, kind, phase, qualityOfReading, itemKind) and timestamp fields tooneOf: [integer epoch, ISO-8601 string](DateTimeInterval.start, statusTimeStamp, timeStamp, LineItem.dateTime); looseningIntervalReading.value/costandSummaryMeasurement.valuefromintegertonumber; and array-wrappingIntervalBlock.IntervalReadingandUsageSummary.costAdditionalDetailLastPeriod(XSDmaxOccurs=unboundedelements the generator had emitted as single$refs).issuer.licenseNumber(required upstream) and changingcredentialStatus.typeliteral from"dedi"to"dediregistry"in all examples; addingstatusTimeStampto eachUsageSummaryentry in the billing summary example.🤖 Generated with Claude Code