@enyo-energy/energy-app-sdk 0.0.183 → 0.0.185
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 +281 -0
- package/dist/cjs/energy-app-package-definition.cjs +12 -1
- package/dist/cjs/energy-app-package-definition.d.cts +155 -1
- package/dist/cjs/energy-app-permission.type.cjs +2 -0
- package/dist/cjs/energy-app-permission.type.d.cts +4 -2
- package/dist/cjs/energy-app.cjs +45 -0
- package/dist/cjs/energy-app.d.cts +42 -0
- package/dist/cjs/enyo-energy-app-sdk.d.cts +9 -0
- package/dist/cjs/implementations/device-test/device-test-validators.cjs +223 -0
- package/dist/cjs/implementations/device-test/device-test-validators.d.cts +84 -0
- package/dist/cjs/implementations/firmware/define-firmware-file.cjs +142 -0
- package/dist/cjs/implementations/firmware/define-firmware-file.d.cts +110 -0
- package/dist/cjs/implementations/firmware/firmware-validators.cjs +314 -0
- package/dist/cjs/implementations/firmware/firmware-validators.d.cts +98 -0
- package/dist/cjs/implementations/onboarding-v2/define-onboarding-guide-v2.cjs +22 -0
- package/dist/cjs/implementations/onboarding-v2/define-onboarding-guide-v2.d.cts +17 -2
- package/dist/cjs/implementations/onboarding-v2/onboarding-v2-validators.cjs +43 -0
- package/dist/cjs/index.cjs +9 -0
- package/dist/cjs/index.d.cts +9 -0
- package/dist/cjs/packages/energy-app-device-test.cjs +2 -0
- package/dist/cjs/packages/energy-app-device-test.d.cts +123 -0
- package/dist/cjs/packages/energy-app-firmware-registry.cjs +2 -0
- package/dist/cjs/packages/energy-app-firmware-registry.d.cts +167 -0
- package/dist/cjs/packages/energy-app-savings.cjs +2 -0
- package/dist/cjs/packages/energy-app-savings.d.cts +126 -0
- package/dist/cjs/types/enyo-device-test.cjs +102 -0
- package/dist/cjs/types/enyo-device-test.d.cts +214 -0
- package/dist/cjs/types/enyo-firmware-registry.cjs +2 -0
- package/dist/cjs/types/enyo-firmware-registry.d.cts +113 -0
- package/dist/cjs/types/enyo-onboarding-v2.cjs +26 -1
- package/dist/cjs/types/enyo-onboarding-v2.d.cts +31 -1
- package/dist/cjs/types/enyo-savings.cjs +71 -0
- package/dist/cjs/types/enyo-savings.d.cts +395 -0
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/energy-app-package-definition.d.ts +155 -1
- package/dist/energy-app-package-definition.js +11 -0
- package/dist/energy-app-permission.type.d.ts +4 -2
- package/dist/energy-app-permission.type.js +2 -0
- package/dist/energy-app.d.ts +42 -0
- package/dist/energy-app.js +45 -0
- package/dist/enyo-energy-app-sdk.d.ts +9 -0
- package/dist/implementations/device-test/device-test-validators.d.ts +84 -0
- package/dist/implementations/device-test/device-test-validators.js +216 -0
- package/dist/implementations/firmware/define-firmware-file.d.ts +110 -0
- package/dist/implementations/firmware/define-firmware-file.js +136 -0
- package/dist/implementations/firmware/firmware-validators.d.ts +98 -0
- package/dist/implementations/firmware/firmware-validators.js +308 -0
- package/dist/implementations/onboarding-v2/define-onboarding-guide-v2.d.ts +17 -2
- package/dist/implementations/onboarding-v2/define-onboarding-guide-v2.js +23 -1
- package/dist/implementations/onboarding-v2/onboarding-v2-validators.js +44 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/packages/energy-app-device-test.d.ts +123 -0
- package/dist/packages/energy-app-device-test.js +1 -0
- package/dist/packages/energy-app-firmware-registry.d.ts +167 -0
- package/dist/packages/energy-app-firmware-registry.js +1 -0
- package/dist/packages/energy-app-savings.d.ts +126 -0
- package/dist/packages/energy-app-savings.js +1 -0
- package/dist/types/enyo-device-test.d.ts +214 -0
- package/dist/types/enyo-device-test.js +99 -0
- package/dist/types/enyo-firmware-registry.d.ts +113 -0
- package/dist/types/enyo-firmware-registry.js +1 -0
- package/dist/types/enyo-onboarding-v2.d.ts +31 -1
- package/dist/types/enyo-onboarding-v2.js +25 -0
- package/dist/types/enyo-savings.d.ts +395 -0
- package/dist/types/enyo-savings.js +68 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,6 +32,12 @@ The official TypeScript SDK for building Energy Apps on the enyo platform. Creat
|
|
|
32
32
|
- [NetworkAccessGuard](#networkaccessguard)
|
|
33
33
|
- [NetworkDeviceManager](#networkdevicemanager)
|
|
34
34
|
- [Startup pattern](#startup-pattern)
|
|
35
|
+
- [Firmware Update Registry](#firmware-update-registry)
|
|
36
|
+
- [Declaring firmware](#declaring-firmware)
|
|
37
|
+
- [Firmware modes](#firmware-modes)
|
|
38
|
+
- [Resolving the next version](#resolving-the-next-version)
|
|
39
|
+
- [Downloading a file](#downloading-a-file)
|
|
40
|
+
- [Validating the graph](#validating-the-graph)
|
|
35
41
|
- [Retry Framework](#retry-framework)
|
|
36
42
|
- [Device Integrations](#device-integrations)
|
|
37
43
|
- [IntegrationEnergyApp (Base Class)](#integrationenergyapp-base-class)
|
|
@@ -346,6 +352,7 @@ Energy Apps use a granular permissions system to control access to system resour
|
|
|
346
352
|
- **`PvForecastRegister`** / **`PvForecastUse`**: Publish / consume PV forecasts
|
|
347
353
|
- **`DynamicPriceForecastRegister`** / **`DynamicPriceForecastUse`**: Publish / consume dynamic-price forecasts
|
|
348
354
|
- **`PvSystemRegister`** / **`PvSystemUse`**: Register / read PV system configuration
|
|
355
|
+
- **`Savings`**: Publish and read back day-scoped savings reports
|
|
349
356
|
|
|
350
357
|
#### Site & Identity Permissions
|
|
351
358
|
|
|
@@ -468,6 +475,66 @@ const inverters = await networkDevices.search({
|
|
|
468
475
|
const deviceInfo = await networkDevices.getDeviceInfo(device.id);
|
|
469
476
|
```
|
|
470
477
|
|
|
478
|
+
#### `useDeviceTest(): EnergyAppDeviceTest`
|
|
479
|
+
|
|
480
|
+
Answer the host's "is this device yours, and did it yield appliances?" question.
|
|
481
|
+
|
|
482
|
+
Every other device API points outward — you scan, or you get notified, and you decide what to do next. This one is inverted: the host has detected a device it cannot identify on its own and calls **into** your app. Register one handler; it is used by the onboarding v2 `device-test` action, by background auto-detection, and by user-triggered re-tests (see `request.origin`).
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
await energyApp.useDeviceTest().registerDeviceTestHandler(async (request) => {
|
|
486
|
+
const devices: EnyoDeviceTestDeviceResult[] = [];
|
|
487
|
+
const appliances: EnyoDeviceTestApplianceResult[] = [];
|
|
488
|
+
|
|
489
|
+
for (const device of request.devices) {
|
|
490
|
+
const identity = await readVendorRegisters(device); // your protocol
|
|
491
|
+
if (!identity) {
|
|
492
|
+
devices.push({networkDeviceId: device.id, outcome: EnyoDeviceTestOutcomeEnum.NotSupported});
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const existing = await findApplianceForSerial(identity.serialNumber);
|
|
497
|
+
const applianceId = await energyApp.useAppliances().save(buildAppliance(device, identity), existing?.id);
|
|
498
|
+
|
|
499
|
+
appliances.push({
|
|
500
|
+
applianceId,
|
|
501
|
+
applianceType: EnyoApplianceTypeEnum.Inverter,
|
|
502
|
+
disposition: existing
|
|
503
|
+
? EnyoDeviceTestApplianceDispositionEnum.Updated
|
|
504
|
+
: EnyoDeviceTestApplianceDispositionEnum.Created,
|
|
505
|
+
networkDeviceId: device.id
|
|
506
|
+
});
|
|
507
|
+
devices.push({
|
|
508
|
+
networkDeviceId: device.id,
|
|
509
|
+
outcome: existing
|
|
510
|
+
? EnyoDeviceTestOutcomeEnum.AppliancesAlreadyExisted
|
|
511
|
+
: EnyoDeviceTestOutcomeEnum.AppliancesCreated,
|
|
512
|
+
vendor: identity.vendor,
|
|
513
|
+
model: identity.model,
|
|
514
|
+
serialNumber: identity.serialNumber
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return {
|
|
519
|
+
requestId: request.requestId,
|
|
520
|
+
outcome: aggregateDeviceTestOutcome(devices),
|
|
521
|
+
devices,
|
|
522
|
+
appliances
|
|
523
|
+
};
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
Rules worth respecting:
|
|
528
|
+
|
|
529
|
+
- **The host owns the clock.** `request.timeoutMs` is your budget; the host stops waiting when it expires and treats the run as `failed`. Your handler is *not* told, so bound socket timeouts and retries to fit and never leave connections open past the point where an answer could matter.
|
|
530
|
+
- **One handler per package.** Registering again replaces the previous one. Register during startup — a request arriving before registration is answered `failed`, which in a guided run means the installer sees the failure branch.
|
|
531
|
+
- **Answer for every device.** A twelve-device scan needs twelve verdicts; "three are mine, one needs a password, eight are the neighbour's printer" is the normal case.
|
|
532
|
+
- **`created` vs `already-existed` are different answers.** Both are successes, but the guide branches differently — one is "set up", the other "already set up".
|
|
533
|
+
- **Derive the aggregate with `aggregateDeviceTestOutcome()`.** Success dominates a sibling device's failure, and actionable outcomes outrank unactionable ones; hand-rolling that precedence is where the bugs are.
|
|
534
|
+
- **No permission is needed to register**, but the work inside needs `NetworkDeviceAccess` to reach a device and `Appliance` to create one. Without them, answer `access-not-granted` rather than throwing.
|
|
535
|
+
|
|
536
|
+
Validate a result during development with `validateDeviceTestResult(result, request)` — it catches contradictions like `appliances-created` with no created appliance, which would otherwise route an installer to a success screen for appliances that do not exist.
|
|
537
|
+
|
|
471
538
|
#### `useModbus(): EnergyAppModbus`
|
|
472
539
|
|
|
473
540
|
Access Modbus communication:
|
|
@@ -1120,6 +1187,66 @@ diag.energyManagerDiagnostics(
|
|
|
1120
1187
|
);
|
|
1121
1188
|
```
|
|
1122
1189
|
|
|
1190
|
+
#### `useSavings(): EnergyAppSavings`
|
|
1191
|
+
|
|
1192
|
+
Publish what the energy management saved the customer on a finished day, and read back which days were already reported.
|
|
1193
|
+
|
|
1194
|
+
The app settles a day by replaying its **measured** environment through a simulation of the same house running **uncontrolled**, and pricing both worlds against the tariff that actually applied. Publishing is an upsert keyed by `dayIso` + `method`, so a day may be recomputed after a backfill or a bugfix. The platform stores days and owns every aggregation above them (month, year, lifetime) — and excludes `Low` confidence days from those rollups.
|
|
1195
|
+
|
|
1196
|
+
```typescript
|
|
1197
|
+
const savings = energyApp.useSavings();
|
|
1198
|
+
|
|
1199
|
+
// On boot: which days still need settling?
|
|
1200
|
+
const { missingDayIsos } = await savings.getDailySavings({
|
|
1201
|
+
startDayIso: '2026-07-01',
|
|
1202
|
+
endDayIso: '2026-07-31'
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
for (const dayIso of missingDayIsos) {
|
|
1206
|
+
await savings.publishDailySavings({
|
|
1207
|
+
schemaVersion: 1,
|
|
1208
|
+
dayIso,
|
|
1209
|
+
timeZone: 'Europe/Berlin',
|
|
1210
|
+
dayStartUtcMs: startOfLocalDayUtcMs(dayIso),
|
|
1211
|
+
dayEndUtcMs: endOfLocalDayUtcMs(dayIso), // 23 or 25 h on DST days
|
|
1212
|
+
method: EnyoSavingsMethodEnum.Settled,
|
|
1213
|
+
computedAtIso: new Date().toISOString(),
|
|
1214
|
+
calculatorVersion: '3.2.0',
|
|
1215
|
+
confidence: EnyoSavingsConfidenceEnum.High,
|
|
1216
|
+
confidenceIssues: [],
|
|
1217
|
+
costs: {
|
|
1218
|
+
currency: EnyoCurrencyEnum.EUR,
|
|
1219
|
+
optimizedCost: 1.42,
|
|
1220
|
+
baselineCost: 3.07,
|
|
1221
|
+
savings: 1.65,
|
|
1222
|
+
savingsFromSelfConsumption: 1.12,
|
|
1223
|
+
savingsFromArbitrage: 0.53
|
|
1224
|
+
},
|
|
1225
|
+
energy: { /* both worlds, Wh */ },
|
|
1226
|
+
metrics: { /* both worlds */ },
|
|
1227
|
+
attribution: [
|
|
1228
|
+
{ applianceType: EnergyAppApplianceTypeEnum.Charger, savings: 0.91, shiftedEnergyWh: 12400 }
|
|
1229
|
+
],
|
|
1230
|
+
coverage: [
|
|
1231
|
+
{ series: 'pv', source: EnyoSavingsDataSourceEnum.Measured, expectedBuckets: 96, presentBuckets: 96 }
|
|
1232
|
+
],
|
|
1233
|
+
assumptions: [
|
|
1234
|
+
{ key: 'battery.dischargeEfficiency', value: 0.95 }
|
|
1235
|
+
]
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
```
|
|
1239
|
+
|
|
1240
|
+
Notes worth respecting when producing a report:
|
|
1241
|
+
|
|
1242
|
+
- **Publish both worlds, never only the delta.** A lone savings number is unauditable and cannot be re-aggregated.
|
|
1243
|
+
- **Assumptions travel with the report.** The counterfactual rests on guesses; without them, changing a default silently rewrites history.
|
|
1244
|
+
- **`dayIso` is a local calendar date.** The IANA zone and the exact UTC bounds go alongside — anything assuming 96 buckets is wrong twice a year.
|
|
1245
|
+
- **Per-slot detail (`slots`) is opt-in.** Settlement is stateless, so the app can regenerate it on demand; only publish it for days under investigation.
|
|
1246
|
+
- **Units follow the platform:** energy in Wh, power in W, prices per kWh, currency as `EnyoCurrencyEnum`.
|
|
1247
|
+
|
|
1248
|
+
Requires the `Savings` permission.
|
|
1249
|
+
|
|
1123
1250
|
### Operational Utilities
|
|
1124
1251
|
|
|
1125
1252
|
#### `useOnboarding(): EnergyAppOnboarding`
|
|
@@ -1567,6 +1694,160 @@ async function connectDevice(networkDeviceId: string) {
|
|
|
1567
1694
|
|
|
1568
1695
|
This pattern matches the wiring used by real Sungrow / Fronius energy-app packages: one `NetworkDeviceManager` per package, `ensureAccess` before every connect, `withAccessGuard` around every poll, and a single `getDevices({ accessStatus: 'granted' })` pass at startup to cover the warm-restart case.
|
|
1569
1696
|
|
|
1697
|
+
## Firmware Update Registry
|
|
1698
|
+
|
|
1699
|
+
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.
|
|
1700
|
+
|
|
1701
|
+
Requires the `FirmwareRegistry` permission.
|
|
1702
|
+
|
|
1703
|
+
**Firmware versions are opaque strings.** A version is whatever the vendor calls it — `2.4.1`, `2024-11-rc3`, `A7F2` — and is never parsed, ordered, or compared beyond exact equality. Nothing can be derived from the string itself, so the update order is declared rather than computed. `firmwareMode` picks which form that takes.
|
|
1704
|
+
|
|
1705
|
+
### Firmware modes
|
|
1706
|
+
|
|
1707
|
+
| `firmwareMode` | Order comes from | Use when |
|
|
1708
|
+
|---|---|---|
|
|
1709
|
+
| `'latest'` *(default)* | **Declaration order** — the last entry declared for the device's model is always the one offered | Devices accept any image directly |
|
|
1710
|
+
| `'dependent'` | The explicit **`installForFirmwareVersion`** edges on each entry | Devices must be stepped through intermediate versions |
|
|
1711
|
+
|
|
1712
|
+
### Declaring firmware
|
|
1713
|
+
|
|
1714
|
+
`firmwareMode: 'latest'` — a plain list, last one wins:
|
|
1715
|
+
|
|
1716
|
+
```typescript
|
|
1717
|
+
import { defineEnergyAppPackage, defineFirmwareFile, EnergyAppPackageFirmwareModeEnum, EnergyAppPermissionTypeEnum } from '@enyo-energy/energy-app-sdk';
|
|
1718
|
+
|
|
1719
|
+
export default defineEnergyAppPackage({
|
|
1720
|
+
version: '1',
|
|
1721
|
+
packageName: 'acme-wallbox',
|
|
1722
|
+
// ...
|
|
1723
|
+
permissions: [EnergyAppPermissionTypeEnum.FirmwareRegistry],
|
|
1724
|
+
firmwareMode: EnergyAppPackageFirmwareModeEnum.Latest,
|
|
1725
|
+
firmware: [
|
|
1726
|
+
defineFirmwareFile({
|
|
1727
|
+
fileId: 'ac22-2024-11',
|
|
1728
|
+
path: './firmware/ac22-2024-11.bin',
|
|
1729
|
+
firmwareVersion: '2024-11-rc3',
|
|
1730
|
+
modelNames: ['AC-22-Pro']
|
|
1731
|
+
}),
|
|
1732
|
+
defineFirmwareFile({
|
|
1733
|
+
fileId: 'ac22-current',
|
|
1734
|
+
path: './firmware/ac22-current.bin',
|
|
1735
|
+
firmwareVersion: 'A7F2',
|
|
1736
|
+
modelNames: ['AC-22-Pro']
|
|
1737
|
+
})
|
|
1738
|
+
// ↑ last declared for AC-22-Pro — every AC-22-Pro is offered this one
|
|
1739
|
+
]
|
|
1740
|
+
});
|
|
1741
|
+
```
|
|
1742
|
+
|
|
1743
|
+
`firmwareMode: 'dependent'` — each entry declares the versions it installs *for*:
|
|
1744
|
+
|
|
1745
|
+
```typescript
|
|
1746
|
+
firmwareMode: EnergyAppPackageFirmwareModeEnum.Dependent,
|
|
1747
|
+
firmware: [
|
|
1748
|
+
defineFirmwareFile({
|
|
1749
|
+
fileId: 'ac22-baseline',
|
|
1750
|
+
path: './firmware/ac22-2024-11-rc3.bin',
|
|
1751
|
+
firmwareVersion: '2024-11-rc3',
|
|
1752
|
+
modelNames: ['AC-22-Pro'],
|
|
1753
|
+
// offered to devices whose reported version matches no declared entry
|
|
1754
|
+
fallbackForUnknownVersion: true
|
|
1755
|
+
}),
|
|
1756
|
+
defineFirmwareFile({
|
|
1757
|
+
fileId: 'ac22-hotfix-a',
|
|
1758
|
+
path: './firmware/ac22-hotfix-a.bin',
|
|
1759
|
+
firmwareVersion: 'A7F2',
|
|
1760
|
+
installForFirmwareVersion: ['2024-11-rc3'],
|
|
1761
|
+
modelNames: ['AC-22-Pro']
|
|
1762
|
+
}),
|
|
1763
|
+
defineFirmwareFile({
|
|
1764
|
+
fileId: 'ac22-stable',
|
|
1765
|
+
path: './firmware/ac22-stable.bin',
|
|
1766
|
+
firmwareVersion: '1.0',
|
|
1767
|
+
// collapses two old versions into one image
|
|
1768
|
+
installForFirmwareVersion: ['A7F2', 'legacy-b'],
|
|
1769
|
+
modelNames: ['AC-22-Pro'],
|
|
1770
|
+
releaseNotes: [
|
|
1771
|
+
{ language: 'en', value: 'Fixes phase rotation detection.' },
|
|
1772
|
+
{ language: 'de', value: 'Behebt die Erkennung der Phasenlage.' }
|
|
1773
|
+
]
|
|
1774
|
+
})
|
|
1775
|
+
]
|
|
1776
|
+
```
|
|
1777
|
+
|
|
1778
|
+
`installForFirmwareVersion` is the whole graph. Three entries each naming their predecessor form a chain; two entries naming the same predecessor for *different* models form a branch; one entry naming several predecessors merges old versions into a single image. Omitting it makes an entry a root that is never offered as an update to a known version. Under `'latest'` the field is ignored (and the validator warns if you set it).
|
|
1779
|
+
|
|
1780
|
+
`modelNames` scopes resolution in both modes — an entry without it applies to every model the package supports.
|
|
1781
|
+
|
|
1782
|
+
### Resolving the next version
|
|
1783
|
+
|
|
1784
|
+
```typescript
|
|
1785
|
+
const registry = energyApp.useFirmwareRegistry();
|
|
1786
|
+
|
|
1787
|
+
const next = await registry.getNextFirmware(device.reportedVersion, { modelName: 'AC-22-Pro' });
|
|
1788
|
+
if (!next) {
|
|
1789
|
+
// Already up to date — the normal outcome, not an error.
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
console.log(`Update available: ${next.firmwareVersion} (${next.sizeBytes} bytes)`);
|
|
1793
|
+
```
|
|
1794
|
+
|
|
1795
|
+
Under `'dependent'`, `getNextFirmware()` returns **one hop**, not the destination. After the device installs the image and reports its new version, call again to continue the chain — each step is verified on the device before the next is offered. When you need the whole chain up front:
|
|
1796
|
+
|
|
1797
|
+
```typescript
|
|
1798
|
+
const path = await registry.getFirmwareUpdatePath(device.reportedVersion, { modelName: 'AC-22-Pro' });
|
|
1799
|
+
const totalMb = path.reduce((sum, file) => sum + file.sizeBytes, 0) / 1_000_000;
|
|
1800
|
+
console.log(`${path.length} updates pending, ${totalMb.toFixed(1)} MB total`);
|
|
1801
|
+
```
|
|
1802
|
+
|
|
1803
|
+
Under `'latest'` there is no chain to walk: `getNextFirmware()` hands back the last declared entry for the model until the device runs it, and `getFirmwareUpdatePath()` never returns more than one entry.
|
|
1804
|
+
|
|
1805
|
+
### Downloading a file
|
|
1806
|
+
|
|
1807
|
+
Firmware images are large, so the bytes never cross the app/host boundary. Request a signed, time-limited URL instead — one that many wallboxes and inverters can fetch themselves:
|
|
1808
|
+
|
|
1809
|
+
```typescript
|
|
1810
|
+
const download = await registry.requestDownloadUrl(next.fileId, { ttlSeconds: 900 });
|
|
1811
|
+
|
|
1812
|
+
// Either hand the URL to the device...
|
|
1813
|
+
await device.installFirmwareFromUrl(download.url, download.sha256);
|
|
1814
|
+
|
|
1815
|
+
// ...or stream it into the app.
|
|
1816
|
+
const response = await fetch(download.url);
|
|
1817
|
+
```
|
|
1818
|
+
|
|
1819
|
+
Two rules:
|
|
1820
|
+
|
|
1821
|
+
- **Request the URL at the moment of use.** It expires at `download.expiresAt` (epoch ms) and the storage backend then rejects it. Never cache or persist it.
|
|
1822
|
+
- **Always verify `sha256`** against the downloaded bytes before flashing.
|
|
1823
|
+
|
|
1824
|
+
### Validating the graph
|
|
1825
|
+
|
|
1826
|
+
An ambiguous or cyclic `'dependent'` graph has no correct resolution at runtime, so validate before releasing:
|
|
1827
|
+
|
|
1828
|
+
```typescript
|
|
1829
|
+
import { validateFirmwareRegistry, assertValidFirmwareRegistry } from '@enyo-energy/energy-app-sdk';
|
|
1830
|
+
|
|
1831
|
+
const result = validateFirmwareRegistry(packageDefinition);
|
|
1832
|
+
if (!result.ok) console.error(result.errors);
|
|
1833
|
+
console.warn(result.warnings);
|
|
1834
|
+
|
|
1835
|
+
assertValidFirmwareRegistry(packageDefinition); // or throw on the first failure
|
|
1836
|
+
```
|
|
1837
|
+
|
|
1838
|
+
Blocking errors in both modes: duplicate `fileId`s, two entries installing the same version for overlapping models, and declaring firmware without the `FirmwareRegistry` permission. Under `'dependent'` additionally: two entries installing for the same current version on overlapping models, cycles, an entry listing its own version in `installForFirmwareVersion`, and multiple fallbacks per model.
|
|
1839
|
+
|
|
1840
|
+
Warnings: under `'latest'`, entries that declare `installForFirmwareVersion` or `fallbackForUnknownVersion` — both are ignored there, so declaring them usually means `'dependent'` was intended. Under `'dependent'`: a source version matching no declared entry — which is exactly how you attach a chain to firmware that shipped before this registry existed — and entries that are neither reachable nor a fallback. In both modes: models or vendors missing from `compatibility`.
|
|
1841
|
+
|
|
1842
|
+
For local unit tests, `resolveNextFirmware()` and `resolveFirmwareUpdatePath()` run the same resolution the host performs, against a plain array of entries:
|
|
1843
|
+
|
|
1844
|
+
```typescript
|
|
1845
|
+
resolveNextFirmware(definition.firmware ?? [], currentVersion, {
|
|
1846
|
+
modelName: 'AC-22-Pro',
|
|
1847
|
+
firmwareMode: definition.firmwareMode
|
|
1848
|
+
});
|
|
1849
|
+
```
|
|
1850
|
+
|
|
1570
1851
|
## Retry Framework
|
|
1571
1852
|
|
|
1572
1853
|
`RetryManager` centralises retry / backoff / circuit-breaker logic so polling loops don't have to reinvent it. Register one entry per logical operation, give it a `RetryPolicy`, and run attempts through `execute(id, fn)` — the manager handles attempt counting, exponential backoff, transition into `Open` after repeated failures, and recovery on the next success.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.EnergyAppPackageCategory = void 0;
|
|
3
|
+
exports.EnergyAppPackageFirmwareModeEnum = exports.EnergyAppPackageCategory = void 0;
|
|
4
4
|
exports.defineEnergyAppPackage = defineEnergyAppPackage;
|
|
5
5
|
const version_js_1 = require("./version.cjs");
|
|
6
6
|
var EnergyAppPackageCategory;
|
|
@@ -20,6 +20,17 @@ var EnergyAppPackageCategory;
|
|
|
20
20
|
EnergyAppPackageCategory["HeatingRod"] = "heating-rod";
|
|
21
21
|
EnergyAppPackageCategory["Other"] = "other";
|
|
22
22
|
})(EnergyAppPackageCategory || (exports.EnergyAppPackageCategory = EnergyAppPackageCategory = {}));
|
|
23
|
+
/**
|
|
24
|
+
* Enum form of {@link EnergyAppPackageFirmwareMode} for use in package
|
|
25
|
+
* definitions.
|
|
26
|
+
*/
|
|
27
|
+
var EnergyAppPackageFirmwareModeEnum;
|
|
28
|
+
(function (EnergyAppPackageFirmwareModeEnum) {
|
|
29
|
+
/** Always offer the last declared firmware entry for the device's model. */
|
|
30
|
+
EnergyAppPackageFirmwareModeEnum["Latest"] = "latest";
|
|
31
|
+
/** Follow the explicit `installForFirmwareVersion` upgrade graph. */
|
|
32
|
+
EnergyAppPackageFirmwareModeEnum["Dependent"] = "dependent";
|
|
33
|
+
})(EnergyAppPackageFirmwareModeEnum || (exports.EnergyAppPackageFirmwareModeEnum = EnergyAppPackageFirmwareModeEnum = {}));
|
|
23
34
|
/**
|
|
24
35
|
* Defines an Energy App package with automatic SDK version injection.
|
|
25
36
|
* This function automatically adds the current SDK version to the package definition
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EnergyAppPermissionType } from "./energy-app-permission.type.cjs";
|
|
2
2
|
import { EnergyAppModelFeatureEnum } from "./energy-app-model-feature.enum.cjs";
|
|
3
|
+
import type { EnyoFileTranslation } from "./types/enyo-file.cjs";
|
|
3
4
|
export type EnergyAppPackageLanguage = 'de' | 'en';
|
|
4
5
|
export declare enum EnergyAppPackageCategory {
|
|
5
6
|
Inverter = "inverter",
|
|
@@ -219,7 +220,12 @@ export interface EnergyAppPackageCompatibilityModel {
|
|
|
219
220
|
displayName?: string;
|
|
220
221
|
/**
|
|
221
222
|
* Optional minimum firmware version the package supports for this model.
|
|
222
|
-
*
|
|
223
|
+
*
|
|
224
|
+
* A free-form, vendor-defined string used for display and internal
|
|
225
|
+
* documentation only. It is **not** an ordering primitive: firmware versions
|
|
226
|
+
* are opaque and are never parsed or compared by the SDK or the host. To
|
|
227
|
+
* express which firmware can be updated to which, declare the explicit
|
|
228
|
+
* upgrade graph in {@link EnergyAppPackageDefinition.firmware} instead.
|
|
223
229
|
*/
|
|
224
230
|
minimumFirmwareVersion?: string;
|
|
225
231
|
/** Optional internal note explaining model-specific caveats or limitations */
|
|
@@ -243,6 +249,134 @@ export interface EnergyAppPackageCompatibilityVendor {
|
|
|
243
249
|
/** Models from this vendor that the package supports */
|
|
244
250
|
models: EnergyAppPackageCompatibilityModel[];
|
|
245
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* How the firmware registry decides which image a device should install next.
|
|
254
|
+
*
|
|
255
|
+
* - `'latest'` — every device is offered the **last declared** firmware entry
|
|
256
|
+
* that applies to its model, whatever version it currently runs. Since
|
|
257
|
+
* firmware versions are opaque strings and cannot be ordered, "latest" means
|
|
258
|
+
* last in the `firmware` array — declaration order *is* the order. Use this
|
|
259
|
+
* for devices that accept any image directly; `installForFirmwareVersion` is
|
|
260
|
+
* ignored.
|
|
261
|
+
* - `'dependent'` — the update order is the explicit graph declared through
|
|
262
|
+
* {@link EnergyAppPackageFirmwareFile.installForFirmwareVersion}: each image
|
|
263
|
+
* names the versions it can be installed on top of, and the registry walks
|
|
264
|
+
* that graph one hop at a time. Use this for devices that must be stepped
|
|
265
|
+
* through intermediate versions.
|
|
266
|
+
*/
|
|
267
|
+
export type EnergyAppPackageFirmwareMode = 'latest' | 'dependent';
|
|
268
|
+
/**
|
|
269
|
+
* Enum form of {@link EnergyAppPackageFirmwareMode} for use in package
|
|
270
|
+
* definitions.
|
|
271
|
+
*/
|
|
272
|
+
export declare enum EnergyAppPackageFirmwareModeEnum {
|
|
273
|
+
/** Always offer the last declared firmware entry for the device's model. */
|
|
274
|
+
Latest = "latest",
|
|
275
|
+
/** Follow the explicit `installForFirmwareVersion` upgrade graph. */
|
|
276
|
+
Dependent = "dependent"
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* A firmware image published together with an Energy App package.
|
|
280
|
+
*
|
|
281
|
+
* The file is declared here by its local `path`; the enyo CLI uploads it during
|
|
282
|
+
* `enyo release`, replacing the path with a registry reference, so the released
|
|
283
|
+
* package tarball never carries the bytes. At runtime the app reaches the
|
|
284
|
+
* uploaded image through {@link EnergyAppFirmwareRegistry}.
|
|
285
|
+
*
|
|
286
|
+
* **Firmware versions are opaque strings.** `firmwareVersion` is whatever the
|
|
287
|
+
* vendor calls it — `'2.4.1'`, `'2024-11-rc3'`, `'A7F2'` — and is never parsed,
|
|
288
|
+
* ordered or compared beyond exact string equality. Nothing can therefore be
|
|
289
|
+
* derived from the string itself, which is why the order comes from
|
|
290
|
+
* {@link EnergyAppPackageDefinition.firmwareMode}: declaration order under
|
|
291
|
+
* `'latest'`, or the explicit {@link installForFirmwareVersion} edges under
|
|
292
|
+
* `'dependent'`.
|
|
293
|
+
*
|
|
294
|
+
* Under `'dependent'`, chains, branches and merges all fall out of that one
|
|
295
|
+
* field: three entries each naming their predecessor form a chain; two entries
|
|
296
|
+
* naming the same predecessor for different models form a branch; one entry
|
|
297
|
+
* naming several predecessors collapses old versions into a single image.
|
|
298
|
+
*
|
|
299
|
+
* Validate the declaration with `validateFirmwareRegistry()` before releasing —
|
|
300
|
+
* an ambiguous or cyclic graph has no correct resolution and is rejected rather
|
|
301
|
+
* than silently resolved.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* // firmwareMode: 'dependent' — stepped through intermediate versions
|
|
306
|
+
* firmware: [
|
|
307
|
+
* defineFirmwareFile({
|
|
308
|
+
* fileId: 'ac22-baseline',
|
|
309
|
+
* path: './firmware/ac22-2024-11-rc3.bin',
|
|
310
|
+
* firmwareVersion: '2024-11-rc3',
|
|
311
|
+
* modelNames: ['AC-22-Pro'],
|
|
312
|
+
* fallbackForUnknownVersion: true
|
|
313
|
+
* }),
|
|
314
|
+
* defineFirmwareFile({
|
|
315
|
+
* fileId: 'ac22-hotfix-a',
|
|
316
|
+
* path: './firmware/ac22-hotfix-a.bin',
|
|
317
|
+
* firmwareVersion: 'hotfix-a',
|
|
318
|
+
* installForFirmwareVersion: ['2024-11-rc3'],
|
|
319
|
+
* modelNames: ['AC-22-Pro']
|
|
320
|
+
* })
|
|
321
|
+
* ]
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
export interface EnergyAppPackageFirmwareFile {
|
|
325
|
+
/**
|
|
326
|
+
* Stable, app-chosen identifier for this firmware image. Used as the lookup
|
|
327
|
+
* key at runtime and must be unique within the package.
|
|
328
|
+
*/
|
|
329
|
+
fileId: string;
|
|
330
|
+
/**
|
|
331
|
+
* Path to the firmware file relative to the package root, e.g.
|
|
332
|
+
* `'./firmware/wallbox-2.4.1.bin'`. Resolved and uploaded by the enyo CLI on
|
|
333
|
+
* release; the published definition carries a registry reference instead.
|
|
334
|
+
*/
|
|
335
|
+
path: string;
|
|
336
|
+
/**
|
|
337
|
+
* The firmware version this file installs. An opaque, vendor-defined string
|
|
338
|
+
* that is only ever equality-matched — never parsed or ordered.
|
|
339
|
+
*/
|
|
340
|
+
firmwareVersion: string;
|
|
341
|
+
/**
|
|
342
|
+
* The versions this image is installed for — the incoming edges of this node
|
|
343
|
+
* in the upgrade graph. Each string is matched by exact equality against the
|
|
344
|
+
* version a device reports as currently installed; when it matches, this
|
|
345
|
+
* image is the device's next step.
|
|
346
|
+
*
|
|
347
|
+
* Only meaningful when {@link EnergyAppPackageDefinition.firmwareMode} is
|
|
348
|
+
* `'dependent'`; ignored under `'latest'`.
|
|
349
|
+
*
|
|
350
|
+
* Omit (or leave empty) for a root entry: one that heads a chain and is
|
|
351
|
+
* never offered as an update to a known version.
|
|
352
|
+
*/
|
|
353
|
+
installForFirmwareVersion?: string[];
|
|
354
|
+
/**
|
|
355
|
+
* When true, this image is offered to devices whose reported version matches
|
|
356
|
+
* no declared node — a recovery or baseline image. At most one entry per
|
|
357
|
+
* model may set this.
|
|
358
|
+
*
|
|
359
|
+
* Only meaningful under `firmwareMode: 'dependent'`; ignored under
|
|
360
|
+
* `'latest'`, where every unrecognised version already receives the last
|
|
361
|
+
* declared image.
|
|
362
|
+
*/
|
|
363
|
+
fallbackForUnknownVersion?: boolean;
|
|
364
|
+
/**
|
|
365
|
+
* Optional vendor this firmware belongs to. Should match a `vendorName` from
|
|
366
|
+
* {@link EnergyAppPackageDefinition.compatibility}.
|
|
367
|
+
*/
|
|
368
|
+
vendorName?: string;
|
|
369
|
+
/**
|
|
370
|
+
* Optional models this firmware applies to. Scopes graph resolution: an
|
|
371
|
+
* update is only offered to a device whose model is listed here. Omit when
|
|
372
|
+
* the image applies to every model the package supports.
|
|
373
|
+
*/
|
|
374
|
+
modelNames?: string[];
|
|
375
|
+
/** Optional translated release notes shown in the host UI. */
|
|
376
|
+
releaseNotes?: EnyoFileTranslation[];
|
|
377
|
+
/** Optional internal note explaining this image; never shown to users. */
|
|
378
|
+
internalComment?: string;
|
|
379
|
+
}
|
|
246
380
|
/**
|
|
247
381
|
* Complete definition for a enyo Energy App package.
|
|
248
382
|
* This interface defines all the metadata, permissions, and configuration
|
|
@@ -277,6 +411,26 @@ export interface EnergyAppPackageDefinition {
|
|
|
277
411
|
* single vendor implicitly or has no fixed compatibility surface.
|
|
278
412
|
*/
|
|
279
413
|
compatibility: EnergyAppPackageCompatibilityVendor[];
|
|
414
|
+
/**
|
|
415
|
+
* Firmware images shipped with this package, declared as local file paths
|
|
416
|
+
* and uploaded by the enyo CLI on release.
|
|
417
|
+
*
|
|
418
|
+
* The app reaches them at runtime through
|
|
419
|
+
* {@link EnergyAppFirmwareRegistry}; how the next image is chosen is set by
|
|
420
|
+
* {@link firmwareMode}. Requires the `FirmwareRegistry` permission. Omit for
|
|
421
|
+
* packages that do not distribute firmware.
|
|
422
|
+
*/
|
|
423
|
+
firmware?: EnergyAppPackageFirmwareFile[];
|
|
424
|
+
/**
|
|
425
|
+
* How the registry picks the next image for a device. Defaults to
|
|
426
|
+
* `'latest'`, which always offers the last declared entry for the device's
|
|
427
|
+
* model. Set to `'dependent'` when devices must be stepped through
|
|
428
|
+
* intermediate versions — the order is then taken from each entry's
|
|
429
|
+
* `installForFirmwareVersion` edges.
|
|
430
|
+
*
|
|
431
|
+
* Only relevant when {@link firmware} is declared.
|
|
432
|
+
*/
|
|
433
|
+
firmwareMode?: EnergyAppPackageFirmwareMode;
|
|
280
434
|
}
|
|
281
435
|
/**
|
|
282
436
|
* Defines an Energy App package with automatic SDK version injection.
|
|
@@ -50,4 +50,6 @@ var EnergyAppPermissionTypeEnum;
|
|
|
50
50
|
EnergyAppPermissionTypeEnum["Udp"] = "Udp";
|
|
51
51
|
EnergyAppPermissionTypeEnum["ProvidedFiles"] = "ProvidedFiles";
|
|
52
52
|
EnergyAppPermissionTypeEnum["Automation"] = "Automation";
|
|
53
|
+
EnergyAppPermissionTypeEnum["Savings"] = "Savings";
|
|
54
|
+
EnergyAppPermissionTypeEnum["FirmwareRegistry"] = "FirmwareRegistry";
|
|
53
55
|
})(EnergyAppPermissionTypeEnum || (exports.EnergyAppPermissionTypeEnum = EnergyAppPermissionTypeEnum = {}));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type EnergyAppPermissionType = 'RestrictedInternetAccess' | 'NetworkDeviceDiscovery' | 'NetworkDeviceSearch' | 'NetworkDeviceAccess' | 'AllNetworkDeviceAccess' | 'Modbus' | 'Storage' | 'Appliance' | 'AllAppliances' | 'SendDataBusValues' | 'SubscribeDataBus' | 'SendDataBusCommands' | 'OcppServer' | 'ChargingCard' | 'Vehicle' | 'Charge' | 'SecretManager' | 'LocationZipCode' | 'LocationCoordinates' | 'Timeseries' | 'EnergyManagerInfo' | 'ElectricityTariff' | 'WeatherForecastRegister' | 'WeatherForecastUse' | 'PvForecastRegister' | 'PvForecastUse' | 'DynamicPriceForecastRegister' | 'DynamicPriceForecastUse' | 'PvSystemRegister' | 'PvSystemUse' | 'InverterControlCommands' | 'BatteryControlCommands' | 'BatteryStorageState' | 'ChargerControlCommands' | 'ModbusRtu' | 'EnergyPrices' | 'EnergyManager' | 'EebusDeviceManagement' | 'EebusDataAccess' | 'EebusControl' | 'Mqtt' | 'Bluetooth' | 'Wifi' | 'ChildProcess' | 'Udp' | 'ProvidedFiles' | 'Automation';
|
|
1
|
+
export type EnergyAppPermissionType = 'RestrictedInternetAccess' | 'NetworkDeviceDiscovery' | 'NetworkDeviceSearch' | 'NetworkDeviceAccess' | 'AllNetworkDeviceAccess' | 'Modbus' | 'Storage' | 'Appliance' | 'AllAppliances' | 'SendDataBusValues' | 'SubscribeDataBus' | 'SendDataBusCommands' | 'OcppServer' | 'ChargingCard' | 'Vehicle' | 'Charge' | 'SecretManager' | 'LocationZipCode' | 'LocationCoordinates' | 'Timeseries' | 'EnergyManagerInfo' | 'ElectricityTariff' | 'WeatherForecastRegister' | 'WeatherForecastUse' | 'PvForecastRegister' | 'PvForecastUse' | 'DynamicPriceForecastRegister' | 'DynamicPriceForecastUse' | 'PvSystemRegister' | 'PvSystemUse' | 'InverterControlCommands' | 'BatteryControlCommands' | 'BatteryStorageState' | 'ChargerControlCommands' | 'ModbusRtu' | 'EnergyPrices' | 'EnergyManager' | 'EebusDeviceManagement' | 'EebusDataAccess' | 'EebusControl' | 'Mqtt' | 'Bluetooth' | 'Wifi' | 'ChildProcess' | 'Udp' | 'ProvidedFiles' | 'Automation' | 'Savings' | 'FirmwareRegistry';
|
|
2
2
|
export declare enum EnergyAppPermissionTypeEnum {
|
|
3
3
|
RestrictedInternetAccess = "RestrictedInternetAccess",
|
|
4
4
|
NetworkDeviceDiscovery = "NetworkDeviceDiscovery",
|
|
@@ -46,5 +46,7 @@ export declare enum EnergyAppPermissionTypeEnum {
|
|
|
46
46
|
ChildProcess = "ChildProcess",
|
|
47
47
|
Udp = "Udp",
|
|
48
48
|
ProvidedFiles = "ProvidedFiles",
|
|
49
|
-
Automation = "Automation"
|
|
49
|
+
Automation = "Automation",
|
|
50
|
+
Savings = "Savings",
|
|
51
|
+
FirmwareRegistry = "FirmwareRegistry"
|
|
50
52
|
}
|
package/dist/cjs/energy-app.cjs
CHANGED
|
@@ -339,6 +339,23 @@ class EnergyApp {
|
|
|
339
339
|
useFiles() {
|
|
340
340
|
return this.energyAppSdk.useFiles();
|
|
341
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* Gets the Firmware Registry API for the firmware images published with this
|
|
344
|
+
* package.
|
|
345
|
+
*
|
|
346
|
+
* Firmware versions are opaque vendor strings, so the update order is
|
|
347
|
+
* declared explicitly in the package definition as an upgrade graph. Call
|
|
348
|
+
* `getNextFirmware(currentVersion)` to resolve the single next step for a
|
|
349
|
+
* device — it returns `undefined` when the device is already up to date —
|
|
350
|
+
* then `requestDownloadUrl()` for a signed, time-limited URL the device can
|
|
351
|
+
* fetch itself.
|
|
352
|
+
* @returns The Firmware Registry API instance
|
|
353
|
+
* @throws {EnergyAppPermissionNotGrantedError} If the `FirmwareRegistry`
|
|
354
|
+
* permission is not granted.
|
|
355
|
+
*/
|
|
356
|
+
useFirmwareRegistry() {
|
|
357
|
+
return this.energyAppSdk.useFirmwareRegistry();
|
|
358
|
+
}
|
|
342
359
|
/**
|
|
343
360
|
* Gets the Automation API for reading user-configured automations and
|
|
344
361
|
* listening for their creation, update and removal. Apps holding the
|
|
@@ -352,6 +369,34 @@ class EnergyApp {
|
|
|
352
369
|
useAutomations() {
|
|
353
370
|
return this.energyAppSdk.useAutomations();
|
|
354
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Gets the Savings API for publishing day-scoped savings reports and reading
|
|
374
|
+
* them back. An energy manager app settles a finished day by replaying its
|
|
375
|
+
* measured environment against an uncontrolled simulation and publishes both
|
|
376
|
+
* worlds here; the platform stores the days and owns every aggregation above
|
|
377
|
+
* them (month, year, lifetime).
|
|
378
|
+
* @returns The Savings API instance
|
|
379
|
+
* @throws {EnergyAppPermissionNotGrantedError} If the `Savings` permission is
|
|
380
|
+
* not granted.
|
|
381
|
+
*/
|
|
382
|
+
useSavings() {
|
|
383
|
+
return this.energyAppSdk.useSavings();
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Gets the Device Test API for answering the host's requests to test
|
|
387
|
+
* detected network devices. The app registers one handler; the host calls it
|
|
388
|
+
* from an onboarding v2 `device-test` action, from background auto-detection,
|
|
389
|
+
* or from a user-triggered re-test, and branches on whether appliances were
|
|
390
|
+
* found or created.
|
|
391
|
+
*
|
|
392
|
+
* Available to every app — this API is not permission-gated, though reaching
|
|
393
|
+
* a device (`NetworkDeviceAccess`) and creating an appliance (`Appliance`)
|
|
394
|
+
* still are.
|
|
395
|
+
* @returns The Device Test API instance
|
|
396
|
+
*/
|
|
397
|
+
useDeviceTest() {
|
|
398
|
+
return this.energyAppSdk.useDeviceTest();
|
|
399
|
+
}
|
|
355
400
|
/**
|
|
356
401
|
* Gets the current SDK version.
|
|
357
402
|
* @returns The semantic version string of the SDK
|
|
@@ -38,7 +38,10 @@ import { EnergyAppConfigurationManager } from "./packages/energy-app-configurati
|
|
|
38
38
|
import { EnergyAppApplianceEnergyManagerForecast } from "./packages/energy-app-appliance-energy-manager-forecast.cjs";
|
|
39
39
|
import { EnergyAppBattery } from "./packages/energy-app-battery.cjs";
|
|
40
40
|
import { EnergyAppFile } from "./packages/energy-app-file.cjs";
|
|
41
|
+
import { EnergyAppFirmwareRegistry } from "./packages/energy-app-firmware-registry.cjs";
|
|
41
42
|
import { EnergyAppAutomation } from "./packages/energy-app-automation.cjs";
|
|
43
|
+
import { EnergyAppSavings } from "./packages/energy-app-savings.cjs";
|
|
44
|
+
import { EnergyAppDeviceTest } from "./packages/energy-app-device-test.cjs";
|
|
42
45
|
import { UseFetchOptions } from "./types/enyo-fetch.cjs";
|
|
43
46
|
/**
|
|
44
47
|
* Concrete implementation of {@link EnyoEnergyAppSdk} that delegates every call
|
|
@@ -270,6 +273,21 @@ export declare class EnergyApp implements EnyoEnergyAppSdk {
|
|
|
270
273
|
* permission is not granted.
|
|
271
274
|
*/
|
|
272
275
|
useFiles(): EnergyAppFile;
|
|
276
|
+
/**
|
|
277
|
+
* Gets the Firmware Registry API for the firmware images published with this
|
|
278
|
+
* package.
|
|
279
|
+
*
|
|
280
|
+
* Firmware versions are opaque vendor strings, so the update order is
|
|
281
|
+
* declared explicitly in the package definition as an upgrade graph. Call
|
|
282
|
+
* `getNextFirmware(currentVersion)` to resolve the single next step for a
|
|
283
|
+
* device — it returns `undefined` when the device is already up to date —
|
|
284
|
+
* then `requestDownloadUrl()` for a signed, time-limited URL the device can
|
|
285
|
+
* fetch itself.
|
|
286
|
+
* @returns The Firmware Registry API instance
|
|
287
|
+
* @throws {EnergyAppPermissionNotGrantedError} If the `FirmwareRegistry`
|
|
288
|
+
* permission is not granted.
|
|
289
|
+
*/
|
|
290
|
+
useFirmwareRegistry(): EnergyAppFirmwareRegistry;
|
|
273
291
|
/**
|
|
274
292
|
* Gets the Automation API for reading user-configured automations and
|
|
275
293
|
* listening for their creation, update and removal. Apps holding the
|
|
@@ -281,6 +299,30 @@ export declare class EnergyApp implements EnyoEnergyAppSdk {
|
|
|
281
299
|
* not granted.
|
|
282
300
|
*/
|
|
283
301
|
useAutomations(): EnergyAppAutomation;
|
|
302
|
+
/**
|
|
303
|
+
* Gets the Savings API for publishing day-scoped savings reports and reading
|
|
304
|
+
* them back. An energy manager app settles a finished day by replaying its
|
|
305
|
+
* measured environment against an uncontrolled simulation and publishes both
|
|
306
|
+
* worlds here; the platform stores the days and owns every aggregation above
|
|
307
|
+
* them (month, year, lifetime).
|
|
308
|
+
* @returns The Savings API instance
|
|
309
|
+
* @throws {EnergyAppPermissionNotGrantedError} If the `Savings` permission is
|
|
310
|
+
* not granted.
|
|
311
|
+
*/
|
|
312
|
+
useSavings(): EnergyAppSavings;
|
|
313
|
+
/**
|
|
314
|
+
* Gets the Device Test API for answering the host's requests to test
|
|
315
|
+
* detected network devices. The app registers one handler; the host calls it
|
|
316
|
+
* from an onboarding v2 `device-test` action, from background auto-detection,
|
|
317
|
+
* or from a user-triggered re-test, and branches on whether appliances were
|
|
318
|
+
* found or created.
|
|
319
|
+
*
|
|
320
|
+
* Available to every app — this API is not permission-gated, though reaching
|
|
321
|
+
* a device (`NetworkDeviceAccess`) and creating an appliance (`Appliance`)
|
|
322
|
+
* still are.
|
|
323
|
+
* @returns The Device Test API instance
|
|
324
|
+
*/
|
|
325
|
+
useDeviceTest(): EnergyAppDeviceTest;
|
|
284
326
|
/**
|
|
285
327
|
* Gets the current SDK version.
|
|
286
328
|
* @returns The semantic version string of the SDK
|