Technical Overview: New Measurement Processing

As announced in the Important Update: Evolving Our Data Platform for a Scalable Future post, starting September 22nd we will begin rolling out the new measurement processing to all HEMS systems. We are starting with Battery Measurements. In preparation for that switch, we have prepared the following technical overview.

Current situation

Currently, assets connected to a gridBox provide raw measurements at ~ 2-second intervals. These measurements can be retrieved using the Appliance’s Raw Measurements API.

:warning: This endpoint is deprecated as transferring data that fine grained is inefficient for little benefit.

New Measurement Processing

We are introducing a new measurement processing, for greater scalability and efficiency. By optimizing the data granularity for cloud communication from 2-second to 30-second intervals, we reduce the amount of data sent to the cloud.

This comes with the following changes and improvements.

Flexible granularity

As announced, we will support a ā€œgranularity fine-tuned for use-cases and flexible for testing and debugging purposesā€. To achieve this, we needed a new measurement specification to support different intervals, example 2-second to 30-second intervals.

The new measurement specification:

  • includes time metadata
    • for a sampled measurement, represents the asset’s state at a specific point in time
    • for an aggregated measurement, represents the asset’s state over a specific time interval.
  • to simplify the specs, all number fields are now floats.

API

We have developed a new List Asset Measurements API, that is designed to handle measurements of different granularity (sampled vs aggregated).

:warning: The API is currently in draft mode, feedback is welcome.

Improvements compared to the existing API

The following improvements have been made to the new API specification, vs the existing one:

  • assets are now linked to the system, not the gateway
    • to cater to systems without physical gateways
    • to allow for virtual or multiple gateways in the future, and because they are functionally unrelated to gateways
  • battery measurements are returned, not inverter measurements, which aligns with the actual raw data

Sampled Measurements

In Phase 1, starting September 22nd, we will begin shifting gridBoxes to the new measurement processing, while keeping the granularity at 2-second intervals.

Sampled measurements are raw measurements, with no aggregation applied to them. The timestamp is unmodified.

{
  "type": "BATTERY",
  "measurements": [
    {
      "capacity": 6400,
      "stateOfCharge": 10,
      "chargePower": 0,
      "dischargePower": 0,
      "measuredAt": "2025-08-29T08:30:00Z"
    },
    {
      "capacity": 6400,
      "stateOfCharge": 10,
      "chargePower": 0,
      "dischargePower": 0,
      "measuredAt": "2025-08-29T08:30:02Z"
    },
    {
      "capacity": 6400,
      "stateOfCharge": 10,
      "chargePower": 0,
      "dischargePower": 0,
      "measuredAt": "2025-08-29T08:30:04Z"
    }
  ]
}

Aggregated (Downsampled) Measurements

In Phase 2, the default granularity will change from 2-second to 30-second intervals. This is done by downsampling on the gridBox. Raw measurements are cached for 30s, downsampled, then sent to the cloud.

:information_source: This does not affect measurements on the gridBox or the EMS.

When a measurement has been aggregated, it contains the interval. For example, when aggregated over 30-seconds, it will look like this:

"measuredFrom": "2025-09-05T18:00:00Z",
"measuredTo": "2025-09-05T18:00:30Z",

The downsampling of raw measurements is done on a field by field basis, and could be the min, max, last or average value over the interval. Averages are calculated using time-weighted-average.

Here’s an example set of aggregated measurements:

{
  "type": "BATTERY",
  "measurements": [
    {
      "activePower": 0,
      "capacity": 6400,
      "chargePower": 0,
      "dischargePower": 0,
      "measuredFrom": "2025-09-09T18:00:00Z",
      "measuredTo": "2025-09-05T18:00:29Z",
      "stateOfCharge": 99
    },
    {
      "activePower": 0,
      "capacity": 6400.000000000001,
      "chargePower": 0,
      "dischargePower": 0,
      "measuredFrom": "2025-09-05T18:00:29Z",
      "measuredTo": "2025-09-05T18:00:59Z",
      "stateOfCharge": 99.00000000000001
    },
    {
      "activePower": 0,
      "capacity": 6400.000000000002,
      "chargePower": 0,
      "dischargePower": 0,
      "measuredFrom": "2025-09-05T18:00:59Z",
      "measuredTo": "2025-09-05T18:01:29Z",
      "stateOfCharge": 99
    },
    {
      "activePower": 0,
      "capacity": 6399.999999999999,
      "chargePower": 0,
      "dischargePower": 0,
      "measuredFrom": "2025-09-05T18:01:29Z",
      "measuredTo": "2025-09-05T18:01:59Z",
      "stateOfCharge": 99
    },
    {
      "activePower": 0,
      "capacity": 6400,
      "chargePower": 0,
      "dischargePower": 0,
      "measuredFrom": "2025-09-05T18:02:00Z",
      "measuredTo": "2025-09-05T18:02:29Z",
      "stateOfCharge": 98.99999999999999
    }
  ]
}

Existing Appliance’s Raw Measurements API

The existing List Appliance’s Raw Measurements API will continue to function with the new measurement types, with some adjustments

The API will have to convert the new measurements to fit the existing format.

  • the measuredAt field will correspond to
    • the measuredAt of a sampled measurement
    • the measuredTo of an aggregated measurement
  • due to the float → integer conversion, some precision will be lost

API response with 2-second interval

[
  {
    "battery": {
      "capacity": 6400,
      "measuredAt": "2025-09-10T13:29:50Z",
      "presentCharge": 0,
      "presentDischarge": 0,
      "stateOfCharge": 99
    },
    "measuredAt": "2025-09-10T13:29:50Z"
  },
  {
    "battery": {
      "capacity": 6400,
      "measuredAt": "2025-09-10T13:29:52Z",
      "presentCharge": 0,
      "presentDischarge": 0,
      "stateOfCharge": 99
    },
    "measuredAt": "2025-09-10T13:29:52Z"
  },
  {
    "battery": {
      "capacity": 6400,
      "measuredAt": "2025-09-10T13:29:54Z",
      "presentCharge": 0,
      "presentDischarge": 0,
      "stateOfCharge": 99
    },
    "measuredAt": "2025-09-10T13:29:54Z"
  },
  {
    "battery": {
      "capacity": 6400,
      "measuredAt": "2025-09-10T13:29:56Z",
      "presentCharge": 0,
      "presentDischarge": 0,
      "stateOfCharge": 99
    },
    "measuredAt": "2025-09-10T13:29:56Z"
  }
]

API response with 30-second interval

[
  {
    "battery": {
      "capacity": 6399,
      "measuredAt": "2025-09-10T13:30:29Z",
      "presentCharge": 0,
      "presentDischarge": 0,
      "stateOfCharge": 98
    },
    "measuredAt": "2025-09-10T13:30:29Z"
  },
  {
    "battery": {
      "capacity": 6400,
      "measuredAt": "2025-09-10T13:30:59Z",
      "presentCharge": 0,
      "presentDischarge": 0,
      "stateOfCharge": 99
    },
    "measuredAt": "2025-09-10T13:30:59Z"
  },
  {
    "battery": {
      "capacity": 6400,
      "measuredAt": "2025-09-10T13:31:29Z",
      "presentCharge": 0,
      "presentDischarge": 0,
      "stateOfCharge": 99
    },
    "measuredAt": "2025-09-10T13:31:29Z"
  },
  {
    "battery": {
      "capacity": 6400,
      "measuredAt": "2025-09-10T13:31:59Z",
      "presentCharge": 0,
      "presentDischarge": 0,
      "stateOfCharge": 98
    },
    "measuredAt": "2025-09-10T13:31:59Z"
  }
]

Migration plan

There is no urgency to migrate right away. It will take some months before all assets are migrated to the new API. In the meantime, the existing API will continue to work (even after migration). The existing API will be deprecated sometime in 2026.

However, to take full advantage of the new measurement data, you should migrate to the new APIs.

Future Plans

In Phase 3, we will extend the functionality to all asset types.

1 Like

Starting October 21st, 2025, the API response was changed to return an Object. The response now contains a type with a list of measurements. The response now enforces that measurements are all of the same type.

Hi @c.coltsman, what about the Appliance’s Combined Measurements endpoint? e.g. /gateways/{gatewayID}/appliances/{applianceID}/measurements

Will it continue to work (with the aggregated data I believe) or should we also migrate away from it? If yes, this implies we should start ingesting Energy Management measurements separately too?

Thank you

Hi @Antonio . Thank you for pointing this out, we should definitely address this issue. At the moment, this is currently not relevant for your use case, since it only applies to HEMS systems. You will continue to use the existing APIs.

1 Like