Protocol version changelog
This page tracks changes to the Tensor Cloud battery optimization protocol. The version reflected here is info.version in the AsyncAPI specification and the schema_version field every EMS emits on every message.
Versioning follows semver-style: MAJOR.MINOR.PATCH.
- MAJOR - backwards-incompatible changes to topic structure, payload shape, or required fields that existing integrations cannot satisfy without code changes.
- MINOR - additive changes (new fields, new conditional validation, new behaviour) that strengthen guarantees but remain readable by clients on prior versions. Tensor Cloud remains backwards-compatible with messages emitted under older minor revisions.
- PATCH - documentation clarifications, example corrections, and other changes with no payload impact. Because a PATCH release has no payload impact, the wire
schema_versiondoes not change: integrations keep emitting the current MINOR version (e.g.2.3.0) until a MINOR or MAJOR release changes the payload.
2.8.0 - 2026-08-17
Batched telemetry for instantaneous power and grid frequency. Additive and optional; single-message telemetry is unchanged.
- New optional topics
dt/{siteId}/{gatewayId}/{metric}/power/batchanddt/{siteId}/{gatewayId}/frequency/batch, carryingPowerInstantBatchandGridFrequencyBatch. No other channel gains a batched form. - A batch states
unit,aggregation,aggregation_windowandpre_qualificationonce; each entry inmeasurementscarries its ownmessage_id,measurement_tsandvalue. Split the batch whenever a stated field changes. - Entries must be strictly ascending on
measurement_ts, with timestamps and entrymessage_idvalues unique within the batch. No entrymessage_idmay equal the batch's own.minItems1,maxItems900, encoded payload at most 122,880 bytes. - A batch is accepted in full or rejected in full, as for command validation in 2.7.0.
- Deduplication keys on each entry's
message_id. The batch's own identifies the publish attempt only, so readings may be re-grouped or retried in the single-message form under their original ids. - Batch topics require QoS 1 and must not set the MQTT RETAIN flag.
DUPLICATEclarified: an unchanged resend under the originalmessage_idis an idempotent success, not a duplicate. Applies to single-message telemetry too; no behaviour change.- Batching is enabled per site and is backfill-only by default. See the integrator guide.
- New integrator checklist items
BA-1throughBA-6. - Wire
schema_versionmoves to2.8.0.
2.7.0 - 2026-08-13
A GRID_OTHER alert code, and all-or-nothing command validation. Additive and backward-compatible.
- New
GRID_OTHERvalue onAlertCode, for AC-side grid faults that no existing code covers: loss of the grid connection, a protection relay or grid-interconnection breaker trip, an out-of-tolerance voltage or frequency condition at the connection point, or a site-wide outage the EMS can still report. Previously these had to be reported asUNKNOWN_FAULT, which carried no subsystem. See the integrator guide's "Alert codes reference" section. - Documented that a single fault may raise more than one alert code, and that Tensor Cloud expects rather than deduplicates this. On a DC-linked system a fault in hardware shared by the PV array and the battery (a hybrid inverter, a common power conditioning subsystem, a common control or aggregation unit) is reported as both
PV_OTHERandBATT_OTHER. Where the EMS reaches both subsystems through a single collector device and cannot see per-BMS or per-PVPCS communication status, raisingBATT_COMM_FAILandPV_COMM_FAILsimultaneously on loss of communication with that collector is acceptable. New checklist itemA-6 - Shared-hardware faults raise every applicable code, verified by integrator test only. - Documented that command validation is all-or-nothing. If any item in
control.schedulefails validation, the EMS applies none of the items in that command, including the valid ones, and continues executing the previously valid schedule. This holds forBatteryPowerCommandandBatteryFcrCommand, and for FCRaction: "cancel"as well asaction: "execute".CommandResponse.statushas no partial value, so a partially applied command could not be acknowledged accurately; dropped slots would also fall back to older commands under the per-slot resolution rules, silently reviving a schedule that was meant to be replaced.errors[]must carry one entry per invalid item rather than stopping at the first. New integrator checklist itemsAR-15 - Mixed valid and invalid schedule itemsfor power commands andFC-10 - Mixed valid and invalid schedule items (FCR)for FCR execute and cancel, both verified by integrator test only. - Documented that the
alertStatesnapshot is published on its schedule whether or not any alert is firing. With nothing active, publish an emptymeasurement_valuearray rather than suppressing the publish: the empty array is the positive statement that the site is healthy, and without it Tensor Cloud cannot distinguish a healthy site from a silent EMS. New checklist itemA-5 - alertState snapshot with no active alerts. - New optional
reference_pointon eachBatteryPowerCommandschedule interval,"battery"or"grid", naming the point that interval'spower_kwrefers to."battery"means the value refers to the battery itself and co-located generation flows through untouched, so0is a battery stand-down."grid"means it refers to the site's metering point (受電点, wheremeter_export_acandmeter_import_acare measured, which is not the inverter's AC output on a site with on-site load), so0holds the meter at zero and the battery absorbs whatever is generated. Omitting the field means"battery", so every command issued before 2.7.0 keeps exactly the meaning it had. The reference point is never inferred from the site's topology: on DC-coupled systems, where the battery and PV share an inverter, the EMS honours"battery"by compensating its AC setpoint against measured PV, which keeps solar forecast error off the battery. Tensor Cloud states the field on every command and sends"grid"only to sites whose EMS reportsschema_version2.7.0 or later. New checklist itemAR-16 - reference_point interpretation, and the first workedBatteryPowerCommandexamples in the specification. - New
SETPOINT_UNREACHABLEvalue onAlertCode, and a new schedule interpretation rule 9. When the EMS cannot deliver a commanded setpoint - an inverter limit on a"battery"interval, a state-of-energy limit on a"grid"interval - it clamps to the closest achievable value, keeps executing, and raises the alert naming the limit it hit. It does not reject the command or stop the battery, consistent with the 2.3.1 rule that the acknowledgement covers receipt-time validation only. This case previously had no defined behaviour. New checklist itemAR-17 - Unreachable setpoint clamps and alerts, verified by integrator test only. - Resolved a contradiction over whether curtailment is required. The
Curtailmentmessage summary called it optional, and singled out stand-alone systems as the case it mattered most for, while the integrator guide marked it 🔴 Required for every topology. Curtailment is required for every topology, including stand-alone batteries: a site with no co-located solar can still be subject to TSO output control. The guide was correct and is unchanged; the message summary and thecurtailmentchannel description now agree with it, and checklist itemPT-Sstates that curtailment remains required for stand-alone even though irradiation does not apply.SO-3keeps its existing scope, since it tests the solar-specific case. No payload change: the channel and message shape are untouched. - Wire
schema_versionbumps to2.7.0. Per the versioning policy, a MINOR release changes the wire version, so integrations should emitschema_version: "2.7.0"going forward. Tensor Cloud remains backwards-compatible with messages emitted under prior versions.
2.6.1 - 2026-07-28
measurement_ts on windowed measurements clarified. Documentation only: no payload changes.
- Documented that on any measurement covering a period of time,
measurement_tsalways carries the start of that period, never its end or midpoint. This applies to windowed energy telemetry (where it equalsmeasurement_value.start_ts) and to power or grid frequency telemetry sent withaggregation: "average"(where it is the start ofaggregation_window). On point-in-time telemetry - lifetime counters,aggregation: "instant"power, irradiation, solar DC voltage and current, battery state, alerts -measurement_tsremains simply the instant the value was measured. - The
measurement_tsdescriptions onEnergyWindowed,PowerInstant, andGridFrequency, and the specification'sinfo.description, state this rule explicitly. See the integrator guide's "Timestamp boundary convention" section. - Documented
measurement_tsonCurtailment, which is a schedule rather than a measurement: set it to the schedule's creation time as issued by the TSO when the TSO data carries it, otherwise the time the EMS received the schedule from the TSO. The periods the schedule covers remain inmeasurement_value[].start_tsandmeasurement_value[].end_ts. - New integrator checklist item
E-7 - measurement_ts alignment, in the page and in the downloadable Excel checklist. - Added a sequence diagram of the alert message flow to the integrator guide's "Events and alerts" section.
- Per the versioning policy, a PATCH release does not change the wire
schema_version: integrations keep emitting2.6.0.
2.6.0 - 2026-07-13
Solar DC voltage and current telemetry for DC-linked systems. Additive and backward-compatible.
- New
solarDcTelemetrychannel (dt/{siteId}/{gatewayId}/solar) with theSolarDcElectricalmessage and asendSolarDcoperation. DC-coupled (DC-link) PV plus battery sites publish the PV array's DC voltage (V) and current (A), measured at the DC link upstream of the inverter as a single value aggregated across the whole array. Voltage and current are sampled at the same instant and sent together as one matched pair, at 1-minute resolution.measurement_valuecarriesvoltageandcurrent, each a{value, unit}object (unitisVorA, values ≥ 0). Applies only to DC-link sites; AC-coupled and stand-alone sites do not send it. See the integrator guide's "DC-linked telemetry" section. - Wire
schema_versionbumps to2.6.0. Per the versioning policy, a MINOR release changes the wire version, so integrations should emitschema_version: "2.6.0"going forward. Tensor Cloud remains backwards-compatible with messages emitted under prior versions.
2.5.0 - 2026-07-10
Malformed telemetry can now be acknowledged. Additive and backward-compatible.
TelemetryFeedback.correlation_idis no longer constrained to themsg_UUID pattern. When incoming telemetry cannot be parsed (MESSAGE_MALFORMED) and itsmessage_idcannot be recovered, Tensor Cloud setscorrelation_idto the sentinel string"unknown". Previously the pattern made such a feedback message impossible to construct, so no acknowledgement was sent at all and the integrator never learned the message had been rejected. If themessage_idis partially recoverable, the recovered value is echoed instead. This mirrors the"unknown"sentinel already used byCommandResponse.command_id.TelemetryFeedbackgains an optionaltopicfield carrying the topic the offending message was published on. It is present only whenstatusiserror, and is the only way to identify the rejected message whencorrelation_idis"unknown". The schema enforces its absence onstatus: "ok"through the sameif/then/elseblock that already gatescodeanddetail.- Corrected the Japanese
TelemetryFeedbackdefinition, which listedschema_versionas required but never defined the property, leaving its examples invalid against their own schema. - Wire
schema_versionbumps to2.5.0. Per the versioning policy, a MINOR release changes the wire version, so integrations should emitschema_version: "2.5.0"going forward. Tensor Cloud remains backwards-compatible with messages emitted under prior versions.
2.4.0 - 2026-07-06
Grid frequency telemetry for FCR, plus a pre-qualification (事前審査) test flag. Both are additive and backward-compatible.
- New
gridFrequencyTelemetrychannel (dt/{siteId}/{gatewayId}/frequency) with theGridFrequencymessage and asendGridFrequencyoperation. Resources awarded FCR must publish grid frequency at 1 Hz for the full duration of every FCR-awarded slot, as the mean over each 1-second window, measured at the grid connection point from the live AC waveform and reported to at least 0.0001 Hz resolution. These readings are time-aligned with the 1 Hz supplied-power telemetry used for FCR Assessment II. See the integrator guide's "FCR Assessment II reporting" section. PowerInstantandGridFrequencygain an optionalpre_qualificationboolean. The EMS sets it totrueon instantaneous-power and grid-frequency telemetry emitted while in FCR pre-qualification (事前審査) test mode, a mode the EMS operator activates, not Tensor Cloud. Tensor Cloud uses the flag to exclude that window from optimization and from FCR Assessment II submissions. Optional and backward-compatible: omitting it preserves normal-operation semantics.- Wire
schema_versionbumps to2.4.0. Per the versioning policy, a MINOR release changes the wire version, so integrations should emitschema_version: "2.4.0"going forward. Tensor Cloud remains backwards-compatible with messages emitted under prior versions.
2.3.1 - 2026-06-29
ACK and INTERNAL_ERROR semantics clarified. Documentation only: no payload changes.
- Clarified that the
CommandResponse.statusfield reflects validation and acceptance at receipt time, not the execution outcome. The ACK is sent immediately after the command is received, parsed, and committed (not at execution time) and cannot report a failure that surfaces only later at execution. - Clarified that
INTERNAL_ERRORalso covers a well-formed command that fails during receipt-time handling and cannot be accepted/committed before the ACK is sent (e.g. an internal failure committing a requested schedule change). UseINTERNAL_ERRORwith a descriptivedetail. Failures that surface only at execution time are reported through alerts/telemetry, not the ACK. - Documented that PATCH releases do not change the wire
schema_version(see the versioning note above).
2.3.0 - 2026-06-16
FCR Assessment II telemetry.
- The instantaneous-power topics (
dt/{siteId}/{gatewayId}/{metric}/power) are now documented as the channel for offline FCR Assessment II data. Resources offering FCR must publish 1-second-resolution supplied power for every FCR-awarded slot, viameter_export_ac/meter_import_ac(grid-connection-point registration) orbattery_discharge_ac/battery_charge_ac(equipment-point registration). Tensor Cloud assembles the TSO's Assessment II template (Form 35) from this data and submits it on behalf of the aggregator. See the integrator guide's "FCR Assessment II telemetry" section. powerTelemetrychannel description in the AsyncAPI specification updated to note this Assessment II use.PowerInstant.measurement_valuegains two optional fields:aggregation(instantdefault, oraverage) andaggregation_window(ISO-8601 duration, e.g.PT1S), withaggregation_windowconditionally required whenaggregationisaverage(enforced via JSON Schemaif/then). This lets a power sample declare whether it is an instantaneous point reading or a windowed mean; FCR Assessment II usesaverageoverPT1S. Additive and backward-compatible: omitting both fields keeps the prior instantaneous semantics, and prior-version messages remain accepted.
2.2.0 - 2026-05-28
Alerts, acknowledgements, and commands strengthened.
schema_versionis now required onAlertEventandAlertStatepayloads. Previously the field was defined but not in therequiredlist of either alert message. Tensor Cloud continues to accept alert payloads emitted under prior versions that omitschema_version; EMS implementations should add the field to alert payloads going forward.CommandResponse.errorsis now conditionally required by the schema: present (≥ 1 item) whenstatus: "error", absent whenstatus: "ok". Enforced via JSON Schemaif/then/else. Previously the rule was prose-only. No producer-side change required for EMS implementations that already followed the prose rule.TelemetryFeedback.codeandTelemetryFeedback.detailare now conditionally required by the schema: both present whenstatus: "error", both absent whenstatus: "ok". Enforced via JSON Schemaif/then/else. Affects the testing-only telemetry feedback channel; Tensor Cloud is the producer, EMS implementations only consume.BatteryFcrCommand.control.schedule[*].capacity_kwis now conditionally required by the schema: required whencontrol.actionisexecute(the default) and forbidden whencontrol.actioniscancel. Enforced via JSON Schemaif/then/else.BatteryPowerCommand.control.scheduleandBatteryFcrCommand.control.schedulenow declareminItems: 1. Empty schedules are rejected at the schema layer.- Embedded schema examples corrected:
CommandResponseexamples now include the requiredschema_version; FCR cancel examples usemessage_idvalues that match the documented^msg_[0-9a-f]{8}-…$pattern. - Top-level
additionalPropertiesis nowtrueon every message family (includingBatteryPowerCommandandBatteryFcrCommand). Previously commands were strict and other families lenient - the asymmetry is removed so forward-compatibility is uniform across the protocol.
2.1.0 - Previous baseline
Pre-changelog baseline. Includes the full set of telemetry, command, alert, and response channels documented in the integrator guide and AsyncAPI spec.