PHP2Shell alert: critical PHP flaws CVE-2026-109618 / 109619 — check your servers and get patched fast
HashTech Systems
EV Charging
Part 8 of 12

OCPP 1.6 Configuration Keys, TriggerMessage and DataTransfer

Managing OCPP 1.6 charger configuration: GetConfiguration, ChangeConfiguration, the standard keys that matter, TriggerMessage and DataTransfer.

HashTech Engineering · October 26, 2026 · 5 min read

Most of a charger's OCPP behaviour is controlled by configuration keys: how often it sends meter values, what it does offline, whether it stops a session when the cable is pulled. Getting these right per hardware model is a large part of making a fleet behave consistently. This part covers reading and writing configuration, the standard keys worth knowing, TriggerMessage for requesting messages on demand, and DataTransfer for vendor extensions. It is part 8 of the series.

GetConfiguration

json
[2, "csms-gc-401", "GetConfiguration", {"key": ["HeartbeatInterval", "MeterValueSampleInterval", "VendorFooBar"]}]
json
[
  3,
  "csms-gc-401",
  {
    "configurationKey": [
      { "key": "HeartbeatInterval", "readonly": false, "value": "300" },
      { "key": "MeterValueSampleInterval", "readonly": false, "value": "60" }
    ],
    "unknownKey": ["VendorFooBar"]
  }
]

key is an optional array. Omit it to get every key the charger has, including vendor-specific ones. That full dump is worth storing on first connection and after each firmware update; diffing it across firmware versions shows you what a vendor changed. GetConfigurationMaxKeys tells you how many keys you can request in one call.

Each entry has key, readonly and an optional value. Values are always strings, even for integers and booleans, which are sent as "true" and "false". Lists (CSL, comma-separated lists) are single strings like "Energy.Active.Import.Register,SoC".

ChangeConfiguration

json
[2, "csms-cc-402", "ChangeConfiguration", {"key": "HeartbeatInterval", "value": "900"}]
[3, "csms-cc-402", {"status": "Accepted"}]
statusMeaning
AcceptedChange applied
RejectedKey is known but the value is not acceptable, or the key is read-only
RebootRequiredChange stored, but only takes effect after a reboot
NotSupportedKey is not known to the charger

One key per message. key is a CiString50 and value a CiString500. Note that value must be a string: sending "value": 900 as a number is a TypeConstraintViolation on strict chargers and silently works on lenient ones, which is how this bug survives testing.

Standard keys worth knowing

OCPP 1.6 defines many standard keys, some required and some optional, grouped by feature profile. These are the ones you will touch most often.

KeyWhat it controlsSee
HeartbeatIntervalSeconds between heartbeatsPart 2
WebSocketPingIntervalSeconds between WebSocket pings; 0 disablesPart 2
ConnectionTimeOutSeconds to wait for a cable after authorizationPart 7
MeterValueSampleInterval / MeterValuesSampledDataTransaction sampling interval and measurandsPart 6
ClockAlignedDataInterval / MeterValuesAlignedDataClock-aligned samplingPart 6
StopTxnSampledData / StopTxnAlignedDataContents of transactionData in StopTransactionPart 5
AuthorizeRemoteTxRequestsWhether remote starts are authorized firstPart 4
LocalAuthorizeOffline / LocalPreAuthorizeUse of cache and local listPart 4
AllowOfflineTxForUnknownIdAllow unknown tags while offlinePart 4
AuthorizationCacheEnabled / LocalAuthListEnabledEnable cache and local listPart 4
StopTransactionOnEVSideDisconnectWhether unplugging at the vehicle ends the transactionPart 5
UnlockConnectorOnEVSideDisconnectWhether the charger-side lock releases when the vehicle side is unplugged
StopTransactionOnInvalidId / MaxEnergyOnInvalidIdBehaviour when a started tag turns out invalidPart 5
TransactionMessageAttempts / TransactionMessageRetryIntervalRetry policy for transaction messagesPart 5
MinimumStatusDurationDebounce for status changesPart 3
NumberOfConnectorsRead-only connector count
SupportedFeatureProfilesRead-only list of supported profilesPart 1
ChargeProfileMaxStackLevel, ChargingScheduleAllowedChargingRateUnit, ChargingScheduleMaxPeriods, MaxChargingProfilesInstalledSmart charging capabilitiesPart 9

Reading the response carefully

  • A key that appears in unknownKey is not supported. Do not keep trying to set it on every boot.
  • readonly: true keys cannot be changed with ChangeConfiguration; a Rejected for them is expected.
  • A key that is returned without value is known but has no value set, which is different from an empty string.
  • Vendor-specific keys show up alongside standard ones in the full dump. They often control important behaviour (cable lock timing, display language, the CSMS URL itself), so document them per model rather than ignoring them.
  • Some firmware returns keys with different capitalisation from the spec. Keys are case-insensitive strings, so compare case-insensitively.

Configuration as code

A pattern that works well on a mixed fleet is to treat configuration as desired state:

  1. Define a baseline profile of key values, with per-model overrides where hardware needs different values.
  2. On BootNotification (or during Pending, see part 2), read the full configuration with GetConfiguration.
  3. Diff against the desired state and send ChangeConfiguration for each difference, one at a time.
  4. Record results. NotSupported and Rejected go into a per-model exceptions list rather than being retried on every boot.

This catches chargers that were factory reset, swapped by a field technician, or changed by someone using a vendor tool on site.

TriggerMessage

TriggerMessage (Remote Trigger profile) asks the charger to send a specific message now, rather than waiting for its normal schedule.

json
[2, "csms-tm-403", "TriggerMessage", {"requestedMessage": "MeterValues", "connectorId": 1}]
[3, "csms-tm-403", {"status": "Accepted"}]
[2, "mv-9055", "MeterValues", {"connectorId": 1, "transactionId": 880214, "meterValue": [{"timestamp": "2026-10-26T11:02:13Z", "sampledValue": [{"value": "1302200", "context": "Trigger"}]}]}]
[3, "mv-9055", {}]

requestedMessage can be BootNotification, DiagnosticsStatusNotification, FirmwareStatusNotification, Heartbeat, MeterValues or StatusNotification. connectorId is optional. The response is Accepted, Rejected or NotImplemented, and the triggered message is sent after the response. Useful cases:

  • StatusNotification after a CSMS restart or a suspected missed status.
  • MeterValues to refresh a live session display when the driver opens the app.
  • Heartbeat as a cheap "are you really there?" check.
  • BootNotification to finish provisioning a Pending charger.
  • FirmwareStatusNotification or DiagnosticsStatusNotification to check progress of an update or upload (part 10).

DataTransfer

DataTransfer is OCPP's extension mechanism. Either side can send it, with a vendor identifier, an optional message identifier and an optional data string.

json
[
  2,
  "dt-77",
  "DataTransfer",
  {
    "vendorId": "com.vendorx",
    "messageId": "CableTemperature",
    "data": "{\"connectorId\":1,\"celsius\":41.5}"
  }
]
json
[3, "dt-77", {"status": "Accepted"}]

vendorId (CiString255) identifies the extension owner; a reversed DNS name is the convention. messageId is a CiString50. data has no length limit in the spec and no defined format; it is a string, so JSON payloads are usually embedded as escaped JSON as above, though some chargers send a JSON object directly in that field, which is not schema-compliant. The response status is Accepted, Rejected, UnknownMessageId or UnknownVendorId, with an optional data string.

Vendors use DataTransfer for things the 1.6 core does not cover: display messages, tariff text, extra diagnostics, payment terminal results. Handle unknown vendor IDs by returning UnknownVendorId rather than a CALLERROR, and keep each vendor's extensions behind an adapter so they do not leak into your core transaction logic. Many of the things vendors added this way became standard messages in OCPP 2.0.1; see OCPP 2.0.1 display messages and costs.

Key takeaways

  • Configuration values are strings: integers, booleans and lists included.
  • Handle RebootRequired explicitly and verify changes by reading them back.
  • Manage configuration as desired state per model, reconciled on boot.
  • Use TriggerMessage instead of waiting for periodic messages, and keep DataTransfer extensions isolated per vendor.

Previous: Part 7, remote commands. Next: Part 9, smart charging. The OCPP 2.0.1 replacement for configuration keys is the device model.

Let's Talk

Ready to build something that lasts?

Whether it's a charging network, an AI rollout, or a core enterprise system — let's talk about what you're building.