@enyo-energy/energy-app-sdk 0.0.140 → 0.0.141

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 (45) hide show
  1. package/dist/cjs/packages/eebus/eebus-cevc-client.d.cts +2 -1
  2. package/dist/cjs/packages/eebus/eebus-evcc-client.d.cts +2 -1
  3. package/dist/cjs/packages/eebus/eebus-evcem-client.d.cts +2 -1
  4. package/dist/cjs/packages/eebus/eebus-evsecc-client.d.cts +2 -1
  5. package/dist/cjs/packages/eebus/eebus-evsoc-client.d.cts +2 -1
  6. package/dist/cjs/packages/eebus/eebus-hvac-client.d.cts +2 -1
  7. package/dist/cjs/packages/eebus/eebus-lpc-client.d.cts +77 -5
  8. package/dist/cjs/packages/eebus/eebus-lpp-client.d.cts +76 -5
  9. package/dist/cjs/packages/eebus/eebus-mgcp-client.d.cts +2 -1
  10. package/dist/cjs/packages/eebus/eebus-mpc-client.d.cts +2 -1
  11. package/dist/cjs/packages/eebus/eebus-ohpcf-client.d.cts +2 -1
  12. package/dist/cjs/packages/eebus/eebus-opev-client.d.cts +2 -1
  13. package/dist/cjs/packages/eebus/eebus-oscev-client.d.cts +2 -1
  14. package/dist/cjs/packages/eebus/eebus-setpoint-client.d.cts +2 -1
  15. package/dist/cjs/packages/eebus/eebus-use-case-client.cjs +2 -0
  16. package/dist/cjs/packages/eebus/eebus-use-case-client.d.cts +26 -0
  17. package/dist/cjs/packages/eebus/eebus-vabd-client.d.cts +2 -1
  18. package/dist/cjs/packages/eebus/eebus-vapd-client.d.cts +2 -1
  19. package/dist/cjs/packages/eebus/energy-app-eebus.d.cts +1 -0
  20. package/dist/cjs/types/enyo-eebus-use-cases.d.cts +41 -0
  21. package/dist/cjs/version.cjs +1 -1
  22. package/dist/cjs/version.d.cts +1 -1
  23. package/dist/packages/eebus/eebus-cevc-client.d.ts +2 -1
  24. package/dist/packages/eebus/eebus-evcc-client.d.ts +2 -1
  25. package/dist/packages/eebus/eebus-evcem-client.d.ts +2 -1
  26. package/dist/packages/eebus/eebus-evsecc-client.d.ts +2 -1
  27. package/dist/packages/eebus/eebus-evsoc-client.d.ts +2 -1
  28. package/dist/packages/eebus/eebus-hvac-client.d.ts +2 -1
  29. package/dist/packages/eebus/eebus-lpc-client.d.ts +77 -5
  30. package/dist/packages/eebus/eebus-lpp-client.d.ts +76 -5
  31. package/dist/packages/eebus/eebus-mgcp-client.d.ts +2 -1
  32. package/dist/packages/eebus/eebus-mpc-client.d.ts +2 -1
  33. package/dist/packages/eebus/eebus-ohpcf-client.d.ts +2 -1
  34. package/dist/packages/eebus/eebus-opev-client.d.ts +2 -1
  35. package/dist/packages/eebus/eebus-oscev-client.d.ts +2 -1
  36. package/dist/packages/eebus/eebus-setpoint-client.d.ts +2 -1
  37. package/dist/packages/eebus/eebus-use-case-client.d.ts +26 -0
  38. package/dist/packages/eebus/eebus-use-case-client.js +1 -0
  39. package/dist/packages/eebus/eebus-vabd-client.d.ts +2 -1
  40. package/dist/packages/eebus/eebus-vapd-client.d.ts +2 -1
  41. package/dist/packages/eebus/energy-app-eebus.d.ts +1 -0
  42. package/dist/types/enyo-eebus-use-cases.d.ts +41 -0
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusCevcAck, EebusCevcChargingPlan, EebusOhpcfIncentiveTable } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.cevc}.
6
7
  */
@@ -33,7 +34,7 @@ export interface CevcClientOptions {
33
34
  * until `ElectricalConnectionClient` and `TimeSeriesClient` both land
34
35
  * in `@enyo-energy/eebus`.
35
36
  */
36
- export interface EebusCevcClient {
37
+ export interface EebusCevcClient extends EebusUseCaseClient {
37
38
  /**
38
39
  * Send a time-series charging plan to the EV. The EV ack carries
39
40
  * either acceptance or a reason for rejection (e.g. plan exceeds
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusEvCommunicationStandardEnum, EebusEvConnectionState, EebusEvIdentification } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.evcc}.
6
7
  *
@@ -34,7 +35,7 @@ export interface EvccClientOptions {
34
35
  * `@enyo-energy/eebus`. The SDK interface is shipped now so consumers
35
36
  * can compile against the final shape.
36
37
  */
37
- export interface EebusEvccClient {
38
+ export interface EebusEvccClient extends EebusUseCaseClient {
38
39
  /**
39
40
  * Read the EV's identification (EVCCID and identification type).
40
41
  * Returns `undefined` when the EV does not publish an
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusEvcemReading } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.evcem}.
6
7
  */
@@ -26,7 +27,7 @@ export interface EvcemClientOptions {
26
27
  * {@link EebusFeatureUnavailableError} from the `connect-core` runtime
27
28
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
28
29
  */
29
- export interface EebusEvcemClient {
30
+ export interface EebusEvcemClient extends EebusUseCaseClient {
30
31
  /**
31
32
  * Read the most recent telemetry sample from the EV charging session.
32
33
  *
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusEvseManufacturerData, EebusEvseOperatingState } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.evsecc}.
6
7
  *
@@ -44,7 +45,7 @@ export interface EvseccClientOptions {
44
45
  * present in the EEBUS library, so this client is fully wired
45
46
  * immediately (no missing-library throws).
46
47
  */
47
- export interface EebusEvseccClient {
48
+ export interface EebusEvseccClient extends EebusUseCaseClient {
48
49
  /**
49
50
  * Read the EVSE's `DeviceClassification.ManufacturerData` — vendor /
50
51
  * model identifiers and revisions.
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusEvSocReading } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.evsoc}.
6
7
  */
@@ -25,7 +26,7 @@ export interface EvsocClientOptions {
25
26
  * {@link EebusFeatureUnavailableError} from the `connect-core` runtime
26
27
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
27
28
  */
28
- export interface EebusEvsocClient {
29
+ export interface EebusEvsocClient extends EebusUseCaseClient {
29
30
  /**
30
31
  * Read the most recent SoC sample, in percent (0–100).
31
32
  *
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusHvacOperationMode, EebusHvacZoneState } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.hvac}.
6
7
  *
@@ -53,7 +54,7 @@ export interface HvacClientOptions {
53
54
  * `EebusFeatureUnavailableError` is thrown only when no `Hvac` server
54
55
  * feature exists on the peer at all.
55
56
  */
56
- export interface EebusHvacClient {
57
+ export interface EebusHvacClient extends EebusUseCaseClient {
57
58
  /**
58
59
  * Read the active heating/cooling operation mode from the remote node.
59
60
  */
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
- import { EebusLpcAck, EebusLpcFailsafe, EebusLpcLimit } from '../../types/enyo-eebus-use-cases.cjs';
2
+ import { EebusLpcAck, EebusLpcFailsafe, EebusLpcLimit, EebusLpcNack } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.lpc}.
6
7
  *
@@ -38,21 +39,53 @@ export interface LpcClientOptions {
38
39
  * {@link EebusLppClient} which is a recommendation.
39
40
  *
40
41
  * The client exposes both actor roles on a single interface:
41
- * - **EMS role (outbound):** {@link setConsumptionLimit}, {@link getActiveConsumptionLimit},
42
- * {@link getFailsafeLimit}
43
- * - **CS role (inbound):** {@link onConsumptionLimitReceived}, {@link provideFailsafeLimit}
42
+ * - **EMS role (outbound):** {@link setConsumptionLimit}, {@link setFailsafeLimit},
43
+ * {@link getActiveConsumptionLimit}, {@link getFailsafeLimit}
44
+ * - **EMS role (inbound):** {@link onActiveConsumptionLimitChanged},
45
+ * {@link onConsumptionLimitNack}, {@link onFailsafeChanged}
46
+ * - **CS role (inbound):** {@link onConsumptionLimitReceived},
47
+ * {@link provideFailsafeLimit}
44
48
  *
45
49
  * Consumers that only act in one role simply never call the other half — there is
46
50
  * no `asManager` / `asAppliance` split.
51
+ *
52
+ * **Acknowledgement semantics.** {@link setConsumptionLimit} resolves once
53
+ * the SPINE write-ack lands — the CS has accepted the message into its
54
+ * queue. That is *not* the same as the CS having applied the limit; for
55
+ * the latter, subscribe to {@link onActiveConsumptionLimitChanged}.
56
+ * Explicit rejections (limit out of permitted set, failsafe override
57
+ * engaged, etc.) arrive via {@link onConsumptionLimitNack} so EMS code
58
+ * does not have to poll {@link getActiveConsumptionLimit} to detect them.
47
59
  */
48
- export interface EebusLpcClient {
60
+ export interface EebusLpcClient extends EebusUseCaseClient {
49
61
  /**
50
62
  * Send a consumption limit to the controllable system. The remote is
51
63
  * obligated to respect the limit until it expires, is replaced, or is
52
64
  * cleared by sending a limit with `isActive: false`.
65
+ *
66
+ * Resolves on the SPINE write-ack. See the class-level note for the
67
+ * difference between "accepted" and "applied"; subscribe to
68
+ * {@link onActiveConsumptionLimitChanged} and
69
+ * {@link onConsumptionLimitNack} to observe the CS's downstream
70
+ * decision.
71
+ *
53
72
  * @param limit The consumption limit to apply
54
73
  */
55
74
  setConsumptionLimit: (limit: EebusLpcLimit) => Promise<void>;
75
+ /**
76
+ * Configure the controllable system's failsafe limit — the value it
77
+ * falls back to when the SHIP connection to this EMS drops. The
78
+ * canonical use case is §14a EnWG, where a grid-operator-acting
79
+ * EMS pushes a 4.2 kW (or jurisdictional equivalent) floor and a
80
+ * fall-back duration that survives transient disconnects.
81
+ *
82
+ * Resolves on the SPINE write-ack. To learn about subsequent
83
+ * CS-side revisions (e.g. the CS rounds the value to its nearest
84
+ * supported set-point), subscribe to {@link onFailsafeChanged}.
85
+ *
86
+ * @param failsafe The failsafe configuration to apply on the CS
87
+ */
88
+ setFailsafeLimit: (failsafe: EebusLpcFailsafe) => Promise<void>;
56
89
  /**
57
90
  * Read the consumption limit currently active on the controllable system,
58
91
  * if any. Useful for verifying that a previously-sent limit was applied,
@@ -65,6 +98,45 @@ export interface EebusLpcClient {
65
98
  * it loses the connection to this EMS.
66
99
  */
67
100
  getFailsafeLimit: () => Promise<EebusLpcFailsafe>;
101
+ /**
102
+ * Subscribe to changes in the *active* consumption limit reported by
103
+ * the CS — fires on every inbound `loadControlLimitListData` notify.
104
+ * The handler receives the new active limit, or `undefined` when the
105
+ * CS clears the active limit (e.g. on expiry).
106
+ *
107
+ * Use this instead of polling {@link getActiveConsumptionLimit} after
108
+ * a {@link setConsumptionLimit} call: the SPINE write-ack resolves
109
+ * before the CS publishes its updated active state, so the polling
110
+ * pattern races against the notify.
111
+ *
112
+ * @param handler Callback invoked with the new active limit (or `undefined`)
113
+ * @returns Listener ID that can be passed to {@link removeListener}
114
+ */
115
+ onActiveConsumptionLimitChanged: (handler: (limit: EebusLpcLimit | undefined) => void) => string;
116
+ /**
117
+ * Subscribe to explicit NACKs from the CS — fires when the CS
118
+ * rejects a previously-sent limit with a reason (e.g. value
119
+ * out-of-range, failsafe override active, command queue full).
120
+ * Distinct from the SPINE write-ack that {@link setConsumptionLimit}
121
+ * resolves on: a write-ack means "received", a NACK arrives as a
122
+ * separate event when the CS subsequently decides not to honour
123
+ * the limit.
124
+ *
125
+ * @param handler Callback invoked with the NACK payload
126
+ * @returns Listener ID that can be passed to {@link removeListener}
127
+ */
128
+ onConsumptionLimitNack: (handler: (nack: EebusLpcNack) => void) => string;
129
+ /**
130
+ * Subscribe to CS-published failsafe revisions — fires on every
131
+ * inbound `deviceConfigurationKeyValueListData` notify carrying
132
+ * a new failsafe value or duration. Allowed by the LPC UC TS as
133
+ * a mid-session signal; consumers that only read the failsafe at
134
+ * warm-up time will otherwise miss it.
135
+ *
136
+ * @param handler Callback invoked with the revised failsafe
137
+ * @returns Listener ID that can be passed to {@link removeListener}
138
+ */
139
+ onFailsafeChanged: (handler: (failsafe: EebusLpcFailsafe) => void) => string;
68
140
  /**
69
141
  * Register a handler invoked when a remote EMS sends a consumption limit
70
142
  * to this device. The handler MUST return an acknowledgement.
@@ -1,4 +1,5 @@
1
- import { EebusLppAck, EebusLppFailsafe, EebusLppLimit } from '../../types/enyo-eebus-use-cases.cjs';
1
+ import { EebusLppAck, EebusLppFailsafe, EebusLppLimit, EebusLppNack } from '../../types/enyo-eebus-use-cases.cjs';
2
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
2
3
  /**
3
4
  * Client for the EEBUS **Limitation of Power Production (LPP)** use case.
4
5
  *
@@ -8,16 +9,46 @@ import { EebusLppAck, EebusLppFailsafe, EebusLppLimit } from '../../types/enyo-e
8
9
  * is an obligation.
9
10
  *
10
11
  * The client exposes both actor roles on a single interface:
11
- * - **EMS role (outbound):** {@link setProductionLimit}, {@link getActiveProductionLimit},
12
- * {@link getFailsafeLimit}
13
- * - **CS role (inbound):** {@link onProductionLimitReceived}, {@link provideFailsafeLimit}
12
+ * - **EMS role (outbound):** {@link setProductionLimit}, {@link setFailsafeLimit},
13
+ * {@link getActiveProductionLimit}, {@link getFailsafeLimit}
14
+ * - **EMS role (inbound):** {@link onActiveProductionLimitChanged},
15
+ * {@link onProductionLimitNack}, {@link onFailsafeChanged}
16
+ * - **CS role (inbound):** {@link onProductionLimitReceived},
17
+ * {@link provideFailsafeLimit}
18
+ *
19
+ * **Acknowledgement semantics.** {@link setProductionLimit} resolves once
20
+ * the SPINE write-ack lands — the CS has accepted the message into its
21
+ * queue. That is *not* the same as the CS having applied the
22
+ * recommendation; for the latter, subscribe to
23
+ * {@link onActiveProductionLimitChanged}. Because LPP is advisory, a
24
+ * producer is free to decline; explicit declines arrive via
25
+ * {@link onProductionLimitNack}.
14
26
  */
15
- export interface EebusLppClient {
27
+ export interface EebusLppClient extends EebusUseCaseClient {
16
28
  /**
17
29
  * Send a production limit recommendation to the producing controllable system.
30
+ *
31
+ * Resolves on the SPINE write-ack. See the class-level note for the
32
+ * difference between "accepted" and "applied"; subscribe to
33
+ * {@link onActiveProductionLimitChanged} and
34
+ * {@link onProductionLimitNack} to observe the producer's downstream
35
+ * decision.
36
+ *
18
37
  * @param limit The production limit recommendation to apply
19
38
  */
20
39
  setProductionLimit: (limit: EebusLppLimit) => Promise<void>;
40
+ /**
41
+ * Configure the producing controllable system's failsafe limit — the
42
+ * value it falls back to when the SHIP connection to this EMS drops.
43
+ * Used to enforce a feed-in cap (e.g. 70 % of nameplate) that
44
+ * survives transient disconnects even when LPP itself is advisory.
45
+ *
46
+ * Resolves on the SPINE write-ack. To learn about subsequent
47
+ * CS-side revisions, subscribe to {@link onFailsafeChanged}.
48
+ *
49
+ * @param failsafe The failsafe configuration to apply on the producer
50
+ */
51
+ setFailsafeLimit: (failsafe: EebusLppFailsafe) => Promise<void>;
21
52
  /**
22
53
  * Read the production limit currently active on the controllable system,
23
54
  * if any.
@@ -29,6 +60,46 @@ export interface EebusLppClient {
29
60
  * it loses the connection to this EMS.
30
61
  */
31
62
  getFailsafeLimit: () => Promise<EebusLppFailsafe>;
63
+ /**
64
+ * Subscribe to changes in the *active* production limit reported by
65
+ * the producer — fires on every inbound `loadControlLimitListData`
66
+ * notify. The handler receives the new active limit, or `undefined`
67
+ * when the producer clears the active limit.
68
+ *
69
+ * Use this instead of polling {@link getActiveProductionLimit} after
70
+ * a {@link setProductionLimit} call: the SPINE write-ack resolves
71
+ * before the producer publishes its updated active state, so the
72
+ * polling pattern races against the notify.
73
+ *
74
+ * @param handler Callback invoked with the new active limit (or `undefined`)
75
+ * @returns Listener ID that can be passed to {@link removeListener}
76
+ */
77
+ onActiveProductionLimitChanged: (handler: (limit: EebusLppLimit | undefined) => void) => string;
78
+ /**
79
+ * Subscribe to explicit declines from the producer — fires when the
80
+ * producer rejects a previously-sent recommendation with a reason.
81
+ * LPP being advisory, a NACK does not breach the use case; it just
82
+ * tells the EMS that the producer chose not to honour the value
83
+ * (e.g. self-consumption priority is engaged on the inverter).
84
+ *
85
+ * Distinct from the SPINE write-ack that
86
+ * {@link setProductionLimit} resolves on.
87
+ *
88
+ * @param handler Callback invoked with the NACK payload
89
+ * @returns Listener ID that can be passed to {@link removeListener}
90
+ */
91
+ onProductionLimitNack: (handler: (nack: EebusLppNack) => void) => string;
92
+ /**
93
+ * Subscribe to producer-published failsafe revisions — fires on every
94
+ * inbound `deviceConfigurationKeyValueListData` notify carrying
95
+ * a new failsafe value or duration. Allowed by the LPP UC TS as a
96
+ * mid-session signal; consumers that only read the failsafe at
97
+ * warm-up time will otherwise miss it.
98
+ *
99
+ * @param handler Callback invoked with the revised failsafe
100
+ * @returns Listener ID that can be passed to {@link removeListener}
101
+ */
102
+ onFailsafeChanged: (handler: (failsafe: EebusLppFailsafe) => void) => string;
32
103
  /**
33
104
  * Register a handler invoked when a remote EMS sends a production limit
34
105
  * recommendation to this device.
@@ -1,4 +1,5 @@
1
1
  import { EebusMgcpReading } from '../../types/enyo-eebus-use-cases.cjs';
2
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
2
3
  /**
3
4
  * Client for the EEBUS **Monitoring of Grid Connection Point (MGCP)** use case.
4
5
  *
@@ -10,7 +11,7 @@ import { EebusMgcpReading } from '../../types/enyo-eebus-use-cases.cjs';
10
11
  * - **CEM role (consume):** {@link getReading}, {@link onReading}
11
12
  * - **GCP role (provide):** {@link provideReading}
12
13
  */
13
- export interface EebusMgcpClient {
14
+ export interface EebusMgcpClient extends EebusUseCaseClient {
14
15
  /**
15
16
  * Read the latest telemetry from the grid connection point.
16
17
  */
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusMpcReading } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.mpc}.
6
7
  *
@@ -62,7 +63,7 @@ export interface MpcClientOptions {
62
63
  * `EebusFeatureUnavailableError` when no `Measurement` server feature
63
64
  * exists at all on the peer.
64
65
  */
65
- export interface EebusMpcClient {
66
+ export interface EebusMpcClient extends EebusUseCaseClient {
66
67
  /**
67
68
  * Read the latest consumption telemetry from the controllable system.
68
69
  */
@@ -1,5 +1,6 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusOhpcfAnnouncement, EebusOhpcfApplianceContext, EebusOhpcfFlavour, EebusOhpcfFlexibility, EebusOhpcfIncentiveTable, EebusOhpcfPlanState } from '../../types/enyo-eebus-use-cases.cjs';
3
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
3
4
  /**
4
5
  * Per-call configuration for {@link EebusUseCaseRegistry.ohpcf}.
5
6
  *
@@ -59,7 +60,7 @@ export interface OhpcfClientOptions {
59
60
  * @see https://techdocs.wago.com/Software/EEBUS_Connector/en-US/3657311371.html
60
61
  * @see https://github.com/enbility/eebus-go/pull/122
61
62
  */
62
- export interface EebusOhpcfClient {
63
+ export interface EebusOhpcfClient extends EebusUseCaseClient {
63
64
  /**
64
65
  * Send an incentive table to the heat pump. The heat pump will use
65
66
  * the table to plan its compressor operation over the covered horizon.
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusOpevAck, EebusOpevLimit } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.opev}.
6
7
  */
@@ -34,7 +35,7 @@ export interface OpevClientOptions {
34
35
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`
35
36
  * (LoadControl itself is already present).
36
37
  */
37
- export interface EebusOpevClient {
38
+ export interface EebusOpevClient extends EebusUseCaseClient {
38
39
  /**
39
40
  * Send a per-phase current limit to the EVSE. The EVSE MUST respect
40
41
  * the limit; ack is the EVSE's accept / reject decision.
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusOscevAck, EebusOscevLimit } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.oscev}.
6
7
  */
@@ -22,7 +23,7 @@ export interface OscevClientOptions {
22
23
  * {@link EebusFeatureUnavailableError} from the `connect-core` runtime
23
24
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
24
25
  */
25
- export interface EebusOscevClient {
26
+ export interface EebusOscevClient extends EebusUseCaseClient {
26
27
  /**
27
28
  * Send a per-phase current recommendation to the EVSE.
28
29
  *
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusSetpointValue } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.setpoint}.
6
7
  *
@@ -54,7 +55,7 @@ export interface SetpointClientOptions {
54
55
  * supported. `EebusFeatureUnavailableError` is thrown only when no
55
56
  * `Setpoint` server feature exists on the peer at all.
56
57
  */
57
- export interface EebusSetpointClient {
58
+ export interface EebusSetpointClient extends EebusUseCaseClient {
58
59
  /**
59
60
  * Read the current setpoints reported by the remote node.
60
61
  * @returns The full list of setpoints currently published by the remote.
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Common shape inherited by every typed EEBUS use-case client.
3
+ *
4
+ * Adding a shared base avoids each client growing its own warm-up
5
+ * vocabulary. Today vendor packages trigger the lazy SPINE handshake
6
+ * by issuing a fake call (e.g. `onReading(noop)` on
7
+ * {@link EebusMpcClient}) just to make the description-list reads
8
+ * happen. {@link ready} replaces that ritual with an explicit hook.
9
+ */
10
+ export interface EebusUseCaseClient {
11
+ /**
12
+ * Drive the SPINE binding + description-list reads for this
13
+ * use-case client to completion without dispatching any real
14
+ * read, write, or subscription. Resolves once the handshake has
15
+ * landed (or rejects with an {@link EebusFeatureUnavailableError}
16
+ * / {@link EebusFeatureNotResolvedError} /
17
+ * {@link EebusRequestTimeoutError} if the peer cannot satisfy it
18
+ * within the client's configured `descriptionReadTimeoutMs`).
19
+ *
20
+ * Idempotent: subsequent calls resolve as soon as the handshake
21
+ * has succeeded once. Safe to call from package start-up to
22
+ * surface "peer is not ready" early instead of letting the first
23
+ * real call fail later.
24
+ */
25
+ ready: () => Promise<void>;
26
+ }
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusVabdTelemetry } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.vabd}.
6
7
  */
@@ -29,7 +30,7 @@ export interface VabdClientOptions {
29
30
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
30
31
  * `Measurement` and `DeviceConfiguration` are already present.
31
32
  */
32
- export interface EebusVabdClient {
33
+ export interface EebusVabdClient extends EebusUseCaseClient {
33
34
  /**
34
35
  * Read the battery's current state of charge in percent (0–100).
35
36
  *
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.cjs';
2
2
  import { EebusVapdTelemetry } from '../../types/enyo-eebus-use-cases.cjs';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.cjs';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.cjs';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.vapd}.
6
7
  */
@@ -28,7 +29,7 @@ export interface VapdClientOptions {
28
29
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
29
30
  * `Measurement` and `DeviceConfiguration` are already present.
30
31
  */
31
- export interface EebusVapdClient {
32
+ export interface EebusVapdClient extends EebusUseCaseClient {
32
33
  /**
33
34
  * Read the PV system's current active production in Watts.
34
35
  *
@@ -7,6 +7,7 @@ export { EebusDeviceManagement } from './eebus-device-management.cjs';
7
7
  export { EebusFeatureCatalog, EebusFeatureAddressMatch } from './eebus-feature-catalog.cjs';
8
8
  export { EebusIdentityService } from './eebus-identity-service.cjs';
9
9
  export { EebusSpineLowLevel } from './eebus-spine-low-level.cjs';
10
+ export { EebusUseCaseClient } from './eebus-use-case-client.cjs';
10
11
  export { EebusUseCaseRegistry } from './eebus-use-case-registry.cjs';
11
12
  export { EebusHvacClient, HvacClientOptions } from './eebus-hvac-client.cjs';
12
13
  export { EebusLpcClient, LpcClientOptions } from './eebus-lpc-client.cjs';
@@ -54,6 +54,27 @@ export interface EebusLpcAck {
54
54
  /** Optional human-readable reason when {@link accepted} is `false` */
55
55
  reason?: string;
56
56
  }
57
+ /**
58
+ * Push-side rejection from a controllable system, delivered to an EMS
59
+ * subscriber via {@link EebusLpcClient.onConsumptionLimitNack}.
60
+ *
61
+ * Distinct from the SPINE write-ack that
62
+ * {@link EebusLpcClient.setConsumptionLimit} resolves on: a write-ack
63
+ * means "the CS received the limit message". A NACK arrives as a
64
+ * separate event when the CS subsequently decides not to honour the
65
+ * limit (out-of-range value, failsafe override active, queue full,
66
+ * etc.).
67
+ */
68
+ export interface EebusLpcNack {
69
+ /** Human-readable reason the CS rejected the limit. */
70
+ reason: string;
71
+ /**
72
+ * The limit the CS rejected, when attribution to the originating
73
+ * write is available. Omitted on peers that don't echo the
74
+ * rejected payload (some VICTRON / KEBA firmwares).
75
+ */
76
+ rejectedLimit?: EebusLpcLimit;
77
+ }
57
78
  /**
58
79
  * A production limit issued by an Energy Management System to a producing
59
80
  * Controllable System (e.g. a PV inverter). LPP limits are recommendations:
@@ -89,6 +110,26 @@ export interface EebusLppAck {
89
110
  /** Optional human-readable reason when {@link accepted} is `false` */
90
111
  reason?: string;
91
112
  }
113
+ /**
114
+ * Push-side rejection from a producing controllable system, delivered to
115
+ * an EMS subscriber via {@link EebusLppClient.onProductionLimitNack}.
116
+ *
117
+ * LPP is a *recommendation*: the producing CS may decline a
118
+ * recommendation without violating the use case (compare with LPC,
119
+ * where a NACK means the obligation could not be honoured). A NACK
120
+ * arrives as a separate event after the SPINE write-ack that
121
+ * {@link EebusLppClient.setProductionLimit} resolves on.
122
+ */
123
+ export interface EebusLppNack {
124
+ /** Human-readable reason the producer declined the recommendation. */
125
+ reason: string;
126
+ /**
127
+ * The recommendation the producer declined, when attribution to the
128
+ * originating write is available. Omitted on peers that don't echo
129
+ * the declined payload.
130
+ */
131
+ rejectedLimit?: EebusLppLimit;
132
+ }
92
133
  /**
93
134
  * A single telemetry reading from a grid connection point.
94
135
  * Positive power values indicate import (consumption from the grid);
@@ -9,7 +9,7 @@ exports.getSdkVersion = getSdkVersion;
9
9
  /**
10
10
  * Current version of the enyo Energy App SDK.
11
11
  */
12
- exports.SDK_VERSION = '0.0.140';
12
+ exports.SDK_VERSION = '0.0.141';
13
13
  /**
14
14
  * Gets the current SDK version.
15
15
  * @returns The semantic version string of the SDK
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Current version of the enyo Energy App SDK.
7
7
  */
8
- export declare const SDK_VERSION = "0.0.140";
8
+ export declare const SDK_VERSION = "0.0.141";
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusCevcAck, EebusCevcChargingPlan, EebusOhpcfIncentiveTable } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.cevc}.
6
7
  */
@@ -33,7 +34,7 @@ export interface CevcClientOptions {
33
34
  * until `ElectricalConnectionClient` and `TimeSeriesClient` both land
34
35
  * in `@enyo-energy/eebus`.
35
36
  */
36
- export interface EebusCevcClient {
37
+ export interface EebusCevcClient extends EebusUseCaseClient {
37
38
  /**
38
39
  * Send a time-series charging plan to the EV. The EV ack carries
39
40
  * either acceptance or a reason for rejection (e.g. plan exceeds
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusEvCommunicationStandardEnum, EebusEvConnectionState, EebusEvIdentification } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.evcc}.
6
7
  *
@@ -34,7 +35,7 @@ export interface EvccClientOptions {
34
35
  * `@enyo-energy/eebus`. The SDK interface is shipped now so consumers
35
36
  * can compile against the final shape.
36
37
  */
37
- export interface EebusEvccClient {
38
+ export interface EebusEvccClient extends EebusUseCaseClient {
38
39
  /**
39
40
  * Read the EV's identification (EVCCID and identification type).
40
41
  * Returns `undefined` when the EV does not publish an
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusEvcemReading } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.evcem}.
6
7
  */
@@ -26,7 +27,7 @@ export interface EvcemClientOptions {
26
27
  * {@link EebusFeatureUnavailableError} from the `connect-core` runtime
27
28
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
28
29
  */
29
- export interface EebusEvcemClient {
30
+ export interface EebusEvcemClient extends EebusUseCaseClient {
30
31
  /**
31
32
  * Read the most recent telemetry sample from the EV charging session.
32
33
  *
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusEvseManufacturerData, EebusEvseOperatingState } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.evsecc}.
6
7
  *
@@ -44,7 +45,7 @@ export interface EvseccClientOptions {
44
45
  * present in the EEBUS library, so this client is fully wired
45
46
  * immediately (no missing-library throws).
46
47
  */
47
- export interface EebusEvseccClient {
48
+ export interface EebusEvseccClient extends EebusUseCaseClient {
48
49
  /**
49
50
  * Read the EVSE's `DeviceClassification.ManufacturerData` — vendor /
50
51
  * model identifiers and revisions.
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusEvSocReading } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.evsoc}.
6
7
  */
@@ -25,7 +26,7 @@ export interface EvsocClientOptions {
25
26
  * {@link EebusFeatureUnavailableError} from the `connect-core` runtime
26
27
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
27
28
  */
28
- export interface EebusEvsocClient {
29
+ export interface EebusEvsocClient extends EebusUseCaseClient {
29
30
  /**
30
31
  * Read the most recent SoC sample, in percent (0–100).
31
32
  *
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusHvacOperationMode, EebusHvacZoneState } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.hvac}.
6
7
  *
@@ -53,7 +54,7 @@ export interface HvacClientOptions {
53
54
  * `EebusFeatureUnavailableError` is thrown only when no `Hvac` server
54
55
  * feature exists on the peer at all.
55
56
  */
56
- export interface EebusHvacClient {
57
+ export interface EebusHvacClient extends EebusUseCaseClient {
57
58
  /**
58
59
  * Read the active heating/cooling operation mode from the remote node.
59
60
  */
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
- import { EebusLpcAck, EebusLpcFailsafe, EebusLpcLimit } from '../../types/enyo-eebus-use-cases.js';
2
+ import { EebusLpcAck, EebusLpcFailsafe, EebusLpcLimit, EebusLpcNack } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.lpc}.
6
7
  *
@@ -38,21 +39,53 @@ export interface LpcClientOptions {
38
39
  * {@link EebusLppClient} which is a recommendation.
39
40
  *
40
41
  * The client exposes both actor roles on a single interface:
41
- * - **EMS role (outbound):** {@link setConsumptionLimit}, {@link getActiveConsumptionLimit},
42
- * {@link getFailsafeLimit}
43
- * - **CS role (inbound):** {@link onConsumptionLimitReceived}, {@link provideFailsafeLimit}
42
+ * - **EMS role (outbound):** {@link setConsumptionLimit}, {@link setFailsafeLimit},
43
+ * {@link getActiveConsumptionLimit}, {@link getFailsafeLimit}
44
+ * - **EMS role (inbound):** {@link onActiveConsumptionLimitChanged},
45
+ * {@link onConsumptionLimitNack}, {@link onFailsafeChanged}
46
+ * - **CS role (inbound):** {@link onConsumptionLimitReceived},
47
+ * {@link provideFailsafeLimit}
44
48
  *
45
49
  * Consumers that only act in one role simply never call the other half — there is
46
50
  * no `asManager` / `asAppliance` split.
51
+ *
52
+ * **Acknowledgement semantics.** {@link setConsumptionLimit} resolves once
53
+ * the SPINE write-ack lands — the CS has accepted the message into its
54
+ * queue. That is *not* the same as the CS having applied the limit; for
55
+ * the latter, subscribe to {@link onActiveConsumptionLimitChanged}.
56
+ * Explicit rejections (limit out of permitted set, failsafe override
57
+ * engaged, etc.) arrive via {@link onConsumptionLimitNack} so EMS code
58
+ * does not have to poll {@link getActiveConsumptionLimit} to detect them.
47
59
  */
48
- export interface EebusLpcClient {
60
+ export interface EebusLpcClient extends EebusUseCaseClient {
49
61
  /**
50
62
  * Send a consumption limit to the controllable system. The remote is
51
63
  * obligated to respect the limit until it expires, is replaced, or is
52
64
  * cleared by sending a limit with `isActive: false`.
65
+ *
66
+ * Resolves on the SPINE write-ack. See the class-level note for the
67
+ * difference between "accepted" and "applied"; subscribe to
68
+ * {@link onActiveConsumptionLimitChanged} and
69
+ * {@link onConsumptionLimitNack} to observe the CS's downstream
70
+ * decision.
71
+ *
53
72
  * @param limit The consumption limit to apply
54
73
  */
55
74
  setConsumptionLimit: (limit: EebusLpcLimit) => Promise<void>;
75
+ /**
76
+ * Configure the controllable system's failsafe limit — the value it
77
+ * falls back to when the SHIP connection to this EMS drops. The
78
+ * canonical use case is §14a EnWG, where a grid-operator-acting
79
+ * EMS pushes a 4.2 kW (or jurisdictional equivalent) floor and a
80
+ * fall-back duration that survives transient disconnects.
81
+ *
82
+ * Resolves on the SPINE write-ack. To learn about subsequent
83
+ * CS-side revisions (e.g. the CS rounds the value to its nearest
84
+ * supported set-point), subscribe to {@link onFailsafeChanged}.
85
+ *
86
+ * @param failsafe The failsafe configuration to apply on the CS
87
+ */
88
+ setFailsafeLimit: (failsafe: EebusLpcFailsafe) => Promise<void>;
56
89
  /**
57
90
  * Read the consumption limit currently active on the controllable system,
58
91
  * if any. Useful for verifying that a previously-sent limit was applied,
@@ -65,6 +98,45 @@ export interface EebusLpcClient {
65
98
  * it loses the connection to this EMS.
66
99
  */
67
100
  getFailsafeLimit: () => Promise<EebusLpcFailsafe>;
101
+ /**
102
+ * Subscribe to changes in the *active* consumption limit reported by
103
+ * the CS — fires on every inbound `loadControlLimitListData` notify.
104
+ * The handler receives the new active limit, or `undefined` when the
105
+ * CS clears the active limit (e.g. on expiry).
106
+ *
107
+ * Use this instead of polling {@link getActiveConsumptionLimit} after
108
+ * a {@link setConsumptionLimit} call: the SPINE write-ack resolves
109
+ * before the CS publishes its updated active state, so the polling
110
+ * pattern races against the notify.
111
+ *
112
+ * @param handler Callback invoked with the new active limit (or `undefined`)
113
+ * @returns Listener ID that can be passed to {@link removeListener}
114
+ */
115
+ onActiveConsumptionLimitChanged: (handler: (limit: EebusLpcLimit | undefined) => void) => string;
116
+ /**
117
+ * Subscribe to explicit NACKs from the CS — fires when the CS
118
+ * rejects a previously-sent limit with a reason (e.g. value
119
+ * out-of-range, failsafe override active, command queue full).
120
+ * Distinct from the SPINE write-ack that {@link setConsumptionLimit}
121
+ * resolves on: a write-ack means "received", a NACK arrives as a
122
+ * separate event when the CS subsequently decides not to honour
123
+ * the limit.
124
+ *
125
+ * @param handler Callback invoked with the NACK payload
126
+ * @returns Listener ID that can be passed to {@link removeListener}
127
+ */
128
+ onConsumptionLimitNack: (handler: (nack: EebusLpcNack) => void) => string;
129
+ /**
130
+ * Subscribe to CS-published failsafe revisions — fires on every
131
+ * inbound `deviceConfigurationKeyValueListData` notify carrying
132
+ * a new failsafe value or duration. Allowed by the LPC UC TS as
133
+ * a mid-session signal; consumers that only read the failsafe at
134
+ * warm-up time will otherwise miss it.
135
+ *
136
+ * @param handler Callback invoked with the revised failsafe
137
+ * @returns Listener ID that can be passed to {@link removeListener}
138
+ */
139
+ onFailsafeChanged: (handler: (failsafe: EebusLpcFailsafe) => void) => string;
68
140
  /**
69
141
  * Register a handler invoked when a remote EMS sends a consumption limit
70
142
  * to this device. The handler MUST return an acknowledgement.
@@ -1,4 +1,5 @@
1
- import { EebusLppAck, EebusLppFailsafe, EebusLppLimit } from '../../types/enyo-eebus-use-cases.js';
1
+ import { EebusLppAck, EebusLppFailsafe, EebusLppLimit, EebusLppNack } from '../../types/enyo-eebus-use-cases.js';
2
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
2
3
  /**
3
4
  * Client for the EEBUS **Limitation of Power Production (LPP)** use case.
4
5
  *
@@ -8,16 +9,46 @@ import { EebusLppAck, EebusLppFailsafe, EebusLppLimit } from '../../types/enyo-e
8
9
  * is an obligation.
9
10
  *
10
11
  * The client exposes both actor roles on a single interface:
11
- * - **EMS role (outbound):** {@link setProductionLimit}, {@link getActiveProductionLimit},
12
- * {@link getFailsafeLimit}
13
- * - **CS role (inbound):** {@link onProductionLimitReceived}, {@link provideFailsafeLimit}
12
+ * - **EMS role (outbound):** {@link setProductionLimit}, {@link setFailsafeLimit},
13
+ * {@link getActiveProductionLimit}, {@link getFailsafeLimit}
14
+ * - **EMS role (inbound):** {@link onActiveProductionLimitChanged},
15
+ * {@link onProductionLimitNack}, {@link onFailsafeChanged}
16
+ * - **CS role (inbound):** {@link onProductionLimitReceived},
17
+ * {@link provideFailsafeLimit}
18
+ *
19
+ * **Acknowledgement semantics.** {@link setProductionLimit} resolves once
20
+ * the SPINE write-ack lands — the CS has accepted the message into its
21
+ * queue. That is *not* the same as the CS having applied the
22
+ * recommendation; for the latter, subscribe to
23
+ * {@link onActiveProductionLimitChanged}. Because LPP is advisory, a
24
+ * producer is free to decline; explicit declines arrive via
25
+ * {@link onProductionLimitNack}.
14
26
  */
15
- export interface EebusLppClient {
27
+ export interface EebusLppClient extends EebusUseCaseClient {
16
28
  /**
17
29
  * Send a production limit recommendation to the producing controllable system.
30
+ *
31
+ * Resolves on the SPINE write-ack. See the class-level note for the
32
+ * difference between "accepted" and "applied"; subscribe to
33
+ * {@link onActiveProductionLimitChanged} and
34
+ * {@link onProductionLimitNack} to observe the producer's downstream
35
+ * decision.
36
+ *
18
37
  * @param limit The production limit recommendation to apply
19
38
  */
20
39
  setProductionLimit: (limit: EebusLppLimit) => Promise<void>;
40
+ /**
41
+ * Configure the producing controllable system's failsafe limit — the
42
+ * value it falls back to when the SHIP connection to this EMS drops.
43
+ * Used to enforce a feed-in cap (e.g. 70 % of nameplate) that
44
+ * survives transient disconnects even when LPP itself is advisory.
45
+ *
46
+ * Resolves on the SPINE write-ack. To learn about subsequent
47
+ * CS-side revisions, subscribe to {@link onFailsafeChanged}.
48
+ *
49
+ * @param failsafe The failsafe configuration to apply on the producer
50
+ */
51
+ setFailsafeLimit: (failsafe: EebusLppFailsafe) => Promise<void>;
21
52
  /**
22
53
  * Read the production limit currently active on the controllable system,
23
54
  * if any.
@@ -29,6 +60,46 @@ export interface EebusLppClient {
29
60
  * it loses the connection to this EMS.
30
61
  */
31
62
  getFailsafeLimit: () => Promise<EebusLppFailsafe>;
63
+ /**
64
+ * Subscribe to changes in the *active* production limit reported by
65
+ * the producer — fires on every inbound `loadControlLimitListData`
66
+ * notify. The handler receives the new active limit, or `undefined`
67
+ * when the producer clears the active limit.
68
+ *
69
+ * Use this instead of polling {@link getActiveProductionLimit} after
70
+ * a {@link setProductionLimit} call: the SPINE write-ack resolves
71
+ * before the producer publishes its updated active state, so the
72
+ * polling pattern races against the notify.
73
+ *
74
+ * @param handler Callback invoked with the new active limit (or `undefined`)
75
+ * @returns Listener ID that can be passed to {@link removeListener}
76
+ */
77
+ onActiveProductionLimitChanged: (handler: (limit: EebusLppLimit | undefined) => void) => string;
78
+ /**
79
+ * Subscribe to explicit declines from the producer — fires when the
80
+ * producer rejects a previously-sent recommendation with a reason.
81
+ * LPP being advisory, a NACK does not breach the use case; it just
82
+ * tells the EMS that the producer chose not to honour the value
83
+ * (e.g. self-consumption priority is engaged on the inverter).
84
+ *
85
+ * Distinct from the SPINE write-ack that
86
+ * {@link setProductionLimit} resolves on.
87
+ *
88
+ * @param handler Callback invoked with the NACK payload
89
+ * @returns Listener ID that can be passed to {@link removeListener}
90
+ */
91
+ onProductionLimitNack: (handler: (nack: EebusLppNack) => void) => string;
92
+ /**
93
+ * Subscribe to producer-published failsafe revisions — fires on every
94
+ * inbound `deviceConfigurationKeyValueListData` notify carrying
95
+ * a new failsafe value or duration. Allowed by the LPP UC TS as a
96
+ * mid-session signal; consumers that only read the failsafe at
97
+ * warm-up time will otherwise miss it.
98
+ *
99
+ * @param handler Callback invoked with the revised failsafe
100
+ * @returns Listener ID that can be passed to {@link removeListener}
101
+ */
102
+ onFailsafeChanged: (handler: (failsafe: EebusLppFailsafe) => void) => string;
32
103
  /**
33
104
  * Register a handler invoked when a remote EMS sends a production limit
34
105
  * recommendation to this device.
@@ -1,4 +1,5 @@
1
1
  import { EebusMgcpReading } from '../../types/enyo-eebus-use-cases.js';
2
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
2
3
  /**
3
4
  * Client for the EEBUS **Monitoring of Grid Connection Point (MGCP)** use case.
4
5
  *
@@ -10,7 +11,7 @@ import { EebusMgcpReading } from '../../types/enyo-eebus-use-cases.js';
10
11
  * - **CEM role (consume):** {@link getReading}, {@link onReading}
11
12
  * - **GCP role (provide):** {@link provideReading}
12
13
  */
13
- export interface EebusMgcpClient {
14
+ export interface EebusMgcpClient extends EebusUseCaseClient {
14
15
  /**
15
16
  * Read the latest telemetry from the grid connection point.
16
17
  */
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusMpcReading } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.mpc}.
6
7
  *
@@ -62,7 +63,7 @@ export interface MpcClientOptions {
62
63
  * `EebusFeatureUnavailableError` when no `Measurement` server feature
63
64
  * exists at all on the peer.
64
65
  */
65
- export interface EebusMpcClient {
66
+ export interface EebusMpcClient extends EebusUseCaseClient {
66
67
  /**
67
68
  * Read the latest consumption telemetry from the controllable system.
68
69
  */
@@ -1,5 +1,6 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusOhpcfAnnouncement, EebusOhpcfApplianceContext, EebusOhpcfFlavour, EebusOhpcfFlexibility, EebusOhpcfIncentiveTable, EebusOhpcfPlanState } from '../../types/enyo-eebus-use-cases.js';
3
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
3
4
  /**
4
5
  * Per-call configuration for {@link EebusUseCaseRegistry.ohpcf}.
5
6
  *
@@ -59,7 +60,7 @@ export interface OhpcfClientOptions {
59
60
  * @see https://techdocs.wago.com/Software/EEBUS_Connector/en-US/3657311371.html
60
61
  * @see https://github.com/enbility/eebus-go/pull/122
61
62
  */
62
- export interface EebusOhpcfClient {
63
+ export interface EebusOhpcfClient extends EebusUseCaseClient {
63
64
  /**
64
65
  * Send an incentive table to the heat pump. The heat pump will use
65
66
  * the table to plan its compressor operation over the covered horizon.
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusOpevAck, EebusOpevLimit } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.opev}.
6
7
  */
@@ -34,7 +35,7 @@ export interface OpevClientOptions {
34
35
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`
35
36
  * (LoadControl itself is already present).
36
37
  */
37
- export interface EebusOpevClient {
38
+ export interface EebusOpevClient extends EebusUseCaseClient {
38
39
  /**
39
40
  * Send a per-phase current limit to the EVSE. The EVSE MUST respect
40
41
  * the limit; ack is the EVSE's accept / reject decision.
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusOscevAck, EebusOscevLimit } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.oscev}.
6
7
  */
@@ -22,7 +23,7 @@ export interface OscevClientOptions {
22
23
  * {@link EebusFeatureUnavailableError} from the `connect-core` runtime
23
24
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
24
25
  */
25
- export interface EebusOscevClient {
26
+ export interface EebusOscevClient extends EebusUseCaseClient {
26
27
  /**
27
28
  * Send a per-phase current recommendation to the EVSE.
28
29
  *
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusSetpointValue } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.setpoint}.
6
7
  *
@@ -54,7 +55,7 @@ export interface SetpointClientOptions {
54
55
  * supported. `EebusFeatureUnavailableError` is thrown only when no
55
56
  * `Setpoint` server feature exists on the peer at all.
56
57
  */
57
- export interface EebusSetpointClient {
58
+ export interface EebusSetpointClient extends EebusUseCaseClient {
58
59
  /**
59
60
  * Read the current setpoints reported by the remote node.
60
61
  * @returns The full list of setpoints currently published by the remote.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Common shape inherited by every typed EEBUS use-case client.
3
+ *
4
+ * Adding a shared base avoids each client growing its own warm-up
5
+ * vocabulary. Today vendor packages trigger the lazy SPINE handshake
6
+ * by issuing a fake call (e.g. `onReading(noop)` on
7
+ * {@link EebusMpcClient}) just to make the description-list reads
8
+ * happen. {@link ready} replaces that ritual with an explicit hook.
9
+ */
10
+ export interface EebusUseCaseClient {
11
+ /**
12
+ * Drive the SPINE binding + description-list reads for this
13
+ * use-case client to completion without dispatching any real
14
+ * read, write, or subscription. Resolves once the handshake has
15
+ * landed (or rejects with an {@link EebusFeatureUnavailableError}
16
+ * / {@link EebusFeatureNotResolvedError} /
17
+ * {@link EebusRequestTimeoutError} if the peer cannot satisfy it
18
+ * within the client's configured `descriptionReadTimeoutMs`).
19
+ *
20
+ * Idempotent: subsequent calls resolve as soon as the handshake
21
+ * has succeeded once. Safe to call from package start-up to
22
+ * surface "peer is not ready" early instead of letting the first
23
+ * real call fail later.
24
+ */
25
+ ready: () => Promise<void>;
26
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusVabdTelemetry } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.vabd}.
6
7
  */
@@ -29,7 +30,7 @@ export interface VabdClientOptions {
29
30
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
30
31
  * `Measurement` and `DeviceConfiguration` are already present.
31
32
  */
32
- export interface EebusVabdClient {
33
+ export interface EebusVabdClient extends EebusUseCaseClient {
33
34
  /**
34
35
  * Read the battery's current state of charge in percent (0–100).
35
36
  *
@@ -1,6 +1,7 @@
1
1
  import { SpineRemoteTarget } from '../../types/enyo-eebus.js';
2
2
  import { EebusVapdTelemetry } from '../../types/enyo-eebus-use-cases.js';
3
3
  import { SpineEntityType } from '../../types/enyo-spine.js';
4
+ import { EebusUseCaseClient } from './eebus-use-case-client.js';
4
5
  /**
5
6
  * Per-call configuration for {@link EebusUseCaseRegistry.vapd}.
6
7
  */
@@ -28,7 +29,7 @@ export interface VapdClientOptions {
28
29
  * until `ElectricalConnectionClient` lands in `@enyo-energy/eebus`.
29
30
  * `Measurement` and `DeviceConfiguration` are already present.
30
31
  */
31
- export interface EebusVapdClient {
32
+ export interface EebusVapdClient extends EebusUseCaseClient {
32
33
  /**
33
34
  * Read the PV system's current active production in Watts.
34
35
  *
@@ -7,6 +7,7 @@ export { EebusDeviceManagement } from './eebus-device-management.js';
7
7
  export { EebusFeatureCatalog, EebusFeatureAddressMatch } from './eebus-feature-catalog.js';
8
8
  export { EebusIdentityService } from './eebus-identity-service.js';
9
9
  export { EebusSpineLowLevel } from './eebus-spine-low-level.js';
10
+ export { EebusUseCaseClient } from './eebus-use-case-client.js';
10
11
  export { EebusUseCaseRegistry } from './eebus-use-case-registry.js';
11
12
  export { EebusHvacClient, HvacClientOptions } from './eebus-hvac-client.js';
12
13
  export { EebusLpcClient, LpcClientOptions } from './eebus-lpc-client.js';
@@ -54,6 +54,27 @@ export interface EebusLpcAck {
54
54
  /** Optional human-readable reason when {@link accepted} is `false` */
55
55
  reason?: string;
56
56
  }
57
+ /**
58
+ * Push-side rejection from a controllable system, delivered to an EMS
59
+ * subscriber via {@link EebusLpcClient.onConsumptionLimitNack}.
60
+ *
61
+ * Distinct from the SPINE write-ack that
62
+ * {@link EebusLpcClient.setConsumptionLimit} resolves on: a write-ack
63
+ * means "the CS received the limit message". A NACK arrives as a
64
+ * separate event when the CS subsequently decides not to honour the
65
+ * limit (out-of-range value, failsafe override active, queue full,
66
+ * etc.).
67
+ */
68
+ export interface EebusLpcNack {
69
+ /** Human-readable reason the CS rejected the limit. */
70
+ reason: string;
71
+ /**
72
+ * The limit the CS rejected, when attribution to the originating
73
+ * write is available. Omitted on peers that don't echo the
74
+ * rejected payload (some VICTRON / KEBA firmwares).
75
+ */
76
+ rejectedLimit?: EebusLpcLimit;
77
+ }
57
78
  /**
58
79
  * A production limit issued by an Energy Management System to a producing
59
80
  * Controllable System (e.g. a PV inverter). LPP limits are recommendations:
@@ -89,6 +110,26 @@ export interface EebusLppAck {
89
110
  /** Optional human-readable reason when {@link accepted} is `false` */
90
111
  reason?: string;
91
112
  }
113
+ /**
114
+ * Push-side rejection from a producing controllable system, delivered to
115
+ * an EMS subscriber via {@link EebusLppClient.onProductionLimitNack}.
116
+ *
117
+ * LPP is a *recommendation*: the producing CS may decline a
118
+ * recommendation without violating the use case (compare with LPC,
119
+ * where a NACK means the obligation could not be honoured). A NACK
120
+ * arrives as a separate event after the SPINE write-ack that
121
+ * {@link EebusLppClient.setProductionLimit} resolves on.
122
+ */
123
+ export interface EebusLppNack {
124
+ /** Human-readable reason the producer declined the recommendation. */
125
+ reason: string;
126
+ /**
127
+ * The recommendation the producer declined, when attribution to the
128
+ * originating write is available. Omitted on peers that don't echo
129
+ * the declined payload.
130
+ */
131
+ rejectedLimit?: EebusLppLimit;
132
+ }
92
133
  /**
93
134
  * A single telemetry reading from a grid connection point.
94
135
  * Positive power values indicate import (consumption from the grid);
package/dist/version.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Current version of the enyo Energy App SDK.
7
7
  */
8
- export declare const SDK_VERSION = "0.0.140";
8
+ export declare const SDK_VERSION = "0.0.141";
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK
package/dist/version.js CHANGED
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Current version of the enyo Energy App SDK.
7
7
  */
8
- export const SDK_VERSION = '0.0.140';
8
+ export const SDK_VERSION = '0.0.141';
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enyo-energy/energy-app-sdk",
3
- "version": "0.0.140",
3
+ "version": "0.0.141",
4
4
  "description": "enyo Energy App SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",