@enyo-energy/energy-app-sdk 0.0.198 → 1.0.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.
- package/README.md +5 -3
- package/dist/cjs/energy-app-permission.type.cjs +6 -0
- package/dist/cjs/energy-app-permission.type.d.cts +11 -1
- package/dist/cjs/implementations/energy-manager-settings/energy-manager-settings-utils.cjs +102 -0
- package/dist/cjs/implementations/energy-manager-settings/energy-manager-settings-utils.d.cts +78 -0
- package/dist/cjs/implementations/energy-manager-settings/energy-manager-settings-validators.cjs +48 -28
- package/dist/cjs/implementations/energy-manager-settings/energy-manager-settings-validators.d.cts +9 -6
- package/dist/cjs/implementations/onboarding-v2/onboarding-v2-validators.cjs +36 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/types/enyo-energy-manager-settings.cjs +76 -11
- package/dist/cjs/types/enyo-energy-manager-settings.d.cts +102 -42
- package/dist/cjs/types/enyo-onboarding-v2.cjs +21 -0
- package/dist/cjs/types/enyo-onboarding-v2.d.cts +41 -1
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/energy-app-permission.type.d.ts +11 -1
- package/dist/energy-app-permission.type.js +6 -0
- package/dist/implementations/energy-manager-settings/energy-manager-settings-utils.d.ts +78 -0
- package/dist/implementations/energy-manager-settings/energy-manager-settings-utils.js +98 -0
- package/dist/implementations/energy-manager-settings/energy-manager-settings-validators.d.ts +9 -6
- package/dist/implementations/energy-manager-settings/energy-manager-settings-validators.js +49 -29
- package/dist/implementations/onboarding-v2/onboarding-v2-validators.js +37 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/enyo-energy-manager-settings.d.ts +102 -42
- package/dist/types/enyo-energy-manager-settings.js +75 -10
- package/dist/types/enyo-onboarding-v2.d.ts +41 -1
- package/dist/types/enyo-onboarding-v2.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1136,8 +1136,9 @@ A closed, SDK-defined set of user-facing controls the active energy manager hono
|
|
|
1136
1136
|
| `BatteryControl` | boolean |
|
|
1137
1137
|
| `BatteryChargingMode` | `paced` \| `immediate` |
|
|
1138
1138
|
| `BatteryChargeFromGrid` | boolean |
|
|
1139
|
-
| `
|
|
1140
|
-
| `
|
|
1139
|
+
| `BatteryEvDischargeMode` | `fixed-wh` \| `soc-limit` \| `intelligent` \| `block-discharge` \| `unmanaged` |
|
|
1140
|
+
| `BatteryEvDischargeFixedWh` | number, **Wh** (only under `fixed-wh`) |
|
|
1141
|
+
| `BatteryEvDischargeSocLimitPercent` | number, **%** floor (only under `soc-limit`) |
|
|
1141
1142
|
| `HeatpumpControl` | boolean |
|
|
1142
1143
|
| `HeatingRodControl` | boolean |
|
|
1143
1144
|
| `HeatingRodMode` | `pv-surplus-only` \| `boost` |
|
|
@@ -1183,7 +1184,8 @@ em.unsubscribeEnergyManagerSettings(id);
|
|
|
1183
1184
|
Three things to get right:
|
|
1184
1185
|
|
|
1185
1186
|
- **Absent is not `false`.** `undefined` means unsupported or never chosen; `false` means the user switched it off. Check `supported` first, then the value — collapsing the two steers hardware someone deliberately disabled.
|
|
1186
|
-
- **
|
|
1187
|
+
- **How the battery may feed a charging EV is one mode plus its parameter.** `BatteryEvDischargeMode` picks the strategy; `BatteryEvDischargeFixedWh` and `BatteryEvDischargeSocLimitPercent` are read only under their own mode. `block-discharge` (actively hold the battery back) and `unmanaged` (do not intervene either way) are **not** synonyms.
|
|
1188
|
+
- **Eight settings are gated by another** (`heatingRodMode` needs `heatingRodControl`, `priceLimitCtPerKwh` only applies under `price-limit`, …). The tree is exported as `ENERGY_MANAGER_SETTING_DEPENDENCIES`, with two helpers over it: `getEnergyManagerSettingDependency(setting)` returns the direct gate and the value it must hold (or `null` for an ungated root), and `isEnergyManagerSettingActive(setting, values)` walks the whole chain — the gates are now two deep, so a Wh budget is live only when the mode is `fixed-wh` *and* battery control is on.
|
|
1187
1189
|
- **`priceLimitCtPerKwh` is in cents**, unlike the SDK's machine-readable price fields (`electricityPricePerKwh`, EUR/kWh). Divide by 100 when comparing. `validateEnergyManagerSettingsState()` warns on values outside a plausible ct band, which catches the mix-up.
|
|
1188
1190
|
|
|
1189
1191
|
#### `useElectricityTariff(): EnergyAppElectricityTariff`
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EnergyAppPermissionTypeEnum = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* All permissions an Energy App package can request.
|
|
6
|
+
*
|
|
7
|
+
* Source of truth for the permission catalogue — {@link EnergyAppPermissionType}
|
|
8
|
+
* is derived from it.
|
|
9
|
+
*/
|
|
4
10
|
var EnergyAppPermissionTypeEnum;
|
|
5
11
|
(function (EnergyAppPermissionTypeEnum) {
|
|
6
12
|
EnergyAppPermissionTypeEnum["RestrictedInternetAccess"] = "RestrictedInternetAccess";
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* All permissions an Energy App package can request.
|
|
3
|
+
*
|
|
4
|
+
* Source of truth for the permission catalogue — {@link EnergyAppPermissionType}
|
|
5
|
+
* is derived from it.
|
|
6
|
+
*/
|
|
2
7
|
export declare enum EnergyAppPermissionTypeEnum {
|
|
3
8
|
RestrictedInternetAccess = "RestrictedInternetAccess",
|
|
4
9
|
NetworkDeviceDiscovery = "NetworkDeviceDiscovery",
|
|
@@ -52,3 +57,8 @@ export declare enum EnergyAppPermissionTypeEnum {
|
|
|
52
57
|
EpexSpotPrices = "EpexSpotPrices",
|
|
53
58
|
FirmwareRegistry = "FirmwareRegistry"
|
|
54
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* String union of every permission name, derived from
|
|
62
|
+
* {@link EnergyAppPermissionTypeEnum} so both spellings stay interchangeable.
|
|
63
|
+
*/
|
|
64
|
+
export type EnergyAppPermissionType = `${EnergyAppPermissionTypeEnum}`;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Lookups over the energy-manager settings gate tree.
|
|
4
|
+
*
|
|
5
|
+
* {@link ENERGY_MANAGER_SETTING_DEPENDENCIES} is the data; these are the two
|
|
6
|
+
* questions worth asking of it. Both exist so a cockpit, an energy manager and
|
|
7
|
+
* the validator answer them the same way instead of each restating the tree.
|
|
8
|
+
*
|
|
9
|
+
* The tree is not flat. `BatteryEvDischargeFixedWh` is gated on
|
|
10
|
+
* `BatteryEvDischargeMode`, which is itself gated on `BatteryControl` — so
|
|
11
|
+
* "which setting does this depend on" and "may this setting take effect right
|
|
12
|
+
* now" are genuinely different questions, and the second one has to walk.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getEnergyManagerSettingDependency = getEnergyManagerSettingDependency;
|
|
16
|
+
exports.isEnergyManagerSettingActive = isEnergyManagerSettingActive;
|
|
17
|
+
const enyo_energy_manager_settings_js_1 = require("../../types/enyo-energy-manager-settings.cjs");
|
|
18
|
+
/**
|
|
19
|
+
* The setting a given setting depends on, and the value that gate must hold.
|
|
20
|
+
*
|
|
21
|
+
* Returns `null` for an ungated setting — `BatteryControl`, `HeatpumpControl`,
|
|
22
|
+
* `HeatingRodControl` and `ChargerControl` are the roots of the tree and depend
|
|
23
|
+
* on nothing.
|
|
24
|
+
*
|
|
25
|
+
* The gate's required *value* comes back with it, because the gate alone is not
|
|
26
|
+
* actionable: knowing `PriceLimitCtPerKwh` depends on `DefaultChargeMode` does
|
|
27
|
+
* not tell you it needs that mode to be `price-limit` specifically.
|
|
28
|
+
*
|
|
29
|
+
* Only the **direct** gate is returned, one level up. Use
|
|
30
|
+
* {@link isEnergyManagerSettingActive} to resolve a whole chain.
|
|
31
|
+
*
|
|
32
|
+
* @param setting - The setting to look up.
|
|
33
|
+
* @returns Its {@link EnergyManagerSettingDependency}, or `null` when ungated.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* getEnergyManagerSettingDependency(EnergyManagerSettingEnum.HeatingRodMode);
|
|
38
|
+
* // → {requires: EnergyManagerSettingEnum.HeatingRodControl, equals: true}
|
|
39
|
+
*
|
|
40
|
+
* getEnergyManagerSettingDependency(EnergyManagerSettingEnum.BatteryEvDischargeFixedWh);
|
|
41
|
+
* // → {requires: EnergyManagerSettingEnum.BatteryEvDischargeMode, equals: 'fixed-wh'}
|
|
42
|
+
*
|
|
43
|
+
* getEnergyManagerSettingDependency(EnergyManagerSettingEnum.BatteryControl);
|
|
44
|
+
* // → null
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function getEnergyManagerSettingDependency(setting) {
|
|
48
|
+
return enyo_energy_manager_settings_js_1.ENERGY_MANAGER_SETTING_DEPENDENCIES[setting] ?? null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Whether a setting can take effect given the values currently stored — the
|
|
52
|
+
* question a cockpit asks before rendering a control, and an energy manager asks
|
|
53
|
+
* before acting on one.
|
|
54
|
+
*
|
|
55
|
+
* Walks the whole chain, not just the direct gate: a fixed-Wh budget is live
|
|
56
|
+
* only when the mode is `fixed-wh` **and** battery control is on. Checking one
|
|
57
|
+
* level would report a budget as active under a mode whose own gate is closed.
|
|
58
|
+
*
|
|
59
|
+
* An ungated setting is always active. A gate that is unset (`undefined`) counts
|
|
60
|
+
* as not holding — consistent with the rest of this model, where absent is
|
|
61
|
+
* neither `true` nor `false` but "no choice was made".
|
|
62
|
+
*
|
|
63
|
+
* Says nothing about whether the setting is *supported*; check
|
|
64
|
+
* {@link EnergyManagerSettingsState.supported} for that. A setting can be
|
|
65
|
+
* perfectly active and still not implemented by the installed energy manager.
|
|
66
|
+
*
|
|
67
|
+
* @param setting - The setting to test.
|
|
68
|
+
* @param values - The currently stored values.
|
|
69
|
+
* @returns True when every gate above this setting holds.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const values = {
|
|
74
|
+
* batteryControl: true,
|
|
75
|
+
* batteryEvDischargeMode: EnergyManagerBatteryEvDischargeModeEnum.SocLimit,
|
|
76
|
+
* };
|
|
77
|
+
*
|
|
78
|
+
* isEnergyManagerSettingActive(EnergyManagerSettingEnum.BatteryEvDischargeSocLimitPercent, values);
|
|
79
|
+
* // → true
|
|
80
|
+
* isEnergyManagerSettingActive(EnergyManagerSettingEnum.BatteryEvDischargeFixedWh, values);
|
|
81
|
+
* // → false — the mode is soc-limit, so a Wh budget could never be spent
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
function isEnergyManagerSettingActive(setting, values) {
|
|
85
|
+
// The tree is small and authored by hand, but a cycle would hang the walk —
|
|
86
|
+
// bound it by the number of settings rather than trusting the data.
|
|
87
|
+
const seen = new Set();
|
|
88
|
+
let current = setting;
|
|
89
|
+
while (current) {
|
|
90
|
+
if (seen.has(current))
|
|
91
|
+
return false;
|
|
92
|
+
seen.add(current);
|
|
93
|
+
const dependency = getEnergyManagerSettingDependency(current);
|
|
94
|
+
if (!dependency)
|
|
95
|
+
return true;
|
|
96
|
+
const [key] = enyo_energy_manager_settings_js_1.ENERGY_MANAGER_SETTING_VALUE_KEYS[dependency.requires];
|
|
97
|
+
if (!key || values[key] !== dependency.equals)
|
|
98
|
+
return false;
|
|
99
|
+
current = dependency.requires;
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lookups over the energy-manager settings gate tree.
|
|
3
|
+
*
|
|
4
|
+
* {@link ENERGY_MANAGER_SETTING_DEPENDENCIES} is the data; these are the two
|
|
5
|
+
* questions worth asking of it. Both exist so a cockpit, an energy manager and
|
|
6
|
+
* the validator answer them the same way instead of each restating the tree.
|
|
7
|
+
*
|
|
8
|
+
* The tree is not flat. `BatteryEvDischargeFixedWh` is gated on
|
|
9
|
+
* `BatteryEvDischargeMode`, which is itself gated on `BatteryControl` — so
|
|
10
|
+
* "which setting does this depend on" and "may this setting take effect right
|
|
11
|
+
* now" are genuinely different questions, and the second one has to walk.
|
|
12
|
+
*/
|
|
13
|
+
import type { EnergyManagerSettingDependency, EnergyManagerSettingEnum, EnergyManagerSettingValues } from '../../types/enyo-energy-manager-settings.cjs';
|
|
14
|
+
/**
|
|
15
|
+
* The setting a given setting depends on, and the value that gate must hold.
|
|
16
|
+
*
|
|
17
|
+
* Returns `null` for an ungated setting — `BatteryControl`, `HeatpumpControl`,
|
|
18
|
+
* `HeatingRodControl` and `ChargerControl` are the roots of the tree and depend
|
|
19
|
+
* on nothing.
|
|
20
|
+
*
|
|
21
|
+
* The gate's required *value* comes back with it, because the gate alone is not
|
|
22
|
+
* actionable: knowing `PriceLimitCtPerKwh` depends on `DefaultChargeMode` does
|
|
23
|
+
* not tell you it needs that mode to be `price-limit` specifically.
|
|
24
|
+
*
|
|
25
|
+
* Only the **direct** gate is returned, one level up. Use
|
|
26
|
+
* {@link isEnergyManagerSettingActive} to resolve a whole chain.
|
|
27
|
+
*
|
|
28
|
+
* @param setting - The setting to look up.
|
|
29
|
+
* @returns Its {@link EnergyManagerSettingDependency}, or `null` when ungated.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* getEnergyManagerSettingDependency(EnergyManagerSettingEnum.HeatingRodMode);
|
|
34
|
+
* // → {requires: EnergyManagerSettingEnum.HeatingRodControl, equals: true}
|
|
35
|
+
*
|
|
36
|
+
* getEnergyManagerSettingDependency(EnergyManagerSettingEnum.BatteryEvDischargeFixedWh);
|
|
37
|
+
* // → {requires: EnergyManagerSettingEnum.BatteryEvDischargeMode, equals: 'fixed-wh'}
|
|
38
|
+
*
|
|
39
|
+
* getEnergyManagerSettingDependency(EnergyManagerSettingEnum.BatteryControl);
|
|
40
|
+
* // → null
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function getEnergyManagerSettingDependency(setting: EnergyManagerSettingEnum): EnergyManagerSettingDependency | null;
|
|
44
|
+
/**
|
|
45
|
+
* Whether a setting can take effect given the values currently stored — the
|
|
46
|
+
* question a cockpit asks before rendering a control, and an energy manager asks
|
|
47
|
+
* before acting on one.
|
|
48
|
+
*
|
|
49
|
+
* Walks the whole chain, not just the direct gate: a fixed-Wh budget is live
|
|
50
|
+
* only when the mode is `fixed-wh` **and** battery control is on. Checking one
|
|
51
|
+
* level would report a budget as active under a mode whose own gate is closed.
|
|
52
|
+
*
|
|
53
|
+
* An ungated setting is always active. A gate that is unset (`undefined`) counts
|
|
54
|
+
* as not holding — consistent with the rest of this model, where absent is
|
|
55
|
+
* neither `true` nor `false` but "no choice was made".
|
|
56
|
+
*
|
|
57
|
+
* Says nothing about whether the setting is *supported*; check
|
|
58
|
+
* {@link EnergyManagerSettingsState.supported} for that. A setting can be
|
|
59
|
+
* perfectly active and still not implemented by the installed energy manager.
|
|
60
|
+
*
|
|
61
|
+
* @param setting - The setting to test.
|
|
62
|
+
* @param values - The currently stored values.
|
|
63
|
+
* @returns True when every gate above this setting holds.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const values = {
|
|
68
|
+
* batteryControl: true,
|
|
69
|
+
* batteryEvDischargeMode: EnergyManagerBatteryEvDischargeModeEnum.SocLimit,
|
|
70
|
+
* };
|
|
71
|
+
*
|
|
72
|
+
* isEnergyManagerSettingActive(EnergyManagerSettingEnum.BatteryEvDischargeSocLimitPercent, values);
|
|
73
|
+
* // → true
|
|
74
|
+
* isEnergyManagerSettingActive(EnergyManagerSettingEnum.BatteryEvDischargeFixedWh, values);
|
|
75
|
+
* // → false — the mode is soc-limit, so a Wh budget could never be spent
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function isEnergyManagerSettingActive(setting: EnergyManagerSettingEnum, values: EnergyManagerSettingValues): boolean;
|
package/dist/cjs/implementations/energy-manager-settings/energy-manager-settings-validators.cjs
CHANGED
|
@@ -59,15 +59,16 @@ const TIME_RE = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
|
59
59
|
const PRICE_LIMIT_MIN_CT = -100;
|
|
60
60
|
const PRICE_LIMIT_MAX_CT = 200;
|
|
61
61
|
/**
|
|
62
|
-
* Below this, a {@link EnergyManagerSettingValues.
|
|
62
|
+
* Below this, a {@link EnergyManagerSettingValues.batteryEvDischargeFixedWh}
|
|
63
63
|
* budget is almost certainly kWh entered into a Wh field.
|
|
64
64
|
*
|
|
65
|
-
* `10` would be ten watt-hours — a rounding error against any house battery,
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* disabled.
|
|
65
|
+
* `10` would be ten watt-hours — a rounding error against any house battery,
|
|
66
|
+
* where `10` kWh was plainly meant. `0` is handled separately: it is legal, and
|
|
67
|
+
* warned about for duplicating mode `block-discharge` rather than for being a unit slip.
|
|
69
68
|
*/
|
|
70
69
|
const DISCHARGE_BUDGET_MIN_PLAUSIBLE_WH = 100;
|
|
70
|
+
/** Every {@link EnergyManagerBatteryEvDischargeModeEnum} value. */
|
|
71
|
+
const EV_DISCHARGE_MODES = new Set(Object.values(enyo_energy_manager_settings_js_1.EnergyManagerBatteryEvDischargeModeEnum));
|
|
71
72
|
/** Value enums checked per field, for the enum-valued settings. */
|
|
72
73
|
const BATTERY_CHARGING_MODES = new Set(Object.values(enyo_energy_manager_settings_js_1.EnergyManagerBatteryChargingModeEnum));
|
|
73
74
|
const HEATING_ROD_MODES = new Set(Object.values(enyo_energy_manager_settings_js_1.EnergyManagerHeatingRodModeEnum));
|
|
@@ -115,12 +116,15 @@ function gateValue(values, setting) {
|
|
|
115
116
|
* zone the runtime resolves (**error**).
|
|
116
117
|
* - `priceLimitCtPerKwh` is a finite number (**error**), and lies in a plausible
|
|
117
118
|
* ct/kWh band (**warning** — catches a EUR/kWh value in a ct/kWh field).
|
|
118
|
-
* - `
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
119
|
+
* - `batteryEvDischargeMode` holds an enum member (**error**).
|
|
120
|
+
* - `batteryEvDischargeFixedWh` is a finite non-negative number (**error**), and
|
|
121
|
+
* is neither `0` nor a negligible positive figure (**warning** — the first
|
|
122
|
+
* duplicates mode `block-discharge`, the second catches a kWh value in a Wh field).
|
|
123
|
+
* - `batteryEvDischargeSocLimitPercent` is a finite number in 0…100 (**error**),
|
|
124
|
+
* and not `100` (**warning** — a floor nothing can discharge past).
|
|
125
|
+
* - A parameter belonging to a mode other than the selected one is flagged by
|
|
126
|
+
* the gate check below, since {@link ENERGY_MANAGER_SETTING_DEPENDENCIES}
|
|
127
|
+
* gates each on its own mode.
|
|
124
128
|
* - A value stored for an unsupported setting (**warning** — the energy manager
|
|
125
129
|
* will ignore it).
|
|
126
130
|
* - A value stored while its gate does not hold (**warning** — it can never take
|
|
@@ -162,8 +166,7 @@ function validateEnergyManagerSettingsState(state) {
|
|
|
162
166
|
}
|
|
163
167
|
const values = state.values ?? {};
|
|
164
168
|
// ── value formats ──────────────────────────────────────────────────────
|
|
165
|
-
for (const key of ['batteryControl', 'batteryChargeFromGrid',
|
|
166
|
-
'blockBatteryDischargeWhileEvCharging', 'heatpumpControl',
|
|
169
|
+
for (const key of ['batteryControl', 'batteryChargeFromGrid', 'heatpumpControl',
|
|
167
170
|
'heatingRodControl', 'chargerControl']) {
|
|
168
171
|
if (values[key] !== undefined && typeof values[key] !== 'boolean') {
|
|
169
172
|
errors.push(`\`${key}\` must be a boolean when set.`);
|
|
@@ -191,27 +194,44 @@ function validateEnergyManagerSettingsState(state) {
|
|
|
191
194
|
'cents per kWh, not EUR per kWh.');
|
|
192
195
|
}
|
|
193
196
|
}
|
|
194
|
-
if (values.
|
|
195
|
-
&& values.
|
|
196
|
-
|
|
197
|
+
if (values.batteryEvDischargeMode !== undefined
|
|
198
|
+
&& !EV_DISCHARGE_MODES.has(values.batteryEvDischargeMode)) {
|
|
199
|
+
errors.push(`\`batteryEvDischargeMode\` "${values.batteryEvDischargeMode}" is not an ` +
|
|
200
|
+
'EnergyManagerBatteryEvDischargeModeEnum member.');
|
|
201
|
+
}
|
|
202
|
+
if (values.batteryEvDischargeFixedWh !== undefined) {
|
|
203
|
+
const budget = values.batteryEvDischargeFixedWh;
|
|
197
204
|
if (typeof budget !== 'number' || !Number.isFinite(budget)) {
|
|
198
|
-
errors.push('`
|
|
205
|
+
errors.push('`batteryEvDischargeFixedWh` must be a finite number when set.');
|
|
199
206
|
}
|
|
200
207
|
else if (budget < 0) {
|
|
201
|
-
errors.push(`\`
|
|
202
|
-
|
|
208
|
+
errors.push(`\`batteryEvDischargeFixedWh\` is ${budget}; a budget cannot be negative. ` +
|
|
209
|
+
`Use mode "${enyo_energy_manager_settings_js_1.EnergyManagerBatteryEvDischargeModeEnum.BlockDischarge}" to forbid the transfer.`);
|
|
210
|
+
}
|
|
211
|
+
else if (budget === 0) {
|
|
212
|
+
warnings.push('`batteryEvDischargeFixedWh` is 0, which says the same as mode ' +
|
|
213
|
+
`"${enyo_energy_manager_settings_js_1.EnergyManagerBatteryEvDischargeModeEnum.BlockDischarge}" — prefer the mode, which says it ` +
|
|
214
|
+
'where a reader will look.');
|
|
203
215
|
}
|
|
204
|
-
else if (budget
|
|
205
|
-
warnings.push(`\`
|
|
206
|
-
'
|
|
216
|
+
else if (budget < DISCHARGE_BUDGET_MIN_PLAUSIBLE_WH) {
|
|
217
|
+
warnings.push(`\`batteryEvDischargeFixedWh\` is ${budget} Wh, which is negligible against any ` +
|
|
218
|
+
'house battery — this field is in watt-hours, not kilowatt-hours.');
|
|
207
219
|
}
|
|
208
220
|
}
|
|
209
|
-
if (values.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
221
|
+
if (values.batteryEvDischargeSocLimitPercent !== undefined) {
|
|
222
|
+
const soc = values.batteryEvDischargeSocLimitPercent;
|
|
223
|
+
if (typeof soc !== 'number' || !Number.isFinite(soc)) {
|
|
224
|
+
errors.push('`batteryEvDischargeSocLimitPercent` must be a finite number when set.');
|
|
225
|
+
}
|
|
226
|
+
else if (soc < 0 || soc > 100) {
|
|
227
|
+
errors.push(`\`batteryEvDischargeSocLimitPercent\` is ${soc}; it is a percentage and must lie ` +
|
|
228
|
+
'between 0 and 100.');
|
|
229
|
+
}
|
|
230
|
+
else if (soc === 100) {
|
|
231
|
+
warnings.push('`batteryEvDischargeSocLimitPercent` is 100, a floor the battery is already at, so ' +
|
|
232
|
+
`nothing can ever be discharged — mode "${enyo_energy_manager_settings_js_1.EnergyManagerBatteryEvDischargeModeEnum.BlockDischarge}" ` +
|
|
233
|
+
'states that intent directly.');
|
|
234
|
+
}
|
|
215
235
|
}
|
|
216
236
|
if (values.costOptimizedTargetTime !== undefined) {
|
|
217
237
|
if (typeof values.costOptimizedTargetTime !== 'string'
|
package/dist/cjs/implementations/energy-manager-settings/energy-manager-settings-validators.d.cts
CHANGED
|
@@ -56,12 +56,15 @@ export interface EnergyManagerSettingsValidationResult {
|
|
|
56
56
|
* zone the runtime resolves (**error**).
|
|
57
57
|
* - `priceLimitCtPerKwh` is a finite number (**error**), and lies in a plausible
|
|
58
58
|
* ct/kWh band (**warning** — catches a EUR/kWh value in a ct/kWh field).
|
|
59
|
-
* - `
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
59
|
+
* - `batteryEvDischargeMode` holds an enum member (**error**).
|
|
60
|
+
* - `batteryEvDischargeFixedWh` is a finite non-negative number (**error**), and
|
|
61
|
+
* is neither `0` nor a negligible positive figure (**warning** — the first
|
|
62
|
+
* duplicates mode `block-discharge`, the second catches a kWh value in a Wh field).
|
|
63
|
+
* - `batteryEvDischargeSocLimitPercent` is a finite number in 0…100 (**error**),
|
|
64
|
+
* and not `100` (**warning** — a floor nothing can discharge past).
|
|
65
|
+
* - A parameter belonging to a mode other than the selected one is flagged by
|
|
66
|
+
* the gate check below, since {@link ENERGY_MANAGER_SETTING_DEPENDENCIES}
|
|
67
|
+
* gates each on its own mode.
|
|
65
68
|
* - A value stored for an unsupported setting (**warning** — the energy manager
|
|
66
69
|
* will ignore it).
|
|
67
70
|
* - A value stored while its gate does not hold (**warning** — it can never take
|
|
@@ -147,6 +147,7 @@ function validateOnboardingGuideV2(guide, context) {
|
|
|
147
147
|
`"${enyo_onboarding_v2_js_1.EnyoOnboardingV2PauseReason.EnyoTodo}" when enyo takes the setup over.`);
|
|
148
148
|
}
|
|
149
149
|
validateNetworkScanFlag(guide, warnings);
|
|
150
|
+
validateApplianceBinding(guide, errors, warnings);
|
|
150
151
|
return { ok: errors.length === 0, errors, warnings };
|
|
151
152
|
}
|
|
152
153
|
/**
|
|
@@ -645,6 +646,41 @@ function validateAdditionalSetupBlocks(step, at, errors, warnings) {
|
|
|
645
646
|
}
|
|
646
647
|
}
|
|
647
648
|
}
|
|
649
|
+
/**
|
|
650
|
+
* Checks {@link EnyoOnboardingV2Guide.applianceId} against the guide's
|
|
651
|
+
* {@link EnyoOnboardingV2Guide.startVariant}.
|
|
652
|
+
*
|
|
653
|
+
* The binding is required on {@link EnyoOnboardingV2StartVariant.Maintenance}
|
|
654
|
+
* and meaningless everywhere else. A maintenance run services an appliance that
|
|
655
|
+
* already exists, so a guide that does not name one cannot be bound to anything
|
|
656
|
+
* — that is a blocking error, not advice. The reverse is only a warning: an
|
|
657
|
+
* installation guide carrying an appliance id is harmless, the host ignores it,
|
|
658
|
+
* but it is a sign the wrong variant was chosen.
|
|
659
|
+
*
|
|
660
|
+
* @param guide - The guide being validated.
|
|
661
|
+
* @param errors - Collector for blocking problems.
|
|
662
|
+
* @param warnings - Collector for advisory problems.
|
|
663
|
+
*/
|
|
664
|
+
function validateApplianceBinding(guide, errors, warnings) {
|
|
665
|
+
const isMaintenance = guide.startVariant === enyo_onboarding_v2_js_1.EnyoOnboardingV2StartVariant.Maintenance;
|
|
666
|
+
const applianceId = typeof guide.applianceId === 'string' ? guide.applianceId.trim() : undefined;
|
|
667
|
+
if (isMaintenance) {
|
|
668
|
+
if (!applianceId) {
|
|
669
|
+
errors.push('`applianceId` is required on a `' +
|
|
670
|
+
`${enyo_onboarding_v2_js_1.EnyoOnboardingV2StartVariant.Maintenance}` +
|
|
671
|
+
'` guide — a maintenance run services an appliance that already exists, so the ' +
|
|
672
|
+
'guide must name it.');
|
|
673
|
+
}
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
if (applianceId) {
|
|
677
|
+
warnings.push('`applianceId` is set on a `' +
|
|
678
|
+
`${guide.startVariant}` +
|
|
679
|
+
'` guide and is ignored — only a `' +
|
|
680
|
+
`${enyo_onboarding_v2_js_1.EnyoOnboardingV2StartVariant.Maintenance}` +
|
|
681
|
+
'` guide binds an existing appliance.');
|
|
682
|
+
}
|
|
683
|
+
}
|
|
648
684
|
/**
|
|
649
685
|
* Checks {@link EnyoOnboardingV2Guide.requiresNetworkScan} against what the guide
|
|
650
686
|
* actually does.
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -42,6 +42,7 @@ __exportStar(require("./types/enyo-energy-manager.cjs"), exports);
|
|
|
42
42
|
__exportStar(require("./packages/energy-app-energy-manager.cjs"), exports);
|
|
43
43
|
__exportStar(require("./types/enyo-energy-manager-settings.cjs"), exports);
|
|
44
44
|
__exportStar(require("./implementations/energy-manager-settings/energy-manager-settings-validators.cjs"), exports);
|
|
45
|
+
__exportStar(require("./implementations/energy-manager-settings/energy-manager-settings-utils.cjs"), exports);
|
|
45
46
|
__exportStar(require("./types/enyo-electricity-tariff.cjs"), exports);
|
|
46
47
|
__exportStar(require("./packages/energy-app-electricity-tariff.cjs"), exports);
|
|
47
48
|
__exportStar(require("./types/enyo-pv-forecast.cjs"), exports);
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -26,6 +26,7 @@ export * from './types/enyo-energy-manager.cjs';
|
|
|
26
26
|
export * from './packages/energy-app-energy-manager.cjs';
|
|
27
27
|
export * from './types/enyo-energy-manager-settings.cjs';
|
|
28
28
|
export * from './implementations/energy-manager-settings/energy-manager-settings-validators.cjs';
|
|
29
|
+
export * from './implementations/energy-manager-settings/energy-manager-settings-utils.cjs';
|
|
29
30
|
export * from './types/enyo-electricity-tariff.cjs';
|
|
30
31
|
export * from './packages/energy-app-electricity-tariff.cjs';
|
|
31
32
|
export * from './types/enyo-pv-forecast.cjs';
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* (`../implementations/energy-manager-settings/energy-manager-settings-validators.ts`).
|
|
28
28
|
*/
|
|
29
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
-
exports.ENERGY_MANAGER_SETTING_VALUE_KEYS = exports.ENERGY_MANAGER_SETTING_DEPENDENCIES = exports.EnergyManagerHeatingRodModeEnum = exports.EnergyManagerBatteryChargingModeEnum = exports.EnergyManagerSettingEnum = void 0;
|
|
30
|
+
exports.ENERGY_MANAGER_SETTING_VALUE_KEYS = exports.ENERGY_MANAGER_SETTING_DEPENDENCIES = exports.EnergyManagerHeatingRodModeEnum = exports.EnergyManagerBatteryEvDischargeModeEnum = exports.EnergyManagerBatteryChargingModeEnum = exports.EnergyManagerSettingEnum = void 0;
|
|
31
31
|
/**
|
|
32
32
|
* The general settings an energy manager can honour.
|
|
33
33
|
*
|
|
@@ -44,10 +44,12 @@ var EnergyManagerSettingEnum;
|
|
|
44
44
|
EnergyManagerSettingEnum["BatteryChargingMode"] = "battery-charging-mode";
|
|
45
45
|
/** Whether the battery may be charged from the grid, not only from PV surplus. */
|
|
46
46
|
EnergyManagerSettingEnum["BatteryChargeFromGrid"] = "battery-charge-from-grid";
|
|
47
|
-
/** How
|
|
48
|
-
EnergyManagerSettingEnum["
|
|
49
|
-
/**
|
|
50
|
-
EnergyManagerSettingEnum["
|
|
47
|
+
/** How the battery may feed a charging vehicle — see {@link EnergyManagerBatteryEvDischargeModeEnum}. */
|
|
48
|
+
EnergyManagerSettingEnum["BatteryEvDischargeMode"] = "battery-ev-discharge-mode";
|
|
49
|
+
/** The per-session budget, in Wh. Only under {@link EnergyManagerBatteryEvDischargeModeEnum.FixedWh}. */
|
|
50
|
+
EnergyManagerSettingEnum["BatteryEvDischargeFixedWh"] = "battery-ev-discharge-fixed-wh";
|
|
51
|
+
/** The SoC floor, in %. Only under {@link EnergyManagerBatteryEvDischargeModeEnum.SocLimit}. */
|
|
52
|
+
EnergyManagerSettingEnum["BatteryEvDischargeSocLimitPercent"] = "battery-ev-discharge-soc-limit-percent";
|
|
51
53
|
// ── Heat pump ──────────────────────────────────────────────────────────
|
|
52
54
|
/** Whether the energy manager may steer the heat pump. */
|
|
53
55
|
EnergyManagerSettingEnum["HeatpumpControl"] = "heatpump-control";
|
|
@@ -86,6 +88,64 @@ var EnergyManagerBatteryChargingModeEnum;
|
|
|
86
88
|
*/
|
|
87
89
|
EnergyManagerBatteryChargingModeEnum["Immediate"] = "immediate";
|
|
88
90
|
})(EnergyManagerBatteryChargingModeEnum || (exports.EnergyManagerBatteryChargingModeEnum = EnergyManagerBatteryChargingModeEnum = {}));
|
|
91
|
+
/**
|
|
92
|
+
* How the house battery may feed a vehicle that is charging.
|
|
93
|
+
*
|
|
94
|
+
* Replaces the earlier pair of a boolean block and a nullable Wh budget. That
|
|
95
|
+
* shape could express "off" two ways and had no room for the answers installers
|
|
96
|
+
* actually want — drain to a floor, or let enyo work it out — so the strategy is
|
|
97
|
+
* now named once here and its parameter lives in a separate setting.
|
|
98
|
+
*
|
|
99
|
+
* Read {@link None} and {@link Unmanaged} carefully: they are not synonyms, and
|
|
100
|
+
* confusing them is the difference between the energy manager holding the
|
|
101
|
+
* battery back and it simply not looking.
|
|
102
|
+
*/
|
|
103
|
+
var EnergyManagerBatteryEvDischargeModeEnum;
|
|
104
|
+
(function (EnergyManagerBatteryEvDischargeModeEnum) {
|
|
105
|
+
/**
|
|
106
|
+
* Allow a fixed budget per session, given by
|
|
107
|
+
* {@link EnergyManagerSettingValues.batteryEvDischargeFixedWh}.
|
|
108
|
+
*
|
|
109
|
+
* The plain answer to "how much of my house battery may go into the car" —
|
|
110
|
+
* an amount, spent and then stopped.
|
|
111
|
+
*/
|
|
112
|
+
EnergyManagerBatteryEvDischargeModeEnum["FixedWh"] = "fixed-wh";
|
|
113
|
+
/**
|
|
114
|
+
* Discharge into the vehicle until the battery reaches the floor given by
|
|
115
|
+
* {@link EnergyManagerSettingValues.batteryEvDischargeSocLimitPercent}.
|
|
116
|
+
*
|
|
117
|
+
* The same intent as {@link FixedWh} expressed in the unit owners actually
|
|
118
|
+
* reason in — "keep half the battery for the house" survives a change of
|
|
119
|
+
* battery, where a watt-hour figure does not.
|
|
120
|
+
*/
|
|
121
|
+
EnergyManagerBatteryEvDischargeModeEnum["SocLimit"] = "soc-limit";
|
|
122
|
+
/**
|
|
123
|
+
* Let enyo decide, session by session.
|
|
124
|
+
*
|
|
125
|
+
* The energy manager weighs price, forecast, house load and departure time
|
|
126
|
+
* instead of following a fixed rule. Nothing further to configure — the
|
|
127
|
+
* other two settings carry no meaning here.
|
|
128
|
+
*/
|
|
129
|
+
EnergyManagerBatteryEvDischargeModeEnum["Intelligent"] = "intelligent";
|
|
130
|
+
/**
|
|
131
|
+
* Never discharge the battery into a vehicle. The energy manager actively
|
|
132
|
+
* holds it back.
|
|
133
|
+
*
|
|
134
|
+
* This is an instruction, not an absence of one — contrast {@link Unmanaged},
|
|
135
|
+
* which is the absence. Named for what it does rather than for the amount it
|
|
136
|
+
* permits, so that the two cannot be read as the same answer.
|
|
137
|
+
*/
|
|
138
|
+
EnergyManagerBatteryEvDischargeModeEnum["BlockDischarge"] = "block-discharge";
|
|
139
|
+
/**
|
|
140
|
+
* The energy manager does not manage this flow at all.
|
|
141
|
+
*
|
|
142
|
+
* It neither permits nor prevents: whatever the hardware does on its own
|
|
143
|
+
* stands, and the battery may well end up feeding the car as a side effect.
|
|
144
|
+
* Choose this when something else owns the decision, never as a way to
|
|
145
|
+
* express "no discharge" — that is {@link BlockDischarge}.
|
|
146
|
+
*/
|
|
147
|
+
EnergyManagerBatteryEvDischargeModeEnum["Unmanaged"] = "unmanaged";
|
|
148
|
+
})(EnergyManagerBatteryEvDischargeModeEnum || (exports.EnergyManagerBatteryEvDischargeModeEnum = EnergyManagerBatteryEvDischargeModeEnum = {}));
|
|
89
149
|
/**
|
|
90
150
|
* What the heating rod is allowed to do.
|
|
91
151
|
*
|
|
@@ -131,13 +191,17 @@ exports.ENERGY_MANAGER_SETTING_DEPENDENCIES = {
|
|
|
131
191
|
requires: EnergyManagerSettingEnum.BatteryControl,
|
|
132
192
|
equals: true,
|
|
133
193
|
},
|
|
134
|
-
[EnergyManagerSettingEnum.
|
|
194
|
+
[EnergyManagerSettingEnum.BatteryEvDischargeMode]: {
|
|
135
195
|
requires: EnergyManagerSettingEnum.BatteryControl,
|
|
136
196
|
equals: true,
|
|
137
197
|
},
|
|
138
|
-
[EnergyManagerSettingEnum.
|
|
139
|
-
requires: EnergyManagerSettingEnum.
|
|
140
|
-
equals:
|
|
198
|
+
[EnergyManagerSettingEnum.BatteryEvDischargeFixedWh]: {
|
|
199
|
+
requires: EnergyManagerSettingEnum.BatteryEvDischargeMode,
|
|
200
|
+
equals: EnergyManagerBatteryEvDischargeModeEnum.FixedWh,
|
|
201
|
+
},
|
|
202
|
+
[EnergyManagerSettingEnum.BatteryEvDischargeSocLimitPercent]: {
|
|
203
|
+
requires: EnergyManagerSettingEnum.BatteryEvDischargeMode,
|
|
204
|
+
equals: EnergyManagerBatteryEvDischargeModeEnum.SocLimit,
|
|
141
205
|
},
|
|
142
206
|
[EnergyManagerSettingEnum.HeatingRodMode]: {
|
|
143
207
|
requires: EnergyManagerSettingEnum.HeatingRodControl,
|
|
@@ -167,8 +231,9 @@ exports.ENERGY_MANAGER_SETTING_VALUE_KEYS = {
|
|
|
167
231
|
[EnergyManagerSettingEnum.BatteryControl]: ['batteryControl'],
|
|
168
232
|
[EnergyManagerSettingEnum.BatteryChargingMode]: ['batteryChargingMode'],
|
|
169
233
|
[EnergyManagerSettingEnum.BatteryChargeFromGrid]: ['batteryChargeFromGrid'],
|
|
170
|
-
[EnergyManagerSettingEnum.
|
|
171
|
-
[EnergyManagerSettingEnum.
|
|
234
|
+
[EnergyManagerSettingEnum.BatteryEvDischargeMode]: ['batteryEvDischargeMode'],
|
|
235
|
+
[EnergyManagerSettingEnum.BatteryEvDischargeFixedWh]: ['batteryEvDischargeFixedWh'],
|
|
236
|
+
[EnergyManagerSettingEnum.BatteryEvDischargeSocLimitPercent]: ['batteryEvDischargeSocLimitPercent'],
|
|
172
237
|
[EnergyManagerSettingEnum.HeatpumpControl]: ['heatpumpControl'],
|
|
173
238
|
[EnergyManagerSettingEnum.HeatingRodControl]: ['heatingRodControl'],
|
|
174
239
|
[EnergyManagerSettingEnum.HeatingRodMode]: ['heatingRodMode'],
|