Skip to content

Node Meter Reading List Request

The NodeMeterReadingListRequest retrieves the historical meter readings of a single node over a specified time range. For each sampled timestamp, the response returns the total charged and discharged energy at that point, together with the schedule that was applied and the control state of the node at that moment.

Typical use cases include billing, energy reporting, charts of charge/discharge behaviour, and verifying that a specific schedule was in effect during a given time window.

Preparations

  • Launch the development client as described in the FlexConnect API — First Steps.
  • Navigate to http://localhost:8080/ui.
  • Select the documentation for Node Meter Reading List Request in the left pane.
  • Have the identifier of the node ready — use NodeStateListRequest to discover it if needed.

One node per request

Unlike NodeStateListRequest, this request operates on a single node: filter.id is one identifier, not a list. Repeat the request — or iterate over your nodes — to retrieve readings for multiple nodes.

Request

Run the NodeMeterReadingListRequest using the JSON body below.

  1. Run the request on app/v1/NodeMeterReadingListRequest.
  2. Replace the stringValue in filter.id with the identifier of the node you want to query.
  3. Set startTime and endTime to the time range you want to query, in seconds since epoch. startTime is inclusive, endTime is exclusive.
  4. Set pagination.limit to the maximum number of meter-reading samples you want returned in a single response.

Request body

json
{
  "header": {
    "reqId": 1234,
    "timeoutMs": 10000
  },
  "pagination": {
    "limit": 100
  },
  "filter": {
    "id": {
      "type": { "id": 2 },
      "stringValue": "54F2664E28EDF2593B9CAAAF041687BEDB0A15C8"
    }
  },
  "startTime": 1779541075,
  "endTime": 1779541675
}

Request fields

FieldDescription
header.reqIdClient-defined identifier for the request. The same value is returned in the response header to correlate requests and responses.
header.timeoutMsMaximum time (in milliseconds) the platform waits for the result before responding with a timeout error.
pagination.limitMaximum number of meter-reading samples returned in a single response.
pagination.cursorValueCursor value returned in a previous response as cursorNext or cursorPrevious. Use it to iterate through large result sets.
filter.idIdentifier of the single node to query. The identifier type used here determines the type used in the response.
startTimeStart of the time range to query, in seconds since epoch, inclusive.
endTimeEnd of the time range to query, in seconds since epoch, exclusive.

Response

Response body

json
{
  "header": {
    "reqId": 1234
  },
  "pagination": {
    "cursorNext": "1wsf="
  },
  "nodeMeterReadings": {
    "id": {
      "type": { "id": 2 },
      "stringValue": "54F2664E28EDF2593B9CAAAF041687BEDB0A15C8"
    },
    "timestamp": [1779541075, 1779541135, 1779541195],
    "positiveEnergy": [1000.0, 1001.0, 1002.0],
    "negativeEnergy": [2000.0, 2001.0, 2002.0],
    "scheduleIds": [582, 582, 583],
    "controlStates": [3, 3, 3]
  }
}

Index-aligned arrays

All arrays in nodeMeterReadings are aligned by index: the value at index i of positiveEnergy, negativeEnergy, scheduleIds, and controlStates belongs to the timestamp at index i of timestamp. In the example above, index 0 describes the sample at 17795410751000.0 kWh charged, 2000.0 kWh discharged, under schedule 582 in control state POWER (3).

Response fields

FieldDescription
nodeMeterReadings.idIdentifier of the node. The identifier type matches the type used in filter.id of the request.
nodeMeterReadings.timestampOrdered timestamps of the meter readings, in seconds since epoch.
nodeMeterReadings.positiveEnergyTotal energy imported by the battery (charged) at the corresponding timestamp, in kWh. This is a running meter total — it monotonically increases over time, never resets. Subtract values from two timestamps to get the energy imported between them.
nodeMeterReadings.negativeEnergyTotal energy exported by the battery (discharged) at the corresponding timestamp, in kWh. Like positiveEnergy, this is a monotonically increasing meter total.
nodeMeterReadings.scheduleIdsIdentifier of the schedule that was applied at the corresponding timestamp. See scheduleIds special values.
nodeMeterReadings.controlStatesControl state of the node at the corresponding timestamp. Values match the controlState table on the Power Schedules page, with 1 (IDLE) and 2 (FAILSAFE) also possible here.
pagination.cursorNext / cursorPreviousReturned when the result set is larger than limit. Pass either value as pagination.cursorValue in a follow-up request to paginate.

scheduleIds special values

ValueDescription
> 0The identifier of the power schedule that was applied at the corresponding timestamp.
0No schedule was applied (the node was running its firmware default).
-1The system could not apply a schedule due to a failure.

Computing energy in a time window

Because positiveEnergy and negativeEnergy are cumulative meter totals, the energy imported or exported between two samples is the difference of the two values:

  • energyCharged = positiveEnergy[j] - positiveEnergy[i] (kWh imported between sample i and sample j, with i < j).
  • energyDischarged = negativeEnergy[j] - negativeEnergy[i] (kWh exported between sample i and sample j).
  • netEnergy = energyCharged - energyDischarged (positive = net charge, negative = net discharge).

To get the energy across the entire response, subtract the first sample's values from the last sample's values. To get energy across the full requested range when paginating, hold on to the cumulative totals across pages.

Pagination

When the requested time range contains more samples than the pagination.limit, the response includes a pagination.cursorNext value (and, when iterating, a cursorPrevious value).

To retrieve the next page, repeat the request — keeping filter.id, startTime, and endTime unchanged — and pass the received cursorNext value as pagination.cursorValue. Iteration ends when no further cursor is returned.

json
{
  "header": {
    "reqId": 1235,
    "timeoutMs": 10000
  },
  "pagination": {
    "limit": 100,
    "cursorValue": "1wsf="
  },
  "filter": {
    "id": {
      "type": { "id": 2 },
      "stringValue": "54F2664E28EDF2593B9CAAAF041687BEDB0A15C8"
    }
  },
  "startTime": 1779541075,
  "endTime": 1779541675
}

Keep the request parameters stable across pages

When paginating, the filter.id, startTime, and endTime of every page must match the original request. Only the pagination.cursorValue changes.