@enyo-energy/energy-app-sdk 1.41.0 → 1.43.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 +158 -8
- package/dist/cjs/energy-app-package-definition.cjs +51 -1
- package/dist/cjs/energy-app-package-definition.d.cts +172 -0
- package/dist/cjs/implementations/appliances/appliance-manager.cjs +56 -0
- package/dist/cjs/implementations/appliances/appliance-manager.d.cts +34 -1
- package/dist/cjs/implementations/compatibility/compatibility-validators.cjs +253 -0
- package/dist/cjs/implementations/compatibility/compatibility-validators.d.cts +111 -0
- package/dist/cjs/implementations/heatpump/heatpump-control-validators.cjs +61 -0
- package/dist/cjs/implementations/heatpump/heatpump-control-validators.d.cts +38 -1
- package/dist/cjs/implementations/heatpump/heatpump-heating-curve-offset.cjs +119 -0
- package/dist/cjs/implementations/heatpump/heatpump-heating-curve-offset.d.cts +77 -0
- package/dist/cjs/implementations/heatpump/heatpump-metadata-validators.cjs +72 -0
- package/dist/cjs/implementations/heatpump/heatpump-metadata-validators.d.cts +3 -0
- package/dist/cjs/implementations/installer-mail/define-installer-mail.cjs +89 -0
- package/dist/cjs/implementations/installer-mail/define-installer-mail.d.cts +80 -0
- package/dist/cjs/implementations/installer-mail/installer-mail-validators.cjs +251 -0
- package/dist/cjs/implementations/installer-mail/installer-mail-validators.d.cts +88 -0
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/index.d.cts +4 -0
- package/dist/cjs/integrations/heatpump-integration-energy-app.cjs +89 -0
- package/dist/cjs/integrations/heatpump-integration-energy-app.d.cts +75 -1
- package/dist/cjs/types/enyo-data-bus-value.cjs +2 -0
- package/dist/cjs/types/enyo-data-bus-value.d.cts +60 -0
- package/dist/cjs/types/enyo-heatpump-appliance.cjs +27 -1
- package/dist/cjs/types/enyo-heatpump-appliance.d.cts +151 -1
- package/dist/cjs/types/enyo-vehicle.d.cts +16 -0
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/energy-app-package-definition.d.ts +172 -0
- package/dist/energy-app-package-definition.js +50 -0
- package/dist/implementations/appliances/appliance-manager.d.ts +34 -1
- package/dist/implementations/appliances/appliance-manager.js +56 -0
- package/dist/implementations/compatibility/compatibility-validators.d.ts +111 -0
- package/dist/implementations/compatibility/compatibility-validators.js +246 -0
- package/dist/implementations/heatpump/heatpump-control-validators.d.ts +38 -1
- package/dist/implementations/heatpump/heatpump-control-validators.js +60 -0
- package/dist/implementations/heatpump/heatpump-heating-curve-offset.d.ts +77 -0
- package/dist/implementations/heatpump/heatpump-heating-curve-offset.js +113 -0
- package/dist/implementations/heatpump/heatpump-metadata-validators.d.ts +3 -0
- package/dist/implementations/heatpump/heatpump-metadata-validators.js +72 -0
- package/dist/implementations/installer-mail/define-installer-mail.d.ts +80 -0
- package/dist/implementations/installer-mail/define-installer-mail.js +83 -0
- package/dist/implementations/installer-mail/installer-mail-validators.d.ts +88 -0
- package/dist/implementations/installer-mail/installer-mail-validators.js +244 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/integrations/heatpump-integration-energy-app.d.ts +75 -1
- package/dist/integrations/heatpump-integration-energy-app.js +90 -1
- package/dist/types/enyo-data-bus-value.d.ts +60 -0
- package/dist/types/enyo-data-bus-value.js +2 -0
- package/dist/types/enyo-heatpump-appliance.d.ts +151 -1
- package/dist/types/enyo-heatpump-appliance.js +26 -0
- package/dist/types/enyo-vehicle.d.ts +16 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,8 @@ The official TypeScript SDK for building Energy Apps on the enyo platform. Creat
|
|
|
34
34
|
- [Startup pattern](#startup-pattern)
|
|
35
35
|
- [Package Files](#package-files)
|
|
36
36
|
- [Printable Manual Setup Guide](#printable-manual-setup-guide)
|
|
37
|
+
- [Installer Mail](#installer-mail)
|
|
38
|
+
- [Compatibility Declaration](#compatibility-declaration)
|
|
37
39
|
- [Firmware Update Registry](#firmware-update-registry)
|
|
38
40
|
- [Declaring firmware](#declaring-firmware)
|
|
39
41
|
- [Firmware modes](#firmware-modes)
|
|
@@ -994,23 +996,36 @@ Pairing needs the `VehicleIntegration` permission; reading vehicles needs only
|
|
|
994
996
|
|
|
995
997
|
##### Declaring supported brands
|
|
996
998
|
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
999
|
+
Declare every brand the package serves. Where you know the model line-up, list the models
|
|
1000
|
+
with their **model years** — a model name alone is ambiguous, because the same name is sold
|
|
1001
|
+
across generations that talk to different APIs. Give each generation its own entry; the same
|
|
1002
|
+
`modelName` may appear more than once as long as the `modelYears` ranges do not overlap.
|
|
1003
|
+
Leave out `to` while a model is still built.
|
|
1000
1004
|
|
|
1001
1005
|
```typescript
|
|
1002
1006
|
categories: [EnergyAppPackageCategory.Vehicle],
|
|
1003
1007
|
compatibility: [{
|
|
1008
|
+
vendorName: 'Volkswagen',
|
|
1009
|
+
defaultEnergyApp: true,
|
|
1010
|
+
models: [
|
|
1011
|
+
{modelName: 'ID.3', modelYears: {from: 2020, to: 2023}, features: [EnergyAppModelFeatureEnum.VehicleSocReadout]},
|
|
1012
|
+
{modelName: 'ID.3', modelYears: {from: 2024}, features: [EnergyAppModelFeatureEnum.VehicleSocReadout]},
|
|
1013
|
+
],
|
|
1014
|
+
}, {
|
|
1015
|
+
// Brand-wide support: an empty `models` array reads as "every car of this brand".
|
|
1004
1016
|
vendorName: 'Tesla',
|
|
1005
|
-
|
|
1017
|
+
defaultEnergyApp: true,
|
|
1006
1018
|
models: [],
|
|
1007
1019
|
}],
|
|
1008
1020
|
```
|
|
1009
1021
|
|
|
1010
|
-
|
|
1011
|
-
`
|
|
1022
|
+
When the user picked a model and year in the enyo app, the pair handler receives them as
|
|
1023
|
+
`context.modelName` and `context.modelYear` next to `context.vendorName`.
|
|
1024
|
+
|
|
1025
|
+
Set `features` honestly — a brand whose API only reports SoC
|
|
1012
1026
|
(`VehicleSocReadout`) should not look like one that can also start a charge
|
|
1013
|
-
(`VehicleChargeStartStop`). See `EnergyAppModelFeatureEnum`'s vehicle group
|
|
1027
|
+
(`VehicleChargeStartStop`). See `EnergyAppModelFeatureEnum`'s vehicle group, and validate
|
|
1028
|
+
the list with `validatePackageCompatibility()` (see [Compatibility Declaration](#compatibility-declaration)).
|
|
1014
1029
|
|
|
1015
1030
|
##### Charge modes
|
|
1016
1031
|
|
|
@@ -3297,6 +3312,99 @@ const {ok, errors, warnings} = validatePackageOnboardingGuide(packageDef);
|
|
|
3297
3312
|
The complete authoring guide, with the reason behind each rule and a full example, is the
|
|
3298
3313
|
JSDoc of `EnergyAppPackageDefinition.onboardingGuide`.
|
|
3299
3314
|
|
|
3315
|
+
## Installer Mail
|
|
3316
|
+
|
|
3317
|
+
A package can declare the mail a customer sends to their installer from the enyo customer
|
|
3318
|
+
portal, telling the installer what to do. The enyo CLI reads it during `enyo release`. In the
|
|
3319
|
+
portal the customer enters the installer's address and details only they know, such as the
|
|
3320
|
+
device's serial number; enyo fills in the placeholders, renders the Markdown body as an HTML
|
|
3321
|
+
mail and sends it — with the PDF of the [Printable Manual Setup Guide](#printable-manual-setup-guide)
|
|
3322
|
+
attached when the package declares one (`attachOnboardingGuide: false` turns that off).
|
|
3323
|
+
|
|
3324
|
+
- `subject` is plain text on one line, `body` is Markdown (raw HTML is not rendered); both
|
|
3325
|
+
need `de` and `en`.
|
|
3326
|
+
- Placeholders are written as `{{name}}`; `installerMailPlaceholder()` writes them for you.
|
|
3327
|
+
The list is closed (`EnyoInstallerMailPlaceholder`): `customerName`, `customerNumber`,
|
|
3328
|
+
`customerEmail`, `customerPhone`, `installationStreet`, `installationZip`,
|
|
3329
|
+
`installationCity`, `serialNumber` (entered by the customer), `vendorName`, `modelName`,
|
|
3330
|
+
`energyAppName`, `onboardingGuideUrl`.
|
|
3331
|
+
- Any value can be missing when the mail is sent and is then left empty — put placeholders in
|
|
3332
|
+
lists of details rather than in the middle of a sentence.
|
|
3333
|
+
- `attachments` names further files declared in `files`.
|
|
3334
|
+
|
|
3335
|
+
```typescript
|
|
3336
|
+
import {
|
|
3337
|
+
defineEnergyAppPackage,
|
|
3338
|
+
defineInstallerMail,
|
|
3339
|
+
EnyoInstallerMailPlaceholder as P,
|
|
3340
|
+
installerMailPlaceholder as p,
|
|
3341
|
+
renderInstallerMail,
|
|
3342
|
+
validatePackageInstallerMail
|
|
3343
|
+
} from '@enyo-energy/energy-app-sdk';
|
|
3344
|
+
|
|
3345
|
+
const packageDef = defineEnergyAppPackage({
|
|
3346
|
+
// ...
|
|
3347
|
+
onboardingGuide: manualSetupGuide,
|
|
3348
|
+
onboardingFlowInstallerMail: defineInstallerMail({
|
|
3349
|
+
subject: [
|
|
3350
|
+
{language: 'de', value: `Einrichtung ${p(P.EnergyAppName)} bei ${p(P.CustomerName)}`},
|
|
3351
|
+
{language: 'en', value: `${p(P.EnergyAppName)} setup for ${p(P.CustomerName)}`}
|
|
3352
|
+
],
|
|
3353
|
+
body: [
|
|
3354
|
+
{language: 'de', value: [
|
|
3355
|
+
'Bitte aktiviere Modbus TCP am Wechselrichter, damit enyo ihn steuern kann.',
|
|
3356
|
+
'',
|
|
3357
|
+
`- **Kunde:** ${p(P.CustomerName)} (${p(P.CustomerNumber)})`,
|
|
3358
|
+
`- **Adresse:** ${p(P.InstallationStreet)}, ${p(P.InstallationZip)} ${p(P.InstallationCity)}`,
|
|
3359
|
+
`- **Gerät:** ${p(P.VendorName)} ${p(P.ModelName)}, Seriennummer ${p(P.SerialNumber)}`,
|
|
3360
|
+
'',
|
|
3361
|
+
`Die Schritt-für-Schritt-Anleitung findest du [hier](${p(P.OnboardingGuideUrl)}).`
|
|
3362
|
+
].join('\n')},
|
|
3363
|
+
{language: 'en', value: '...'}
|
|
3364
|
+
]
|
|
3365
|
+
})
|
|
3366
|
+
});
|
|
3367
|
+
|
|
3368
|
+
const {ok, errors, warnings} = validatePackageInstallerMail(packageDef);
|
|
3369
|
+
|
|
3370
|
+
// Preview what the installer receives:
|
|
3371
|
+
const preview = renderInstallerMail(packageDef.onboardingFlowInstallerMail!, 'de', {
|
|
3372
|
+
[P.CustomerName]: 'Erika Mustermann',
|
|
3373
|
+
[P.SerialNumber]: 'SN-123'
|
|
3374
|
+
});
|
|
3375
|
+
```
|
|
3376
|
+
|
|
3377
|
+
Unknown placeholders, unpaired `{{` / `}}`, a missing language, a multi-line subject,
|
|
3378
|
+
`{{onboardingGuideUrl}}` or `attachOnboardingGuide: true` without an `onboardingGuide`, and
|
|
3379
|
+
attachments not declared in `files` are errors; raw HTML in the body and different
|
|
3380
|
+
placeholders per language are warnings.
|
|
3381
|
+
|
|
3382
|
+
## Compatibility Declaration
|
|
3383
|
+
|
|
3384
|
+
`compatibility` is the list of vendors and models enyo shows customers in the enyo Store,
|
|
3385
|
+
the onboarding flows and the customer portal. Each model may carry `modelYears`
|
|
3386
|
+
(`{from?, to?}`, both inclusive) — use it whenever a model name spans several generations,
|
|
3387
|
+
for vehicles as well as for inverters, wallboxes or heat pumps.
|
|
3388
|
+
|
|
3389
|
+
```typescript
|
|
3390
|
+
import {isYearInCompatibilityRange, validatePackageCompatibility} from '@enyo-energy/energy-app-sdk';
|
|
3391
|
+
|
|
3392
|
+
compatibility: [{
|
|
3393
|
+
vendorName: 'SolarEdge',
|
|
3394
|
+
models: [
|
|
3395
|
+
{modelName: 'SE10K', modelYears: {from: 2016, to: 2020}, features: []},
|
|
3396
|
+
{modelName: 'SE10K-RW0TEBNN4', modelYears: {from: 2021}, features: []}
|
|
3397
|
+
]
|
|
3398
|
+
}]
|
|
3399
|
+
|
|
3400
|
+
const {ok, errors, warnings} = validatePackageCompatibility(packageDef);
|
|
3401
|
+
isYearInCompatibilityRange({from: 2021}, 2023); // true
|
|
3402
|
+
```
|
|
3403
|
+
|
|
3404
|
+
Duplicate vendors, the same model name for overlapping years, `from` after `to` and years
|
|
3405
|
+
outside 1990 to two years ahead are errors. An empty range, and a vehicle model without
|
|
3406
|
+
`modelYears`, are warnings.
|
|
3407
|
+
|
|
3300
3408
|
## Firmware Update Registry
|
|
3301
3409
|
|
|
3302
3410
|
Ship firmware images with your package and hand them to devices at runtime. You declare the files by local path in the package definition, the enyo CLI uploads them during `enyo release`, and the app reaches them through `energyApp.useFirmwareRegistry()`. The release tarball never carries the bytes.
|
|
@@ -3558,12 +3666,13 @@ Drives a heatpump. Manages building / DHW overheating commands and grid-power-av
|
|
|
3558
3666
|
|
|
3559
3667
|
> **Preferred: control heatpumps with the V3 messages.** `HeatpumpControlV3` (power, power sources, which zones to heat now, until when), `HeatpumpControlCancelV3` (cancel a session) and `HeatpumpControlStatusV3` (progress) are the preferred way to control a heatpump — for energy managers sending commands and for integrations receiving them. Use them for all new work. `HeatpumpOverheatingV1`, `SetHeatpumpAvailablePowerV2` and `HeatpumpAvailablePowerAnnouncementV1` are deprecated and only remain for heatpumps that do not declare `ControlV3`. See [HeatpumpControlV3](#heatpumpcontrolv3). Likewise, a heatpump offers its flexibility with `HeatpumpFlexibilityAnnouncementV3` rather than the generic `ApplianceFlexibilityAnnouncementV1` / `V2` — see [HeatpumpFlexibilityAnnouncementV3](#heatpumpflexibilityannouncementv3).
|
|
3560
3668
|
|
|
3561
|
-
- **Subscribed commands:** `HeatpumpControlV3`, `HeatpumpControlCancelV3`, `HeatpumpProgramSwitchV3`, `HeatpumpOverheatingV1` (deprecated), `HeatpumpAvailablePowerAnnouncementV1` (deprecated), `SetHeatpumpAvailablePowerV2` (deprecated), `SetHeatpumpRoomTemperatureV1`, `GridOperatorPowerLimitationV1` (broadcast)
|
|
3669
|
+
- **Subscribed commands:** `HeatpumpControlV3`, `HeatpumpControlCancelV3`, `HeatpumpProgramSwitchV3`, `SetHeatpumpHeatingCurveOffsetV1`, `HeatpumpOverheatingV1` (deprecated), `HeatpumpAvailablePowerAnnouncementV1` (deprecated), `SetHeatpumpAvailablePowerV2` (deprecated), `SetHeatpumpRoomTemperatureV1`, `GridOperatorPowerLimitationV1` (broadcast)
|
|
3562
3670
|
- **Implement:** `handleHeatpumpOverheating`, `handleHeatpumpAvailablePowerAnnouncement`, `handleSetHeatpumpAvailablePower`, `handleGridOperatorPowerLimitation`
|
|
3563
3671
|
- **Optional overrides:**
|
|
3564
3672
|
- `handleSetHeatpumpRoomTemperature` — write a measured room temperature into a heating circuit. Answers `NotSupported` by default; override it when the heatpump declares `RoomTemperatureInput`.
|
|
3565
3673
|
- `handleHeatpumpControl` — support `HeatpumpControlV3` (see below). Answers `NotSupported` by default; override it and declare `ControlV3`.
|
|
3566
3674
|
- `handleHeatpumpProgramSwitch(request)` — switch a zone to comfort or eco, or back to its time program (see [HeatpumpProgramSwitchV3](#heatpumpprogramswitchv3)). Answers `NotSupported` by default; override it and declare `ProgramSwitch`.
|
|
3675
|
+
- `handleHeatpumpHeatingCurveOffset(message)` — shift a heating circuit's curve permanently, relative to its initial curve (see [SetHeatpumpHeatingCurveOffsetV1](#setheatpumpheatingcurveoffsetv1)). Answers `NotSupported` by default; override it and declare `HeatingCurveOffset`.
|
|
3567
3676
|
- `handleHeatpumpControlCancel` — withdraw a cancelled session on the device. By default `Accepted` for heatpumps declaring `ControlV3`, `NotSupported` otherwise.
|
|
3568
3677
|
- `onHeatpumpControlEnded(applianceId, cause)` — return the heatpump to its own behaviour when a session ends; `cause` is `HeatpumpControlEndCauseEnum.Expired`, `Ended` or `Cancelled`. Does nothing by default.
|
|
3569
3678
|
- `resolveHeatpumpMetadata(applianceId)` — the metadata actions are validated against. Defaults to the stored appliance's `heatpump` metadata.
|
|
@@ -3624,6 +3733,44 @@ Switches one heating circuit or DHW zone to its **comfort** or **eco** setpoint
|
|
|
3624
3733
|
- **Owner's consent for price-driven eco.** An energy manager switches zones to eco for price reasons only while the general setting `heatpumpEcoModeInExpensiveTimes` (and `heatpumpControl`) is `true` — see [General settings](#general-settings).
|
|
3625
3734
|
- **Validation** (run by the base class before the handler, or `validateHeatpumpProgramSwitch(data, metadata)` directly): target `Room` / `Dhw`, a known mode, a valid `untilIso` for comfort / eco (`Rejected`); `ProgramSwitch` declared and the mode listed for the zone (`NotSupported`); a known zone index (`Rejected`).
|
|
3626
3735
|
|
|
3736
|
+
#### SetHeatpumpHeatingCurveOffsetV1
|
|
3737
|
+
|
|
3738
|
+
Shifts the heating curve of one heating circuit in parallel — **permanently**, until the next message. The energy manager uses it to lower the curve as far as the measured room temperature allows (less flow temperature, roughly 2.5 % less heating electricity per K).
|
|
3739
|
+
|
|
3740
|
+
```typescript
|
|
3741
|
+
{
|
|
3742
|
+
heatingCircuitIndex: 0,
|
|
3743
|
+
offsetK: -1.5, // K of flow temperature, relative to the initial curve; 0 restores it
|
|
3744
|
+
}
|
|
3745
|
+
```
|
|
3746
|
+
|
|
3747
|
+
- **Relative to the initial curve, never to the current one.** Before the first offset other than `0`, the integration stores the curve set on the device as `heatingCircuits[].initialHeatingCurve` (`ApplianceManager.rememberHeatpumpInitialHeatingCurve` keeps an already stored one). The same message may therefore arrive twice.
|
|
3748
|
+
- **`offsetK: 0` restores** the initial curve exactly, including vendor parameters, then clears it (`ApplianceManager.clearHeatpumpInitialHeatingCurve`, which also sets `activeHeatingCurveOffsetK` to `0`).
|
|
3749
|
+
- **No expiry.** If the hub is offline nobody could reset it anyway; the stored initial curve is the safety net.
|
|
3750
|
+
- **Vendor units.** Convert to whatever the device shifts in (K of room temperature, steps, …) and report the effective shift in K of flow temperature as `heatingCircuits[].activeHeatingCurveOffsetK`, read back from the device. The energy manager waits for it before the next change.
|
|
3751
|
+
- **Changed by hand.** If the curve read from the device differs from `initialHeatingCurve` shifted by `activeHeatingCurveOffsetK` by more than 0.5 K at any point (`isHeatingCurveManuallyChanged(initial, offsetK, read)`), store the read curve as the new `initialHeatingCurve`, set `activeHeatingCurveOffsetK` to `0` and log it in a plain sentence.
|
|
3752
|
+
- **Alongside `HeatpumpControlV3` and `HeatpumpProgramSwitchV3`.** Boost and eco act on top; the offset is the new base.
|
|
3753
|
+
- **Validation** (run by the base class before the handler via `checkHeatingCurveOffset`, or `validateHeatpumpHeatingCurveOffset(data, metadata)` directly): a valid index and finite `offsetK` (`Rejected`); `HeatingCurveOffset` declared (`NotSupported`); a known circuit and — unless `offsetK` is `0` — within `heatingCurveOffsetRangeK` (`Rejected`).
|
|
3754
|
+
- **Customer settings.** Whether to optimise at all, and which rooms of the home the circuit heats (`roomIds`, whether or not a room has a sensor), live in `heatingCircuits[].curveOptimization`. The host resolves them into `rooms`: per room its target temperature (set in the enyo app, `HEATPUMP_CURVE_OPTIMIZATION_DEFAULT_TARGET_C` = 21 °C until then) and the temperature sensors assigned to it. Rooms without a sensor are left out; the room furthest below its target counts, and the curve is lowered by at most `HEATPUMP_CURVE_OPTIMIZATION_MAX_LOWERING_K` (3 K). Integrations only read them.
|
|
3755
|
+
|
|
3756
|
+
```typescript
|
|
3757
|
+
protected async handleHeatpumpHeatingCurveOffset(message: EnyoDataBusSetHeatpumpHeatingCurveOffsetV1) {
|
|
3758
|
+
const {heatingCircuitIndex: index, offsetK} = message.data;
|
|
3759
|
+
if (offsetK !== 0) {
|
|
3760
|
+
await this.appliances.rememberHeatpumpInitialHeatingCurve(message.applianceId, index, await this.readCurve(index));
|
|
3761
|
+
}
|
|
3762
|
+
await this.device.writeCurveShift(index, offsetK);
|
|
3763
|
+
if (offsetK === 0) {
|
|
3764
|
+
await this.appliances.clearHeatpumpInitialHeatingCurve(message.applianceId, index);
|
|
3765
|
+
} else {
|
|
3766
|
+
await this.appliances.updateHeatpumpHeatingCircuit(message.applianceId, index, {
|
|
3767
|
+
activeHeatingCurveOffsetK: await this.readEffectiveShiftK(index),
|
|
3768
|
+
});
|
|
3769
|
+
}
|
|
3770
|
+
return {answer: EnyoCommandAcknowledgeAnswerEnum.Accepted};
|
|
3771
|
+
}
|
|
3772
|
+
```
|
|
3773
|
+
|
|
3627
3774
|
#### HeatpumpFlexibilityAnnouncementV3
|
|
3628
3775
|
|
|
3629
3776
|
The heatpump's offer, in the vocabulary of `HeatpumpControlV3`: per zone (`target` + `index`), how far it can be raised right now (`maxDeltaK` above `setpointC`, room in Kelvin of room temperature) and the smallest raise that actually starts it (`minDeltaK`, e.g. the remaining hysteresis), with which heat source at what power (`heatSources`: compressor and heating rod as separate entries, each with a `power` band and an optional `estimatedElectricalKwh` for the full raise), and when (`earliestStartIso` / `latestStartIso`, `minDurationMinutes`). An optional `required: {deltaK, byIso}` turns a "may" into a "must, by then" — e.g. hot water dropping below comfort at 18:00. Declare `FlexibilityAnnouncementV3` on the heatpump; for such heatpumps it supersedes the generic `ApplianceFlexibilityAnnouncementV1` / `V2`.
|
|
@@ -3659,6 +3806,9 @@ Beyond tanks and circuits, the heatpump metadata (`EnyoHeatpumpApplianceMetadata
|
|
|
3659
3806
|
| `ProgramSwitch` | `heatingCircuits[].supportedProgramModes` / `programModeTemperaturesC` / `activeProgramMode` and the same on `domesticHotWater[]` — which zones can be switched to comfort / eco with `HeatpumpProgramSwitchV3`, at which setpoints, and the mode they run in now |
|
|
3660
3807
|
| `RoomTemperature` | `heatingCircuits[].roomTemperatureC` in `HeatpumpTemperaturesUpdateV1`; where it is measured goes in `heatingCircuits[].roomTemperatureSource` (`None` / `Internal` / `External`) and, for an enyo sensor, `roomTemperatureSensor` |
|
|
3661
3808
|
| `RoomTemperatureInput` | The heatpump accepts measured room temperatures via `SetHeatpumpRoomTemperatureV1` |
|
|
3809
|
+
| `HeatingCurveOffset` | The heatpump's app shifts a circuit's curve via `SetHeatpumpHeatingCurveOffsetV1`. `heatingCircuits[].heatingCurveOffsetRangeK` (allowed range, must contain 0), `activeHeatingCurveOffsetK` (effective shift read back) and `initialHeatingCurve` (the curve before the first shift) |
|
|
3810
|
+
| — | `heatingCircuits[].curveOptimization` — the customer's choice for the room-temperature based curve optimisation: `enabled` (off by default), `roomIds` (the rooms the circuit heats) and, resolved by the host, `rooms` — per room `roomId`, `name`, its `targetRoomTemperatureC` (16–26 °C) and the `sensors` assigned to it. Customer-owned; integrations only read it |
|
|
3811
|
+
| — | `building.recommendedHeatingCurve` — the curve the building actually needs, learned from the days the room held its target |
|
|
3662
3812
|
| `PvSurplusSignal` | The heatpump takes `availablePowerW` of `HeatpumpControlV3` as a PV surplus signal (e.g. Lambda register 102). Supersedes the deprecated `AvailablePowerAnnouncement` |
|
|
3663
3813
|
| `ControlV3` | The heatpump's app handles `HeatpumpControlV3` / `HeatpumpControlCancelV3` and reports `HeatpumpControlStatusV3`. The energy manager sends V3 only to heatpumps declaring it. Needs at least one overheating feature to be actionable |
|
|
3664
3814
|
| `FlexibilityAnnouncementV3` | The heatpump publishes `HeatpumpFlexibilityAnnouncementV3` offers; the energy manager plans from them instead of deriving the headroom from metadata. Needs at least one overheating feature to be actionable |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EnergyAppPackageFirmwareModeEnum = exports.EnergyAppPackageCompatibilityStatus = exports.EnergyAppPackageOptionsDeviceDetectionModbusModeEnum = exports.EnergyAppPackageCategory = void 0;
|
|
3
|
+
exports.EnyoInstallerMailPlaceholder = exports.EnergyAppPackageFirmwareModeEnum = exports.EnergyAppPackageCompatibilityStatus = exports.EnergyAppPackageOptionsDeviceDetectionModbusModeEnum = exports.EnergyAppPackageCategory = void 0;
|
|
4
4
|
exports.defineEnergyAppPackage = defineEnergyAppPackage;
|
|
5
5
|
const version_js_1 = require("./version.cjs");
|
|
6
6
|
var EnergyAppPackageCategory;
|
|
@@ -84,6 +84,56 @@ var EnergyAppPackageFirmwareModeEnum;
|
|
|
84
84
|
/** Follow the explicit `installForFirmwareVersion` upgrade graph. */
|
|
85
85
|
EnergyAppPackageFirmwareModeEnum["Dependent"] = "dependent";
|
|
86
86
|
})(EnergyAppPackageFirmwareModeEnum || (exports.EnergyAppPackageFirmwareModeEnum = EnergyAppPackageFirmwareModeEnum = {}));
|
|
87
|
+
/**
|
|
88
|
+
* The values enyo can insert into an
|
|
89
|
+
* {@link EnergyAppPackageInstallerMail installer mail}.
|
|
90
|
+
*
|
|
91
|
+
* Write a placeholder into the subject or body as `{{name}}` — for example
|
|
92
|
+
* `{{customerName}}` — or build it with `installerMailPlaceholder()`. The list
|
|
93
|
+
* is closed: the mail is sent by enyo while the app is not involved, so every
|
|
94
|
+
* value has to come from enyo, and `validatePackageInstallerMail()` rejects
|
|
95
|
+
* any name not listed here.
|
|
96
|
+
*
|
|
97
|
+
* Any value can be missing when the mail is sent (a customer without a phone
|
|
98
|
+
* number, a serial number the customer skipped). enyo then inserts an empty
|
|
99
|
+
* string, so write sentences that still read well without the value — put
|
|
100
|
+
* placeholders in lists of details rather than in the middle of a sentence.
|
|
101
|
+
*/
|
|
102
|
+
var EnyoInstallerMailPlaceholder;
|
|
103
|
+
(function (EnyoInstallerMailPlaceholder) {
|
|
104
|
+
/** Full name of the customer. */
|
|
105
|
+
EnyoInstallerMailPlaceholder["CustomerName"] = "customerName";
|
|
106
|
+
/** The customer's enyo customer number. */
|
|
107
|
+
EnyoInstallerMailPlaceholder["CustomerNumber"] = "customerNumber";
|
|
108
|
+
/** The customer's e-mail address — where the installer can reply. */
|
|
109
|
+
EnyoInstallerMailPlaceholder["CustomerEmail"] = "customerEmail";
|
|
110
|
+
/** The customer's phone number. */
|
|
111
|
+
EnyoInstallerMailPlaceholder["CustomerPhone"] = "customerPhone";
|
|
112
|
+
/** Street and house number of the installation site. */
|
|
113
|
+
EnyoInstallerMailPlaceholder["InstallationStreet"] = "installationStreet";
|
|
114
|
+
/** Postal code of the installation site. */
|
|
115
|
+
EnyoInstallerMailPlaceholder["InstallationZip"] = "installationZip";
|
|
116
|
+
/** City of the installation site. */
|
|
117
|
+
EnyoInstallerMailPlaceholder["InstallationCity"] = "installationCity";
|
|
118
|
+
/**
|
|
119
|
+
* Serial number of the device to set up (e.g. the inverter), as the
|
|
120
|
+
* customer entered it in the portal. enyo does not know it from anywhere
|
|
121
|
+
* else, so it is the value most likely to be missing.
|
|
122
|
+
*/
|
|
123
|
+
EnyoInstallerMailPlaceholder["SerialNumber"] = "serialNumber";
|
|
124
|
+
/** Vendor the customer selected, one of the package's `compatibility` vendors. */
|
|
125
|
+
EnyoInstallerMailPlaceholder["VendorName"] = "vendorName";
|
|
126
|
+
/** Model the customer selected, one of that vendor's `compatibility` models. */
|
|
127
|
+
EnyoInstallerMailPlaceholder["ModelName"] = "modelName";
|
|
128
|
+
/** Display title of the Energy App from its store entry, in the mail's language. */
|
|
129
|
+
EnyoInstallerMailPlaceholder["EnergyAppName"] = "energyAppName";
|
|
130
|
+
/**
|
|
131
|
+
* Public link to the PDF rendered from
|
|
132
|
+
* {@link EnergyAppPackageDefinition.onboardingGuide}. Only allowed when the
|
|
133
|
+
* package declares that guide.
|
|
134
|
+
*/
|
|
135
|
+
EnyoInstallerMailPlaceholder["OnboardingGuideUrl"] = "onboardingGuideUrl";
|
|
136
|
+
})(EnyoInstallerMailPlaceholder || (exports.EnyoInstallerMailPlaceholder = EnyoInstallerMailPlaceholder = {}));
|
|
87
137
|
/**
|
|
88
138
|
* Defines an Energy App package with automatic SDK version injection.
|
|
89
139
|
* This function automatically adds the current SDK version to the package definition
|
|
@@ -2,6 +2,7 @@ import { EnergyAppPermissionType } from "./energy-app-permission.type.cjs";
|
|
|
2
2
|
import { EnergyAppModelFeatureEnum } from "./energy-app-model-feature.enum.cjs";
|
|
3
3
|
import type { EnyoFileTranslation } from "./types/enyo-file.cjs";
|
|
4
4
|
import type { EnyoOnboardingV2Guide } from "./types/enyo-onboarding-v2.cjs";
|
|
5
|
+
import type { EnyoOnboardingTranslatedContent } from "./types/enyo-onboarding.cjs";
|
|
5
6
|
import type { EnyoSubscriptionMode, EnyoSubscriptionPaymentInterval, EnyoSubscriptionPrice, EnyoSubscriptionPricingModel } from "./types/enyo-subscription.cjs";
|
|
6
7
|
export type EnergyAppPackageLanguage = 'de' | 'en';
|
|
7
8
|
export declare enum EnergyAppPackageCategory {
|
|
@@ -387,6 +388,38 @@ export declare enum EnergyAppPackageCompatibilityStatus {
|
|
|
387
388
|
/** The package has been verified **not** to work with this vendor or model. */
|
|
388
389
|
NotCompatible = "not-compatible"
|
|
389
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* The model years a {@link EnergyAppPackageCompatibilityModel} entry covers,
|
|
393
|
+
* both ends inclusive.
|
|
394
|
+
*
|
|
395
|
+
* Model names alone are ambiguous for products that are sold under one name
|
|
396
|
+
* for many years: a 2020 "ID.3" and a 2024 "ID.3" can talk to completely
|
|
397
|
+
* different vendor APIs, and the same holds for inverter generations. The range
|
|
398
|
+
* lets the enyo Store, onboarding flows and the customer portal tell a user
|
|
399
|
+
* whether *their* device is covered.
|
|
400
|
+
*
|
|
401
|
+
* Years are whole calendar years (model years for vehicles, years of
|
|
402
|
+
* manufacture for other devices). Leave out {@link to} for a model that is
|
|
403
|
+
* still being built; leave out {@link from} only when the start is genuinely
|
|
404
|
+
* unknown. A product with several generations is declared as several model
|
|
405
|
+
* entries, one range each.
|
|
406
|
+
*
|
|
407
|
+
* Validated by `validatePackageCompatibility()`.
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ```typescript
|
|
411
|
+
* models: [
|
|
412
|
+
* {modelName: 'ID.3', modelYears: {from: 2020, to: 2023}, features: [...]},
|
|
413
|
+
* {modelName: 'ID.3', modelYears: {from: 2024}, features: [...]},
|
|
414
|
+
* ]
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
export interface EnergyAppPackageCompatibilityYearRange {
|
|
418
|
+
/** First supported year, inclusive. Omit when the start is unknown. */
|
|
419
|
+
from?: number;
|
|
420
|
+
/** Last supported year, inclusive. Omit while the model is still built. */
|
|
421
|
+
to?: number;
|
|
422
|
+
}
|
|
390
423
|
/**
|
|
391
424
|
* A specific device model supported by an Energy App package.
|
|
392
425
|
* the concrete models the package has been verified to work with.
|
|
@@ -394,6 +427,16 @@ export declare enum EnergyAppPackageCompatibilityStatus {
|
|
|
394
427
|
export interface EnergyAppPackageCompatibilityModel {
|
|
395
428
|
/** Human-readable model name as marketed by the vendor (e.g. "SE10K-RW0TEBNN4") */
|
|
396
429
|
modelName: string;
|
|
430
|
+
/**
|
|
431
|
+
* Optional range of model years this entry covers.
|
|
432
|
+
*
|
|
433
|
+
* Recommended for every model whose name is reused across generations —
|
|
434
|
+
* always for vehicles, and for inverters, wallboxes or heat pumps where a
|
|
435
|
+
* name spans hardware revisions. The same `modelName` may appear more than
|
|
436
|
+
* once per vendor as long as the ranges do not overlap. Omit when the entry
|
|
437
|
+
* applies to every year the model was built.
|
|
438
|
+
*/
|
|
439
|
+
modelYears?: EnergyAppPackageCompatibilityYearRange;
|
|
397
440
|
/**
|
|
398
441
|
* Optional internal display name shown in the enyo Store / Admin UI when
|
|
399
442
|
* different from the official `modelName` (e.g. a friendlier label).
|
|
@@ -669,6 +712,117 @@ export interface EnergyAppPackageFirmwareFile {
|
|
|
669
712
|
/** Optional internal note explaining this image; never shown to users. */
|
|
670
713
|
internalComment?: string;
|
|
671
714
|
}
|
|
715
|
+
/**
|
|
716
|
+
* The values enyo can insert into an
|
|
717
|
+
* {@link EnergyAppPackageInstallerMail installer mail}.
|
|
718
|
+
*
|
|
719
|
+
* Write a placeholder into the subject or body as `{{name}}` — for example
|
|
720
|
+
* `{{customerName}}` — or build it with `installerMailPlaceholder()`. The list
|
|
721
|
+
* is closed: the mail is sent by enyo while the app is not involved, so every
|
|
722
|
+
* value has to come from enyo, and `validatePackageInstallerMail()` rejects
|
|
723
|
+
* any name not listed here.
|
|
724
|
+
*
|
|
725
|
+
* Any value can be missing when the mail is sent (a customer without a phone
|
|
726
|
+
* number, a serial number the customer skipped). enyo then inserts an empty
|
|
727
|
+
* string, so write sentences that still read well without the value — put
|
|
728
|
+
* placeholders in lists of details rather than in the middle of a sentence.
|
|
729
|
+
*/
|
|
730
|
+
export declare enum EnyoInstallerMailPlaceholder {
|
|
731
|
+
/** Full name of the customer. */
|
|
732
|
+
CustomerName = "customerName",
|
|
733
|
+
/** The customer's enyo customer number. */
|
|
734
|
+
CustomerNumber = "customerNumber",
|
|
735
|
+
/** The customer's e-mail address — where the installer can reply. */
|
|
736
|
+
CustomerEmail = "customerEmail",
|
|
737
|
+
/** The customer's phone number. */
|
|
738
|
+
CustomerPhone = "customerPhone",
|
|
739
|
+
/** Street and house number of the installation site. */
|
|
740
|
+
InstallationStreet = "installationStreet",
|
|
741
|
+
/** Postal code of the installation site. */
|
|
742
|
+
InstallationZip = "installationZip",
|
|
743
|
+
/** City of the installation site. */
|
|
744
|
+
InstallationCity = "installationCity",
|
|
745
|
+
/**
|
|
746
|
+
* Serial number of the device to set up (e.g. the inverter), as the
|
|
747
|
+
* customer entered it in the portal. enyo does not know it from anywhere
|
|
748
|
+
* else, so it is the value most likely to be missing.
|
|
749
|
+
*/
|
|
750
|
+
SerialNumber = "serialNumber",
|
|
751
|
+
/** Vendor the customer selected, one of the package's `compatibility` vendors. */
|
|
752
|
+
VendorName = "vendorName",
|
|
753
|
+
/** Model the customer selected, one of that vendor's `compatibility` models. */
|
|
754
|
+
ModelName = "modelName",
|
|
755
|
+
/** Display title of the Energy App from its store entry, in the mail's language. */
|
|
756
|
+
EnergyAppName = "energyAppName",
|
|
757
|
+
/**
|
|
758
|
+
* Public link to the PDF rendered from
|
|
759
|
+
* {@link EnergyAppPackageDefinition.onboardingGuide}. Only allowed when the
|
|
760
|
+
* package declares that guide.
|
|
761
|
+
*/
|
|
762
|
+
OnboardingGuideUrl = "onboardingGuideUrl"
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* A mail the customer sends to their installer from the enyo customer portal,
|
|
766
|
+
* declared in {@link EnergyAppPackageDefinition.onboardingFlowInstallerMail}.
|
|
767
|
+
*
|
|
768
|
+
* ## Format
|
|
769
|
+
*
|
|
770
|
+
* - {@link subject} is plain text on one line.
|
|
771
|
+
* - {@link body} is Markdown (CommonMark: paragraphs, headings, emphasis,
|
|
772
|
+
* lists, links). enyo renders it into its HTML mail template, so do not add a
|
|
773
|
+
* greeting header, footer or styling of your own. Raw HTML is not rendered.
|
|
774
|
+
* - Both may contain {@link EnyoInstallerMailPlaceholder placeholders} written
|
|
775
|
+
* as `{{name}}`. enyo inserts the values as text, escaped for Markdown, so a
|
|
776
|
+
* customer name cannot break the layout.
|
|
777
|
+
* - Both need a `de` and an `en` entry; enyo picks the one matching the
|
|
778
|
+
* customer's language.
|
|
779
|
+
*
|
|
780
|
+
* @example
|
|
781
|
+
* ```typescript
|
|
782
|
+
* const p = installerMailPlaceholder;
|
|
783
|
+
* const P = EnyoInstallerMailPlaceholder;
|
|
784
|
+
*
|
|
785
|
+
* onboardingFlowInstallerMail: defineInstallerMail({
|
|
786
|
+
* subject: [
|
|
787
|
+
* {language: 'de', value: `Einrichtung ${p(P.EnergyAppName)} für ${p(P.CustomerName)}`},
|
|
788
|
+
* {language: 'en', value: `${p(P.EnergyAppName)} setup for ${p(P.CustomerName)}`},
|
|
789
|
+
* ],
|
|
790
|
+
* body: [
|
|
791
|
+
* {language: 'de', value: [
|
|
792
|
+
* 'Bitte aktiviere Modbus TCP am Wechselrichter, damit enyo ihn steuern kann.',
|
|
793
|
+
* '',
|
|
794
|
+
* `- Kunde: ${p(P.CustomerName)} (${p(P.CustomerNumber)})`,
|
|
795
|
+
* `- Seriennummer: ${p(P.SerialNumber)}`,
|
|
796
|
+
* '',
|
|
797
|
+
* `[Anleitung (PDF)](${p(P.OnboardingGuideUrl)})`,
|
|
798
|
+
* ].join('\n')},
|
|
799
|
+
* {language: 'en', value: '...'},
|
|
800
|
+
* ],
|
|
801
|
+
* })
|
|
802
|
+
* ```
|
|
803
|
+
*/
|
|
804
|
+
export interface EnergyAppPackageInstallerMail {
|
|
805
|
+
/** Translated subject line: plain text, one line, may contain placeholders. */
|
|
806
|
+
subject: EnyoOnboardingTranslatedContent[];
|
|
807
|
+
/** Translated Markdown body, may contain placeholders. */
|
|
808
|
+
body: EnyoOnboardingTranslatedContent[];
|
|
809
|
+
/**
|
|
810
|
+
* Whether enyo attaches the PDF rendered from
|
|
811
|
+
* {@link EnergyAppPackageDefinition.onboardingGuide}. Defaults to `true`
|
|
812
|
+
* when the package declares that guide. Setting it to `true` without a
|
|
813
|
+
* guide is a validation error.
|
|
814
|
+
*/
|
|
815
|
+
attachOnboardingGuide?: boolean;
|
|
816
|
+
/**
|
|
817
|
+
* Further attachments, by the `name` of a file declared in
|
|
818
|
+
* {@link EnergyAppPackageDefinition.files} (a datasheet, a wiring diagram).
|
|
819
|
+
* Those files are public anyway; attaching them only saves the installer
|
|
820
|
+
* a download.
|
|
821
|
+
*/
|
|
822
|
+
attachments?: string[];
|
|
823
|
+
/** Optional internal note explaining this mail; never shown to anyone. */
|
|
824
|
+
internalComment?: string;
|
|
825
|
+
}
|
|
672
826
|
/**
|
|
673
827
|
* Complete definition for a enyo Energy App package.
|
|
674
828
|
* This interface defines all the metadata, permissions, and configuration
|
|
@@ -879,6 +1033,24 @@ export interface EnergyAppPackageDefinition {
|
|
|
879
1033
|
* Omit the field for packages that have no manual setup to document.
|
|
880
1034
|
*/
|
|
881
1035
|
onboardingGuide?: EnyoOnboardingV2Guide;
|
|
1036
|
+
/**
|
|
1037
|
+
* The mail a customer sends to their installer from the enyo customer
|
|
1038
|
+
* portal, telling the installer what to do to set the device up.
|
|
1039
|
+
*
|
|
1040
|
+
* The enyo CLI reads it at release time. In the portal the customer enters
|
|
1041
|
+
* the installer's address and the details only they know (such as the
|
|
1042
|
+
* device's serial number); enyo fills in the
|
|
1043
|
+
* {@link EnyoInstallerMailPlaceholder placeholders}, renders the Markdown
|
|
1044
|
+
* body as an HTML mail and sends it — attaching the PDF of
|
|
1045
|
+
* {@link onboardingGuide} unless told otherwise.
|
|
1046
|
+
*
|
|
1047
|
+
* Validate it with `validatePackageInstallerMail()` before publishing; the
|
|
1048
|
+
* CLI refuses the release on errors. See
|
|
1049
|
+
* {@link EnergyAppPackageInstallerMail} for the format.
|
|
1050
|
+
*
|
|
1051
|
+
* Omit for packages that need no installer.
|
|
1052
|
+
*/
|
|
1053
|
+
onboardingFlowInstallerMail?: EnergyAppPackageInstallerMail;
|
|
882
1054
|
/**
|
|
883
1055
|
* Subscription plans this package sells, including their prices. The enyo
|
|
884
1056
|
* CLI reads them at release time; enyo offers them to the customer and
|
|
@@ -618,6 +618,62 @@ class ApplianceManager {
|
|
|
618
618
|
await this.energyApp.useAppliances().save(this.mergeApplianceData(appliance, { heatpump: { domesticHotWater: zones } }), applianceId);
|
|
619
619
|
await this.primeCacheFromSdk(applianceId);
|
|
620
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* Remembers the heating curve a circuit had before the first
|
|
623
|
+
* `SetHeatpumpHeatingCurveOffsetV1` changed it, as the circuit's
|
|
624
|
+
* `initialHeatingCurve` — the curve `offsetK: 0` restores. Call it before
|
|
625
|
+
* writing the first offset other than `0`.
|
|
626
|
+
*
|
|
627
|
+
* Keeps an already stored initial curve: every later offset is relative to
|
|
628
|
+
* the curve before the *first* change, so it must not be overwritten with
|
|
629
|
+
* an already shifted one. Works like {@link updateHeatpumpHeatingCircuit}
|
|
630
|
+
* otherwise.
|
|
631
|
+
*
|
|
632
|
+
* Does nothing when the appliance does not exist.
|
|
633
|
+
*
|
|
634
|
+
* @param applianceId The ID of the heatpump appliance
|
|
635
|
+
* @param index The `index` of the heating circuit
|
|
636
|
+
* @param curve The curve currently set on the device
|
|
637
|
+
* @returns `true` when the curve was stored, `false` when an initial curve
|
|
638
|
+
* was already stored or the appliance does not exist
|
|
639
|
+
* @throws {ApplianceManagerDisposedError} when called after {@link dispose}
|
|
640
|
+
*/
|
|
641
|
+
async rememberHeatpumpInitialHeatingCurve(applianceId, index, curve) {
|
|
642
|
+
this.throwIfDisposed();
|
|
643
|
+
const appliance = await this.energyApp.useAppliances().getById(applianceId);
|
|
644
|
+
if (!appliance)
|
|
645
|
+
return false;
|
|
646
|
+
const circuit = appliance.heatpump?.heatingCircuits?.find(c => c.index === index);
|
|
647
|
+
if (circuit?.initialHeatingCurve)
|
|
648
|
+
return false;
|
|
649
|
+
await this.updateHeatpumpHeatingCircuit(applianceId, index, { initialHeatingCurve: curve });
|
|
650
|
+
return true;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Forgets a circuit's `initialHeatingCurve` after the integration restored
|
|
654
|
+
* it on the device (`offsetK: 0`), and sets `activeHeatingCurveOffsetK` to
|
|
655
|
+
* `0`. Other circuits and fields are left untouched.
|
|
656
|
+
*
|
|
657
|
+
* Does nothing when the appliance or the circuit does not exist.
|
|
658
|
+
*
|
|
659
|
+
* @param applianceId The ID of the heatpump appliance
|
|
660
|
+
* @param index The `index` of the heating circuit
|
|
661
|
+
* @throws {ApplianceManagerDisposedError} when called after {@link dispose}
|
|
662
|
+
*/
|
|
663
|
+
async clearHeatpumpInitialHeatingCurve(applianceId, index) {
|
|
664
|
+
this.throwIfDisposed();
|
|
665
|
+
const appliance = await this.energyApp.useAppliances().getById(applianceId);
|
|
666
|
+
if (!appliance)
|
|
667
|
+
return;
|
|
668
|
+
const circuits = [...(appliance.heatpump?.heatingCircuits ?? [])];
|
|
669
|
+
const position = circuits.findIndex(c => c.index === index);
|
|
670
|
+
if (position < 0)
|
|
671
|
+
return;
|
|
672
|
+
const { initialHeatingCurve: _removed, ...rest } = circuits[position];
|
|
673
|
+
circuits[position] = { ...rest, activeHeatingCurveOffsetK: 0 };
|
|
674
|
+
await this.energyApp.useAppliances().save(this.mergeApplianceData(appliance, { heatpump: { heatingCircuits: circuits } }), applianceId);
|
|
675
|
+
await this.primeCacheFromSdk(applianceId);
|
|
676
|
+
}
|
|
621
677
|
/**
|
|
622
678
|
* Refetches an appliance from the SDK and reflects the result in the
|
|
623
679
|
* cache. Used by mutating methods to keep cache reads consistent with
|
|
@@ -3,7 +3,7 @@ import type { EnyoNetworkDevice } from "../../types/enyo-network-device.cjs";
|
|
|
3
3
|
import { EnyoAppliance, EnyoApplianceAvailableFeaturesEnum, EnyoApplianceConnectionType, EnyoApplianceGroup, EnyoApplianceMetadata, EnyoApplianceName, EnyoApplianceStateEnum, EnyoApplianceTopology, EnyoApplianceTypeEnum } from "../../types/enyo-appliance.cjs";
|
|
4
4
|
import type { EnyoApplianceCreatedFilter } from "../../packages/energy-app-appliance.cjs";
|
|
5
5
|
import type { EnyoChargerApplianceMetadata } from "../../types/enyo-charger-appliance.cjs";
|
|
6
|
-
import type { EnyoHeatpumpApplianceDomesticHotWater, EnyoHeatpumpApplianceHeatingCircuit, EnyoHeatpumpApplianceMetadata } from "../../types/enyo-heatpump-appliance.cjs";
|
|
6
|
+
import type { EnyoHeatpumpApplianceDomesticHotWater, EnyoHeatpumpApplianceHeatingCircuit, EnyoHeatpumpApplianceHeatingCurve, EnyoHeatpumpApplianceMetadata } from "../../types/enyo-heatpump-appliance.cjs";
|
|
7
7
|
import type { EnyoBatteryApplianceMetadata } from "../../types/enyo-battery-appliance.cjs";
|
|
8
8
|
import type { EnyoInverterApplianceMetadata } from "../../types/enyo-inverter-appliance.cjs";
|
|
9
9
|
import type { EnyoMeterAppliance } from "../../types/enyo-meter-appliance.cjs";
|
|
@@ -401,6 +401,39 @@ export declare class ApplianceManager {
|
|
|
401
401
|
* @throws {Error} when the zone does not exist and `patch` lacks `targetTemperatureC`
|
|
402
402
|
*/
|
|
403
403
|
updateHeatpumpDomesticHotWater(applianceId: string, index: number, patch: Partial<Omit<EnyoHeatpumpApplianceDomesticHotWater, 'index'>>): Promise<void>;
|
|
404
|
+
/**
|
|
405
|
+
* Remembers the heating curve a circuit had before the first
|
|
406
|
+
* `SetHeatpumpHeatingCurveOffsetV1` changed it, as the circuit's
|
|
407
|
+
* `initialHeatingCurve` — the curve `offsetK: 0` restores. Call it before
|
|
408
|
+
* writing the first offset other than `0`.
|
|
409
|
+
*
|
|
410
|
+
* Keeps an already stored initial curve: every later offset is relative to
|
|
411
|
+
* the curve before the *first* change, so it must not be overwritten with
|
|
412
|
+
* an already shifted one. Works like {@link updateHeatpumpHeatingCircuit}
|
|
413
|
+
* otherwise.
|
|
414
|
+
*
|
|
415
|
+
* Does nothing when the appliance does not exist.
|
|
416
|
+
*
|
|
417
|
+
* @param applianceId The ID of the heatpump appliance
|
|
418
|
+
* @param index The `index` of the heating circuit
|
|
419
|
+
* @param curve The curve currently set on the device
|
|
420
|
+
* @returns `true` when the curve was stored, `false` when an initial curve
|
|
421
|
+
* was already stored or the appliance does not exist
|
|
422
|
+
* @throws {ApplianceManagerDisposedError} when called after {@link dispose}
|
|
423
|
+
*/
|
|
424
|
+
rememberHeatpumpInitialHeatingCurve(applianceId: string, index: number, curve: EnyoHeatpumpApplianceHeatingCurve): Promise<boolean>;
|
|
425
|
+
/**
|
|
426
|
+
* Forgets a circuit's `initialHeatingCurve` after the integration restored
|
|
427
|
+
* it on the device (`offsetK: 0`), and sets `activeHeatingCurveOffsetK` to
|
|
428
|
+
* `0`. Other circuits and fields are left untouched.
|
|
429
|
+
*
|
|
430
|
+
* Does nothing when the appliance or the circuit does not exist.
|
|
431
|
+
*
|
|
432
|
+
* @param applianceId The ID of the heatpump appliance
|
|
433
|
+
* @param index The `index` of the heating circuit
|
|
434
|
+
* @throws {ApplianceManagerDisposedError} when called after {@link dispose}
|
|
435
|
+
*/
|
|
436
|
+
clearHeatpumpInitialHeatingCurve(applianceId: string, index: number): Promise<void>;
|
|
404
437
|
/**
|
|
405
438
|
* Refetches an appliance from the SDK and reflects the result in the
|
|
406
439
|
* cache. Used by mutating methods to keep cache reads consistent with
|