@camstack/addon-provider-enpal 0.1.20 → 0.1.21
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/CHANGELOG.md +8 -0
- package/assets/icon.png +0 -0
- package/dist/addon.js +241 -85
- package/dist/addon.mjs +241 -85
- package/i18n/en.json +3 -1
- package/i18n/it.json +3 -1
- package/package.json +3 -3
- package/assets/icon.svg +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.21] - 2026-11-14
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Enpal: the grid frequency shows in Hz, and the LTE RSRQ and SNR in dB
|
|
15
|
+
- The integration shows the official Enpal icon
|
|
16
|
+
- House and heat-pump meters are named apart, and the energy system reports battery health.
|
|
17
|
+
|
|
10
18
|
## [0.1.20] - 2026-11-13
|
|
11
19
|
|
|
12
20
|
### Changed
|
package/assets/icon.png
ADDED
|
Binary file
|
package/dist/addon.js
CHANGED
|
@@ -6066,7 +6066,7 @@ var ZodIssueCode = {
|
|
|
6066
6066
|
var ZodFirstPartyTypeKind;
|
|
6067
6067
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6068
6068
|
//#endregion
|
|
6069
|
-
//#region ../types/dist/sleep-
|
|
6069
|
+
//#region ../types/dist/sleep-D7hCDd7y.mjs
|
|
6070
6070
|
/**
|
|
6071
6071
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6072
6072
|
* window to float samples (D455).
|
|
@@ -10377,6 +10377,8 @@ var READING_QUANTITIES = [
|
|
|
10377
10377
|
"information",
|
|
10378
10378
|
"sound-level",
|
|
10379
10379
|
"signal-level",
|
|
10380
|
+
"signal-ratio",
|
|
10381
|
+
"frequency",
|
|
10380
10382
|
"colour-temperature",
|
|
10381
10383
|
"angle",
|
|
10382
10384
|
"bitrate",
|
|
@@ -10420,6 +10422,8 @@ var QUANTITY_BASE = {
|
|
|
10420
10422
|
information: "B",
|
|
10421
10423
|
"sound-level": "dBFS",
|
|
10422
10424
|
"signal-level": "dBm",
|
|
10425
|
+
"signal-ratio": "dB",
|
|
10426
|
+
frequency: "Hz",
|
|
10423
10427
|
"colour-temperature": "mired",
|
|
10424
10428
|
angle: "°",
|
|
10425
10429
|
bitrate: "kbps",
|
|
@@ -10772,41 +10776,57 @@ var CAP_VOCABULARY_BY_NAME = {
|
|
|
10772
10776
|
en: "Switch",
|
|
10773
10777
|
it: "Interruttore"
|
|
10774
10778
|
},
|
|
10775
|
-
actions: [
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
10793
|
-
id: "switch.off",
|
|
10794
|
-
method: "setState",
|
|
10795
|
-
label: {
|
|
10796
|
-
en: "Turn off",
|
|
10797
|
-
it: "Spegni"
|
|
10779
|
+
actions: [
|
|
10780
|
+
{
|
|
10781
|
+
id: "switch.on",
|
|
10782
|
+
method: "setState",
|
|
10783
|
+
label: {
|
|
10784
|
+
en: "Turn on",
|
|
10785
|
+
it: "Accendi"
|
|
10786
|
+
},
|
|
10787
|
+
phrase: {
|
|
10788
|
+
en: "Turn on {device}",
|
|
10789
|
+
it: "Accendi {device}"
|
|
10790
|
+
},
|
|
10791
|
+
icon: "power",
|
|
10792
|
+
args: { on: true },
|
|
10793
|
+
effect: {
|
|
10794
|
+
field: "on",
|
|
10795
|
+
value: true
|
|
10796
|
+
}
|
|
10798
10797
|
},
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
10798
|
+
{
|
|
10799
|
+
id: "switch.off",
|
|
10800
|
+
method: "setState",
|
|
10801
|
+
label: {
|
|
10802
|
+
en: "Turn off",
|
|
10803
|
+
it: "Spegni"
|
|
10804
|
+
},
|
|
10805
|
+
phrase: {
|
|
10806
|
+
en: "Turn off {device}",
|
|
10807
|
+
it: "Spegni {device}"
|
|
10808
|
+
},
|
|
10809
|
+
icon: "power-off",
|
|
10810
|
+
args: { on: false },
|
|
10811
|
+
effect: {
|
|
10812
|
+
field: "on",
|
|
10813
|
+
value: false
|
|
10814
|
+
}
|
|
10802
10815
|
},
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10816
|
+
{
|
|
10817
|
+
id: "switch.toggle",
|
|
10818
|
+
method: "toggle",
|
|
10819
|
+
label: {
|
|
10820
|
+
en: "Toggle",
|
|
10821
|
+
it: "Commuta"
|
|
10822
|
+
},
|
|
10823
|
+
phrase: {
|
|
10824
|
+
en: "Toggle {device}",
|
|
10825
|
+
it: "Commuta {device}"
|
|
10826
|
+
},
|
|
10827
|
+
icon: "toggle-right"
|
|
10808
10828
|
}
|
|
10809
|
-
|
|
10829
|
+
],
|
|
10810
10830
|
state: [{
|
|
10811
10831
|
kind: "boolean",
|
|
10812
10832
|
field: "on",
|
|
@@ -20339,6 +20359,10 @@ Object.freeze({
|
|
|
20339
20359
|
{
|
|
20340
20360
|
"path": "storage.dischargedTodayKwh",
|
|
20341
20361
|
"valueType": "number"
|
|
20362
|
+
},
|
|
20363
|
+
{
|
|
20364
|
+
"path": "storage.healthPct",
|
|
20365
|
+
"valueType": "number"
|
|
20342
20366
|
}
|
|
20343
20367
|
],
|
|
20344
20368
|
"enum-sensor": [{
|
|
@@ -20719,6 +20743,10 @@ Object.freeze({
|
|
|
20719
20743
|
"path": "isMuted",
|
|
20720
20744
|
"valueType": "boolean"
|
|
20721
20745
|
},
|
|
20746
|
+
{
|
|
20747
|
+
"path": "muteReadback",
|
|
20748
|
+
"valueType": "boolean"
|
|
20749
|
+
},
|
|
20722
20750
|
{
|
|
20723
20751
|
"path": "source",
|
|
20724
20752
|
"valueType": "string"
|
|
@@ -22839,7 +22867,7 @@ var NodeColorIdSchema = _enum([
|
|
|
22839
22867
|
"node-h"
|
|
22840
22868
|
]);
|
|
22841
22869
|
//#endregion
|
|
22842
|
-
//#region ../types/dist/convert-
|
|
22870
|
+
//#region ../types/dist/convert-BwMfbk5b.mjs
|
|
22843
22871
|
/**
|
|
22844
22872
|
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
22845
22873
|
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
@@ -23172,6 +23200,21 @@ var UNIT_TABLE = {
|
|
|
23172
23200
|
factor: 1,
|
|
23173
23201
|
offset: 0
|
|
23174
23202
|
},
|
|
23203
|
+
dB: {
|
|
23204
|
+
dimension: "signal-ratio",
|
|
23205
|
+
factor: 1,
|
|
23206
|
+
offset: 0
|
|
23207
|
+
},
|
|
23208
|
+
Hz: {
|
|
23209
|
+
dimension: "frequency",
|
|
23210
|
+
factor: 1,
|
|
23211
|
+
offset: 0
|
|
23212
|
+
},
|
|
23213
|
+
kHz: {
|
|
23214
|
+
dimension: "frequency",
|
|
23215
|
+
factor: 1e3,
|
|
23216
|
+
offset: 0
|
|
23217
|
+
},
|
|
23175
23218
|
mired: {
|
|
23176
23219
|
dimension: "colour-temperature",
|
|
23177
23220
|
factor: 1,
|
|
@@ -55494,7 +55537,9 @@ var ClusterUpdateFailureReasonSchema = _enum([
|
|
|
55494
55537
|
"status-unreadable",
|
|
55495
55538
|
"addon-update-failed",
|
|
55496
55539
|
"addons-not-converged",
|
|
55497
|
-
"interrupted"
|
|
55540
|
+
"interrupted",
|
|
55541
|
+
"timeout-stall",
|
|
55542
|
+
"timeout-ceiling"
|
|
55498
55543
|
]);
|
|
55499
55544
|
var ClusterUpdateStepSchema = object({
|
|
55500
55545
|
kind: ClusterUpdateStepKindSchema,
|
|
@@ -57061,6 +57106,12 @@ var MediaPlayerStatusSchema = object({
|
|
|
57061
57106
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
57062
57107
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
57063
57108
|
isMuted: boolean().nullable(),
|
|
57109
|
+
/**
|
|
57110
|
+
* True only when the provider READS the mute state back from the device.
|
|
57111
|
+
* Absent or false: mute is a momentary key. A non-null `isMuted` is not a
|
|
57112
|
+
* reading on its own — an infrared send can leave a value without this flag.
|
|
57113
|
+
*/
|
|
57114
|
+
muteReadback: boolean().optional(),
|
|
57064
57115
|
/** Active source / input. Empty when no source surface. */
|
|
57065
57116
|
source: string(),
|
|
57066
57117
|
/** Selectable sources. Empty when no source surface.
|
|
@@ -59764,9 +59815,15 @@ var SiteZoneSchema = object({
|
|
|
59764
59815
|
locationKeys: array(string())
|
|
59765
59816
|
});
|
|
59766
59817
|
var DeviceSearchRequiresSchema = object({
|
|
59767
|
-
/** Capability names the field wants a value of. */
|
|
59768
|
-
caps: array(string()).readonly(),
|
|
59769
|
-
/**
|
|
59818
|
+
/** Capability names the field wants a value of. Absent when the field wants actions only. */
|
|
59819
|
+
caps: array(string()).readonly().optional(),
|
|
59820
|
+
/**
|
|
59821
|
+
* Vocabulary action ids (`cover.open`) the device must offer. Compatible means
|
|
59822
|
+
* the device's bindings resolve those actions; `values` stays empty when no
|
|
59823
|
+
* cap was required. `mode` applies the same way as for `caps`.
|
|
59824
|
+
*/
|
|
59825
|
+
actions: array(string()).readonly().optional(),
|
|
59826
|
+
/** `any` (default): one of the named caps, and one of the named actions, is enough. `all`: every one. */
|
|
59770
59827
|
mode: _enum(["any", "all"]).optional()
|
|
59771
59828
|
});
|
|
59772
59829
|
var DeviceSearchFiltersSchema = object({
|
|
@@ -63117,7 +63174,9 @@ var EnergyStorageSchema = object({
|
|
|
63117
63174
|
/** Lifetime discharged, kWh. */
|
|
63118
63175
|
dischargedKwh: number$1().nullable().meta(readingMeta("energy")),
|
|
63119
63176
|
chargedTodayKwh: number$1().nullable().meta(readingMeta("energy")),
|
|
63120
|
-
dischargedTodayKwh: number$1().nullable().meta(readingMeta("energy"))
|
|
63177
|
+
dischargedTodayKwh: number$1().nullable().meta(readingMeta("energy")),
|
|
63178
|
+
/** State of health, 0..100. Null when the system did not report it. */
|
|
63179
|
+
healthPct: number$1().nullable().meta(readingMeta("percentage"))
|
|
63121
63180
|
});
|
|
63122
63181
|
var EnergySystemStatusSchema = object({
|
|
63123
63182
|
solar: EnergySolarSchema.nullable(),
|
|
@@ -63229,6 +63288,12 @@ var energySystemCapability = {
|
|
|
63229
63288
|
kind: "counter",
|
|
63230
63289
|
unit: "kWh",
|
|
63231
63290
|
displayName: "Storage discharged"
|
|
63291
|
+
},
|
|
63292
|
+
"storage.healthPct": {
|
|
63293
|
+
kind: "gauge",
|
|
63294
|
+
unit: "%",
|
|
63295
|
+
deadband: 1,
|
|
63296
|
+
displayName: "Storage health"
|
|
63232
63297
|
}
|
|
63233
63298
|
} },
|
|
63234
63299
|
volatileStateFields: ["lastFetchedAt"],
|
|
@@ -66123,7 +66188,7 @@ var HeroModelSchema = object({
|
|
|
66123
66188
|
*
|
|
66124
66189
|
* - `extras` are the further inline controls of the types that carry more than one
|
|
66125
66190
|
* ({@link ROW_EXTRAS_BY_TYPE}): climate setpoint, a robot's return to base,
|
|
66126
|
-
* a player's volume and remote. Each is a control the model already has, named by id,
|
|
66191
|
+
* a player's volume and remote, an automation's enabled switch. Each is a control the model already has, named by id,
|
|
66127
66192
|
* in that order and at most {@link ROW_EXTRAS_MAX}; one the model lacks, or lists in
|
|
66128
66193
|
* `gated`, is absent, and the one `primary` already is never repeats. Empty = the
|
|
66129
66194
|
* row of an older server: `primary` alone.
|
|
@@ -66183,7 +66248,7 @@ new Set([
|
|
|
66183
66248
|
"valve"
|
|
66184
66249
|
]);
|
|
66185
66250
|
DeviceType.Climate;
|
|
66186
|
-
DeviceType.Climate, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer;
|
|
66251
|
+
DeviceType.Climate, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.Automation;
|
|
66187
66252
|
/**
|
|
66188
66253
|
* hero-layout — what a device's hero says (D1023). Read-only: the FIXED
|
|
66189
66254
|
* layouts live in `@camstack/types` and nothing here stores or edits one.
|
|
@@ -79306,6 +79371,13 @@ var NcHistoryEntrySchema = object({
|
|
|
79306
79371
|
error: string().optional(),
|
|
79307
79372
|
subject: NcHistorySubjectSchema,
|
|
79308
79373
|
/**
|
|
79374
|
+
* The title and body actually sent, frozen at delivery. Absent on a row
|
|
79375
|
+
* still pending, a row suppressed before a notification was built, and a
|
|
79376
|
+
* row delivered before this field shipped.
|
|
79377
|
+
*/
|
|
79378
|
+
title: string().optional(),
|
|
79379
|
+
body: string().optional(),
|
|
79380
|
+
/**
|
|
79309
79381
|
* Ids of the artefacts (still, then gif, then clip) this row's successful
|
|
79310
79382
|
* delivery indexed in the artefact library — a REFERENCE, never the bytes
|
|
79311
79383
|
* (an artefact is often megabytes; this row is durable JSON rewritten on
|
|
@@ -87616,7 +87688,8 @@ var ServerUpdateActionResultSchema = object({
|
|
|
87616
87688
|
outcome: ServerUpdateOutcomeSchema.optional(),
|
|
87617
87689
|
/**
|
|
87618
87690
|
* Stable, greppable cause for `refused` / `failed` (the engine's
|
|
87619
|
-
* `UpdateRefusalReason`, `staging-failed`,
|
|
87691
|
+
* `UpdateRefusalReason`, `staging-failed`, `timeout-stall`,
|
|
87692
|
+
* `timeout-ceiling`). `null` on success.
|
|
87620
87693
|
*/
|
|
87621
87694
|
reason: string().nullable().optional(),
|
|
87622
87695
|
/**
|
|
@@ -87738,6 +87811,14 @@ var smokeCapability = {
|
|
|
87738
87811
|
}]
|
|
87739
87812
|
}
|
|
87740
87813
|
};
|
|
87814
|
+
var EmailImagePartSchema = object({
|
|
87815
|
+
ticket: PeerBytesTicketSchema,
|
|
87816
|
+
mime: string().min(1),
|
|
87817
|
+
name: string().min(1),
|
|
87818
|
+
contentId: string().min(1),
|
|
87819
|
+
placement: _enum(["inline", "attachment"]),
|
|
87820
|
+
deviceId: number$1().int().nonnegative().optional()
|
|
87821
|
+
});
|
|
87741
87822
|
/**
|
|
87742
87823
|
* `smtp-provider` — pluggable email delivery surface.
|
|
87743
87824
|
*
|
|
@@ -87747,8 +87828,8 @@ var smokeCapability = {
|
|
|
87747
87828
|
* ready provider OR target a specific addonId.
|
|
87748
87829
|
*
|
|
87749
87830
|
* The shape stays small on purpose — `sendEmail` is enough for the
|
|
87750
|
-
* 90% case.
|
|
87751
|
-
*
|
|
87831
|
+
* 90% case. An image is not a byte field on this method (D613): `images`
|
|
87832
|
+
* names `peerBytes` tickets the sender opens and folds into one MIME body.
|
|
87752
87833
|
*/
|
|
87753
87834
|
var EmailAddressSchema = email();
|
|
87754
87835
|
/**
|
|
@@ -87775,7 +87856,12 @@ var SendEmailInputSchema = object({
|
|
|
87775
87856
|
* for clients that strip HTML — including most spam filters). */
|
|
87776
87857
|
text: string(),
|
|
87777
87858
|
/** Optional HTML body. Renders alongside `text` as multi-part. */
|
|
87778
|
-
html: string().optional()
|
|
87859
|
+
html: string().optional(),
|
|
87860
|
+
/**
|
|
87861
|
+
* Images the caller already offered over `peerBytes`. Absent = a mail with
|
|
87862
|
+
* no image. The sender opens each ticket; one it cannot read is left out.
|
|
87863
|
+
*/
|
|
87864
|
+
images: array(EmailImagePartSchema).max(3).optional()
|
|
87779
87865
|
});
|
|
87780
87866
|
var SendEmailResultSchema = object({
|
|
87781
87867
|
messageId: string(),
|
|
@@ -88805,34 +88891,46 @@ var switchCapability = {
|
|
|
88805
88891
|
DeviceType.Light,
|
|
88806
88892
|
DeviceType.Fan
|
|
88807
88893
|
],
|
|
88808
|
-
methods: {
|
|
88809
|
-
|
|
88810
|
-
|
|
88811
|
-
|
|
88812
|
-
|
|
88813
|
-
|
|
88814
|
-
|
|
88815
|
-
|
|
88816
|
-
|
|
88817
|
-
|
|
88818
|
-
|
|
88819
|
-
|
|
88820
|
-
|
|
88821
|
-
|
|
88822
|
-
|
|
88823
|
-
|
|
88824
|
-
|
|
88825
|
-
|
|
88826
|
-
|
|
88827
|
-
|
|
88828
|
-
|
|
88829
|
-
|
|
88830
|
-
|
|
88831
|
-
|
|
88832
|
-
|
|
88833
|
-
|
|
88834
|
-
|
|
88835
|
-
|
|
88894
|
+
methods: {
|
|
88895
|
+
setState: method(object({
|
|
88896
|
+
deviceId: number$1(),
|
|
88897
|
+
on: boolean()
|
|
88898
|
+
}), _void(), {
|
|
88899
|
+
kind: "mutation",
|
|
88900
|
+
auth: "protected",
|
|
88901
|
+
actions: [{
|
|
88902
|
+
id: "switch.on",
|
|
88903
|
+
label: t("Turn on", "Accendi"),
|
|
88904
|
+
phrase: t("Turn on {device}", "Accendi {device}"),
|
|
88905
|
+
icon: "power",
|
|
88906
|
+
effect: {
|
|
88907
|
+
field: "on",
|
|
88908
|
+
value: true
|
|
88909
|
+
},
|
|
88910
|
+
args: { on: true }
|
|
88911
|
+
}, {
|
|
88912
|
+
id: "switch.off",
|
|
88913
|
+
label: t("Turn off", "Spegni"),
|
|
88914
|
+
phrase: t("Turn off {device}", "Spegni {device}"),
|
|
88915
|
+
icon: "power-off",
|
|
88916
|
+
effect: {
|
|
88917
|
+
field: "on",
|
|
88918
|
+
value: false
|
|
88919
|
+
},
|
|
88920
|
+
args: { on: false }
|
|
88921
|
+
}]
|
|
88922
|
+
}),
|
|
88923
|
+
toggle: optionalMethod(object({ deviceId: number$1() }), _void(), {
|
|
88924
|
+
kind: "mutation",
|
|
88925
|
+
auth: "protected",
|
|
88926
|
+
actions: [{
|
|
88927
|
+
id: "switch.toggle",
|
|
88928
|
+
label: t("Toggle", "Commuta"),
|
|
88929
|
+
phrase: t("Toggle {device}", "Commuta {device}"),
|
|
88930
|
+
icon: "toggle-right"
|
|
88931
|
+
}]
|
|
88932
|
+
})
|
|
88933
|
+
},
|
|
88836
88934
|
events: { onStateChanged: {
|
|
88837
88935
|
data: object({
|
|
88838
88936
|
deviceId: number$1(),
|
|
@@ -96646,7 +96744,11 @@ var temperatureContribution = contribution("temperature-sensor", TemperatureSens
|
|
|
96646
96744
|
var humidityContribution = contribution("humidity-sensor", HumiditySensorStatusSchema, (slice) => measured(sensorFragment(slice?.humidity ?? null, "humidity", "droplets", "Humidity", "Umidità", `${Math.round(slice?.humidity ?? 0)}%`), slice?.humidity == null ? emptyMeasurement("humidity") : humidityMeasurement(slice.humidity, slice.lastFetchedAt)));
|
|
96647
96745
|
var pressureContribution = contribution("pressure-sensor", PressureSensorStatusSchema, (slice) => sensorFragment(slice?.pressure ?? null, "pressure", "gauge", "Pressure", "Pressione", `${Math.round(slice?.pressure ?? 0)} hPa`));
|
|
96648
96746
|
var illuminanceContribution = contribution("ambient-light-sensor", AmbientLightSensorStatusSchema, (slice) => sensorFragment(slice?.illuminance ?? null, "illuminance", "sun", "Light", "Luce", `${Math.round(slice?.illuminance ?? 0)} lx`));
|
|
96649
|
-
var numericContribution = contribution("numeric-sensor", NumericSensorStatusSchema, (slice) =>
|
|
96747
|
+
var numericContribution = contribution("numeric-sensor", NumericSensorStatusSchema, (slice, ctx) => {
|
|
96748
|
+
const unit = ctx.quantity == null ? void 0 : baseUnitOf(ctx.quantity);
|
|
96749
|
+
const text = String(Number((slice?.value ?? 0).toFixed(2)));
|
|
96750
|
+
return sensorFragment(slice?.value ?? null, "reading", "gauge", "Value", "Valore", unit === void 0 ? text : `${text} ${unit}`);
|
|
96751
|
+
});
|
|
96650
96752
|
var enumContribution = contribution("enum-sensor", EnumSensorStatusSchema, (slice) => {
|
|
96651
96753
|
if (slice === void 0 || slice.value === "") return measured({ reading: reading("sensor", "unknown") }, emptyMeasurement("text"));
|
|
96652
96754
|
if (slice.timestamp === true) return { reading: reading("sensor", "on") };
|
|
@@ -106916,6 +107018,13 @@ Object.freeze({
|
|
|
106916
107018
|
access: "create",
|
|
106917
107019
|
role: "viewer"
|
|
106918
107020
|
},
|
|
107021
|
+
"switch.toggle": {
|
|
107022
|
+
capName: "switch",
|
|
107023
|
+
capScope: "device",
|
|
107024
|
+
addonId: null,
|
|
107025
|
+
access: "create",
|
|
107026
|
+
role: "viewer"
|
|
107027
|
+
},
|
|
106919
107028
|
"system.debugWatch": {
|
|
106920
107029
|
capName: "system",
|
|
106921
107030
|
capScope: "system",
|
|
@@ -110743,6 +110852,12 @@ Object.freeze({
|
|
|
110743
110852
|
form: "single",
|
|
110744
110853
|
optional: false
|
|
110745
110854
|
}],
|
|
110855
|
+
"smtpProvider.sendEmail": [{
|
|
110856
|
+
name: "images",
|
|
110857
|
+
form: "object-array",
|
|
110858
|
+
optional: true,
|
|
110859
|
+
itemField: "deviceId"
|
|
110860
|
+
}],
|
|
110746
110861
|
"snapshot.applyDeviceSettingsPatch": [{
|
|
110747
110862
|
name: "deviceId",
|
|
110748
110863
|
form: "single",
|
|
@@ -110909,6 +111024,11 @@ Object.freeze({
|
|
|
110909
111024
|
form: "single",
|
|
110910
111025
|
optional: false
|
|
110911
111026
|
}],
|
|
111027
|
+
"switch.toggle": [{
|
|
111028
|
+
name: "deviceId",
|
|
111029
|
+
form: "single",
|
|
111030
|
+
optional: false
|
|
111031
|
+
}],
|
|
110912
111032
|
"system.debugWatch": [{
|
|
110913
111033
|
name: "deviceIds",
|
|
110914
111034
|
form: "array",
|
|
@@ -111772,6 +111892,28 @@ var STATE_SUMMARY_VARS = [
|
|
|
111772
111892
|
systemEventKinds: [...SUMMARISABLE],
|
|
111773
111893
|
systemEventDeliveries: ["summary"]
|
|
111774
111894
|
},
|
|
111895
|
+
{
|
|
111896
|
+
name: "offlineCount",
|
|
111897
|
+
label: "Summary: how many went offline",
|
|
111898
|
+
example: "2",
|
|
111899
|
+
group: "system",
|
|
111900
|
+
families: ["rule"],
|
|
111901
|
+
fields: [...RULE_TEXT],
|
|
111902
|
+
kinds: ["system"],
|
|
111903
|
+
systemEventKinds: [...SUMMARISABLE],
|
|
111904
|
+
systemEventDeliveries: ["summary"]
|
|
111905
|
+
},
|
|
111906
|
+
{
|
|
111907
|
+
name: "onlineCount",
|
|
111908
|
+
label: "Summary: how many came back",
|
|
111909
|
+
example: "5",
|
|
111910
|
+
group: "system",
|
|
111911
|
+
families: ["rule"],
|
|
111912
|
+
fields: [...RULE_TEXT],
|
|
111913
|
+
kinds: ["system"],
|
|
111914
|
+
systemEventKinds: [...SUMMARISABLE],
|
|
111915
|
+
systemEventDeliveries: ["summary"]
|
|
111916
|
+
},
|
|
111775
111917
|
{
|
|
111776
111918
|
name: "summaryCount",
|
|
111777
111919
|
label: "Summary: items reported",
|
|
@@ -111813,6 +111955,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
111813
111955
|
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
111814
111956
|
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
111815
111957
|
[...RULE_TEXT],
|
|
111958
|
+
[...RULE_TEXT],
|
|
111816
111959
|
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
111817
111960
|
([...RULE_TEXT], [...PACKAGE_UPDATES]),
|
|
111818
111961
|
[...RULE_TEXT],
|
|
@@ -112930,6 +113073,21 @@ function toBase(value, unit, quantity) {
|
|
|
112930
113073
|
}
|
|
112931
113074
|
//#endregion
|
|
112932
113075
|
//#region src/enpal-catalog.ts
|
|
113076
|
+
/**
|
|
113077
|
+
* The two meters the box both called "Consumption". English is the device
|
|
113078
|
+
* name (one string, like every other catalog entry); Italian is the addon
|
|
113079
|
+
* catalogue key `catalog.<id>.name`.
|
|
113080
|
+
*/
|
|
113081
|
+
var ENPAL_CONSUMPTION_NAMES = {
|
|
113082
|
+
house: {
|
|
113083
|
+
en: "House consumption",
|
|
113084
|
+
it: "Consumo casa"
|
|
113085
|
+
},
|
|
113086
|
+
heatpump: {
|
|
113087
|
+
en: "Heat pump consumption",
|
|
113088
|
+
it: "Consumo pompa di calore"
|
|
113089
|
+
}
|
|
113090
|
+
};
|
|
112933
113091
|
var point = (quantity, ...sources) => ({
|
|
112934
113092
|
quantity,
|
|
112935
113093
|
sources: sources.map((s) => typeof s === "string" ? { key: s } : s)
|
|
@@ -113030,7 +113188,7 @@ var ENPAL_SPECS = [
|
|
|
113030
113188
|
{
|
|
113031
113189
|
kind: "power-meter",
|
|
113032
113190
|
id: "house",
|
|
113033
|
-
name:
|
|
113191
|
+
name: ENPAL_CONSUMPTION_NAMES.house.en,
|
|
113034
113192
|
role: DeviceRole.PowerSensor,
|
|
113035
113193
|
power: point("power", "Power.Consumption.Total"),
|
|
113036
113194
|
kwh: point("energy", "Energy.Consumption.Total.Lifetime")
|
|
@@ -113038,7 +113196,7 @@ var ENPAL_SPECS = [
|
|
|
113038
113196
|
{
|
|
113039
113197
|
kind: "power-meter",
|
|
113040
113198
|
id: "heatpump",
|
|
113041
|
-
name:
|
|
113199
|
+
name: ENPAL_CONSUMPTION_NAMES.heatpump.en,
|
|
113042
113200
|
role: DeviceRole.PowerSensor,
|
|
113043
113201
|
power: point("power", "Heatpump.Power.Consumption.Total"),
|
|
113044
113202
|
kwh: point("energy", "Heatpump.Energy.Consumption.Total.Lifetime")
|
|
@@ -113115,11 +113273,8 @@ var ENPAL_SPECS = [
|
|
|
113115
113273
|
id: "grid-frequency",
|
|
113116
113274
|
name: "Frequency",
|
|
113117
113275
|
role: DeviceRole.NumericSensor,
|
|
113118
|
-
quantity: "
|
|
113119
|
-
value:
|
|
113120
|
-
...point("index", "Frequency.Grid"),
|
|
113121
|
-
ignoreUnit: true
|
|
113122
|
-
}
|
|
113276
|
+
quantity: "frequency",
|
|
113277
|
+
value: point("frequency", "Frequency.Grid")
|
|
113123
113278
|
},
|
|
113124
113279
|
numeric("grid-feed-max", "Maximum feed-in power", "power", "Power.Grid.Maximum.Feed", DeviceRole.PowerSensor),
|
|
113125
113280
|
numeric("house-energy-day", "Consumption today", "energy", "Energy.Consumption.Total.Day", DeviceRole.EnergySensor),
|
|
@@ -113153,9 +113308,9 @@ var ENPAL_SPECS = [
|
|
|
113153
113308
|
text("lte-connection-type", "Connection type", "LTE.Connection.Type"),
|
|
113154
113309
|
numeric("lte-quality", "LTE quality", "percentage", "LTE.Quality"),
|
|
113155
113310
|
numeric("lte-rsrp", "RSRP", "signal-level", "LTE.RSRP"),
|
|
113156
|
-
numeric("lte-rsrq", "RSRQ", "
|
|
113311
|
+
numeric("lte-rsrq", "RSRQ", "signal-ratio", "LTE.RSRQ"),
|
|
113157
113312
|
numeric("lte-rssi", "RSSI", "signal-level", "LTE.RSSI"),
|
|
113158
|
-
numeric("lte-snr", "SNR", "
|
|
113313
|
+
numeric("lte-snr", "SNR", "signal-ratio", "LTE.SNR"),
|
|
113159
113314
|
text("lte-failover", "Failover result", "LTE.Failover.Result"),
|
|
113160
113315
|
text("lte-signal-check", "Signal check", "LTE.Cronny.Result"),
|
|
113161
113316
|
text("wifi-state", "Wi-Fi state", "WiFi.State"),
|
|
@@ -113196,7 +113351,7 @@ function resolve(target, snapshot) {
|
|
|
113196
113351
|
for (const source of target.sources) {
|
|
113197
113352
|
const reading = snapshot.readings.get(source.key);
|
|
113198
113353
|
if (reading === void 0) continue;
|
|
113199
|
-
const converted = toBase(reading.value,
|
|
113354
|
+
const converted = toBase(reading.value, reading.unit, target.quantity);
|
|
113200
113355
|
if (!converted.ok) {
|
|
113201
113356
|
refusal = `${source.key}: ${converted.reason} (unit ${reading.unit ?? "none"})`;
|
|
113202
113357
|
continue;
|
|
@@ -113669,7 +113824,8 @@ function computeEnergySystemStatus(snapshot, options, now) {
|
|
|
113669
113824
|
chargedKwh: read.meter("battery-charged"),
|
|
113670
113825
|
dischargedKwh: read.meter("battery-discharged"),
|
|
113671
113826
|
chargedTodayKwh: read.numeric("battery-charge-day"),
|
|
113672
|
-
dischargedTodayKwh: read.numeric("battery-discharge-day")
|
|
113827
|
+
dischargedTodayKwh: read.numeric("battery-discharge-day"),
|
|
113828
|
+
healthPct: read.numeric("battery-health")
|
|
113673
113829
|
};
|
|
113674
113830
|
return {
|
|
113675
113831
|
status: {
|
package/dist/addon.mjs
CHANGED
|
@@ -6065,7 +6065,7 @@ var ZodIssueCode = {
|
|
|
6065
6065
|
var ZodFirstPartyTypeKind;
|
|
6066
6066
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6067
6067
|
//#endregion
|
|
6068
|
-
//#region ../types/dist/sleep-
|
|
6068
|
+
//#region ../types/dist/sleep-D7hCDd7y.mjs
|
|
6069
6069
|
/**
|
|
6070
6070
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6071
6071
|
* window to float samples (D455).
|
|
@@ -10376,6 +10376,8 @@ var READING_QUANTITIES = [
|
|
|
10376
10376
|
"information",
|
|
10377
10377
|
"sound-level",
|
|
10378
10378
|
"signal-level",
|
|
10379
|
+
"signal-ratio",
|
|
10380
|
+
"frequency",
|
|
10379
10381
|
"colour-temperature",
|
|
10380
10382
|
"angle",
|
|
10381
10383
|
"bitrate",
|
|
@@ -10419,6 +10421,8 @@ var QUANTITY_BASE = {
|
|
|
10419
10421
|
information: "B",
|
|
10420
10422
|
"sound-level": "dBFS",
|
|
10421
10423
|
"signal-level": "dBm",
|
|
10424
|
+
"signal-ratio": "dB",
|
|
10425
|
+
frequency: "Hz",
|
|
10422
10426
|
"colour-temperature": "mired",
|
|
10423
10427
|
angle: "°",
|
|
10424
10428
|
bitrate: "kbps",
|
|
@@ -10771,41 +10775,57 @@ var CAP_VOCABULARY_BY_NAME = {
|
|
|
10771
10775
|
en: "Switch",
|
|
10772
10776
|
it: "Interruttore"
|
|
10773
10777
|
},
|
|
10774
|
-
actions: [
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
id: "switch.off",
|
|
10793
|
-
method: "setState",
|
|
10794
|
-
label: {
|
|
10795
|
-
en: "Turn off",
|
|
10796
|
-
it: "Spegni"
|
|
10778
|
+
actions: [
|
|
10779
|
+
{
|
|
10780
|
+
id: "switch.on",
|
|
10781
|
+
method: "setState",
|
|
10782
|
+
label: {
|
|
10783
|
+
en: "Turn on",
|
|
10784
|
+
it: "Accendi"
|
|
10785
|
+
},
|
|
10786
|
+
phrase: {
|
|
10787
|
+
en: "Turn on {device}",
|
|
10788
|
+
it: "Accendi {device}"
|
|
10789
|
+
},
|
|
10790
|
+
icon: "power",
|
|
10791
|
+
args: { on: true },
|
|
10792
|
+
effect: {
|
|
10793
|
+
field: "on",
|
|
10794
|
+
value: true
|
|
10795
|
+
}
|
|
10797
10796
|
},
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10797
|
+
{
|
|
10798
|
+
id: "switch.off",
|
|
10799
|
+
method: "setState",
|
|
10800
|
+
label: {
|
|
10801
|
+
en: "Turn off",
|
|
10802
|
+
it: "Spegni"
|
|
10803
|
+
},
|
|
10804
|
+
phrase: {
|
|
10805
|
+
en: "Turn off {device}",
|
|
10806
|
+
it: "Spegni {device}"
|
|
10807
|
+
},
|
|
10808
|
+
icon: "power-off",
|
|
10809
|
+
args: { on: false },
|
|
10810
|
+
effect: {
|
|
10811
|
+
field: "on",
|
|
10812
|
+
value: false
|
|
10813
|
+
}
|
|
10801
10814
|
},
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10815
|
+
{
|
|
10816
|
+
id: "switch.toggle",
|
|
10817
|
+
method: "toggle",
|
|
10818
|
+
label: {
|
|
10819
|
+
en: "Toggle",
|
|
10820
|
+
it: "Commuta"
|
|
10821
|
+
},
|
|
10822
|
+
phrase: {
|
|
10823
|
+
en: "Toggle {device}",
|
|
10824
|
+
it: "Commuta {device}"
|
|
10825
|
+
},
|
|
10826
|
+
icon: "toggle-right"
|
|
10807
10827
|
}
|
|
10808
|
-
|
|
10828
|
+
],
|
|
10809
10829
|
state: [{
|
|
10810
10830
|
kind: "boolean",
|
|
10811
10831
|
field: "on",
|
|
@@ -20338,6 +20358,10 @@ Object.freeze({
|
|
|
20338
20358
|
{
|
|
20339
20359
|
"path": "storage.dischargedTodayKwh",
|
|
20340
20360
|
"valueType": "number"
|
|
20361
|
+
},
|
|
20362
|
+
{
|
|
20363
|
+
"path": "storage.healthPct",
|
|
20364
|
+
"valueType": "number"
|
|
20341
20365
|
}
|
|
20342
20366
|
],
|
|
20343
20367
|
"enum-sensor": [{
|
|
@@ -20718,6 +20742,10 @@ Object.freeze({
|
|
|
20718
20742
|
"path": "isMuted",
|
|
20719
20743
|
"valueType": "boolean"
|
|
20720
20744
|
},
|
|
20745
|
+
{
|
|
20746
|
+
"path": "muteReadback",
|
|
20747
|
+
"valueType": "boolean"
|
|
20748
|
+
},
|
|
20721
20749
|
{
|
|
20722
20750
|
"path": "source",
|
|
20723
20751
|
"valueType": "string"
|
|
@@ -22838,7 +22866,7 @@ var NodeColorIdSchema = _enum([
|
|
|
22838
22866
|
"node-h"
|
|
22839
22867
|
]);
|
|
22840
22868
|
//#endregion
|
|
22841
|
-
//#region ../types/dist/convert-
|
|
22869
|
+
//#region ../types/dist/convert-BwMfbk5b.mjs
|
|
22842
22870
|
/**
|
|
22843
22871
|
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
22844
22872
|
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
@@ -23171,6 +23199,21 @@ var UNIT_TABLE = {
|
|
|
23171
23199
|
factor: 1,
|
|
23172
23200
|
offset: 0
|
|
23173
23201
|
},
|
|
23202
|
+
dB: {
|
|
23203
|
+
dimension: "signal-ratio",
|
|
23204
|
+
factor: 1,
|
|
23205
|
+
offset: 0
|
|
23206
|
+
},
|
|
23207
|
+
Hz: {
|
|
23208
|
+
dimension: "frequency",
|
|
23209
|
+
factor: 1,
|
|
23210
|
+
offset: 0
|
|
23211
|
+
},
|
|
23212
|
+
kHz: {
|
|
23213
|
+
dimension: "frequency",
|
|
23214
|
+
factor: 1e3,
|
|
23215
|
+
offset: 0
|
|
23216
|
+
},
|
|
23174
23217
|
mired: {
|
|
23175
23218
|
dimension: "colour-temperature",
|
|
23176
23219
|
factor: 1,
|
|
@@ -55493,7 +55536,9 @@ var ClusterUpdateFailureReasonSchema = _enum([
|
|
|
55493
55536
|
"status-unreadable",
|
|
55494
55537
|
"addon-update-failed",
|
|
55495
55538
|
"addons-not-converged",
|
|
55496
|
-
"interrupted"
|
|
55539
|
+
"interrupted",
|
|
55540
|
+
"timeout-stall",
|
|
55541
|
+
"timeout-ceiling"
|
|
55497
55542
|
]);
|
|
55498
55543
|
var ClusterUpdateStepSchema = object({
|
|
55499
55544
|
kind: ClusterUpdateStepKindSchema,
|
|
@@ -57060,6 +57105,12 @@ var MediaPlayerStatusSchema = object({
|
|
|
57060
57105
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
57061
57106
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
57062
57107
|
isMuted: boolean().nullable(),
|
|
57108
|
+
/**
|
|
57109
|
+
* True only when the provider READS the mute state back from the device.
|
|
57110
|
+
* Absent or false: mute is a momentary key. A non-null `isMuted` is not a
|
|
57111
|
+
* reading on its own — an infrared send can leave a value without this flag.
|
|
57112
|
+
*/
|
|
57113
|
+
muteReadback: boolean().optional(),
|
|
57063
57114
|
/** Active source / input. Empty when no source surface. */
|
|
57064
57115
|
source: string(),
|
|
57065
57116
|
/** Selectable sources. Empty when no source surface.
|
|
@@ -59763,9 +59814,15 @@ var SiteZoneSchema = object({
|
|
|
59763
59814
|
locationKeys: array(string())
|
|
59764
59815
|
});
|
|
59765
59816
|
var DeviceSearchRequiresSchema = object({
|
|
59766
|
-
/** Capability names the field wants a value of. */
|
|
59767
|
-
caps: array(string()).readonly(),
|
|
59768
|
-
/**
|
|
59817
|
+
/** Capability names the field wants a value of. Absent when the field wants actions only. */
|
|
59818
|
+
caps: array(string()).readonly().optional(),
|
|
59819
|
+
/**
|
|
59820
|
+
* Vocabulary action ids (`cover.open`) the device must offer. Compatible means
|
|
59821
|
+
* the device's bindings resolve those actions; `values` stays empty when no
|
|
59822
|
+
* cap was required. `mode` applies the same way as for `caps`.
|
|
59823
|
+
*/
|
|
59824
|
+
actions: array(string()).readonly().optional(),
|
|
59825
|
+
/** `any` (default): one of the named caps, and one of the named actions, is enough. `all`: every one. */
|
|
59769
59826
|
mode: _enum(["any", "all"]).optional()
|
|
59770
59827
|
});
|
|
59771
59828
|
var DeviceSearchFiltersSchema = object({
|
|
@@ -63116,7 +63173,9 @@ var EnergyStorageSchema = object({
|
|
|
63116
63173
|
/** Lifetime discharged, kWh. */
|
|
63117
63174
|
dischargedKwh: number$1().nullable().meta(readingMeta("energy")),
|
|
63118
63175
|
chargedTodayKwh: number$1().nullable().meta(readingMeta("energy")),
|
|
63119
|
-
dischargedTodayKwh: number$1().nullable().meta(readingMeta("energy"))
|
|
63176
|
+
dischargedTodayKwh: number$1().nullable().meta(readingMeta("energy")),
|
|
63177
|
+
/** State of health, 0..100. Null when the system did not report it. */
|
|
63178
|
+
healthPct: number$1().nullable().meta(readingMeta("percentage"))
|
|
63120
63179
|
});
|
|
63121
63180
|
var EnergySystemStatusSchema = object({
|
|
63122
63181
|
solar: EnergySolarSchema.nullable(),
|
|
@@ -63228,6 +63287,12 @@ var energySystemCapability = {
|
|
|
63228
63287
|
kind: "counter",
|
|
63229
63288
|
unit: "kWh",
|
|
63230
63289
|
displayName: "Storage discharged"
|
|
63290
|
+
},
|
|
63291
|
+
"storage.healthPct": {
|
|
63292
|
+
kind: "gauge",
|
|
63293
|
+
unit: "%",
|
|
63294
|
+
deadband: 1,
|
|
63295
|
+
displayName: "Storage health"
|
|
63231
63296
|
}
|
|
63232
63297
|
} },
|
|
63233
63298
|
volatileStateFields: ["lastFetchedAt"],
|
|
@@ -66122,7 +66187,7 @@ var HeroModelSchema = object({
|
|
|
66122
66187
|
*
|
|
66123
66188
|
* - `extras` are the further inline controls of the types that carry more than one
|
|
66124
66189
|
* ({@link ROW_EXTRAS_BY_TYPE}): climate setpoint, a robot's return to base,
|
|
66125
|
-
* a player's volume and remote. Each is a control the model already has, named by id,
|
|
66190
|
+
* a player's volume and remote, an automation's enabled switch. Each is a control the model already has, named by id,
|
|
66126
66191
|
* in that order and at most {@link ROW_EXTRAS_MAX}; one the model lacks, or lists in
|
|
66127
66192
|
* `gated`, is absent, and the one `primary` already is never repeats. Empty = the
|
|
66128
66193
|
* row of an older server: `primary` alone.
|
|
@@ -66182,7 +66247,7 @@ new Set([
|
|
|
66182
66247
|
"valve"
|
|
66183
66248
|
]);
|
|
66184
66249
|
DeviceType.Climate;
|
|
66185
|
-
DeviceType.Climate, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer;
|
|
66250
|
+
DeviceType.Climate, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.Automation;
|
|
66186
66251
|
/**
|
|
66187
66252
|
* hero-layout — what a device's hero says (D1023). Read-only: the FIXED
|
|
66188
66253
|
* layouts live in `@camstack/types` and nothing here stores or edits one.
|
|
@@ -79305,6 +79370,13 @@ var NcHistoryEntrySchema = object({
|
|
|
79305
79370
|
error: string().optional(),
|
|
79306
79371
|
subject: NcHistorySubjectSchema,
|
|
79307
79372
|
/**
|
|
79373
|
+
* The title and body actually sent, frozen at delivery. Absent on a row
|
|
79374
|
+
* still pending, a row suppressed before a notification was built, and a
|
|
79375
|
+
* row delivered before this field shipped.
|
|
79376
|
+
*/
|
|
79377
|
+
title: string().optional(),
|
|
79378
|
+
body: string().optional(),
|
|
79379
|
+
/**
|
|
79308
79380
|
* Ids of the artefacts (still, then gif, then clip) this row's successful
|
|
79309
79381
|
* delivery indexed in the artefact library — a REFERENCE, never the bytes
|
|
79310
79382
|
* (an artefact is often megabytes; this row is durable JSON rewritten on
|
|
@@ -87615,7 +87687,8 @@ var ServerUpdateActionResultSchema = object({
|
|
|
87615
87687
|
outcome: ServerUpdateOutcomeSchema.optional(),
|
|
87616
87688
|
/**
|
|
87617
87689
|
* Stable, greppable cause for `refused` / `failed` (the engine's
|
|
87618
|
-
* `UpdateRefusalReason`, `staging-failed`,
|
|
87690
|
+
* `UpdateRefusalReason`, `staging-failed`, `timeout-stall`,
|
|
87691
|
+
* `timeout-ceiling`). `null` on success.
|
|
87619
87692
|
*/
|
|
87620
87693
|
reason: string().nullable().optional(),
|
|
87621
87694
|
/**
|
|
@@ -87737,6 +87810,14 @@ var smokeCapability = {
|
|
|
87737
87810
|
}]
|
|
87738
87811
|
}
|
|
87739
87812
|
};
|
|
87813
|
+
var EmailImagePartSchema = object({
|
|
87814
|
+
ticket: PeerBytesTicketSchema,
|
|
87815
|
+
mime: string().min(1),
|
|
87816
|
+
name: string().min(1),
|
|
87817
|
+
contentId: string().min(1),
|
|
87818
|
+
placement: _enum(["inline", "attachment"]),
|
|
87819
|
+
deviceId: number$1().int().nonnegative().optional()
|
|
87820
|
+
});
|
|
87740
87821
|
/**
|
|
87741
87822
|
* `smtp-provider` — pluggable email delivery surface.
|
|
87742
87823
|
*
|
|
@@ -87746,8 +87827,8 @@ var smokeCapability = {
|
|
|
87746
87827
|
* ready provider OR target a specific addonId.
|
|
87747
87828
|
*
|
|
87748
87829
|
* The shape stays small on purpose — `sendEmail` is enough for the
|
|
87749
|
-
* 90% case.
|
|
87750
|
-
*
|
|
87830
|
+
* 90% case. An image is not a byte field on this method (D613): `images`
|
|
87831
|
+
* names `peerBytes` tickets the sender opens and folds into one MIME body.
|
|
87751
87832
|
*/
|
|
87752
87833
|
var EmailAddressSchema = email();
|
|
87753
87834
|
/**
|
|
@@ -87774,7 +87855,12 @@ var SendEmailInputSchema = object({
|
|
|
87774
87855
|
* for clients that strip HTML — including most spam filters). */
|
|
87775
87856
|
text: string(),
|
|
87776
87857
|
/** Optional HTML body. Renders alongside `text` as multi-part. */
|
|
87777
|
-
html: string().optional()
|
|
87858
|
+
html: string().optional(),
|
|
87859
|
+
/**
|
|
87860
|
+
* Images the caller already offered over `peerBytes`. Absent = a mail with
|
|
87861
|
+
* no image. The sender opens each ticket; one it cannot read is left out.
|
|
87862
|
+
*/
|
|
87863
|
+
images: array(EmailImagePartSchema).max(3).optional()
|
|
87778
87864
|
});
|
|
87779
87865
|
var SendEmailResultSchema = object({
|
|
87780
87866
|
messageId: string(),
|
|
@@ -88804,34 +88890,46 @@ var switchCapability = {
|
|
|
88804
88890
|
DeviceType.Light,
|
|
88805
88891
|
DeviceType.Fan
|
|
88806
88892
|
],
|
|
88807
|
-
methods: {
|
|
88808
|
-
|
|
88809
|
-
|
|
88810
|
-
|
|
88811
|
-
|
|
88812
|
-
|
|
88813
|
-
|
|
88814
|
-
|
|
88815
|
-
|
|
88816
|
-
|
|
88817
|
-
|
|
88818
|
-
|
|
88819
|
-
|
|
88820
|
-
|
|
88821
|
-
|
|
88822
|
-
|
|
88823
|
-
|
|
88824
|
-
|
|
88825
|
-
|
|
88826
|
-
|
|
88827
|
-
|
|
88828
|
-
|
|
88829
|
-
|
|
88830
|
-
|
|
88831
|
-
|
|
88832
|
-
|
|
88833
|
-
|
|
88834
|
-
|
|
88893
|
+
methods: {
|
|
88894
|
+
setState: method(object({
|
|
88895
|
+
deviceId: number$1(),
|
|
88896
|
+
on: boolean()
|
|
88897
|
+
}), _void(), {
|
|
88898
|
+
kind: "mutation",
|
|
88899
|
+
auth: "protected",
|
|
88900
|
+
actions: [{
|
|
88901
|
+
id: "switch.on",
|
|
88902
|
+
label: t("Turn on", "Accendi"),
|
|
88903
|
+
phrase: t("Turn on {device}", "Accendi {device}"),
|
|
88904
|
+
icon: "power",
|
|
88905
|
+
effect: {
|
|
88906
|
+
field: "on",
|
|
88907
|
+
value: true
|
|
88908
|
+
},
|
|
88909
|
+
args: { on: true }
|
|
88910
|
+
}, {
|
|
88911
|
+
id: "switch.off",
|
|
88912
|
+
label: t("Turn off", "Spegni"),
|
|
88913
|
+
phrase: t("Turn off {device}", "Spegni {device}"),
|
|
88914
|
+
icon: "power-off",
|
|
88915
|
+
effect: {
|
|
88916
|
+
field: "on",
|
|
88917
|
+
value: false
|
|
88918
|
+
},
|
|
88919
|
+
args: { on: false }
|
|
88920
|
+
}]
|
|
88921
|
+
}),
|
|
88922
|
+
toggle: optionalMethod(object({ deviceId: number$1() }), _void(), {
|
|
88923
|
+
kind: "mutation",
|
|
88924
|
+
auth: "protected",
|
|
88925
|
+
actions: [{
|
|
88926
|
+
id: "switch.toggle",
|
|
88927
|
+
label: t("Toggle", "Commuta"),
|
|
88928
|
+
phrase: t("Toggle {device}", "Commuta {device}"),
|
|
88929
|
+
icon: "toggle-right"
|
|
88930
|
+
}]
|
|
88931
|
+
})
|
|
88932
|
+
},
|
|
88835
88933
|
events: { onStateChanged: {
|
|
88836
88934
|
data: object({
|
|
88837
88935
|
deviceId: number$1(),
|
|
@@ -96645,7 +96743,11 @@ var temperatureContribution = contribution("temperature-sensor", TemperatureSens
|
|
|
96645
96743
|
var humidityContribution = contribution("humidity-sensor", HumiditySensorStatusSchema, (slice) => measured(sensorFragment(slice?.humidity ?? null, "humidity", "droplets", "Humidity", "Umidità", `${Math.round(slice?.humidity ?? 0)}%`), slice?.humidity == null ? emptyMeasurement("humidity") : humidityMeasurement(slice.humidity, slice.lastFetchedAt)));
|
|
96646
96744
|
var pressureContribution = contribution("pressure-sensor", PressureSensorStatusSchema, (slice) => sensorFragment(slice?.pressure ?? null, "pressure", "gauge", "Pressure", "Pressione", `${Math.round(slice?.pressure ?? 0)} hPa`));
|
|
96647
96745
|
var illuminanceContribution = contribution("ambient-light-sensor", AmbientLightSensorStatusSchema, (slice) => sensorFragment(slice?.illuminance ?? null, "illuminance", "sun", "Light", "Luce", `${Math.round(slice?.illuminance ?? 0)} lx`));
|
|
96648
|
-
var numericContribution = contribution("numeric-sensor", NumericSensorStatusSchema, (slice) =>
|
|
96746
|
+
var numericContribution = contribution("numeric-sensor", NumericSensorStatusSchema, (slice, ctx) => {
|
|
96747
|
+
const unit = ctx.quantity == null ? void 0 : baseUnitOf(ctx.quantity);
|
|
96748
|
+
const text = String(Number((slice?.value ?? 0).toFixed(2)));
|
|
96749
|
+
return sensorFragment(slice?.value ?? null, "reading", "gauge", "Value", "Valore", unit === void 0 ? text : `${text} ${unit}`);
|
|
96750
|
+
});
|
|
96649
96751
|
var enumContribution = contribution("enum-sensor", EnumSensorStatusSchema, (slice) => {
|
|
96650
96752
|
if (slice === void 0 || slice.value === "") return measured({ reading: reading("sensor", "unknown") }, emptyMeasurement("text"));
|
|
96651
96753
|
if (slice.timestamp === true) return { reading: reading("sensor", "on") };
|
|
@@ -106915,6 +107017,13 @@ Object.freeze({
|
|
|
106915
107017
|
access: "create",
|
|
106916
107018
|
role: "viewer"
|
|
106917
107019
|
},
|
|
107020
|
+
"switch.toggle": {
|
|
107021
|
+
capName: "switch",
|
|
107022
|
+
capScope: "device",
|
|
107023
|
+
addonId: null,
|
|
107024
|
+
access: "create",
|
|
107025
|
+
role: "viewer"
|
|
107026
|
+
},
|
|
106918
107027
|
"system.debugWatch": {
|
|
106919
107028
|
capName: "system",
|
|
106920
107029
|
capScope: "system",
|
|
@@ -110742,6 +110851,12 @@ Object.freeze({
|
|
|
110742
110851
|
form: "single",
|
|
110743
110852
|
optional: false
|
|
110744
110853
|
}],
|
|
110854
|
+
"smtpProvider.sendEmail": [{
|
|
110855
|
+
name: "images",
|
|
110856
|
+
form: "object-array",
|
|
110857
|
+
optional: true,
|
|
110858
|
+
itemField: "deviceId"
|
|
110859
|
+
}],
|
|
110745
110860
|
"snapshot.applyDeviceSettingsPatch": [{
|
|
110746
110861
|
name: "deviceId",
|
|
110747
110862
|
form: "single",
|
|
@@ -110908,6 +111023,11 @@ Object.freeze({
|
|
|
110908
111023
|
form: "single",
|
|
110909
111024
|
optional: false
|
|
110910
111025
|
}],
|
|
111026
|
+
"switch.toggle": [{
|
|
111027
|
+
name: "deviceId",
|
|
111028
|
+
form: "single",
|
|
111029
|
+
optional: false
|
|
111030
|
+
}],
|
|
110911
111031
|
"system.debugWatch": [{
|
|
110912
111032
|
name: "deviceIds",
|
|
110913
111033
|
form: "array",
|
|
@@ -111771,6 +111891,28 @@ var STATE_SUMMARY_VARS = [
|
|
|
111771
111891
|
systemEventKinds: [...SUMMARISABLE],
|
|
111772
111892
|
systemEventDeliveries: ["summary"]
|
|
111773
111893
|
},
|
|
111894
|
+
{
|
|
111895
|
+
name: "offlineCount",
|
|
111896
|
+
label: "Summary: how many went offline",
|
|
111897
|
+
example: "2",
|
|
111898
|
+
group: "system",
|
|
111899
|
+
families: ["rule"],
|
|
111900
|
+
fields: [...RULE_TEXT],
|
|
111901
|
+
kinds: ["system"],
|
|
111902
|
+
systemEventKinds: [...SUMMARISABLE],
|
|
111903
|
+
systemEventDeliveries: ["summary"]
|
|
111904
|
+
},
|
|
111905
|
+
{
|
|
111906
|
+
name: "onlineCount",
|
|
111907
|
+
label: "Summary: how many came back",
|
|
111908
|
+
example: "5",
|
|
111909
|
+
group: "system",
|
|
111910
|
+
families: ["rule"],
|
|
111911
|
+
fields: [...RULE_TEXT],
|
|
111912
|
+
kinds: ["system"],
|
|
111913
|
+
systemEventKinds: [...SUMMARISABLE],
|
|
111914
|
+
systemEventDeliveries: ["summary"]
|
|
111915
|
+
},
|
|
111774
111916
|
{
|
|
111775
111917
|
name: "summaryCount",
|
|
111776
111918
|
label: "Summary: items reported",
|
|
@@ -111812,6 +111954,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
111812
111954
|
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
111813
111955
|
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
111814
111956
|
[...RULE_TEXT],
|
|
111957
|
+
[...RULE_TEXT],
|
|
111815
111958
|
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
111816
111959
|
([...RULE_TEXT], [...PACKAGE_UPDATES]),
|
|
111817
111960
|
[...RULE_TEXT],
|
|
@@ -112929,6 +113072,21 @@ function toBase(value, unit, quantity) {
|
|
|
112929
113072
|
}
|
|
112930
113073
|
//#endregion
|
|
112931
113074
|
//#region src/enpal-catalog.ts
|
|
113075
|
+
/**
|
|
113076
|
+
* The two meters the box both called "Consumption". English is the device
|
|
113077
|
+
* name (one string, like every other catalog entry); Italian is the addon
|
|
113078
|
+
* catalogue key `catalog.<id>.name`.
|
|
113079
|
+
*/
|
|
113080
|
+
var ENPAL_CONSUMPTION_NAMES = {
|
|
113081
|
+
house: {
|
|
113082
|
+
en: "House consumption",
|
|
113083
|
+
it: "Consumo casa"
|
|
113084
|
+
},
|
|
113085
|
+
heatpump: {
|
|
113086
|
+
en: "Heat pump consumption",
|
|
113087
|
+
it: "Consumo pompa di calore"
|
|
113088
|
+
}
|
|
113089
|
+
};
|
|
112932
113090
|
var point = (quantity, ...sources) => ({
|
|
112933
113091
|
quantity,
|
|
112934
113092
|
sources: sources.map((s) => typeof s === "string" ? { key: s } : s)
|
|
@@ -113029,7 +113187,7 @@ var ENPAL_SPECS = [
|
|
|
113029
113187
|
{
|
|
113030
113188
|
kind: "power-meter",
|
|
113031
113189
|
id: "house",
|
|
113032
|
-
name:
|
|
113190
|
+
name: ENPAL_CONSUMPTION_NAMES.house.en,
|
|
113033
113191
|
role: DeviceRole.PowerSensor,
|
|
113034
113192
|
power: point("power", "Power.Consumption.Total"),
|
|
113035
113193
|
kwh: point("energy", "Energy.Consumption.Total.Lifetime")
|
|
@@ -113037,7 +113195,7 @@ var ENPAL_SPECS = [
|
|
|
113037
113195
|
{
|
|
113038
113196
|
kind: "power-meter",
|
|
113039
113197
|
id: "heatpump",
|
|
113040
|
-
name:
|
|
113198
|
+
name: ENPAL_CONSUMPTION_NAMES.heatpump.en,
|
|
113041
113199
|
role: DeviceRole.PowerSensor,
|
|
113042
113200
|
power: point("power", "Heatpump.Power.Consumption.Total"),
|
|
113043
113201
|
kwh: point("energy", "Heatpump.Energy.Consumption.Total.Lifetime")
|
|
@@ -113114,11 +113272,8 @@ var ENPAL_SPECS = [
|
|
|
113114
113272
|
id: "grid-frequency",
|
|
113115
113273
|
name: "Frequency",
|
|
113116
113274
|
role: DeviceRole.NumericSensor,
|
|
113117
|
-
quantity: "
|
|
113118
|
-
value:
|
|
113119
|
-
...point("index", "Frequency.Grid"),
|
|
113120
|
-
ignoreUnit: true
|
|
113121
|
-
}
|
|
113275
|
+
quantity: "frequency",
|
|
113276
|
+
value: point("frequency", "Frequency.Grid")
|
|
113122
113277
|
},
|
|
113123
113278
|
numeric("grid-feed-max", "Maximum feed-in power", "power", "Power.Grid.Maximum.Feed", DeviceRole.PowerSensor),
|
|
113124
113279
|
numeric("house-energy-day", "Consumption today", "energy", "Energy.Consumption.Total.Day", DeviceRole.EnergySensor),
|
|
@@ -113152,9 +113307,9 @@ var ENPAL_SPECS = [
|
|
|
113152
113307
|
text("lte-connection-type", "Connection type", "LTE.Connection.Type"),
|
|
113153
113308
|
numeric("lte-quality", "LTE quality", "percentage", "LTE.Quality"),
|
|
113154
113309
|
numeric("lte-rsrp", "RSRP", "signal-level", "LTE.RSRP"),
|
|
113155
|
-
numeric("lte-rsrq", "RSRQ", "
|
|
113310
|
+
numeric("lte-rsrq", "RSRQ", "signal-ratio", "LTE.RSRQ"),
|
|
113156
113311
|
numeric("lte-rssi", "RSSI", "signal-level", "LTE.RSSI"),
|
|
113157
|
-
numeric("lte-snr", "SNR", "
|
|
113312
|
+
numeric("lte-snr", "SNR", "signal-ratio", "LTE.SNR"),
|
|
113158
113313
|
text("lte-failover", "Failover result", "LTE.Failover.Result"),
|
|
113159
113314
|
text("lte-signal-check", "Signal check", "LTE.Cronny.Result"),
|
|
113160
113315
|
text("wifi-state", "Wi-Fi state", "WiFi.State"),
|
|
@@ -113195,7 +113350,7 @@ function resolve(target, snapshot) {
|
|
|
113195
113350
|
for (const source of target.sources) {
|
|
113196
113351
|
const reading = snapshot.readings.get(source.key);
|
|
113197
113352
|
if (reading === void 0) continue;
|
|
113198
|
-
const converted = toBase(reading.value,
|
|
113353
|
+
const converted = toBase(reading.value, reading.unit, target.quantity);
|
|
113199
113354
|
if (!converted.ok) {
|
|
113200
113355
|
refusal = `${source.key}: ${converted.reason} (unit ${reading.unit ?? "none"})`;
|
|
113201
113356
|
continue;
|
|
@@ -113668,7 +113823,8 @@ function computeEnergySystemStatus(snapshot, options, now) {
|
|
|
113668
113823
|
chargedKwh: read.meter("battery-charged"),
|
|
113669
113824
|
dischargedKwh: read.meter("battery-discharged"),
|
|
113670
113825
|
chargedTodayKwh: read.numeric("battery-charge-day"),
|
|
113671
|
-
dischargedTodayKwh: read.numeric("battery-discharge-day")
|
|
113826
|
+
dischargedTodayKwh: read.numeric("battery-discharge-day"),
|
|
113827
|
+
healthPct: read.numeric("battery-health")
|
|
113672
113828
|
};
|
|
113673
113829
|
return {
|
|
113674
113830
|
status: {
|
package/i18n/en.json
CHANGED
|
@@ -15,5 +15,7 @@
|
|
|
15
15
|
"connection.s_source.pagePort.label": "Device page port",
|
|
16
16
|
"connection.s_polling.title": "Polling",
|
|
17
17
|
"connection.s_polling.pollIntervalMs.label": "Poll interval (ms)",
|
|
18
|
-
"connection.s_polling.invertBatteryPower.label": "Invert battery power sign"
|
|
18
|
+
"connection.s_polling.invertBatteryPower.label": "Invert battery power sign",
|
|
19
|
+
"catalog.house.name": "House consumption",
|
|
20
|
+
"catalog.heatpump.name": "Heat pump consumption"
|
|
19
21
|
}
|
package/i18n/it.json
CHANGED
|
@@ -15,5 +15,7 @@
|
|
|
15
15
|
"connection.s_source.pagePort.label": "Porta pagina dispositivo",
|
|
16
16
|
"connection.s_polling.title": "Polling",
|
|
17
17
|
"connection.s_polling.pollIntervalMs.label": "Intervallo di polling (ms)",
|
|
18
|
-
"connection.s_polling.invertBatteryPower.label": "Inverti il segno della potenza batteria"
|
|
18
|
+
"connection.s_polling.invertBatteryPower.label": "Inverti il segno della potenza batteria",
|
|
19
|
+
"catalog.house.name": "Consumo casa",
|
|
20
|
+
"catalog.heatpump.name": "Consumo pompa di calore"
|
|
19
21
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-enpal",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "Enpal solar-box device-provider addon for CamStack — PV, battery, grid, house and heat-pump readings from the box's own web-page channel, its local InfluxDB or its device page",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"version": "0.1.0",
|
|
43
43
|
"description": "Add an Enpal solar box as an integration (its own web-page channel, InfluxDB or the device page) and adopt its equipment: photovoltaic, battery, grid, house and heat pump",
|
|
44
44
|
"entry": "./dist/addon.js",
|
|
45
|
-
"icon": "assets/icon.
|
|
45
|
+
"icon": "assets/icon.png",
|
|
46
46
|
"color": "#f5a623",
|
|
47
47
|
"instanceMode": "multiple",
|
|
48
48
|
"mode": "account",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
}
|
|
67
67
|
],
|
|
68
68
|
"requires": {
|
|
69
|
-
"server": ">=1.2.
|
|
69
|
+
"server": ">=1.2.863"
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"files": [
|
package/assets/icon.svg
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
2
|
-
<!-- Enpal mark: navy tile and amber E from the public favicon. -->
|
|
3
|
-
<rect width="24" height="24" fill="#072543"/>
|
|
4
|
-
<rect x="5" y="5" width="3" height="14" fill="#FFB000"/>
|
|
5
|
-
<rect x="5" y="5" width="14" height="3" fill="#FFB000"/>
|
|
6
|
-
<rect x="5" y="10.5" width="9" height="3" fill="#FFB000"/>
|
|
7
|
-
<rect x="5" y="16" width="14" height="3" fill="#FFB000"/>
|
|
8
|
-
</svg>
|