= ENTSO-E / EPEX SPOT

This implementation uses the https://transparency.entsoe.eu/[ENTSO-E Transparency Platform] to receive day-ahead electricity prices for European bidding zones.

== Authentication

To request a (free) authentication token, please see chapter *"How to get security token?"* in the official API documentation:
https://transparencyplatform.zendesk.com/hc/en-us/articles/12845911031188-How-to-get-security-token

== Currency Conversion

Prices retrieved from ENTSO-E are automatically converted to the user’s configured currency (set in the *Core.Meta* component) using the https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html[ECB Exchange Rates API].

== Configuration

The component expects the following configuration inputs:

* *biddingZone*: ENTSO-E bidding zone (e.g., `GERMANY`)
* *ancillaryCosts*: JSON string defining additional costs on top of the day-ahead price

You can configure ancillary costs in two ways: by using a predefined German Distribution System Operator (DSO) or by providing a custom schedule.

=== Using a Predefined DSO

For convenience, several German DSOs are already predefined in the implementation. For example:

[source,json]
----
{
  "dso": "BAYERNWERK"
}
----

Configuration example:

* `biddingZone`: `GERMANY`
* `ancillaryCosts`: `{"dso":"BAYERNWERK"}`

For a list of predefined DSOs see https://github.com/OpenEMS/openems/blob/develop/io.openems.edge.timeofusetariff.api/src/io/openems/edge/timeofusetariff/api/GermanDSO.java[`GermanDSO.java`].

'''

=== Using Custom Ancillary Costs (DSO = "OTHER")

If your DSO is not on the predefined list, or if you need to define a custom time-of-use tariff structure, you can provide your own schedule.

In this case, set `"dso": "OTHER"` and provide a `schedule` array with quarterly definitions.

Each entry in the schedule contains:

* `year`: calendar year (e.g., `2025`)
* `tariffs`: fixed additional costs (per kWh) for each tariff level (`low`, `standard`, `high`)
* `quarters`: quarterly schedules (Q1–Q4) with `dailySchedule` definitions

Example configuration:

* *biddingZone*:: `GERMANY`
* *ancillaryCosts*:: See the detailed JSON string below.

[source,json]
----
{
  "dso": "OTHER",
  "schedule": [
    {
      "year": 2025,
      "tariffs": {
        "low": 0.10,
        "standard": 0.20,
        "high": 0.30
      },
      "quarters": [
        {
          "quarter": 1,
          "dailySchedule": [
            { "tariff": "low", "from": "00:00", "to": "06:00" },
            { "tariff": "standard", "from": "06:00", "to": "18:00" },
            { "tariff": "high", "from": "18:00", "to": "23:59" }
          ]
        },
        {
          "quarter": 2,
          "dailySchedule": []
        },
        {
          "quarter": 3,
          "dailySchedule": []
        },
        {
          "quarter": 4,
          "dailySchedule": [
            { "tariff": "low", "from": "00:00", "to": "06:00" },
            { "tariff": "standard", "from": "06:00", "to": "18:00" },
            { "tariff": "high", "from": "18:00", "to": "23:59" }
          ]
        }
      ]
    }
  ]
}
----

==== Custom Schedule JSON Structure Explained

The `schedule` is a JSON array where each object defines the tariffs for a specific year.

* `year`:: The year for which this schedule is valid (e.g., `2025`).
* `tariffs`:: An object defining the named price levels. You can define your own names (e.g., `low`, `standard`, `high`) and assign a cost to each.
  The name *`standard`* is special and is used as a fallback if no time slot applies.
* `quarters`:: An array defining the schedule for each quarter of the year.
** `quarter`:: The quarter number (`1` to `4`).
** `dailySchedule`:: An array specifying the time slots and their corresponding tariffs for each day in that quarter.
*** `tariff`:: The tariff name, which must match one of the keys defined in the `tariffs` object.
*** `from`:: The start time of the slot in `HH:mm` format.
*** `to`:: The end time of the slot in `HH:mm` format.

==== Notes

* If the `dailySchedule` for a quarter is empty (`[]`), the system will default to using the price defined for the *`standard`* tariff for that entire quarter. This is useful for seasons with flat ancillary costs.
* Tariff boundaries (`from`/`to`) must not overlap and must follow chronological order.
* Multiple years can be defined by adding more entries to the `schedule` array.


https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.timeofusetariff.entsoe[Source Code icon:github[]]
