Skip to content

Metrics Schema

The metrics schema defines all telemetry metrics as JSON. A generator transforms these definitions into strongly-typed C# code, Elasticsearch mappings, and reference documentation.

Overview

Metric definitions live in schemas/metrics/. Each domain (battery, energy, etc.) has its own registry file in schemas/metrics/registries/. The root metrics.json file defines shared enums (units, profiles) and points to the registries.

The generator reads these definitions and produces:

  • C# classes in src/Voltimax.Iot.Contracts/Metrics/Generated/
  • Elasticsearch mappings in the same output directory
  • Documentation in docs/reference/metrics/

Quick Start

powershell
dotnet run --project tools/Voltimax.Iot.Tools -- generate

This regenerates all output files and removes obsolete generated files automatically.

Registry Format

Each registry file defines a domain and its metrics. The schema for registry files is in schemas/metrics/schemas/. A minimal example:

json
{
  "id": "energy",
  "name": "Energy",
  "description": "Electrical power and energy measurements",
  "metrics": [
    {
      "name": "ActivePower",
      "key": "active_power",
      "unit": "Watt",
      "description": "Active power",
      "scopes": ["sum", "l1", "l2", "l3"],
      "profile": "Basic"
    }
  ]
}

Every metric requires name (PascalCase, becomes the C# property), key (snake_case, becomes the JSON/Elasticsearch field), unit (from the Unit enum in metrics.json), and description. Optional fields: scopes (expands into multi-variant metrics), profile (Basic/Standard/Advanced), and counter (monotonically increasing).

Scopes

The scopes array expands a single definition into multiple metrics. A metric with "scopes": ["sum", "l1", "l2", "l3"] generates four metrics: ActivePower_Sum (ID active_power#sum), ActivePower_L1, ActivePower_L2, ActivePower_L3. Without scopes, a single base metric is generated.

Common scope values: sum (aggregated), l1/l2/l3 (per-phase), n (neutral), l1_l2/l2_l3/l3_l1 (line-to-line), t1/t2 (tariff periods). Choose scopes that match the physical measurement - for example, use sum + per-phase for power, but only line-to-line for line voltages.

Metric ID Format

Metrics use a structured ID: domain.identifier#scope

  • energy.active_power#sum - domain energy, identifier active_power, scope sum
  • battery.soc - no scope (base metric)

The # delimiter enables unambiguous parsing and consistent filtering by domain, identifier, or scope.

Adding New Metrics

1. Define the metric

Add to an existing registry in schemas/metrics/registries/ or create a new file for a new domain:

json
{
  "name": "NewMetric",
  "key": "new_metric",
  "unit": "Watt",
  "description": "Clear description of what this measures",
  "profile": "Standard"
}

2. Regenerate and verify

powershell
dotnet run --project tools/Voltimax.Iot.Tools -- generate
dotnet build

Best Practices

Naming

  • name: PascalCase (ActivePower, VoltageLineToNeutral)
  • key: snake_case (active_power, voltage_ln)
  • Scopes: lowercase (l1, sum, t1)

Descriptions

Write descriptions that explain what the metric measures, not how:

  • Good: "Active power (real power consumed or generated)"
  • Too vague: "Power measurement"
  • Too technical: "P = V × I × cos(φ)"