@enyo-energy/energy-app-sdk 1.17.0 → 1.19.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 +417 -0
- package/dist/cjs/energy-app-model-feature.enum.cjs +13 -0
- package/dist/cjs/energy-app-model-feature.enum.d.cts +12 -0
- package/dist/cjs/energy-app-package-definition.cjs +6 -0
- package/dist/cjs/energy-app-package-definition.d.cts +17 -1
- package/dist/cjs/energy-app-permission.type.cjs +2 -0
- package/dist/cjs/energy-app-permission.type.d.cts +3 -1
- package/dist/cjs/energy-app.cjs +10 -0
- package/dist/cjs/energy-app.d.cts +9 -0
- package/dist/cjs/enyo-energy-app-sdk.d.cts +3 -0
- package/dist/cjs/implementations/calibration/calibration-validators.cjs +292 -0
- package/dist/cjs/implementations/calibration/calibration-validators.d.cts +96 -0
- package/dist/cjs/implementations/energy-distribution/energy-distribution-progress.cjs +120 -0
- package/dist/cjs/implementations/energy-distribution/energy-distribution-progress.d.cts +93 -0
- package/dist/cjs/implementations/energy-distribution/energy-distribution-snapshot-builder.cjs +160 -0
- package/dist/cjs/implementations/energy-distribution/energy-distribution-snapshot-builder.d.cts +168 -0
- package/dist/cjs/implementations/energy-distribution/energy-distribution-validators.cjs +261 -0
- package/dist/cjs/implementations/energy-distribution/energy-distribution-validators.d.cts +46 -0
- package/dist/cjs/index.cjs +8 -0
- package/dist/cjs/index.d.cts +8 -0
- package/dist/cjs/packages/energy-app-authentication.d.cts +10 -0
- package/dist/cjs/packages/energy-app-calibration.cjs +2 -0
- package/dist/cjs/packages/energy-app-calibration.d.cts +226 -0
- package/dist/cjs/packages/energy-app-energy-manager.d.cts +121 -0
- package/dist/cjs/packages/energy-app-vehicle.d.cts +101 -1
- package/dist/cjs/types/enyo-appliance.cjs +15 -0
- package/dist/cjs/types/enyo-appliance.d.cts +83 -1
- package/dist/cjs/types/enyo-calibration.cjs +218 -0
- package/dist/cjs/types/enyo-calibration.d.cts +375 -0
- package/dist/cjs/types/enyo-charge.cjs +22 -1
- package/dist/cjs/types/enyo-charge.d.cts +98 -1
- package/dist/cjs/types/enyo-data-bus-value.cjs +89 -0
- package/dist/cjs/types/enyo-data-bus-value.d.cts +207 -2
- package/dist/cjs/types/enyo-energy-distribution.cjs +63 -0
- package/dist/cjs/types/enyo-energy-distribution.d.cts +156 -0
- package/dist/cjs/types/enyo-energy-manager.cjs +13 -0
- package/dist/cjs/types/enyo-energy-manager.d.cts +13 -1
- package/dist/cjs/types/enyo-flexibility-announcement.d.cts +51 -0
- package/dist/cjs/types/enyo-forecasting.d.cts +26 -1
- package/dist/cjs/types/enyo-grid-connection-point.d.cts +20 -0
- package/dist/cjs/types/enyo-inverter-appliance.cjs +48 -0
- package/dist/cjs/types/enyo-inverter-appliance.d.cts +123 -0
- package/dist/cjs/types/enyo-temperature-sensor-appliance.d.cts +14 -0
- package/dist/cjs/types/enyo-timeseries.d.cts +17 -1
- package/dist/cjs/types/enyo-vehicle.cjs +80 -1
- package/dist/cjs/types/enyo-vehicle.d.cts +223 -0
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/energy-app-model-feature.enum.d.ts +12 -0
- package/dist/energy-app-model-feature.enum.js +13 -0
- package/dist/energy-app-package-definition.d.ts +17 -1
- package/dist/energy-app-package-definition.js +6 -0
- package/dist/energy-app-permission.type.d.ts +3 -1
- package/dist/energy-app-permission.type.js +2 -0
- package/dist/energy-app.d.ts +9 -0
- package/dist/energy-app.js +10 -0
- package/dist/enyo-energy-app-sdk.d.ts +3 -0
- package/dist/implementations/calibration/calibration-validators.d.ts +96 -0
- package/dist/implementations/calibration/calibration-validators.js +286 -0
- package/dist/implementations/energy-distribution/energy-distribution-progress.d.ts +93 -0
- package/dist/implementations/energy-distribution/energy-distribution-progress.js +115 -0
- package/dist/implementations/energy-distribution/energy-distribution-snapshot-builder.d.ts +168 -0
- package/dist/implementations/energy-distribution/energy-distribution-snapshot-builder.js +156 -0
- package/dist/implementations/energy-distribution/energy-distribution-validators.d.ts +46 -0
- package/dist/implementations/energy-distribution/energy-distribution-validators.js +256 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/packages/energy-app-authentication.d.ts +10 -0
- package/dist/packages/energy-app-calibration.d.ts +226 -0
- package/dist/packages/energy-app-calibration.js +1 -0
- package/dist/packages/energy-app-energy-manager.d.ts +121 -0
- package/dist/packages/energy-app-vehicle.d.ts +101 -1
- package/dist/types/enyo-appliance.d.ts +83 -1
- package/dist/types/enyo-appliance.js +15 -0
- package/dist/types/enyo-calibration.d.ts +375 -0
- package/dist/types/enyo-calibration.js +215 -0
- package/dist/types/enyo-charge.d.ts +98 -1
- package/dist/types/enyo-charge.js +21 -0
- package/dist/types/enyo-data-bus-value.d.ts +207 -2
- package/dist/types/enyo-data-bus-value.js +89 -0
- package/dist/types/enyo-energy-distribution.d.ts +156 -0
- package/dist/types/enyo-energy-distribution.js +60 -0
- package/dist/types/enyo-energy-manager.d.ts +13 -1
- package/dist/types/enyo-energy-manager.js +13 -0
- package/dist/types/enyo-flexibility-announcement.d.ts +51 -0
- package/dist/types/enyo-forecasting.d.ts +26 -1
- package/dist/types/enyo-grid-connection-point.d.ts +20 -0
- package/dist/types/enyo-inverter-appliance.d.ts +123 -0
- package/dist/types/enyo-inverter-appliance.js +47 -1
- package/dist/types/enyo-temperature-sensor-appliance.d.ts +14 -0
- package/dist/types/enyo-timeseries.d.ts +17 -1
- package/dist/types/enyo-vehicle.d.ts +223 -0
- package/dist/types/enyo-vehicle.js +79 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,6 +64,12 @@ The official TypeScript SDK for building Energy Apps on the enyo platform. Creat
|
|
|
64
64
|
- [BatteryCommandForecast](#batterycommandforecast)
|
|
65
65
|
- [HeatpumpForecast](#heatpumpforecast)
|
|
66
66
|
- [Validators](#validators)
|
|
67
|
+
- [Energy Distribution Snapshot](#energy-distribution-snapshot)
|
|
68
|
+
- [What the snapshot states](#what-the-snapshot-states)
|
|
69
|
+
- [Stating the goal on an announcement](#stating-the-goal-on-an-announcement)
|
|
70
|
+
- [Publishing a snapshot](#publishing-a-snapshot)
|
|
71
|
+
- [Consuming a snapshot](#consuming-a-snapshot)
|
|
72
|
+
- [Helpers and validation](#helpers-and-validation)
|
|
67
73
|
- [Dynamic Grid Fees & Tariff Bonuses](#dynamic-grid-fees--tariff-bonuses)
|
|
68
74
|
- [The rule that shapes this API](#the-rule-that-shapes-this-api)
|
|
69
75
|
- [Publishing a dynamic grid fee](#publishing-a-dynamic-grid-fee)
|
|
@@ -830,6 +836,126 @@ That message is the only write path for a state of charge; it needs the
|
|
|
830
836
|
`SendDataBusValues` permission. `getSoc()` resolves to `undefined` when nothing
|
|
831
837
|
is known — an ordinary answer for a car with no SoC source, not an error.
|
|
832
838
|
|
|
839
|
+
##### Car integrations: pairing a vehicle
|
|
840
|
+
|
|
841
|
+
A package in the `vehicle` category talks to a manufacturer's cloud and links
|
|
842
|
+
one of its cars to a vehicle the user already created. It does not invent
|
|
843
|
+
vehicles and it does not go looking for them — the flow starts with the user:
|
|
844
|
+
|
|
845
|
+
1. The user signs into the vendor account (`useAuthentication()`, OAuth or
|
|
846
|
+
credentials).
|
|
847
|
+
2. The user picks one of their vehicles in the enyo app and chooses this
|
|
848
|
+
package to link it to. Which packages are offered comes from the brand
|
|
849
|
+
declared in `compatibility` — see below.
|
|
850
|
+
3. The host calls the handler registered with `onPairVehicle()`.
|
|
851
|
+
4. The handler finds the matching car in the account and answers.
|
|
852
|
+
|
|
853
|
+
```typescript
|
|
854
|
+
const vehicles = energyApp.useVehicle();
|
|
855
|
+
|
|
856
|
+
vehicles.onPairVehicle(async (vehicle, selection) => {
|
|
857
|
+
const cars = await vendorApi.listVehicles();
|
|
858
|
+
|
|
859
|
+
// Several cars in the account and nothing to tell them apart —
|
|
860
|
+
// hand the choice back to the user instead of guessing
|
|
861
|
+
if (cars.length > 1 && !selection) {
|
|
862
|
+
return {
|
|
863
|
+
paired: false,
|
|
864
|
+
failureReason: EnyoVehiclePairFailureReasonEnum.SelectionRequired,
|
|
865
|
+
candidates: cars.map(c => ({
|
|
866
|
+
externalId: c.id,
|
|
867
|
+
displayName: c.name,
|
|
868
|
+
vin: c.vin,
|
|
869
|
+
})),
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const car = selection
|
|
874
|
+
? cars.find(c => c.id === selection.externalId)
|
|
875
|
+
: cars[0];
|
|
876
|
+
|
|
877
|
+
if (!car) {
|
|
878
|
+
return {
|
|
879
|
+
paired: false,
|
|
880
|
+
failureReason: EnyoVehiclePairFailureReasonEnum.NoMatchingVehicle,
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
startPolling(car.id, vehicle.id);
|
|
885
|
+
return {
|
|
886
|
+
paired: true,
|
|
887
|
+
externalId: car.id,
|
|
888
|
+
vin: car.vin,
|
|
889
|
+
displayName: car.name,
|
|
890
|
+
// only what you actually read — an invented figure is planned against
|
|
891
|
+
batterySizeKwh: car.batteryKwh,
|
|
892
|
+
maxChargingPowerKw: car.maxChargeKw,
|
|
893
|
+
};
|
|
894
|
+
});
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
The handler is called a second time with `selection` after the user picks from
|
|
898
|
+
`candidates`. A package serving single-car accounts can ignore the parameter.
|
|
899
|
+
|
|
900
|
+
Once paired, the package has the `vehicleId` it was always missing and publishes
|
|
901
|
+
readings the normal way — `VehicleSocUpdateV1`, keyed by that id. Nothing about
|
|
902
|
+
the write path changes.
|
|
903
|
+
|
|
904
|
+
**Unlinking works from both sides.** The user can unlink one car or sign out of
|
|
905
|
+
the vendor account; the package can drop a link it can no longer serve:
|
|
906
|
+
|
|
907
|
+
```typescript
|
|
908
|
+
// The user unlinked a car, deleted the vehicle, or signed out.
|
|
909
|
+
// The link is already gone — this is a notification, not a veto.
|
|
910
|
+
vehicles.onUnpairVehicle(async (link, reason) => {
|
|
911
|
+
stopPolling(link.externalId);
|
|
912
|
+
if (reason !== EnyoVehicleUnpairReasonEnum.SignOut) {
|
|
913
|
+
await vendorApi.revokeVehicleAccess(link.externalId);
|
|
914
|
+
}
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
// The car vanished from the vendor account, or the subscription lapsed.
|
|
918
|
+
// Does NOT call onUnpairVehicle — the package already knows.
|
|
919
|
+
await vehicles.unpairVehicle(vehicleId);
|
|
920
|
+
|
|
921
|
+
// Handlers only fire on change, so pick the links back up after a restart
|
|
922
|
+
for (const link of await vehicles.listLinkedVehicles()) {
|
|
923
|
+
startPolling(link.externalId, link.vehicleId);
|
|
924
|
+
}
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
`listLinkedVehicles()` is not a convenience: without it a package that restarted
|
|
928
|
+
has no idea which cars it is responsible for, and sits idle on a vehicle the
|
|
929
|
+
user believes is connected.
|
|
930
|
+
|
|
931
|
+
**`signOut()` cascades.** Signing out drops every link the package holds, with
|
|
932
|
+
one `onUnpairVehicle` call per link carrying
|
|
933
|
+
`EnyoVehicleUnpairReasonEnum.SignOut`. The vendor session is already gone at
|
|
934
|
+
that point, so stop polling rather than call the vendor's API.
|
|
935
|
+
|
|
936
|
+
Pairing needs the `VehicleIntegration` permission; reading vehicles needs only
|
|
937
|
+
`Vehicle`.
|
|
938
|
+
|
|
939
|
+
##### Declaring supported brands
|
|
940
|
+
|
|
941
|
+
Car integrations declare brands, not model lines — the vendor's cloud serves
|
|
942
|
+
every car in the account and the line-up changes yearly. An empty `models`
|
|
943
|
+
array with `default: true` reads as "every car of this brand":
|
|
944
|
+
|
|
945
|
+
```typescript
|
|
946
|
+
categories: [EnergyAppPackageCategory.Vehicle],
|
|
947
|
+
compatibility: [{
|
|
948
|
+
vendorName: 'Tesla',
|
|
949
|
+
default: true,
|
|
950
|
+
models: [],
|
|
951
|
+
}],
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
Declare per-model entries only where support genuinely differs, and set
|
|
955
|
+
`features` honestly — a brand whose API only reports SoC
|
|
956
|
+
(`VehicleSocReadout`) should not look like one that can also start a charge
|
|
957
|
+
(`VehicleChargeStartStop`). See `EnergyAppModelFeatureEnum`'s vehicle group.
|
|
958
|
+
|
|
833
959
|
##### Charge modes
|
|
834
960
|
|
|
835
961
|
Three modes, one meaning each, identical with and without a dynamic tariff — a
|
|
@@ -928,6 +1054,24 @@ StartTransaction returns the running session instead of opening a second one.
|
|
|
928
1054
|
`save()` remains a whole-object update for a session that already exists; it
|
|
929
1055
|
offers no uniqueness guarantee, so do not open sessions with it.
|
|
930
1056
|
|
|
1057
|
+
**A session records the answers it ran under**, so a listener sees what the
|
|
1058
|
+
customer actually chose rather than only what the charger measured:
|
|
1059
|
+
|
|
1060
|
+
| Field | Meaning |
|
|
1061
|
+
|---|---|
|
|
1062
|
+
| `startSocPercent` / `targetSocPercent` | The SoC the session started from and was to reach. Fixed for the session. |
|
|
1063
|
+
| `priceLimitMode` | Which ceiling applied — `ct-per-kwh`, `cheapest-share`, or absent for none. |
|
|
1064
|
+
| `priceLimitCtPerKwh` / `priceLimitSharePercent` | The ceiling itself, read according to the mode. |
|
|
1065
|
+
| `maxChargingPowerW` | The power the user dialled, in **Watts**. `Immediate` only. |
|
|
1066
|
+
| `vehicleAssignment` | `detected` \| `manual` \| `unknown` — how the session found its car. |
|
|
1067
|
+
|
|
1068
|
+
These mirror the fields on `StartChargeV1`: the command says what a session was
|
|
1069
|
+
asked for, the charge says what it ran with. `maxChargingPowerW` is the opening
|
|
1070
|
+
figure only — the energy manager's `SetChargerAvailablePowerV2` envelope still
|
|
1071
|
+
bounds the session and overrides it. Watch the units: this one is watts, while
|
|
1072
|
+
`EnyoChargeScheduleEntry.limitAmpere` is amperes and the superseded
|
|
1073
|
+
`ChangeChargingPowerV1` is kW.
|
|
1074
|
+
|
|
931
1075
|
React to charging sessions as they happen:
|
|
932
1076
|
|
|
933
1077
|
```typescript
|
|
@@ -1188,6 +1332,120 @@ await learningPhase.completeLearningPhase(heatpumpPhaseId);
|
|
|
1188
1332
|
await learningPhase.removeLearningPhase(phaseId);
|
|
1189
1333
|
```
|
|
1190
1334
|
|
|
1335
|
+
#### `useCalibration(): EnergyAppCalibration`
|
|
1336
|
+
|
|
1337
|
+
Report what an appliance was **proven** to do. An appliance's `availableFeatures`
|
|
1338
|
+
is a claim the app writes from a model database or a register map; a calibration
|
|
1339
|
+
run is the proof. A wallbox that advertises phase switching and fails to switch,
|
|
1340
|
+
or a heat pump wired for SG Ready with nothing on the terminals, is exactly what
|
|
1341
|
+
the claim cannot catch. Both are kept: the claim tells onboarding what to expect,
|
|
1342
|
+
the run tells an energy manager what it may rely on.
|
|
1343
|
+
|
|
1344
|
+
Supported for batteries, wallboxes, inverters, heat pumps and heating rods.
|
|
1345
|
+
|
|
1346
|
+
**A run is a lifecycle, not a call** — unlike `useDeviceTest()`, where the
|
|
1347
|
+
handler's promise is the whole protocol. A battery calibration is a
|
|
1348
|
+
charge/discharge cycle measured in hours, so the app opens a run, reports
|
|
1349
|
+
progress against it, and closes it with a verdict:
|
|
1350
|
+
|
|
1351
|
+
```typescript
|
|
1352
|
+
const calibration = energyApp.useCalibration();
|
|
1353
|
+
|
|
1354
|
+
const runId = await calibration.startRun({ applianceId: 'battery-1' });
|
|
1355
|
+
|
|
1356
|
+
await calibration.reportProgress(runId, {
|
|
1357
|
+
progressPercent: 40,
|
|
1358
|
+
currentStep: [
|
|
1359
|
+
{ language: 'de', value: 'Batterie wird entladen' },
|
|
1360
|
+
{ language: 'en', value: 'Discharging the battery' },
|
|
1361
|
+
],
|
|
1362
|
+
});
|
|
1363
|
+
|
|
1364
|
+
await calibration.completeRun(runId, {
|
|
1365
|
+
confirmedFeatures: [
|
|
1366
|
+
EnyoCalibratedFeatureEnum.BatteryGridCharging,
|
|
1367
|
+
EnyoCalibratedFeatureEnum.BatteryUsableCapacity,
|
|
1368
|
+
],
|
|
1369
|
+
});
|
|
1370
|
+
```
|
|
1371
|
+
|
|
1372
|
+
Always close a run you opened. An app that crashes mid-run leaves it `running`
|
|
1373
|
+
forever, which reads to a user as a device that has been calibrating for three
|
|
1374
|
+
days — report `Interrupted` on restart when you find one of your own runs still
|
|
1375
|
+
open.
|
|
1376
|
+
|
|
1377
|
+
Read it back, or react to anyone's run:
|
|
1378
|
+
|
|
1379
|
+
```typescript
|
|
1380
|
+
const status = await calibration.getStatus('battery-1'); // undefined when never reported
|
|
1381
|
+
if (status?.status === EnyoCalibrationStatusEnum.Succeeded) {
|
|
1382
|
+
console.log(status.confirmedFeatures);
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
const id = calibration.listenForCalibrationStatusChange(async (run) => { /* … */ });
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
**Statuses**
|
|
1389
|
+
|
|
1390
|
+
| Status | Meaning |
|
|
1391
|
+
|---|---|
|
|
1392
|
+
| `not-supported` | This appliance has no run to offer. Stop asking; don't show a control. |
|
|
1393
|
+
| `not-calibrated` | Possible, but something is missing — see `requirements`. |
|
|
1394
|
+
| `ready` | Every prerequisite holds; a run could start now. |
|
|
1395
|
+
| `running` | In progress. See `progressPercent` / `currentStep`. |
|
|
1396
|
+
| `succeeded` | Finished; `confirmedFeatures` holds what it proved. |
|
|
1397
|
+
| `failed` | Did not finish; `failureReason` says whether retrying helps. |
|
|
1398
|
+
| `stale` | A past success that no longer describes the device (firmware, hardware, rewiring). |
|
|
1399
|
+
|
|
1400
|
+
Four things to get right:
|
|
1401
|
+
|
|
1402
|
+
- **`undefined` is not `not-supported`.** No run at all means nobody has said anything; `not-supported` means someone said no. Only the second justifies hiding the feature.
|
|
1403
|
+
- **Succeeding and confirming nothing is a real result.** `confirmedFeatures: []` says the run completed and proved nothing — quite different from the field being absent, which means it never got far enough to say.
|
|
1404
|
+
- **Declare prerequisites even when you never run.** `reportRequirements()` is what turns "not calibrated" into "needs at least 30 % state of charge", which a user can act on.
|
|
1405
|
+
- **Omit `progressPercent` rather than guessing.** A bar that sits at 10 % for three hours is worse than a spinner and an honest `currentStep`.
|
|
1406
|
+
|
|
1407
|
+
An app that can be asked to calibrate — from the cockpit, or an onboarding step —
|
|
1408
|
+
registers a handler. Answer promptly with an *acceptance*, not a result; refusing
|
|
1409
|
+
with unsatisfied `requirements` is a normal answer and more useful than starting a
|
|
1410
|
+
run that is bound to fail:
|
|
1411
|
+
|
|
1412
|
+
```typescript
|
|
1413
|
+
calibration.listenForCalibrationRequest(async (request) => {
|
|
1414
|
+
if (soc < 30) {
|
|
1415
|
+
return {
|
|
1416
|
+
requestId: request.requestId,
|
|
1417
|
+
accepted: false,
|
|
1418
|
+
requirements: [{
|
|
1419
|
+
key: 'min-soc',
|
|
1420
|
+
satisfied: false,
|
|
1421
|
+
description: [
|
|
1422
|
+
{ language: 'de', value: 'Mindestens 30 % Ladestand nötig' },
|
|
1423
|
+
{ language: 'en', value: 'Needs at least 30 % state of charge' },
|
|
1424
|
+
],
|
|
1425
|
+
}],
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
return { requestId: request.requestId, accepted: true, runId: await calibration.startRun({
|
|
1429
|
+
applianceId: request.applianceId,
|
|
1430
|
+
requestId: request.requestId,
|
|
1431
|
+
}) };
|
|
1432
|
+
});
|
|
1433
|
+
```
|
|
1434
|
+
|
|
1435
|
+
`EnyoCalibratedFeatureEnum` is deliberately its own flat vocabulary rather than
|
|
1436
|
+
the per-type `availableFeatures` enums — those describe claims and change for
|
|
1437
|
+
reasons unrelated to what a run can prove. Members are prefixed by device class,
|
|
1438
|
+
and `validateCalibrationRun()` rejects a run reporting a feature from another
|
|
1439
|
+
class, along with the self-contradictory states the optional fields otherwise
|
|
1440
|
+
allow (features on a failed run, a failure reason on a successful one, a run
|
|
1441
|
+
that ended before it began).
|
|
1442
|
+
|
|
1443
|
+
Not to be confused with a **learning phase**: that is open-ended data gathering
|
|
1444
|
+
with no pass/fail and no feature list. The two compose — a calibration run may
|
|
1445
|
+
open a learning phase while it settles.
|
|
1446
|
+
|
|
1447
|
+
Writing requires the `Calibration` permission; reading status requires none.
|
|
1448
|
+
|
|
1191
1449
|
### Networking & Protocols
|
|
1192
1450
|
|
|
1193
1451
|
#### `useEebus(): EnergyAppEebus`
|
|
@@ -2089,6 +2347,30 @@ await applianceManager.updateApplianceState(
|
|
|
2089
2347
|
|
|
2090
2348
|
Identifier strategies are exported from the package — typical choices match on serial number, hostname, or a composite of `manufacturer + model + sn`.
|
|
2091
2349
|
|
|
2350
|
+
### Battery-powered appliances
|
|
2351
|
+
|
|
2352
|
+
An appliance that runs on its own cell — a wireless room sensor, a radio button, a battery-backed gateway — declares `EnyoApplianceAvailableFeaturesEnum.BatteryPowered` and reports `EnyoAppliance.batteryState`:
|
|
2353
|
+
|
|
2354
|
+
```typescript
|
|
2355
|
+
await appliances.save({
|
|
2356
|
+
// …
|
|
2357
|
+
availableFeatures: [EnyoApplianceAvailableFeaturesEnum.BatteryPowered],
|
|
2358
|
+
batteryState: {
|
|
2359
|
+
levelPercent: 62,
|
|
2360
|
+
low: false,
|
|
2361
|
+
replaceable: true,
|
|
2362
|
+
measuredAtIso: new Date().toISOString(),
|
|
2363
|
+
},
|
|
2364
|
+
});
|
|
2365
|
+
```
|
|
2366
|
+
|
|
2367
|
+
Publish changes on `ApplianceStateUpdateV1` (`data.batteryState`) when the level moves meaningfully or `low` flips — not on every reading, or a sensor reporting hourly fills the bus with a number that changes once a month.
|
|
2368
|
+
|
|
2369
|
+
- **This is not a home storage battery.** `EnyoApplianceBatteryState` is about keeping a sensor alive; `EnyoBatteryState` is the runtime state of a `Storage` appliance, in kWh and priced. The names are close and the concepts are unrelated.
|
|
2370
|
+
- **`low` is the load-bearing field, not `levelPercent`.** A primary cell's voltage barely moves until it is nearly flat, so many devices report only a coarse level or none at all. Set `low` from whatever the device actually says rather than leaving a consumer to pick a threshold it cannot calibrate.
|
|
2371
|
+
- **Declare the feature even before the first reading.** It is how a maintenance view knows to watch for a flat battery, and it keeps a device whose reporting is intermittent from appearing and disappearing from that list.
|
|
2372
|
+
- **Always set `measuredAtIso`.** These devices report rarely, so a level without an age says nothing about whether the device is still alive — which is the question a low battery is usually asked alongside.
|
|
2373
|
+
|
|
2092
2374
|
## Network Devices & Access Recovery
|
|
2093
2375
|
|
|
2094
2376
|
Packages that talk to local hardware over TCP (Modbus, SunSpec, EEBUS over SHIP, REST) must deal with two failure modes the `useNetworkDevices()` API exposes only at a low level:
|
|
@@ -3251,6 +3533,141 @@ try {
|
|
|
3251
3533
|
}
|
|
3252
3534
|
```
|
|
3253
3535
|
|
|
3536
|
+
## Energy Distribution Snapshot
|
|
3537
|
+
|
|
3538
|
+
Answers the question an owner actually asks in front of the cockpit: **who is getting the power right now, in what order, how far along are they, and why?**
|
|
3539
|
+
|
|
3540
|
+
An energy manager publishes one snapshot per allocation cycle (and on every slot boundary). Each row is a participant: the appliances it steers, plus the household draw and the feed-in that no plan owns. Every row carries a signed power, a reason ready to render in the user's language, and — where the participant has a goal — how far toward that goal it is.
|
|
3541
|
+
|
|
3542
|
+
**Required permission:** `EnergyManager` (to publish). Reading is open to any app.
|
|
3543
|
+
|
|
3544
|
+
### What the snapshot states
|
|
3545
|
+
|
|
3546
|
+
The model has one rule, and everything else follows from it: **every number is stated by whoever owns it, and carried through verbatim.**
|
|
3547
|
+
|
|
3548
|
+
| Fact | Owned by | Never |
|
|
3549
|
+
|---|---|---|
|
|
3550
|
+
| `rank` — who was served first | the component that ordered the allocation | re-derived from a category precedence the consumer knows |
|
|
3551
|
+
| `progress` — the goal and where the run stands | the appliance manager that owns the goal | back-computed from granted watts, or from a remaining-energy figure |
|
|
3552
|
+
| `state: Complete` | a stated `SessionComplete` reason | inferred from `percent >= 100` |
|
|
3553
|
+
| `reason` + its translation | whoever took the decision | invented per consumer |
|
|
3554
|
+
|
|
3555
|
+
The two that bite hardest:
|
|
3556
|
+
|
|
3557
|
+
**A remaining energy is not a goal.** An announcement states what is *still needed*, and that shrinks every cycle as the appliance fills. A required energy falling from 20 kWh to 2 kWh looks exactly like a target that was always 2 kWh — so a bar built on it stays flat for a session that is nearly done. That is why the goal is stated separately, on the announcement, by the manager that knows it.
|
|
3558
|
+
|
|
3559
|
+
**A full bar is not a finished run.** A measured delivery overshoots a target that was revised mid-session, and a session can be complete while its last meter reading still lags. `Complete` comes from the stated `SessionComplete` cause, and `validateEnergyDistributionSnapshot()` rejects a snapshot that claims otherwise.
|
|
3560
|
+
|
|
3561
|
+
Rows with **no** goal — household draw, feed-in, a charger with no car plugged in — simply carry no `progress`. That is an answer, not missing data: the card renders them without a bar.
|
|
3562
|
+
|
|
3563
|
+
### Stating the goal on an announcement
|
|
3564
|
+
|
|
3565
|
+
Managers put the goal on their flexibility announcement, in the unit the owner sees:
|
|
3566
|
+
|
|
3567
|
+
```typescript
|
|
3568
|
+
// Charger: 8.4 kWh delivered of the 22 kWh this session needs.
|
|
3569
|
+
context: {
|
|
3570
|
+
progress: {
|
|
3571
|
+
unit: EnyoDistributionProgressUnitEnum.Energy,
|
|
3572
|
+
start: 0,
|
|
3573
|
+
current: session.deliveredWh,
|
|
3574
|
+
target: session.requiredWh,
|
|
3575
|
+
},
|
|
3576
|
+
},
|
|
3577
|
+
|
|
3578
|
+
// Battery: 58 % now, heading for the 70 % ceiling the owner set, from 52 % at the start.
|
|
3579
|
+
context: {
|
|
3580
|
+
progress: {
|
|
3581
|
+
unit: EnyoDistributionProgressUnitEnum.StateOfCharge,
|
|
3582
|
+
start: 52,
|
|
3583
|
+
current: 58,
|
|
3584
|
+
target: 70,
|
|
3585
|
+
},
|
|
3586
|
+
},
|
|
3587
|
+
|
|
3588
|
+
// Heat pump: a DHW tank at 31 °C that started at 20 °C and is heading for 48 °C.
|
|
3589
|
+
context: {
|
|
3590
|
+
progress: {
|
|
3591
|
+
unit: EnyoDistributionProgressUnitEnum.Temperature,
|
|
3592
|
+
start: 20,
|
|
3593
|
+
current: 31,
|
|
3594
|
+
target: 48,
|
|
3595
|
+
},
|
|
3596
|
+
},
|
|
3597
|
+
```
|
|
3598
|
+
|
|
3599
|
+
`start` is the bar's zero, and it matters everywhere except energy: without it, a cold tank at 20 °C heading for 48 °C draws a 42 % bar before anything has happened.
|
|
3600
|
+
|
|
3601
|
+
### Publishing a snapshot
|
|
3602
|
+
|
|
3603
|
+
```typescript
|
|
3604
|
+
const em = energyApp.useEnergyManager();
|
|
3605
|
+
em.registerFeatures([EnergyManagerFeatureEnum.EnergyDistributionView]);
|
|
3606
|
+
|
|
3607
|
+
const snapshot = new EnergyDistributionSnapshotBuilder()
|
|
3608
|
+
.addAppliance({
|
|
3609
|
+
rank: 0, // the order the allocation actually used
|
|
3610
|
+
applianceId: 'charger-1',
|
|
3611
|
+
applianceType: EnyoApplianceTypeEnum.Charger,
|
|
3612
|
+
name: 'Wallbox Garage',
|
|
3613
|
+
state: EnyoDistributionParticipantStateEnum.Drawing,
|
|
3614
|
+
powerW: 7400,
|
|
3615
|
+
reason: enrichedPvSurplusReason,
|
|
3616
|
+
progress: makeProgress({
|
|
3617
|
+
unit: EnyoDistributionProgressUnitEnum.Energy,
|
|
3618
|
+
current: 8400,
|
|
3619
|
+
target: 22000,
|
|
3620
|
+
}),
|
|
3621
|
+
})
|
|
3622
|
+
.addAppliance({
|
|
3623
|
+
rank: 1,
|
|
3624
|
+
applianceId: 'charger-2',
|
|
3625
|
+
applianceType: EnyoApplianceTypeEnum.Charger,
|
|
3626
|
+
name: 'Wallbox Hof',
|
|
3627
|
+
state: EnyoDistributionParticipantStateEnum.NotAsking,
|
|
3628
|
+
powerW: 0,
|
|
3629
|
+
reason: enrich({type: EnyoDataBusCommandReasonTypeEnum.NothingConnected}),
|
|
3630
|
+
// no car, so no goal, so no bar
|
|
3631
|
+
})
|
|
3632
|
+
.addHousehold({powerW: 620, name: 'Haushalt'})
|
|
3633
|
+
.addFeedIn({powerW: -1300, name: 'Einspeisung'})
|
|
3634
|
+
.build({slotStartMs: slotStart});
|
|
3635
|
+
|
|
3636
|
+
em.publishEnergyDistribution(snapshot);
|
|
3637
|
+
```
|
|
3638
|
+
|
|
3639
|
+
Include **every** appliance the energy manager knows about, including the ones that asked for nothing — with `NotAsking` or `Skipped` and a reason. A row that silently disappears reads, to an owner, as an appliance that stopped existing.
|
|
3640
|
+
|
|
3641
|
+
The publisher validates before sending, so an invalid snapshot throws rather than going out half-true.
|
|
3642
|
+
|
|
3643
|
+
### Consuming a snapshot
|
|
3644
|
+
|
|
3645
|
+
Read once for the cold start, then follow:
|
|
3646
|
+
|
|
3647
|
+
```typescript
|
|
3648
|
+
const em = energyApp.useEnergyManager();
|
|
3649
|
+
|
|
3650
|
+
const current = await em.getEnergyDistribution(); // null: none configured, or none published yet
|
|
3651
|
+
if (current) render(current);
|
|
3652
|
+
|
|
3653
|
+
const id = em.listenForEnergyDistribution(render);
|
|
3654
|
+
energyApp.onShutdown(() => em.unsubscribeEnergyDistribution(id));
|
|
3655
|
+
```
|
|
3656
|
+
|
|
3657
|
+
Each event carries the **complete** picture of the slot — render it as it arrives rather than merging it into what you had. To tell "will never come" apart from "not yet", check `EnergyManagerInfo.features` for `EnergyDistributionView`.
|
|
3658
|
+
|
|
3659
|
+
### Helpers and validation
|
|
3660
|
+
|
|
3661
|
+
| Helper | What it does |
|
|
3662
|
+
|---|---|
|
|
3663
|
+
| `makeProgress({unit, start?, current, target})` | Builds an `EnyoDistributionProgress` with `percent` computed — `(current − start) / (target − start)`, clamped to 0–100. The single definition of how full a bar is, so no two consumers disagree by a rounding rule. |
|
|
3664
|
+
| `progressPercent(input)` | The same arithmetic on its own, for a caller that already holds a stated triple. |
|
|
3665
|
+
| `progressFromAnnouncement(stated)` | Turns a manager's announced goal into a participant's progress, adding nothing but the percentage. |
|
|
3666
|
+
| `EnergyDistributionSnapshotBuilder` | Assembles the snapshot: orders rows by stated rank, stamps the timestamps, and keeps the measured rows structurally free of a bar. |
|
|
3667
|
+
| `validateEnergyDistributionSnapshot(snapshot)` | Throws `EnergyDistributionValidationError` on the first violated invariant — duplicate ranks, a bar on a household row, a `Complete` without a stated `SessionComplete`, a percentage that does not follow from its own numbers, a "skipped" row still drawing power. |
|
|
3668
|
+
|
|
3669
|
+
New reason types came with this surface, so a skipped row can say *why* instead of falling back to a generic "scheduled optimization": `SessionComplete`, `AppliancePaused`, `NothingConnected`, `DeadlinePassed`, `WaitingForCheaperSlot`, `AboveOwnPriceLimit`, `BelowMinPower`, `OtherApplianceTurn`, `SupplyExhausted`, `OutsideSchedule` — grouped by the new `SessionState` and `Contention` reason categories.
|
|
3670
|
+
|
|
3254
3671
|
## Dynamic Grid Fees & Tariff Bonuses
|
|
3255
3672
|
|
|
3256
3673
|
An electricity price is rarely one number. It is the energy price, plus the grid operator's network
|
|
@@ -51,6 +51,19 @@ var EnergyAppModelFeatureEnum;
|
|
|
51
51
|
EnergyAppModelFeatureEnum["GridPowerReadout"] = "grid-power-readout";
|
|
52
52
|
/** The accumulated energy consumption can be read out */
|
|
53
53
|
EnergyAppModelFeatureEnum["EnergyConsumptionReadout"] = "energy-consumption-readout";
|
|
54
|
+
// Vehicle
|
|
55
|
+
/** The car's state of charge can be read remotely (manufacturer cloud, ISO 15118) */
|
|
56
|
+
EnergyAppModelFeatureEnum["VehicleSocReadout"] = "vehicle-soc-readout";
|
|
57
|
+
/** Charging can be started and stopped through the car rather than the wallbox */
|
|
58
|
+
EnergyAppModelFeatureEnum["VehicleChargeStartStop"] = "vehicle-charge-start-stop";
|
|
59
|
+
/** The car's target state of charge or charging current can be set remotely */
|
|
60
|
+
EnergyAppModelFeatureEnum["VehicleChargeLimit"] = "vehicle-charge-limit";
|
|
61
|
+
/** The car's position can be read, so "is it at home?" can be answered */
|
|
62
|
+
EnergyAppModelFeatureEnum["VehicleLocationReadout"] = "vehicle-location-readout";
|
|
63
|
+
/** The car's odometer reading can be read */
|
|
64
|
+
EnergyAppModelFeatureEnum["VehicleOdometerReadout"] = "vehicle-odometer-readout";
|
|
65
|
+
/** Cabin or battery preconditioning can be triggered remotely */
|
|
66
|
+
EnergyAppModelFeatureEnum["VehiclePreconditioning"] = "vehicle-preconditioning";
|
|
54
67
|
// Smart Plug
|
|
55
68
|
/** The plug can be switched on and off */
|
|
56
69
|
EnergyAppModelFeatureEnum["SwitchOnOff"] = "switch-on-off";
|
|
@@ -41,6 +41,18 @@ export declare enum EnergyAppModelFeatureEnum {
|
|
|
41
41
|
GridPowerReadout = "grid-power-readout",
|
|
42
42
|
/** The accumulated energy consumption can be read out */
|
|
43
43
|
EnergyConsumptionReadout = "energy-consumption-readout",
|
|
44
|
+
/** The car's state of charge can be read remotely (manufacturer cloud, ISO 15118) */
|
|
45
|
+
VehicleSocReadout = "vehicle-soc-readout",
|
|
46
|
+
/** Charging can be started and stopped through the car rather than the wallbox */
|
|
47
|
+
VehicleChargeStartStop = "vehicle-charge-start-stop",
|
|
48
|
+
/** The car's target state of charge or charging current can be set remotely */
|
|
49
|
+
VehicleChargeLimit = "vehicle-charge-limit",
|
|
50
|
+
/** The car's position can be read, so "is it at home?" can be answered */
|
|
51
|
+
VehicleLocationReadout = "vehicle-location-readout",
|
|
52
|
+
/** The car's odometer reading can be read */
|
|
53
|
+
VehicleOdometerReadout = "vehicle-odometer-readout",
|
|
54
|
+
/** Cabin or battery preconditioning can be triggered remotely */
|
|
55
|
+
VehiclePreconditioning = "vehicle-preconditioning",
|
|
44
56
|
/** The plug can be switched on and off */
|
|
45
57
|
SwitchOnOff = "switch-on-off",
|
|
46
58
|
/** The plug can measure the connected load's power */
|
|
@@ -19,6 +19,12 @@ var EnergyAppPackageCategory;
|
|
|
19
19
|
EnergyAppPackageCategory["SmartPlug"] = "smart-plug";
|
|
20
20
|
EnergyAppPackageCategory["HeatingRod"] = "heating-rod";
|
|
21
21
|
EnergyAppPackageCategory["GridOperator"] = "grid-operator";
|
|
22
|
+
/**
|
|
23
|
+
* Integrations that talk to a car — typically a manufacturer cloud API —
|
|
24
|
+
* and link it to one of the user's vehicles. See `EnergyAppVehicle`'s
|
|
25
|
+
* `onPairVehicle` for how the link is made.
|
|
26
|
+
*/
|
|
27
|
+
EnergyAppPackageCategory["Vehicle"] = "vehicle";
|
|
22
28
|
EnergyAppPackageCategory["Other"] = "other";
|
|
23
29
|
})(EnergyAppPackageCategory || (exports.EnergyAppPackageCategory = EnergyAppPackageCategory = {}));
|
|
24
30
|
/**
|
|
@@ -17,6 +17,12 @@ export declare enum EnergyAppPackageCategory {
|
|
|
17
17
|
SmartPlug = "smart-plug",
|
|
18
18
|
HeatingRod = "heating-rod",
|
|
19
19
|
GridOperator = "grid-operator",
|
|
20
|
+
/**
|
|
21
|
+
* Integrations that talk to a car — typically a manufacturer cloud API —
|
|
22
|
+
* and link it to one of the user's vehicles. See `EnergyAppVehicle`'s
|
|
23
|
+
* `onPairVehicle` for how the link is made.
|
|
24
|
+
*/
|
|
25
|
+
Vehicle = "vehicle",
|
|
20
26
|
Other = "other"
|
|
21
27
|
}
|
|
22
28
|
/**
|
|
@@ -259,7 +265,17 @@ export interface EnergyAppPackageCompatibilityModel {
|
|
|
259
265
|
export interface EnergyAppPackageCompatibilityVendor {
|
|
260
266
|
/** Human-readable vendor name (e.g. "SolarEdge", "Fronius") */
|
|
261
267
|
vendorName: string;
|
|
262
|
-
/**
|
|
268
|
+
/**
|
|
269
|
+
* Models from this vendor that the package supports.
|
|
270
|
+
*
|
|
271
|
+
* May be empty for a package whose support is brand-wide rather than
|
|
272
|
+
* model-by-model — the usual case for a
|
|
273
|
+
* {@link EnergyAppPackageCategory.Vehicle} integration, where the vendor's
|
|
274
|
+
* cloud API serves every car in the account and the model lines change
|
|
275
|
+
* yearly. An empty array together with `default: true` reads as "every
|
|
276
|
+
* device of this brand"; listing models you have not actually tested is
|
|
277
|
+
* worse than listing none.
|
|
278
|
+
*/
|
|
263
279
|
models: EnergyAppPackageCompatibilityModel[];
|
|
264
280
|
/**
|
|
265
281
|
* Marks this package as the default Energy App for the vendor when no
|
|
@@ -63,4 +63,6 @@ var EnergyAppPermissionTypeEnum;
|
|
|
63
63
|
EnergyAppPermissionTypeEnum["GridFeeRegister"] = "GridFeeRegister";
|
|
64
64
|
EnergyAppPermissionTypeEnum["GridFeeUse"] = "GridFeeUse";
|
|
65
65
|
EnergyAppPermissionTypeEnum["CommandLog"] = "CommandLog";
|
|
66
|
+
EnergyAppPermissionTypeEnum["Calibration"] = "Calibration";
|
|
67
|
+
EnergyAppPermissionTypeEnum["VehicleIntegration"] = "VehicleIntegration";
|
|
66
68
|
})(EnergyAppPermissionTypeEnum || (exports.EnergyAppPermissionTypeEnum = EnergyAppPermissionTypeEnum = {}));
|
|
@@ -58,7 +58,9 @@ export declare enum EnergyAppPermissionTypeEnum {
|
|
|
58
58
|
FirmwareRegistry = "FirmwareRegistry",
|
|
59
59
|
GridFeeRegister = "GridFeeRegister",
|
|
60
60
|
GridFeeUse = "GridFeeUse",
|
|
61
|
-
CommandLog = "CommandLog"
|
|
61
|
+
CommandLog = "CommandLog",
|
|
62
|
+
Calibration = "Calibration",
|
|
63
|
+
VehicleIntegration = "VehicleIntegration"
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
66
|
* String union of every permission name, derived from
|
package/dist/cjs/energy-app.cjs
CHANGED
|
@@ -293,6 +293,16 @@ class EnergyApp {
|
|
|
293
293
|
useLearningPhase() {
|
|
294
294
|
return this.energyAppSdk.useLearningPhase();
|
|
295
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Gets the Calibration API for reporting what an appliance was proven to do.
|
|
298
|
+
* Provides methods to open, advance and close calibration runs for
|
|
299
|
+
* batteries, wallboxes, inverters, heat pumps and heating rods, to declare
|
|
300
|
+
* their prerequisites, and to answer host requests to calibrate.
|
|
301
|
+
* @returns The Calibration API instance
|
|
302
|
+
*/
|
|
303
|
+
useCalibration() {
|
|
304
|
+
return this.energyAppSdk.useCalibration();
|
|
305
|
+
}
|
|
296
306
|
/**
|
|
297
307
|
* Gets the WiFi API for scanning and listing known WiFi networks (SSIDs).
|
|
298
308
|
* Provides methods to discover saved/known SSIDs that are currently
|
|
@@ -33,6 +33,7 @@ import { EnergyAppMqtt } from "./packages/energy-app-mqtt.cjs";
|
|
|
33
33
|
import { EnergyAppBluetooth } from "./packages/energy-app-bluetooth.cjs";
|
|
34
34
|
import { EnergyAppDiagnostics } from "./packages/energy-app-diagnostics.cjs";
|
|
35
35
|
import { EnergyAppLearningPhase } from "./packages/energy-app-learning-phase.cjs";
|
|
36
|
+
import { EnergyAppCalibration } from "./packages/energy-app-calibration.cjs";
|
|
36
37
|
import { EnergyAppWifi } from "./packages/energy-app-wifi.cjs";
|
|
37
38
|
import { EnergyAppUdp } from "./packages/energy-app-udp.cjs";
|
|
38
39
|
import { EnergyAppGridConnectionPoint } from "./packages/energy-app-grid-connection-point.cjs";
|
|
@@ -242,6 +243,14 @@ export declare class EnergyApp implements EnyoEnergyAppSdk {
|
|
|
242
243
|
* @returns The Learning Phase API instance
|
|
243
244
|
*/
|
|
244
245
|
useLearningPhase(): EnergyAppLearningPhase;
|
|
246
|
+
/**
|
|
247
|
+
* Gets the Calibration API for reporting what an appliance was proven to do.
|
|
248
|
+
* Provides methods to open, advance and close calibration runs for
|
|
249
|
+
* batteries, wallboxes, inverters, heat pumps and heating rods, to declare
|
|
250
|
+
* their prerequisites, and to answer host requests to calibrate.
|
|
251
|
+
* @returns The Calibration API instance
|
|
252
|
+
*/
|
|
253
|
+
useCalibration(): EnergyAppCalibration;
|
|
245
254
|
/**
|
|
246
255
|
* Gets the WiFi API for scanning and listing known WiFi networks (SSIDs).
|
|
247
256
|
* Provides methods to discover saved/known SSIDs that are currently
|
|
@@ -32,6 +32,7 @@ import { EnergyAppMqtt } from "./packages/energy-app-mqtt.cjs";
|
|
|
32
32
|
import { EnergyAppBluetooth } from "./packages/energy-app-bluetooth.cjs";
|
|
33
33
|
import { EnergyAppDiagnostics } from "./packages/energy-app-diagnostics.cjs";
|
|
34
34
|
import { EnergyAppLearningPhase } from "./packages/energy-app-learning-phase.cjs";
|
|
35
|
+
import { EnergyAppCalibration } from "./packages/energy-app-calibration.cjs";
|
|
35
36
|
import { EnergyAppWifi } from "./packages/energy-app-wifi.cjs";
|
|
36
37
|
import { EnergyAppUdp } from "./packages/energy-app-udp.cjs";
|
|
37
38
|
import { EnergyAppGridConnectionPoint } from "./packages/energy-app-grid-connection-point.cjs";
|
|
@@ -141,6 +142,8 @@ export interface EnyoEnergyAppSdk {
|
|
|
141
142
|
useDiagnostics: () => EnergyAppDiagnostics;
|
|
142
143
|
/** Get the Learning Phase API for registering and tracking learning phases */
|
|
143
144
|
useLearningPhase: () => EnergyAppLearningPhase;
|
|
145
|
+
/** Get the Calibration API for reporting what an appliance was proven to do */
|
|
146
|
+
useCalibration: () => EnergyAppCalibration;
|
|
144
147
|
/** Get the WiFi API for scanning and listing known SSIDs */
|
|
145
148
|
useWifi: () => EnergyAppWifi;
|
|
146
149
|
/** Get the UDP communication API for binding sockets and exchanging datagrams */
|