Skip to content
Updated Sep 16, 2026 by Pablo Coufal · Owner: analysisactiveapi-a Edit on GitHub

Calorific Value Management — API Analysis ​

Three surfaces, one store. The platform default catalogue lives on the platform administration application (/v1/admin/…), following the pattern the other cross-tenant catalogues use. The client and gauge scopes live on the tenant backend under the resource that owns them — the client tab reads and writes /v1/client/calorific-values, the gauge detail reads and writes /v1/gauges/{id}/calorific-values. The client scope carries no client id: on the tenant backend every request is already in a client context, because a tenant is exactly one client (platform.tenants.client_id is NOT NULL and UNIQUE) — see Client scope = the request's tenant. All three write the same four facts (combination, value, units, validity date) and go through the same resolution rule at the end of this document. Screens: index.md — UI/UX Design.

Values are dated and append-only at every scope: a correction is a new row with its own validFrom, never an in-place update of the number. That is why the tenant endpoints below are POST to add, PATCH only for the fields that do not change energy (note), and DELETE to withdraw a row entered in error. Four endpoints on the platform administration application for the default catalogue, following the pattern the other cross-tenant catalogues use. The client and gauge scopes are edited through endpoints their own features own — /v1/client/calorific-values in Client Management and the gauge coefficient endpoints in Gauge Management — and are not redocumented here; what this analysis adds to them is the validity date on every value and the resolution rule below.

The project has no shared API-conventions document yet, so the two envelope shapes are stated once here. Success:

json
{
  "data": {},
  "status": 200,
  "message": "OK",
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b21"
}

Error:

json
{
  "errorCode": "ERR_CALORIFIC_VALUE_DUPLICATE",
  "errorMessage": "A default for this combination already starts on this date.",
  "status": 409,
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b21"
}

Authentication and permission failures are answered by the platform application's shared handling and are not restated per endpoint.


📥 GET /v1/admin/calorific-values ​

Returns the whole default catalogue — every medium and primary source, including superseded values — so the administration screen can show each combination's history.

Authorization ​

Requires permission code platform.calorific-values.read, platform-scoped.

Request Headers ​

None beyond the platform application's standard bearer authentication.

Request Body ​

None.

Request Parameters ​

NameInTypeRequiredDefaultDescriptionValidation / NotesDB Mapping
mediumQueryEnumNoall mediaLimits the result to one medium.An entry from Enum - GaugeMedium.defaultCalorificValue.medium
primarySourceQueryIntegerNoall sourcesLimits the result to one primary source.An entry from Enum - PrimarySource; requires medium.defaultCalorificValue.primarySource

Request Logic ​

  • Reads shared.default_calorific_value; writes nothing.
  • Returns withdrawn rows as well, flagged, because the screen shows the history including corrections.
sql
SELECT id, medium, primary_source, value, unit_from, unit_to, valid_from, note, deleted_at
FROM shared.default_calorific_value
WHERE (@medium IS NULL OR medium = @medium)
  AND (@primarySource IS NULL OR primary_source = @primarySource)
ORDER BY medium ASC, primary_source ASC, valid_from DESC;

Transactional Operations ​

N/A — read-only.

✅ Success Response (200) ​

json
{
  "data": [
    {
      "id": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b41",
      "medium": "gas",
      "primarySource": 1,
      "value": 10.550000,
      "unitFrom": "m3",
      "unitTo": "kWh",
      "validFrom": "2024-01-01",
      "note": "ČSN 38 5502",
      "inForce": true,
      "withdrawn": false
    }
  ],
  "status": 200,
  "message": "OK",
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b71"
}

Response Data Mapping ​

Response FieldSource / Value
iddefaultCalorificValue.id
mediumdefaultCalorificValue.medium
primarySourcedefaultCalorificValue.primarySource
valuedefaultCalorificValue.value
unitFromdefaultCalorificValue.unitFrom
unitTodefaultCalorificValue.unitTo
validFromdefaultCalorificValue.validFrom
notedefaultCalorificValue.note
inForceDerived: the row is the latest non-withdrawn one for its combination whose validFrom is not in the future
withdrawnDerived: defaultCalorificValue.deletedAt is set

❌ Error Responses ​

400 ERR_CALORIFIC_VALUE_INVALID_FILTER ​

Thrown when medium or primarySource is not a value of its enum, or primarySource is given without medium.

json
{
  "errorCode": "ERR_CALORIFIC_VALUE_INVALID_FILTER",
  "errorMessage": "primarySource requires medium.",
  "status": 400,
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b71"
}

📥 POST /v1/admin/calorific-values ​

Adds a platform default for one medium and primary source from one date, including a date in the future.

Authorization ​

Requires permission code platform.calorific-values.write, platform-scoped.

Request Headers ​

None beyond the platform application's standard bearer authentication.

Request Body ​

json
{
  "medium": "gas",
  "primarySource": 1,
  "value": 10.550000,
  "unitFrom": "m3",
  "unitTo": "kWh",
  "validFrom": "2026-01-01",
  "note": "ČSN 38 5502, revize 2026"
}

Request Parameters ​

NameInTypeRequiredDefaultDescriptionValidation / NotesDB Mapping
mediumBodyEnumYes-Medium the default applies to.An entry from Enum - GaugeMedium; media that never convert to energy are rejected.defaultCalorificValue.medium
primarySourceBodyIntegerYes-Fuel or source within the medium.An entry from Enum - PrimarySource.defaultCalorificValue.primarySource
valueBodyDecimalYes-Energy yielded by one unit of unitFrom.Must be > 0; at most six decimal places.defaultCalorificValue.value
unitFromBodyEnumYes-Unit converted from.An entry from Enum - Unit; must be a volume or mass unit.defaultCalorificValue.unitFrom
unitToBodyEnumYes-Unit converted to.An entry from Enum - Unit; must be an energy unit.defaultCalorificValue.unitTo
validFromBodyDateYes-First day the default applies.YYYY-MM-DD; may be in the future.defaultCalorificValue.validFrom
noteBodyStringNonullThe standard or measurement the value was taken from.Max 500 characters.defaultCalorificValue.note

Request Logic ​

  • Inserts one row into shared.default_calorific_value with tenant_id null, so the default is readable by every tenant.
  • Collision is left to the partial unique index rather than a preceding read.
  • Writes one platform audit entry, and enqueues recalculation for gauges that resolve to the platform scope for this combination from the validity date.
sql
INSERT INTO shared.default_calorific_value
    (id, tenant_id, medium, primary_source, value, unit_from, unit_to, valid_from, note, created_by, updated_by)
VALUES
    (@id, NULL, @medium, @primarySource, @value, @unitFrom, @unitTo, @validFrom, @note, @actor, @actor);

Transactional Operations ​

The row, its audit entry and the recalculation request commit together; a duplicate rejected by the unique index rolls back all three, so no recalculation is scheduled for a value that was not stored.

✅ Success Response (201) ​

json
{
  "data": {
    "id": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b43"
  },
  "status": 201,
  "message": "Created",
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b72"
}

Response Data Mapping ​

Response FieldSource / Value
iddefaultCalorificValue.id of the created row

❌ Error Responses ​

400 ERR_CALORIFIC_VALUE_INVALID ​

Thrown when the combination is not one that converts to energy, the value is not positive, the units are not a volume-or-mass to energy pair, or the date is not a valid calendar date.

json
{
  "errorCode": "ERR_CALORIFIC_VALUE_INVALID",
  "errorMessage": "unitTo must be an energy unit.",
  "status": 400,
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b72"
}

409 ERR_CALORIFIC_VALUE_DUPLICATE ​

Thrown when a default for the same medium and primary source already starts on the same date.

json
{
  "errorCode": "ERR_CALORIFIC_VALUE_DUPLICATE",
  "errorMessage": "A default for this combination already starts on this date.",
  "status": 409,
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b72"
}

📥 PATCH /v1/admin/calorific-values/{id} ​

Corrects a default that was entered wrongly. The combination is not correctable — a value filed against the wrong medium or source is withdrawn and re-entered, so the history shows what happened.

Authorization ​

Requires permission code platform.calorific-values.write, platform-scoped.

Request Headers ​

None beyond the platform application's standard bearer authentication.

Request Body ​

json
{
  "value": 10.480000,
  "validFrom": "2026-01-01",
  "note": "ČSN 38 5502, revize 2026 — oprava"
}

Request Parameters ​

NameInTypeRequiredDefaultDescriptionValidation / NotesDB Mapping
idPathUUIDYes-The default being corrected.Must exist and not be withdrawn.defaultCalorificValue.id
valueBodyDecimalNounchangedCorrected value.Must be > 0; at most six decimal places.defaultCalorificValue.value
unitFromBodyEnumNounchangedCorrected source unit.Volume or mass unit.defaultCalorificValue.unitFrom
unitToBodyEnumNounchangedCorrected target unit.Energy unit.defaultCalorificValue.unitTo
validFromBodyDateNounchangedCorrected validity date.YYYY-MM-DD.defaultCalorificValue.validFrom
noteBodyStringNounchangedCorrected source reference.Max 500 characters.defaultCalorificValue.note

Request Logic ​

  • Updates the named row, leaving medium and primary_source untouched.
  • Writes one platform audit entry carrying the changed fields only.
  • Enqueues recalculation from the earlier of the old and new validity dates, so a date moved backwards also recomputes the period it now covers.
sql
UPDATE shared.default_calorific_value
SET value      = COALESCE(@value, value),
    unit_from  = COALESCE(@unitFrom, unit_from),
    unit_to    = COALESCE(@unitTo, unit_to),
    valid_from = COALESCE(@validFrom, valid_from),
    note       = COALESCE(@note, note),
    updated_at = now(),
    updated_by = @actor
WHERE id = @id
  AND deleted_at IS NULL;

Transactional Operations ​

The update, its audit entry and the recalculation request commit together. A corrected validity date that collides with another row for the same combination is rejected by the unique index and rolls all three back.

✅ Success Response (200) ​

json
{
  "data": {
    "id": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b43"
  },
  "status": 200,
  "message": "OK",
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b73"
}

Response Data Mapping ​

Response FieldSource / Value
iddefaultCalorificValue.id of the corrected row

❌ Error Responses ​

400 ERR_CALORIFIC_VALUE_INVALID ​

Thrown for the same validation failures as on creation.

json
{
  "errorCode": "ERR_CALORIFIC_VALUE_INVALID",
  "errorMessage": "value must be greater than zero.",
  "status": 400,
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b73"
}

404 ERR_CALORIFIC_VALUE_NOT_FOUND ​

Thrown when no such default exists, or it has already been withdrawn.

json
{
  "errorCode": "ERR_CALORIFIC_VALUE_NOT_FOUND",
  "errorMessage": "Default not found.",
  "status": 404,
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b73"
}

409 ERR_CALORIFIC_VALUE_DUPLICATE ​

Thrown when the corrected validity date collides with another default for the same combination.

json
{
  "errorCode": "ERR_CALORIFIC_VALUE_DUPLICATE",
  "errorMessage": "A default for this combination already starts on this date.",
  "status": 409,
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b73"
}

📥 DELETE /v1/admin/calorific-values/{id} ​

Withdraws a default entered in error. The row stops applying and stays in the history; a superseded default is never withdrawn, because it is what reproduces the energy it converted.

Authorization ​

Requires permission code platform.calorific-values.write, platform-scoped.

Request Headers ​

None beyond the platform application's standard bearer authentication.

Request Body ​

None.

Request Parameters ​

NameInTypeRequiredDefaultDescriptionValidation / NotesDB Mapping
idPathUUIDYes-The default being withdrawn.Must exist and not already be withdrawn.defaultCalorificValue.id

Request Logic ​

  • Sets deleted_at; nothing is physically removed.
  • Frees the combination and date for re-entry, because the unique index ignores withdrawn rows.
  • Writes one platform audit entry carrying the row in full, and enqueues recalculation from its validity date — gauges that resolved to it now resolve to the previous default, or to none.
sql
UPDATE shared.default_calorific_value
SET deleted_at = now(),
    updated_at = now(),
    updated_by = @actor
WHERE id = @id
  AND deleted_at IS NULL;

Transactional Operations ​

The withdrawal, its audit entry and the recalculation request commit together.

✅ Success Response (204) ​

No payload.

Response Data Mapping ​

N/A — no payload.

❌ Error Responses ​

404 ERR_CALORIFIC_VALUE_NOT_FOUND ​

Thrown when no such default exists, or it is already withdrawn.

json
{
  "errorCode": "ERR_CALORIFIC_VALUE_NOT_FOUND",
  "errorMessage": "Default not found.",
  "status": 404,
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b74"
}

Client scope = the request's tenant ​

The client scope is a business notion — nastavení klienta — and keeps the word client in the URL, but it is identified by the tenant of the request, not by an id the caller passes:

  • platform.tenants.client_id is NOT NULL and UNIQUE, so a tenant is exactly one client and every tenant-backend request is already in that client's context.
  • The tenant backend has no /v1/clients controller and gauge has no client_id; rows are scoped by tenant_id through the request context (RLS, app.tenant_id).
  • Hence the singular path /v1/client/calorific-values (+ /history, /{id}) with no client id in the path or query. A clientId parameter must never be added — the same rule the tenant-scoped tolerance read follows.
  • Where a row stores clientId (calorificValue.clientId), the server fills it from the request's tenant; the caller never supplies it.

Response shapes, permissions and rules below are the same for every client-scope endpoint.


📥 GET /v1/client/calorific-values ​

The client tab. One row per combination of medium and primary source that the client's gauges actually use, with the value that resolves for it today, where that value comes from, and how many gauges it covers.

Authorization ​

Permission code tenant.clients.read. Tenant-scoped through the request context; the client is the request's tenant, so no client id is passed.

Request Parameters ​

NameInTypeRequiredDefaultDescriptionValidation / Notes
onDateQueryDateNotodayThe day the resolution is evaluated for — the screen's "Platnost" filter.YYYY-MM-DD
mediumQueryEnumNoallLimits the rows to one medium.Enum - GaugeMedium
scopeQueryEnumNoallown — only combinations with a client value; missing — only combinations with no value at any scope.all | own | missing

Request Logic ​

  • Combinations come from the client's active gauges whose medium converts volume or mass to energy (gas, fuel, phm, heat delivered as GJ) — grouped by (medium, primarySource).
  • For each combination, three reads with the same validity rule as the resolver: the client value valid on onDate, the platform default valid on onDate, and the gauge values valid on onDate for the gauges in the combination.
  • resolved is the client value when one exists, else the platform default, else none; gaugesIndividual and gaugesWithoutValue are counted per gauge through calorificValueFor.
  • summary repeats the four numbers the header shows so the screen needs one request.
sql
SELECT g.medium, g.primary_source, count(*) AS gauge_count
FROM gauge g
-- no client filter: the request's tenant is the client; RLS scopes gauge rows by tenant_id = app.tenant_id
WHERE g.is_archived = false AND g.medium IN ('gas','fuel','phm','heat')
GROUP BY g.medium, g.primary_source
ORDER BY g.medium, g.primary_source;

✅ Success Response (200) ​

json
{
  "data": {
    "summary": { "combinations": 8, "ownValues": 1, "individualGauges": 2, "gaugesWithoutValue": 3 },
    "items": [
      {
        "medium": "gas",
        "primarySource": 1,
        "gaugeCount": 14,
        "resolved": { "scope": "client", "valueId": "018f9c4d-…-6b51", "value": 10.620000, "unitFrom": "m3", "unitTo": "kWh", "validFrom": "2026-01-01", "note": "Prohlášení GasNet Q1/2026" },
        "tiers": {
          "client":   { "valueId": "018f9c4d-…-6b51", "value": 10.620000, "unitFrom": "m3", "unitTo": "kWh", "validFrom": "2026-01-01", "note": "Prohlášení GasNet Q1/2026", "updatedBy": "user:018ed0b3-…" },
          "platform": { "valueId": "018f9c4d-…-6b21", "value": 10.550000, "unitFrom": "m3", "unitTo": "kWh", "validFrom": "2024-01-01", "note": "ČSN 38 5502" }
        },
        "gauges": {
          "individual": [ { "gaugeId": "018f6e2a-…", "gaugeName": "Plynoměr G6", "buildingName": "Kotelna ZŠ Komenského", "value": 10.480000, "validFrom": "2026-03-01" } ],
          "withoutValue": []
        }
      },
      {
        "medium": "fuel",
        "primarySource": 4,
        "gaugeCount": 3,
        "resolved": null,
        "tiers": { "client": null, "platform": null },
        "gauges": { "individual": [], "withoutValue": [ { "gaugeId": "018f6e2b-…", "gaugeName": "Kotel K1", "buildingName": "MŠ Sluníčko" } ] }
      }
    ]
  },
  "status": 200,
  "message": "OK",
  "requestId": "018f9c4d-2c11-7a3e-9b77-4f0d3a5e6b61"
}

Response Data Mapping ​

Response FieldSource / Value
items[].medium, primarySource, gaugeCountGrouped from gauge
items[].resolvedDerived: the tier the resolver would pick for a gauge of this combination with no value of its own
items[].tiers.clientcalorificValue with gaugeId null, valid on onDate
items[].tiers.platformdefaultCalorificValue valid on onDate
items[].gauges.individual[]calorificValue with gaugeId set, valid on onDate
items[].gauges.withoutValue[]Gauges for which calorificValueFor returns none on onDate
summary.gaugesWithoutValuegaugesWithoutValue() for the request's tenant

📥 GET /v1/client/calorific-values/history ​

History of one combination at the client scope — every client value ever stated for it, withdrawn ones flagged — for the "Historie" action on a row.

Request Parameters ​

NameInTypeRequiredDescription
mediumQueryEnumYesCombination's medium.
primarySourceQueryIntegerYesCombination's primary source.

Returns data: [ { valueId, value, unitFrom, unitTo, validFrom, note, withdrawn, createdBy, createdAt } ], newest validFrom first. Read-only, permission tenant.clients.read.


📥 POST /v1/client/calorific-values ​

Adds a client value for one combination from one date — "Nastavit vlastní" and every later correction alike.

Authorization ​

Permission code tenant.clients.write.

Request Body ​

NameTypeRequiredDescriptionValidation / NotesDB Mapping
mediumEnumYesCombination.Must be a medium that converts to energy.calorificValue.medium
primarySourceIntegerYesCombination.An entry from Enum - PrimarySource.calorificValue.primarySource
valueDecimalYesThe factor.> 0, six decimals.calorificValue.value
unitFromEnumYesVolume or mass unit.Must match the unit the combination's gauges read in.calorificValue.unitFrom
unitToEnumYesEnergy unit.calorificValue.unitTo
validFromDateYesFirst day it applies.May be in the future. Unique per combination at the client scope → 409 ERR_CALORIFIC_VALUE_DUPLICATE.calorificValue.validFrom
noteStringNoWhere it comes from.≤ 500 characters.calorificValue.note

Request Logic ​

One transaction: insert the row with gaugeId = null and clientId taken from the request's tenant (platform.tenants.client_id), write the audit entry, enqueue recalculation from validFrom for the client's gauges of this combination that have no gauge value valid in the affected period. The response carries that gauge count so the screen can confirm what the dialog promised.

✅ Success Response (201) ​

json
{ "data": { "id": "018f9c4d-…-6b52", "recalculatedGauges": 12 }, "status": 201, "message": "Created", "requestId": "…" }

❌ Error Responses ​

  • 400 ERR_VALIDATION — body outside the schema; unitFrom not a volume/mass unit; unitTo not an energy unit.
  • 409 ERR_CALORIFIC_VALUE_DUPLICATE — a client value for this combination already starts on validFrom; details carries the existing valueId so the form can point at it.

📥 PATCH /v1/client/calorific-values/{id} ​

Corrects the citation of a client value. The number, units, combination and date are not correctable — a wrong one is withdrawn and re-entered, so the history shows what happened.

Body: { "note": "…" } only. Permission tenant.clients.write. 404 when the value belongs to another client or is withdrawn.


📥 DELETE /v1/client/calorific-values/{id} ​

Withdraws a client value entered in error. The row stops applying, stays in the history, and the affected gauges fall back to the next scope from its validFrom.

Permission tenant.clients.write. Sets deletedAt, writes the audit entry, enqueues recalculation from the withdrawn row's validFrom for the gauges it resolved to. 409 ERR_CALORIFIC_VALUE_SUPERSEDED when a later client value for the same combination exists — a superseded value reproduces the energy of the period it covered and is never withdrawn.


📥 GET /v1/gauges/{gaugeId}/calorific-values ​

The card on the gauge detail: what applies to this gauge today, from which scope, and what would apply without the gauge's own value.

Authorization ​

Permission code tenant.gauges.read.

Request Parameters ​

NameInTypeRequiredDefaultDescription
onDateQueryDateNotodayDay the resolution is evaluated for.

Request Logic ​

calorificValueFor(gaugeId, onDate) plus the two tiers below it, and the gauge's own history. 404 when the gauge's medium does not convert to energy — the card is not shown for such gauges.

✅ Success Response (200) ​

json
{
  "data": {
    "medium": "gas", "primarySource": 1,
    "resolved": { "scope": "gauge", "valueId": "018f9c4d-…-6b70", "value": 10.480000, "unitFrom": "m3", "unitTo": "kWh", "validFrom": "2026-03-01", "note": "Rozbor plynu kotelna 02/2026", "updatedBy": "user:018ed0b3-…" },
    "tiers": {
      "gauge":    { "valueId": "018f9c4d-…-6b70", "value": 10.480000, "validFrom": "2026-03-01", "note": "Rozbor plynu kotelna 02/2026" },
      "client":   { "valueId": "018f9c4d-…-6b51", "value": 10.620000, "validFrom": "2026-01-01", "note": "Prohlášení GasNet Q1/2026" },
      "platform": { "valueId": "018f9c4d-…-6b21", "value": 10.550000, "validFrom": "2024-01-01", "note": "ČSN 38 5502" }
    },
    "history": [ { "valueId": "018f9c4d-…-6b70", "value": 10.480000, "validFrom": "2026-03-01", "withdrawn": false, "createdBy": "user:018ed0b3-…", "createdAt": "2026-02-27T09:12:00Z" } ]
  },
  "status": 200, "message": "OK", "requestId": "…"
}

📥 POST /v1/gauges/{gaugeId}/calorific-values ​

Adds a gauge value from one date — "Nastavit individuální".

Permission tenant.gauges.write. Body as the client POST without medium and primarySource — both are taken from the gauge, so a gauge value can never be filed against a combination the gauge does not have. Inserts the row with gaugeId and the gauge's clientId, writes the audit entry, enqueues recalculation for this gauge from validFrom. 409 ERR_CALORIFIC_VALUE_DUPLICATE on the same validFrom; 404 ERR_GAUGE_NOT_ENERGY_CONVERTIBLE when the medium does not convert.

PATCH /v1/gauges/{gaugeId}/calorific-values/{id} (note only) and DELETE /v1/gauges/{gaugeId}/calorific-values/{id} (withdraw; falls back to the client or platform tier from validFrom) follow the client-scope rules above.


Tenant endpoint summary ​

EndpointScreen elementPermission
GET /v1/client/calorific-valuesClient tab: rows, tiers, gap count, filterstenant.clients.read
GET /v1/client/calorific-values/history"Historie" on a rowtenant.clients.read
POST /v1/client/calorific-values"Nastavit vlastní" / "Upravit vlastní" (new dated row)tenant.clients.write
PATCH …/calorific-values/{id}Fix the citationtenant.clients.write
DELETE …/calorific-values/{id}Withdraw a mistaken valuetenant.clients.write
GET /v1/gauges/{id}/calorific-valuesGauge detail cardtenant.gauges.read
POST /v1/gauges/{id}/calorific-values"Nastavit individuální"tenant.gauges.write

Emission factors are expected to reuse this shape one-to-one (/emission-factors), which is why the response carries tiers generically rather than calorific-specific names.


Internal access — resolving a value ​

The consumption calculation does not go through HTTP: it reads through a port with one operation, which is the only place the three scopes are compared.

calorificValueFor(gaugeId, onDate) -> { value, unitFrom, unitTo, scope, valueId } | none
  • Read-only, no transaction of its own; it participates in the caller's.
  • Resolves in order gauge, client, platform default, taking at each step the latest non-withdrawn value whose validFrom is on or before onDate, and returns the first scope that has one.
  • A client or platform value is considered only when its medium and primary source match the gauge's.
  • Returns none where no scope holds a value — never a constant.
  • scope and valueId come back with the number so the caller can record and explain which value produced a figure.

A second operation reports the gap the screens and the monitor both use:

gaugesWithoutValue(clientId?) -> count
  • Counts gauges whose medium converts to energy and for which calorificValueFor returns none today.