@enyo-energy/energy-app-sdk 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +211 -1
  2. package/dist/cjs/energy-app-package-definition.cjs +1 -0
  3. package/dist/cjs/energy-app-package-definition.d.cts +1 -0
  4. package/dist/cjs/energy-app-permission.type.cjs +2 -0
  5. package/dist/cjs/energy-app-permission.type.d.cts +3 -1
  6. package/dist/cjs/energy-app.cjs +16 -0
  7. package/dist/cjs/energy-app.d.cts +15 -0
  8. package/dist/cjs/enyo-energy-app-sdk.d.cts +3 -0
  9. package/dist/cjs/implementations/pricing/compose-electricity-prices.cjs +218 -0
  10. package/dist/cjs/implementations/pricing/compose-electricity-prices.d.cts +100 -0
  11. package/dist/cjs/implementations/pricing/price-component-validators.cjs +295 -0
  12. package/dist/cjs/implementations/pricing/price-component-validators.d.cts +90 -0
  13. package/dist/cjs/implementations/pricing/price-schedule-resolver.cjs +182 -0
  14. package/dist/cjs/implementations/pricing/price-schedule-resolver.d.cts +95 -0
  15. package/dist/cjs/index.cjs +7 -0
  16. package/dist/cjs/index.d.cts +7 -0
  17. package/dist/cjs/packages/energy-app-electricity-tariff.d.cts +34 -1
  18. package/dist/cjs/packages/energy-app-grid-fee.cjs +2 -0
  19. package/dist/cjs/packages/energy-app-grid-fee.d.cts +181 -0
  20. package/dist/cjs/types/enyo-electricity-tariff.cjs +33 -1
  21. package/dist/cjs/types/enyo-electricity-tariff.d.cts +161 -4
  22. package/dist/cjs/types/enyo-grid-fee.cjs +15 -0
  23. package/dist/cjs/types/enyo-grid-fee.d.cts +129 -0
  24. package/dist/cjs/types/enyo-price-composition.cjs +15 -0
  25. package/dist/cjs/types/enyo-price-composition.d.cts +126 -0
  26. package/dist/cjs/types/enyo-price-schedule.cjs +45 -0
  27. package/dist/cjs/types/enyo-price-schedule.d.cts +137 -0
  28. package/dist/cjs/version.cjs +1 -1
  29. package/dist/cjs/version.d.cts +1 -1
  30. package/dist/energy-app-package-definition.d.ts +1 -0
  31. package/dist/energy-app-package-definition.js +1 -0
  32. package/dist/energy-app-permission.type.d.ts +3 -1
  33. package/dist/energy-app-permission.type.js +2 -0
  34. package/dist/energy-app.d.ts +15 -0
  35. package/dist/energy-app.js +16 -0
  36. package/dist/enyo-energy-app-sdk.d.ts +3 -0
  37. package/dist/implementations/pricing/compose-electricity-prices.d.ts +100 -0
  38. package/dist/implementations/pricing/compose-electricity-prices.js +212 -0
  39. package/dist/implementations/pricing/price-component-validators.d.ts +90 -0
  40. package/dist/implementations/pricing/price-component-validators.js +285 -0
  41. package/dist/implementations/pricing/price-schedule-resolver.d.ts +95 -0
  42. package/dist/implementations/pricing/price-schedule-resolver.js +175 -0
  43. package/dist/index.d.ts +7 -0
  44. package/dist/index.js +7 -0
  45. package/dist/packages/energy-app-electricity-tariff.d.ts +34 -1
  46. package/dist/packages/energy-app-grid-fee.d.ts +181 -0
  47. package/dist/packages/energy-app-grid-fee.js +1 -0
  48. package/dist/types/enyo-electricity-tariff.d.ts +161 -4
  49. package/dist/types/enyo-electricity-tariff.js +32 -0
  50. package/dist/types/enyo-grid-fee.d.ts +129 -0
  51. package/dist/types/enyo-grid-fee.js +12 -0
  52. package/dist/types/enyo-price-composition.d.ts +126 -0
  53. package/dist/types/enyo-price-composition.js +12 -0
  54. package/dist/types/enyo-price-schedule.d.ts +137 -0
  55. package/dist/types/enyo-price-schedule.js +42 -0
  56. package/dist/version.d.ts +1 -1
  57. package/dist/version.js +1 -1
  58. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import { EnyoPriceAppliesToEnum, EnyoPriceSchedule } from './enyo-price-schedule.js';
1
2
  /**
2
3
  * Enum representing the type of electricity tariff pricing model
3
4
  */
@@ -9,10 +10,119 @@ export declare enum ElectricityTariffTypeEnum {
9
10
  /** Price changes dynamically based on market conditions */
10
11
  Dynamic = "dynamic"
11
12
  }
13
+ /**
14
+ * How the grid fee (network charge) of a tariff is determined.
15
+ */
16
+ export declare enum GridFeeModeEnum {
17
+ /**
18
+ * A single constant fee per kWh, carried by the tariff itself
19
+ * (see {@link DynamicTariffData.gridFeePerKwh}).
20
+ */
21
+ Static = "static",
22
+ /**
23
+ * A time-dependent fee, read from the grid fee API with
24
+ * `useGridFee().getDynamicGridFees()`. The tariff only declares *that* the
25
+ * fee is time-dependent — which fee applies is a property of the site's grid
26
+ * connection, not of the tariff.
27
+ */
28
+ Dynamic = "dynamic"
29
+ }
30
+ /**
31
+ * Declares how the grid fee (network charge) that applies alongside a tariff is
32
+ * determined.
33
+ *
34
+ * Mixed into every tariff pricing shape: a fixed energy price combined with
35
+ * time-variable network charges (e.g. §14a EnWG module 3) is just as real a
36
+ * product as a spot-market tariff, so the declaration is not exclusive to
37
+ * dynamic tariffs.
38
+ *
39
+ * A grid fee itself is **not** bound to a tariff — it belongs to the site's grid
40
+ * connection and is registered and resolved through `useGridFee()` independently.
41
+ * The tariff only says whether its grid fee is a constant it carries itself or a
42
+ * time-dependent one to be read from that API.
43
+ *
44
+ * The grid fee is never applied automatically. Energy apps read the fee and
45
+ * compose the effective price themselves — see `composeElectricityPrices()`.
46
+ */
47
+ export interface TariffGridFeeConfig {
48
+ /**
49
+ * How the grid fee is determined. Defaults to {@link GridFeeModeEnum.Static}
50
+ * when omitted, so tariffs registered before this field existed keep their
51
+ * previous behaviour.
52
+ *
53
+ * {@link GridFeeModeEnum.Dynamic} must not be combined with
54
+ * `priceComposition.includesGridFee === true` — a fee already contained in
55
+ * the tariff's prices must not be added again.
56
+ */
57
+ gridFeeMode?: GridFeeModeEnum;
58
+ }
59
+ /**
60
+ * Declares which cost components are **already contained** in the prices this
61
+ * tariff yields.
62
+ *
63
+ * Provider APIs differ: some return all-in prices with network charges, levies
64
+ * and taxes baked in, others return the pure energy price. Consumers must never
65
+ * add a component that is already included — this declaration is what makes the
66
+ * difference machine-readable instead of tribal knowledge.
67
+ *
68
+ * When omitted, prices are treated as **energy price only**.
69
+ */
70
+ export interface TariffPriceCompositionInfo {
71
+ /** `true` when the tariff's prices already contain the grid fee. */
72
+ includesGridFee: boolean;
73
+ /** `true` when the tariff's prices already contain taxes and levies. */
74
+ includesTaxesAndLevies?: boolean;
75
+ /** `true` when the tariff's prices already have its bonuses applied. */
76
+ includesBonuses?: boolean;
77
+ }
78
+ /**
79
+ * A time-dependent discount granted on top of a tariff, expressed in currency
80
+ * per kWh — for example "5 ct/kWh cheaper between 22:00 and 06:00" or a
81
+ * promotional rebate that runs for a fixed number of months.
82
+ *
83
+ * A tariff may carry several bonuses. Amounts in {@link schedule} are positive
84
+ * magnitudes and are **subtracted** from the price.
85
+ *
86
+ * Consumption-quota bonuses ("the first 100 kWh each month are free") are not
87
+ * expressible here — they require consumption accounting that this model
88
+ * deliberately does not carry.
89
+ */
90
+ export interface EnyoTariffBonus {
91
+ /** Unique identifier of the bonus within its tariff. */
92
+ id: string;
93
+ /** Human-readable name shown to the user, e.g. `'Nachtbonus'`. */
94
+ name: string;
95
+ /**
96
+ * When and how much the discount is. Amounts are positive and subtracted
97
+ * from the price.
98
+ */
99
+ schedule: EnyoPriceSchedule;
100
+ /**
101
+ * IANA time zone the schedule's wall-clock times are expressed in, e.g.
102
+ * `'Europe/Berlin'`.
103
+ */
104
+ timezone: string;
105
+ /** Whether the bonus applies to consumption, feed-in, or both. */
106
+ appliesTo: EnyoPriceAppliesToEnum;
107
+ /** Optional start of the bonus's validity in ISO format (inclusive). */
108
+ validFromIso?: string;
109
+ /** Optional end of the bonus's validity in ISO format (exclusive). */
110
+ validUntilIso?: string;
111
+ /**
112
+ * When `true`, this bonus suppresses every lower-priority bonus in the
113
+ * intervals it covers instead of stacking with them.
114
+ */
115
+ exclusive?: boolean;
116
+ /**
117
+ * Ranking used to pick between competing exclusive bonuses — higher wins.
118
+ * Defaults to `0`.
119
+ */
120
+ priority?: number;
121
+ }
12
122
  /**
13
123
  * Pricing data for a static (fixed-price) electricity tariff
14
124
  */
15
- export interface StaticTariffData {
125
+ export interface StaticTariffData extends TariffGridFeeConfig {
16
126
  /** Price per kWh for consumption */
17
127
  pricePerKwh: number;
18
128
  /** Currency code (ISO 4217, e.g., 'EUR', 'USD') */
@@ -21,8 +131,15 @@ export interface StaticTariffData {
21
131
  /**
22
132
  * Pricing data for a dynamic electricity tariff
23
133
  */
24
- export interface DynamicTariffData {
25
- /** Price per kWh for grid fees */
134
+ export interface DynamicTariffData extends TariffGridFeeConfig {
135
+ /**
136
+ * Constant price per kWh for grid fees.
137
+ *
138
+ * @deprecated Set {@link TariffGridFeeConfig.gridFeeMode} to
139
+ * {@link GridFeeModeEnum.Dynamic} and read the fee from
140
+ * `useGridFee().getDynamicGridFees()` instead. Still honoured as the
141
+ * constant fallback while `gridFeeMode` is Static or omitted.
142
+ */
26
143
  gridFeePerKwh?: number;
27
144
  /** Currency code (ISO 4217, e.g., 'EUR', 'USD') */
28
145
  currency: string;
@@ -39,7 +156,7 @@ export interface TimeVariableScheduleEntry {
39
156
  /**
40
157
  * Pricing data for a time-variable electricity tariff
41
158
  */
42
- export interface TimeVariableTariffData {
159
+ export interface TimeVariableTariffData extends TariffGridFeeConfig {
43
160
  /** Schedule of time-based price entries */
44
161
  schedule: TimeVariableScheduleEntry[];
45
162
  /** Currency code (ISO 4217, e.g., 'EUR', 'USD') */
@@ -67,6 +184,17 @@ export interface EnyoElectricityTariff {
67
184
  dynamicTariffData?: DynamicTariffData;
68
185
  /** Optional external tariff id for easy identification */
69
186
  externalTariffId?: string;
187
+ /**
188
+ * Optional declaration of which cost components the tariff's prices already
189
+ * contain. Omitted means "energy price only".
190
+ */
191
+ priceComposition?: TariffPriceCompositionInfo;
192
+ /**
193
+ * Optional discounts granted on top of this tariff. Several bonuses may
194
+ * apply at the same time — overlapping bonuses stack additively unless one
195
+ * of them is {@link EnyoTariffBonus.exclusive}.
196
+ */
197
+ bonuses?: EnyoTariffBonus[];
70
198
  }
71
199
  /**
72
200
  * Tariff registration data extended with default indicator.
@@ -76,3 +204,32 @@ export interface EnyoElectricityTariffWithDefault extends EnyoElectricityTariff
76
204
  /** Indicates whether this tariff is the system default */
77
205
  defaultTariff: boolean;
78
206
  }
207
+ /**
208
+ * What happened to a tariff registration.
209
+ */
210
+ export declare enum EnyoTariffChangeTypeEnum {
211
+ /** A new tariff was registered. */
212
+ Registered = "registered",
213
+ /** An existing tariff's attributes, grid fee link or bonuses changed. */
214
+ Updated = "updated",
215
+ /** A tariff was removed. */
216
+ Removed = "removed",
217
+ /** A different tariff became the system default. */
218
+ DefaultChanged = "default-changed"
219
+ }
220
+ /**
221
+ * Event delivered to listeners registered via
222
+ * {@link EnergyAppElectricityTariff.onTariffChanged}.
223
+ */
224
+ export interface EnyoTariffChangeEvent {
225
+ /** What happened. */
226
+ changeType: EnyoTariffChangeTypeEnum;
227
+ /** Identifier of the affected tariff. */
228
+ tariffId: string;
229
+ /**
230
+ * The tariff after the change, or `null` when it was removed. For
231
+ * {@link EnyoTariffChangeTypeEnum.DefaultChanged} this is the tariff that
232
+ * became the new default.
233
+ */
234
+ tariff: EnyoElectricityTariffWithDefault | null;
235
+ }
@@ -10,3 +10,35 @@ export var ElectricityTariffTypeEnum;
10
10
  /** Price changes dynamically based on market conditions */
11
11
  ElectricityTariffTypeEnum["Dynamic"] = "dynamic";
12
12
  })(ElectricityTariffTypeEnum || (ElectricityTariffTypeEnum = {}));
13
+ /**
14
+ * How the grid fee (network charge) of a tariff is determined.
15
+ */
16
+ export var GridFeeModeEnum;
17
+ (function (GridFeeModeEnum) {
18
+ /**
19
+ * A single constant fee per kWh, carried by the tariff itself
20
+ * (see {@link DynamicTariffData.gridFeePerKwh}).
21
+ */
22
+ GridFeeModeEnum["Static"] = "static";
23
+ /**
24
+ * A time-dependent fee, read from the grid fee API with
25
+ * `useGridFee().getDynamicGridFees()`. The tariff only declares *that* the
26
+ * fee is time-dependent — which fee applies is a property of the site's grid
27
+ * connection, not of the tariff.
28
+ */
29
+ GridFeeModeEnum["Dynamic"] = "dynamic";
30
+ })(GridFeeModeEnum || (GridFeeModeEnum = {}));
31
+ /**
32
+ * What happened to a tariff registration.
33
+ */
34
+ export var EnyoTariffChangeTypeEnum;
35
+ (function (EnyoTariffChangeTypeEnum) {
36
+ /** A new tariff was registered. */
37
+ EnyoTariffChangeTypeEnum["Registered"] = "registered";
38
+ /** An existing tariff's attributes, grid fee link or bonuses changed. */
39
+ EnyoTariffChangeTypeEnum["Updated"] = "updated";
40
+ /** A tariff was removed. */
41
+ EnyoTariffChangeTypeEnum["Removed"] = "removed";
42
+ /** A different tariff became the system default. */
43
+ EnyoTariffChangeTypeEnum["DefaultChanged"] = "default-changed";
44
+ })(EnyoTariffChangeTypeEnum || (EnyoTariffChangeTypeEnum = {}));
@@ -0,0 +1,129 @@
1
+ import { EnyoCurrencyEnum } from './enyo-currency.js';
2
+ import { ForecastResolutionEnum } from './enyo-forecasting.js';
3
+ import { EnyoPriceAppliesToEnum, EnyoPriceSchedule } from './enyo-price-schedule.js';
4
+ /**
5
+ * A registered dynamic grid fee (network charge).
6
+ *
7
+ * A grid fee is the component of the electricity price the grid operator (DSO)
8
+ * charges for transporting the energy. Historically it was a single constant
9
+ * ct/kWh value; with time-variable network charges (e.g. §14a EnWG module 3 in
10
+ * Germany) it varies by time of day, weekday and season, and grid operators
11
+ * increasingly publish it as a dated series.
12
+ *
13
+ * A fee registered here is **not** automatically applied to any price. It is
14
+ * published so that energy apps can read it via
15
+ * {@link EnergyAppGridFee.getDynamicGridFees} and compose the effective
16
+ * electricity price themselves — see `composeElectricityPrices()`. This is
17
+ * deliberate: some tariff providers already return grid-fee-inclusive prices
18
+ * from their own API and must not add the fee a second time.
19
+ */
20
+ export interface EnyoDynamicGridFee {
21
+ /** Unique identifier of this grid fee. */
22
+ id: string;
23
+ /** Human-readable name, e.g. `'Netzentgelt HT/NT 2026'`. */
24
+ name: string;
25
+ /** Name of the grid operator (DSO) that publishes this fee. */
26
+ gridOperator: string;
27
+ /** Currency of every amount in {@link schedule}. */
28
+ currency: EnyoCurrencyEnum;
29
+ /**
30
+ * IANA time zone the schedule's wall-clock times are expressed in, e.g.
31
+ * `'Europe/Berlin'`. Required — network charge windows are published in
32
+ * local time and must survive daylight-saving transitions.
33
+ */
34
+ timezone: string;
35
+ /** Whether the fee applies to consumption, feed-in, or both. */
36
+ appliesTo: EnyoPriceAppliesToEnum;
37
+ /** When and how much the fee is. Amounts are positive and **added** to the energy price. */
38
+ schedule: EnyoPriceSchedule;
39
+ /** Optional start of the fee's validity in ISO format (inclusive). */
40
+ validFromIso?: string;
41
+ /** Optional end of the fee's validity in ISO format (exclusive). */
42
+ validUntilIso?: string;
43
+ /** Optional metering point this fee is bound to (e.g. a German Marktlokations-ID). */
44
+ meteringPointId?: string;
45
+ /**
46
+ * Marks the fee as a time-variable network charge under §14a EnWG module 3.
47
+ * Purely informational — it does not change how the fee is resolved.
48
+ */
49
+ moduleThreeCompliant?: boolean;
50
+ /** When the fee was last registered or updated, in ISO format. Set by the host. */
51
+ publishedAtIso?: string;
52
+ }
53
+ /**
54
+ * Registration payload for {@link EnergyAppGridFee.registerGridFee}.
55
+ * `publishedAtIso` is assigned by the host and therefore not part of the input.
56
+ */
57
+ export type EnyoDynamicGridFeeRegistration = Omit<EnyoDynamicGridFee, 'publishedAtIso'>;
58
+ /**
59
+ * One resolved 15-minute interval of a dynamic grid fee.
60
+ */
61
+ export interface EnyoDynamicGridFeeEntry {
62
+ /** Start of the 15-minute interval in ISO format. */
63
+ timestampIso: string;
64
+ /**
65
+ * Grid fee per kWh for this interval, in the series' currency. Always
66
+ * `>= 0`; `0` for intervals no window covers.
67
+ */
68
+ feePerKwh: number;
69
+ }
70
+ /**
71
+ * A dynamic grid fee resolved to a flat 15-minute series over a requested range.
72
+ *
73
+ * The resolution matches {@link EnergyAppEnergyPrices.getPrices}, so entries can
74
+ * be zipped with a price series index-by-index once both cover the same range.
75
+ */
76
+ export interface EnyoDynamicGridFeeSeries {
77
+ /** Identifier of the grid fee this series was resolved from. */
78
+ gridFeeId: string;
79
+ /** Currency of every amount in {@link entries}. */
80
+ currency: EnyoCurrencyEnum;
81
+ /** Always {@link ForecastResolutionEnum.FifteenMinutes} — present for symmetry with other price APIs. */
82
+ resolution: ForecastResolutionEnum;
83
+ /** IANA time zone the underlying schedule was resolved in. */
84
+ timezone: string;
85
+ /** Direction the fee applies to. */
86
+ appliesTo: EnyoPriceAppliesToEnum;
87
+ /** Resolved entries sorted ascending by `timestampIso`, without gaps. */
88
+ entries: EnyoDynamicGridFeeEntry[];
89
+ }
90
+ /**
91
+ * Selects which grid fee to resolve, and over which range.
92
+ *
93
+ * A grid fee belongs to the site's grid connection, not to a supplier contract —
94
+ * so there is deliberately no tariff selector here. With no selector at all, the
95
+ * grid fee that applies to this device is resolved.
96
+ */
97
+ export interface EnyoDynamicGridFeeFilter {
98
+ /** Start of the requested range in ISO format (inclusive). */
99
+ fromIso: string;
100
+ /** End of the requested range in ISO format (exclusive). */
101
+ untilIso: string;
102
+ /** Resolve this specific grid fee. */
103
+ gridFeeId?: string;
104
+ /** Resolve the grid fee registered for this metering point. */
105
+ meteringPointId?: string;
106
+ }
107
+ /**
108
+ * What happened to a grid fee registration.
109
+ */
110
+ export declare enum EnyoGridFeeChangeTypeEnum {
111
+ /** A new grid fee was registered. */
112
+ Registered = "registered",
113
+ /** An existing grid fee's attributes or schedule changed. */
114
+ Updated = "updated",
115
+ /** A grid fee was removed. */
116
+ Removed = "removed"
117
+ }
118
+ /**
119
+ * Event delivered to listeners registered via
120
+ * {@link EnergyAppGridFee.onGridFeeChanged}.
121
+ */
122
+ export interface EnyoGridFeeChangeEvent {
123
+ /** What happened. */
124
+ changeType: EnyoGridFeeChangeTypeEnum;
125
+ /** Identifier of the affected grid fee. */
126
+ gridFeeId: string;
127
+ /** The grid fee after the change, or `null` when it was removed. */
128
+ gridFee: EnyoDynamicGridFee | null;
129
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * What happened to a grid fee registration.
3
+ */
4
+ export var EnyoGridFeeChangeTypeEnum;
5
+ (function (EnyoGridFeeChangeTypeEnum) {
6
+ /** A new grid fee was registered. */
7
+ EnyoGridFeeChangeTypeEnum["Registered"] = "registered";
8
+ /** An existing grid fee's attributes or schedule changed. */
9
+ EnyoGridFeeChangeTypeEnum["Updated"] = "updated";
10
+ /** A grid fee was removed. */
11
+ EnyoGridFeeChangeTypeEnum["Removed"] = "removed";
12
+ })(EnyoGridFeeChangeTypeEnum || (EnyoGridFeeChangeTypeEnum = {}));
@@ -0,0 +1,126 @@
1
+ import { EnyoTariffBonus, TariffPriceCompositionInfo } from './enyo-electricity-tariff.js';
2
+ import { EnyoDynamicGridFeeSeries } from './enyo-grid-fee.js';
3
+ import { EnyoPriceAppliesToEnum } from './enyo-price-schedule.js';
4
+ /**
5
+ * Where a price component in a composed entry came from.
6
+ */
7
+ export declare enum EnyoPriceComponentOriginEnum {
8
+ /** The component was already contained in the energy price series. */
9
+ Included = "included",
10
+ /** The component was added by the composer on top of the energy price. */
11
+ Added = "added",
12
+ /** No such component applies to this interval. */
13
+ NotApplicable = "not-applicable"
14
+ }
15
+ /**
16
+ * A single energy price point fed into
17
+ * {@link composeElectricityPrices}.
18
+ *
19
+ * Deliberately minimal so any source can be used — spot prices from
20
+ * `useEpexSpotPrices()`, tariff prices from `useElectricityPrices()`, or a
21
+ * series fetched from the provider's own API. Use
22
+ * `fromEnergyPriceEntries()` / `fromEpexSpotEntries()` to adapt the SDK's own
23
+ * shapes.
24
+ */
25
+ export interface EnyoComposableEnergyPriceEntry {
26
+ /** Start of the interval in ISO format. */
27
+ timestampIso: string;
28
+ /** Energy price per kWh for this interval, in the composition's currency. */
29
+ pricePerKwh: number;
30
+ }
31
+ /**
32
+ * Input for {@link composeElectricityPrices}.
33
+ */
34
+ export interface EnyoComposeElectricityPricesInput {
35
+ /**
36
+ * The energy price series to compose on top of. Entries are matched to the
37
+ * grid fee and bonus series by `timestampIso`, so all inputs should cover
38
+ * the same range at 15-minute resolution.
39
+ */
40
+ energyPrices: EnyoComposableEnergyPriceEntry[];
41
+ /**
42
+ * What the {@link energyPrices} already contain, taken from the tariff's
43
+ * `priceComposition`. Components flagged as included are reported in the
44
+ * result but **not added again**. Omitted means "energy price only".
45
+ */
46
+ energyPriceComposition?: TariffPriceCompositionInfo;
47
+ /**
48
+ * The resolved dynamic grid fee series, e.g. from
49
+ * `useGridFee().getDynamicGridFees()`. Ignored when the energy prices
50
+ * already include the grid fee, and may be `null` or omitted when the
51
+ * tariff has no dynamic grid fee.
52
+ */
53
+ gridFees?: EnyoDynamicGridFeeSeries | null;
54
+ /**
55
+ * A constant grid fee per kWh, used when the tariff carries one instead of
56
+ * referencing a dynamic fee. Ignored when {@link gridFees} is given or when
57
+ * the energy prices already include the grid fee.
58
+ */
59
+ constantGridFeePerKwh?: number;
60
+ /**
61
+ * The tariff's bonuses. Overlapping bonuses stack additively unless one is
62
+ * {@link EnyoTariffBonus.exclusive}. Ignored when the energy prices already
63
+ * have bonuses applied.
64
+ */
65
+ bonuses?: EnyoTariffBonus[];
66
+ /**
67
+ * Which direction to compose for. Components whose `appliesTo` does not
68
+ * match are skipped. Defaults to {@link EnyoPriceAppliesToEnum.Consumption}.
69
+ */
70
+ appliesTo?: EnyoPriceAppliesToEnum;
71
+ /**
72
+ * Optional lower bound for {@link EnyoComposedElectricityPriceEntry.effectivePricePerKwh}.
73
+ * Left unset by default — effective prices may legitimately go negative,
74
+ * because wholesale prices do.
75
+ */
76
+ minEffectivePricePerKwh?: number;
77
+ /** Currency code carried through to the result, e.g. `'EUR'`. */
78
+ currency?: string;
79
+ }
80
+ /**
81
+ * One fully composed 15-minute price interval, with every component reported
82
+ * separately so a UI can explain the number and an optimizer can reason about
83
+ * its parts.
84
+ */
85
+ export interface EnyoComposedElectricityPriceEntry {
86
+ /** Start of the interval in ISO format. */
87
+ timestampIso: string;
88
+ /**
89
+ * The price taken from the source series for this interval. When the source
90
+ * was all-in, it already contains the components whose origin is
91
+ * `included`.
92
+ */
93
+ energyPricePerKwh: number;
94
+ /**
95
+ * Grid fee per kWh attributable to this interval; `0` when none applies.
96
+ *
97
+ * Reported even when {@link gridFeeOrigin} is
98
+ * {@link EnyoPriceComponentOriginEnum.Included} — provided a fee series was
99
+ * passed in — so a UI can break down an all-in price without the composer
100
+ * adding the amount a second time.
101
+ */
102
+ gridFeePerKwh: number;
103
+ /**
104
+ * Whether {@link gridFeePerKwh} was added by the composer, was already part
105
+ * of the energy price, or does not apply.
106
+ */
107
+ gridFeeOrigin: EnyoPriceComponentOriginEnum;
108
+ /** Total discount per kWh applied to this interval; `0` when none applies. */
109
+ bonusPerKwh: number;
110
+ /**
111
+ * Whether {@link bonusPerKwh} was applied by the composer, was already part
112
+ * of the energy price, or does not apply.
113
+ */
114
+ bonusOrigin: EnyoPriceComponentOriginEnum;
115
+ /** Ids of the bonuses that contributed to {@link bonusPerKwh}. */
116
+ appliedBonusIds: string[];
117
+ /**
118
+ * The final price per kWh for this interval:
119
+ * `energyPricePerKwh + gridFeePerKwh - bonusPerKwh`, with components whose
120
+ * origin is `included` already contained in `energyPricePerKwh` and
121
+ * therefore not counted twice.
122
+ */
123
+ effectivePricePerKwh: number;
124
+ /** Currency of every amount in this entry, when known. */
125
+ currency?: string;
126
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Where a price component in a composed entry came from.
3
+ */
4
+ export var EnyoPriceComponentOriginEnum;
5
+ (function (EnyoPriceComponentOriginEnum) {
6
+ /** The component was already contained in the energy price series. */
7
+ EnyoPriceComponentOriginEnum["Included"] = "included";
8
+ /** The component was added by the composer on top of the energy price. */
9
+ EnyoPriceComponentOriginEnum["Added"] = "added";
10
+ /** No such component applies to this interval. */
11
+ EnyoPriceComponentOriginEnum["NotApplicable"] = "not-applicable";
12
+ })(EnyoPriceComponentOriginEnum || (EnyoPriceComponentOriginEnum = {}));
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Shared scheduling primitives for time-dependent price components
3
+ * (dynamic grid fees and tariff bonuses).
4
+ *
5
+ * All amounts in this module are expressed **per kilowatt hour** and are always
6
+ * a positive magnitude — the direction is defined by the component that carries
7
+ * the schedule: a grid fee is *added* to the energy price, a tariff bonus is
8
+ * *subtracted* from it. Keeping magnitudes unsigned removes the single most
9
+ * common integration mistake (an inverted sign silently flipping an optimizer's
10
+ * decisions) and is enforced by the validators in
11
+ * `implementations/pricing/price-schedule-validators.ts`.
12
+ */
13
+ /**
14
+ * The kind of schedule a price component follows.
15
+ */
16
+ export declare enum EnyoPriceScheduleTypeEnum {
17
+ /** One amount that applies at every point in time. */
18
+ Constant = "constant",
19
+ /**
20
+ * Calendar-recurring windows — used for high-tariff/low-tariff (HT/NT)
21
+ * network charges, seasonal charges, and weekday-dependent bonuses.
22
+ */
23
+ Recurring = "recurring",
24
+ /**
25
+ * Explicit absolute time windows — used for grid fees or bonuses published
26
+ * as a dated series (e.g. a day-ahead publication by the grid operator).
27
+ */
28
+ Absolute = "absolute"
29
+ }
30
+ /**
31
+ * Which energy direction a price component applies to.
32
+ */
33
+ export declare enum EnyoPriceAppliesToEnum {
34
+ /** Applies to energy drawn from the grid. */
35
+ Consumption = "consumption",
36
+ /** Applies to energy fed into the grid. */
37
+ FeedIn = "feed-in",
38
+ /** Applies to both directions. */
39
+ Both = "both"
40
+ }
41
+ /**
42
+ * A calendar-recurring price window.
43
+ *
44
+ * Times are wall-clock times in the owning component's `timezone`, so a window
45
+ * survives daylight-saving transitions: `'22:00'` stays 22:00 local time all
46
+ * year round.
47
+ */
48
+ export interface EnyoRecurringPriceWindow {
49
+ /**
50
+ * Inclusive start of the window as a local wall-clock time in `HH:mm`
51
+ * 24-hour notation, e.g. `'22:00'`.
52
+ */
53
+ startTimeOfDay: string;
54
+ /**
55
+ * Exclusive end of the window as a local wall-clock time in `HH:mm`
56
+ * notation. May be **earlier** than `startTimeOfDay`, in which case the
57
+ * window wraps past midnight (e.g. `'22:00'` → `'06:00'`).
58
+ */
59
+ endTimeOfDay: string;
60
+ /**
61
+ * Days of the week the window applies to, `0` = Sunday … `6` = Saturday.
62
+ * Omit for "every day".
63
+ *
64
+ * For a window that wraps past midnight the day is evaluated against the
65
+ * day the window **starts** — a Monday 22:00–06:00 window covers Monday
66
+ * evening and the early hours of Tuesday.
67
+ */
68
+ daysOfWeek?: number[];
69
+ /**
70
+ * Months the window applies to, `1` = January … `12` = December. Omit for
71
+ * "every month". Evaluated against the day the window starts, exactly as
72
+ * {@link daysOfWeek}.
73
+ */
74
+ months?: number[];
75
+ /** Positive amount per kWh that applies inside the window. */
76
+ amountPerKwh: number;
77
+ }
78
+ /**
79
+ * An explicit, absolutely-dated price window.
80
+ */
81
+ export interface EnyoAbsolutePriceWindow {
82
+ /** Inclusive start of the window in ISO format. */
83
+ startIso: string;
84
+ /** Exclusive end of the window in ISO format. */
85
+ endIso: string;
86
+ /** Positive amount per kWh that applies inside the window. */
87
+ amountPerKwh: number;
88
+ }
89
+ /**
90
+ * A single amount that applies at all times.
91
+ */
92
+ export interface EnyoConstantPriceSchedule {
93
+ type: EnyoPriceScheduleTypeEnum.Constant;
94
+ /** Positive amount per kWh, applied to every interval. */
95
+ amountPerKwh: number;
96
+ }
97
+ /**
98
+ * A set of calendar-recurring windows. Intervals not covered by any window
99
+ * resolve to `0`.
100
+ */
101
+ export interface EnyoRecurringPriceSchedule {
102
+ type: EnyoPriceScheduleTypeEnum.Recurring;
103
+ /** The recurring windows. Must not overlap each other. */
104
+ windows: EnyoRecurringPriceWindow[];
105
+ }
106
+ /**
107
+ * A set of absolutely-dated windows. Intervals not covered by any window
108
+ * resolve to `0`.
109
+ */
110
+ export interface EnyoAbsolutePriceSchedule {
111
+ type: EnyoPriceScheduleTypeEnum.Absolute;
112
+ /** The dated windows. Must not overlap each other. */
113
+ windows: EnyoAbsolutePriceWindow[];
114
+ }
115
+ /**
116
+ * Any supported price component schedule, discriminated by `type`.
117
+ */
118
+ export type EnyoPriceSchedule = EnyoConstantPriceSchedule | EnyoRecurringPriceSchedule | EnyoAbsolutePriceSchedule;
119
+ /**
120
+ * One resolved 15-minute interval produced by expanding an
121
+ * {@link EnyoPriceSchedule} over a time range.
122
+ */
123
+ export interface EnyoResolvedPriceEntry {
124
+ /** Start of the 15-minute interval in ISO format. */
125
+ timestampIso: string;
126
+ /** Resolved positive amount per kWh for this interval; `0` when uncovered. */
127
+ amountPerKwh: number;
128
+ }
129
+ /**
130
+ * Restricts a price component query to a time range.
131
+ */
132
+ export interface EnyoPriceRangeFilter {
133
+ /** Start of the requested range in ISO format (inclusive). */
134
+ fromIso: string;
135
+ /** End of the requested range in ISO format (exclusive). */
136
+ untilIso: string;
137
+ }