.. _htg_integrate_tariff_and_cost:

#########################
Integrate Tariff and Cost
#########################

This guide explains how to subscribe to tariff and session cost updates
published by EVerest, and how the data flow differs between OCPP 1.6 and
OCPP 2.x.

*************
Prerequisites
*************

- An EVerest deployment with an OCPP module (``OCPP`` for 1.6 or ``OCPP201``
  for 2.x) and the ``Auth`` module and the relevant API modules (see next section).
- An API client that connects via MQTT and subscribes to the relevant
  consumer API topics.

**********************
Relevant Consumer APIs
**********************

Two consumer APIs carry tariff and cost information:

- **Session cost consumer API** — provides the ``tariff_message``,
  ``session_cost``, and ``default_price`` variables on the ``session_cost``
  interface.
- **Auth consumer API** — provides ``token_validation_status``, which may
  include tariff messages received at authorization time.

At least the session cost consumer API must be subscribed to receive tariff and cost
updates.

See the AsyncAPI reference for the `auth_consumer_API <../reference/api/auth_consumer_API/index.html>`_
and the `session_cost_consumer_API <../reference/api/session_cost_consumer_API/index.html>`_ for message schemas.


.. note::

    The OCPP implementations follow the requirements of the OCA California
    Pricing Whitepaper. Note that this whitepaper contains requirements for
    displaying pricing information to the user, so in order to comply with it,
    the tariff and session cost messages must be used to show the required
    information on a charger display. The APIs only provide the necessary data.

*************************
No local cost calculation
*************************

EVerest does not calculate session costs locally. All cost figures
published on the session cost consumer API originate exclusively from the
CSMS:

- In OCPP 2.x, cost values come from the ``totalCost`` field in
  ``TransactionEventResponse`` or from a ``CostUpdated`` message.
- In OCPP 1.6, cost values come from ``RunningCost`` and ``FinalCost``
  DataTransfer messages sent by the CSMS.

EVerest only formats these values (e.g. applying the configured number of
decimal places) before forwarding them. No energy-based or time-based
cost computation is performed on the charging station.

When the charging station is offline, no cost figures are available at
all. The session cost consumer API will only receive human-readable tariff
text messages (from the locally configured fallback variables), never
computed cost amounts. The actual session cost is only published once the
CSMS responds after the connection is restored.

In addition to CSMS-provided cost data, the locally configured fallback
messages (``TariffFallbackMessage``, ``OfflineTariffFallbackMessage``,
``TotalCostFallbackMessage`` in OCPP 2.x; ``DefaultPriceText`` in OCPP 1.6)
are also published via the session cost consumer API as ``tariff_message``
publications. These contain human-readable pricing text only — they carry
no cost figures and are not derived from any local computation.

******************
OCPP configuration
******************

If you plan to use session cost information from OCPP (e.g. according to the California
Pricing requirements), you need to configure the OCPP modules to receive tariff and
cost information from the CSMS.

OCPP 1.6
=========

Enable the ``CostAndPrice`` profile in the OCPP 1.6 module configuration.
Once enabled, the OCPP module registers the tariff message and session cost
callbacks. The relevant configuration keys are:

- **DefaultPriceText** — the tariff fallback message shown when no
  ``SetUserPrice`` DataTransfer is received within the timeout. This is the
  OCPP 1.6 equivalent of ``TariffFallbackMessage`` in OCPP 2.x.
- **WaitForSetUserPriceTimeout** — how long to wait for a ``SetUserPrice``
  DataTransfer before publishing the ``DefaultPriceText`` fallback.

There is no OCPP 1.6 equivalent of ``TotalCostFallbackMessage``: no
fallback cost message is published when a transaction ends while offline.

OCPP 2.x
========

Enable the ``TariffCostCtrlr`` in the OCPP 2.x device model. The
component variables ``TariffEnabled`` and ``CostEnabled`` control which
features are active:

- **TariffEnabled** — publishes tariff / pricing messages via the
  ``tariff_message`` variable.
- **CostEnabled** — publishes running and final session cost via the
  ``session_cost`` variable.

Both can be enabled independently. Also configure other variables of the
``TariffCostCtrlr`` as needed.

Fallback messages
-----------------

When the CSMS provides no tariff information, the charging station
displays locally configured fallback messages. The following
``TariffCostCtrlr`` variables control this:

- **TariffFallbackMessage** — published when tariff is enabled but the
  CSMS provides no ``personalMessage`` in the ``AuthorizeResponse``.
- **OfflineTariffFallbackMessage** — used instead of
  ``TariffFallbackMessage`` when the charging station is offline. If not
  configured, ``TariffFallbackMessage`` is used as a fallback.
- **TotalCostFallbackMessage** — published when a transaction ends while
  the charging station is offline and no CSMS ``totalCost`` response can
  be received.

For multi-language deployments, add a language-specific instance of
``TariffFallbackMessage`` for each supported language (e.g. instance
``de`` for German, ``nl`` for Dutch). The supported languages are derived
from ``DisplayMessageCtrlr.Language.valuesList``. The default-language
text goes into ``personalMessage``; up to four additional language
entries go into ``customData.personalMessageExtra`` per California
Pricing spec 4.3.4. All languages are forwarded together as entries
in the ``messages`` field of the ``tariff_message`` publication.

.. note::

    Additional requirements of the OCPP 2.1 specification with respect to
    tariff and costs have not yet been implemented. The implemented features
    can still be used with OCPP 2.1.

*******************
Tariff message flow
*******************

Tariff messages contain human-readable pricing text in one or more
languages. They are published on the ``tariff_message`` variable of the
session cost consumer API.

OCPP 1.6
=========

Tariff messages originate from a ``SetUserPrice`` DataTransfer message sent
by the CSMS. The CSMS typically sends this message shortly after the
``Authorize.conf``, so the tariff message is available close to
authorization time.

If the ``SetUserPrice`` DataTransfer is not received within the
``WaitForSetUserPriceTimeout``, the ``DefaultPriceText`` fallback (if
configured) is published. The ``identifier_type`` is ``IdToken`` at
authorization time, and ``TransactionId`` once a transaction has started.

OCPP 2.x
========

Tariff messages are published at two points:

1. **Authorization time** — from the ``personalMessage`` field in the
   ``AuthorizeResponse``. The tariff message is also included in the
   ``messages`` field of the ``token_validation_status`` on the auth
   consumer API. At this point the ``identifier_type`` is ``IdToken`` and
   the ``identifier_id`` is the token value, since no transaction exists
   yet.

   If the CSMS does not provide a ``personalMessage``, the charging
   station automatically injects the configured ``TariffFallbackMessage``
   (or ``OfflineTariffFallbackMessage`` when offline) so that a tariff
   message is always published when tariff is enabled and a fallback is
   configured.

2. **During the session** — from the ``updatedPersonalMessage`` field in
   ``TransactionEventResponse`` messages. At this point the
   ``identifier_type`` is ``TransactionId`` and the ``identifier_id`` is
   the OCPP transaction ID.

.. note::

   To correlate auth-time tariff messages (keyed by ``IdToken``) with
   in-session updates (keyed by ``TransactionId``), use the
   ``token_validation_status`` message on the auth consumer API to capture
   the token, then match it against the session information from the EVSE
   manager consumer API.

*****************
Session cost flow
*****************

Session cost messages contain the accumulated cost of a charging session,
broken down into cost chunks (energy, time, flat fees), with current and
next-period pricing. They are published on the ``session_cost`` variable of
the session cost consumer API.

OCPP 1.6
=========

Session cost updates are triggered by ``RunningCost`` and ``FinalCost``
DataTransfer messages from the CSMS.

When a transaction ends while the charging station is offline, the queued
``StopTransaction`` is sent to the CSMS once the connection is
re-established. The ``StopTransactionResponse`` carries no cost data. No
fallback cost message is published. If the CSMS sends a ``FinalCost``
DataTransfer after reconnect, a ``session_cost`` will be published at
that point — but this is entirely at the CSMS's discretion and may not
happen at all.

OCPP 2.x
========

Session cost updates are triggered by:

- ``totalCost`` in a ``TransactionEventResponse`` — publishes a running
  cost update with status ``Running`` or ``Idle``.
- ``CostUpdated`` message — publishes a final cost update with status
  ``Finished``.

When both ``totalCost`` and ``updatedPersonalMessage`` are present in the
same ``TransactionEventResponse``, the personal message appears in both the
``tariff_message`` variable and the ``message`` field of the
``session_cost`` record.

When a transaction ends while the charging station is offline, the CSMS
``totalCost`` response will never arrive. In this case, if
``TotalCostFallbackMessage`` is configured, a ``tariff_message`` is
published with ``identifier_type = TransactionId``. This message contains
human-readable text only — no actual cost figures are available.
Consumers should display this text as a notification that the session
cost is unavailable, rather than as a cost breakdown.

Once the OCPP connection is re-established, the queued
``TransactionEvent(Ended)`` is sent to the CSMS. If the CSMS responds
with a ``totalCost``, a ``session_cost`` with status ``Finished`` is
published for the same transaction ID.

****************************
Station default price
****************************

The ``default_price`` variable on the session cost consumer API carries the
currently applicable station-wide fallback tariff text. Unlike
``tariff_message``, it is not bound to a specific session or token — it
represents the price a customer can expect to pay at this station when no
personalised tariff has been provided by the CSMS.

It is published in the following situations:

- **On startup** — once before the first connection attempt, using the
  offline fallback text (if configured).
- **On connect / reconnect** — with the online fallback text.
- **On disconnect** — with the offline fallback text (if configured);
  falls back to the online text if no offline text is configured.
- **On configuration change** — immediately after the relevant fallback
  variable is updated via ``ChangeConfiguration`` (OCPP 1.6) or
  ``SetVariables`` (OCPP 2.x)

OCPP 1.6
=========

The ``default_price`` variable is populated from the ``DefaultPrice``
configuration key (``CostAndPrice`` section). It contains both a
``priceText`` (online) and a ``priceTextOffline`` field. The relevant
configuration key changes that trigger a re-publication are ``DefaultPrice``
and ``DefaultPriceText,<language>``.

OCPP 2.x
=========

The ``default_price`` variable is populated from the
``TariffFallbackMessage`` (online) and ``OfflineTariffFallbackMessage``
(offline) variables of the ``TariffCostCtrlr`` component. If no offline
message is configured, ``TariffFallbackMessage`` is used in both states.
A change to either variable via ``SetVariables`` triggers an immediate
re-publication.

If neither variable is configured, no ``default_price`` publication occurs.

*****************************
Relationship between the APIs
*****************************

OCPP 2.x
=========

.. list-table::
   :header-rows: 1
   :widths: 30 35 35

   * - Event
     - Auth consumer API
     - Session cost consumer API
   * - Token authorized, CSMS provides tariff
     - ``token_validation_status`` includes ``messages``
     - ``tariff_message`` published (``identifier_type = IdToken``)
   * - Token authorized, no CSMS tariff, fallback configured
     - ``token_validation_status`` includes ``messages``
     - ``tariff_message`` published from ``TariffFallbackMessage`` (``identifier_type = IdToken``)
   * - In-session tariff update
     - —
     - ``tariff_message`` published (``identifier_type = TransactionId``)
   * - Running / final cost (online)
     - —
     - ``session_cost`` published (may include ``message``)
   * - Transaction ended offline, fallback configured
     - —
     - ``tariff_message`` published from ``TotalCostFallbackMessage`` (``identifier_type = TransactionId``); no ``session_cost``
   * - Reconnected, CSMS sends ``totalCost`` for offline transaction
     - —
     - ``session_cost`` with status ``Finished`` published; supersedes the earlier fallback text
   * - Connected / reconnected
     - —
     - ``default_price`` published with online ``TariffFallbackMessage`` (if configured)
   * - Disconnected
     - —
     - ``default_price`` published with ``OfflineTariffFallbackMessage``, or ``TariffFallbackMessage`` if not configured
   * - ``TariffFallbackMessage`` or ``OfflineTariffFallbackMessage`` changed via ``SetVariables``
     - —
     - ``default_price`` re-published with new online text

OCPP 1.6
=========

.. list-table::
   :header-rows: 1
   :widths: 30 35 35

   * - Event
     - Auth consumer API
     - Session cost consumer API
   * - Token authorized, CSMS sends ``SetUserPrice``
     - ``token_validation_status`` includes ``messages``
     - ``tariff_message`` published (``identifier_type = IdToken``)
   * - ``SetUserPrice`` timeout, ``DefaultPriceText`` configured
     - ``token_validation_status`` includes ``messages``
     - ``tariff_message`` published from ``DefaultPriceText`` (``identifier_type = IdToken``)
   * - In-session ``SetUserPrice`` DataTransfer
     - —
     - ``tariff_message`` published (``identifier_type = TransactionId``)
   * - ``RunningCost`` / ``FinalCost`` DataTransfer (online)
     - —
     - ``session_cost`` published (may include ``message``)
   * - Transaction ended offline
     - —
     - nothing published
   * - Reconnected, CSMS sends ``FinalCost`` DataTransfer
     - —
     - ``session_cost`` with status ``Finished`` published
   * - Connected / reconnected
     - —
     - ``default_price`` published with online ``DefaultPrice.priceText`` (if configured)
   * - Disconnected
     - —
     - ``default_price`` published with ``DefaultPrice.priceTextOffline`` (if configured)
   * - ``DefaultPrice`` changed via ``ChangeConfiguration``
     - —
     - ``default_price`` re-published with new online text
