@camstack/addon-provider-homeassistant 1.2.629 → 1.2.631
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/dist/addon.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/{dist-DWMNvtWN.mjs → dist-CdqN_VJZ.mjs} +489 -40
- package/dist/{dist-sQp4D2Eo.js → dist-DV8KQcWd.js} +489 -40
- package/dist/ha-export/ha-export.addon.js +9 -1
- package/dist/ha-export/ha-export.addon.mjs +9 -1
- package/package.json +1 -1
|
@@ -5575,7 +5575,7 @@ var ZodIssueCode = {
|
|
|
5575
5575
|
var ZodFirstPartyTypeKind;
|
|
5576
5576
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5577
5577
|
//#endregion
|
|
5578
|
-
//#region ../types/dist/sleep
|
|
5578
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5579
5579
|
/**
|
|
5580
5580
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5581
5581
|
* window to float samples (D455).
|
|
@@ -9018,6 +9018,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9018
9018
|
"filesystem-browse",
|
|
9019
9019
|
"flood",
|
|
9020
9020
|
"gas",
|
|
9021
|
+
"group-active",
|
|
9021
9022
|
"group-commands",
|
|
9022
9023
|
"group-status",
|
|
9023
9024
|
"heating-valve",
|
|
@@ -9040,6 +9041,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9040
9041
|
"login-method",
|
|
9041
9042
|
"media-player",
|
|
9042
9043
|
"mesh-network",
|
|
9044
|
+
"meter",
|
|
9043
9045
|
"metrics-provider",
|
|
9044
9046
|
"model-convert",
|
|
9045
9047
|
"model-distributor",
|
|
@@ -9838,6 +9840,10 @@ Object.freeze({
|
|
|
9838
9840
|
"path": "detected",
|
|
9839
9841
|
"valueType": "boolean"
|
|
9840
9842
|
}],
|
|
9843
|
+
"group-active": [{
|
|
9844
|
+
"path": "active",
|
|
9845
|
+
"valueType": "boolean"
|
|
9846
|
+
}],
|
|
9841
9847
|
"group-status": [
|
|
9842
9848
|
{
|
|
9843
9849
|
"path": "included",
|
|
@@ -10097,6 +10103,10 @@ Object.freeze({
|
|
|
10097
10103
|
]
|
|
10098
10104
|
}
|
|
10099
10105
|
],
|
|
10106
|
+
"meter": [{
|
|
10107
|
+
"path": "value",
|
|
10108
|
+
"valueType": "number"
|
|
10109
|
+
}],
|
|
10100
10110
|
"motion": [
|
|
10101
10111
|
{
|
|
10102
10112
|
"path": "detected",
|
|
@@ -11199,7 +11209,7 @@ function errMsg(err) {
|
|
|
11199
11209
|
return String(err);
|
|
11200
11210
|
}
|
|
11201
11211
|
//#endregion
|
|
11202
|
-
//#region ../types/dist/composition-
|
|
11212
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11203
11213
|
/**
|
|
11204
11214
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11205
11215
|
*
|
|
@@ -11514,6 +11524,13 @@ var table = {
|
|
|
11514
11524
|
apply: () => {
|
|
11515
11525
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11516
11526
|
}
|
|
11527
|
+
},
|
|
11528
|
+
schmitt: {
|
|
11529
|
+
minArgs: 3,
|
|
11530
|
+
maxArgs: 5,
|
|
11531
|
+
apply: () => {
|
|
11532
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11533
|
+
}
|
|
11517
11534
|
}
|
|
11518
11535
|
};
|
|
11519
11536
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11975,6 +11992,79 @@ var APPLIANCE_KINDS = [
|
|
|
11975
11992
|
];
|
|
11976
11993
|
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11977
11994
|
/**
|
|
11995
|
+
* Statistics and integrals over a history read (D944).
|
|
11996
|
+
*
|
|
11997
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11998
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11999
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
12000
|
+
* as zero. A truncated read is not published.
|
|
12001
|
+
*/
|
|
12002
|
+
var STATISTIC_STATS = [
|
|
12003
|
+
"min",
|
|
12004
|
+
"max",
|
|
12005
|
+
"mean",
|
|
12006
|
+
"sum",
|
|
12007
|
+
"count",
|
|
12008
|
+
"change"
|
|
12009
|
+
];
|
|
12010
|
+
/**
|
|
12011
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
12012
|
+
*
|
|
12013
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
12014
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
12015
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
12016
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
12017
|
+
*/
|
|
12018
|
+
var MINUTE_MS = 6e4;
|
|
12019
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
12020
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
12021
|
+
var ROLLING_SPANS = [
|
|
12022
|
+
"1h",
|
|
12023
|
+
"24h",
|
|
12024
|
+
"2d",
|
|
12025
|
+
"7d",
|
|
12026
|
+
"30d",
|
|
12027
|
+
"custom"
|
|
12028
|
+
];
|
|
12029
|
+
var CALENDAR_PERIODS = [
|
|
12030
|
+
"today",
|
|
12031
|
+
"yesterday",
|
|
12032
|
+
"this-week",
|
|
12033
|
+
"this-month"
|
|
12034
|
+
];
|
|
12035
|
+
var RESET_PERIODS = [
|
|
12036
|
+
"never",
|
|
12037
|
+
"daily",
|
|
12038
|
+
"weekly",
|
|
12039
|
+
"monthly"
|
|
12040
|
+
];
|
|
12041
|
+
5 * MINUTE_MS;
|
|
12042
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
12043
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
12044
|
+
var rollingWindowObject = object({
|
|
12045
|
+
kind: literal("rolling"),
|
|
12046
|
+
span: _enum(ROLLING_SPANS),
|
|
12047
|
+
customMinutes: number().int().min(5).optional()
|
|
12048
|
+
}).check((payload) => {
|
|
12049
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
12050
|
+
code: "custom",
|
|
12051
|
+
message: "a custom range needs a duration in minutes",
|
|
12052
|
+
path: ["customMinutes"],
|
|
12053
|
+
input: payload.value
|
|
12054
|
+
});
|
|
12055
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
12056
|
+
code: "custom",
|
|
12057
|
+
message: "only a custom range carries a duration",
|
|
12058
|
+
path: ["customMinutes"],
|
|
12059
|
+
input: payload.value
|
|
12060
|
+
});
|
|
12061
|
+
});
|
|
12062
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12063
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12064
|
+
kind: literal("calendar"),
|
|
12065
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12066
|
+
})]);
|
|
12067
|
+
/**
|
|
11978
12068
|
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11979
12069
|
* id. Split out so helper schemas can name it without a cycle through
|
|
11980
12070
|
* `composition.ts` (D659).
|
|
@@ -12000,7 +12090,13 @@ var GROUP_TEMPLATE_IDS = [
|
|
|
12000
12090
|
"occupancy",
|
|
12001
12091
|
"binary",
|
|
12002
12092
|
"switch",
|
|
12003
|
-
"light"
|
|
12093
|
+
"light",
|
|
12094
|
+
"fan",
|
|
12095
|
+
"cover",
|
|
12096
|
+
"valve",
|
|
12097
|
+
"lock",
|
|
12098
|
+
"media-player",
|
|
12099
|
+
"climate"
|
|
12004
12100
|
];
|
|
12005
12101
|
var NUMERIC_AGGREGATES = [
|
|
12006
12102
|
"mean",
|
|
@@ -12030,22 +12126,73 @@ var HelperMemberSchema = object({
|
|
|
12030
12126
|
cap: string().min(1),
|
|
12031
12127
|
fieldPath: string().min(1)
|
|
12032
12128
|
});
|
|
12033
|
-
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12034
|
-
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
|
|
12042
|
-
|
|
12043
|
-
|
|
12044
|
-
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
|
|
12129
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12130
|
+
object({
|
|
12131
|
+
kind: literal("group"),
|
|
12132
|
+
templateId: GroupTemplateIdSchema,
|
|
12133
|
+
aggregate: AggregateReducerSchema,
|
|
12134
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12135
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12136
|
+
active: ActiveCriterionSchema.optional()
|
|
12137
|
+
}),
|
|
12138
|
+
object({
|
|
12139
|
+
kind: literal("appliance"),
|
|
12140
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12141
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12142
|
+
thresholdWatts: number().positive(),
|
|
12143
|
+
startDwellMs: number().int().nonnegative(),
|
|
12144
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12145
|
+
member: HelperMemberSchema
|
|
12146
|
+
}),
|
|
12147
|
+
object({
|
|
12148
|
+
kind: literal("statistic"),
|
|
12149
|
+
stat: _enum(STATISTIC_STATS),
|
|
12150
|
+
window: StatisticWindowSchema,
|
|
12151
|
+
source: HelperMemberSchema
|
|
12152
|
+
}),
|
|
12153
|
+
object({
|
|
12154
|
+
kind: literal("integral"),
|
|
12155
|
+
reset: _enum(RESET_PERIODS),
|
|
12156
|
+
output: _enum(["energy", "meter"]),
|
|
12157
|
+
source: HelperMemberSchema
|
|
12158
|
+
}),
|
|
12159
|
+
object({
|
|
12160
|
+
kind: literal("threshold"),
|
|
12161
|
+
source: HelperMemberSchema,
|
|
12162
|
+
high: number(),
|
|
12163
|
+
low: number(),
|
|
12164
|
+
onForMs: number().int().nonnegative(),
|
|
12165
|
+
offForMs: number().int().nonnegative()
|
|
12166
|
+
}),
|
|
12167
|
+
object({
|
|
12168
|
+
kind: literal("arithmetic"),
|
|
12169
|
+
op: _enum([
|
|
12170
|
+
"sum",
|
|
12171
|
+
"difference",
|
|
12172
|
+
"ratio"
|
|
12173
|
+
]),
|
|
12174
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12175
|
+
}),
|
|
12176
|
+
object({
|
|
12177
|
+
kind: literal("expression"),
|
|
12178
|
+
expr: string().min(1),
|
|
12179
|
+
inputs: array(object({
|
|
12180
|
+
name: string().min(1),
|
|
12181
|
+
member: HelperMemberSchema
|
|
12182
|
+
})).min(1).max(64),
|
|
12183
|
+
output: _enum(["number", "boolean"])
|
|
12184
|
+
}),
|
|
12185
|
+
object({
|
|
12186
|
+
kind: literal("derivative"),
|
|
12187
|
+
window: RollingWindowSchema,
|
|
12188
|
+
per: _enum([
|
|
12189
|
+
"second",
|
|
12190
|
+
"minute",
|
|
12191
|
+
"hour"
|
|
12192
|
+
]),
|
|
12193
|
+
source: HelperMemberSchema
|
|
12194
|
+
})
|
|
12195
|
+
]);
|
|
12049
12196
|
/** A composed device's stableId is this prefix plus the block id. */
|
|
12050
12197
|
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12051
12198
|
/** Longest snippet a `code` source may carry (slice 4). */
|
|
@@ -12106,6 +12253,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12106
12253
|
"all"
|
|
12107
12254
|
]),
|
|
12108
12255
|
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12256
|
+
/**
|
|
12257
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12258
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12259
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12260
|
+
*/
|
|
12261
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12109
12262
|
/** `value` is the reading; the others are the member counts. */
|
|
12110
12263
|
publish: _enum([
|
|
12111
12264
|
"value",
|
|
@@ -12119,6 +12272,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12119
12272
|
"omit",
|
|
12120
12273
|
"offline"
|
|
12121
12274
|
])
|
|
12275
|
+
}),
|
|
12276
|
+
object({
|
|
12277
|
+
kind: literal("series"),
|
|
12278
|
+
read: CompositionFieldReadSchema,
|
|
12279
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12280
|
+
publish: _enum([
|
|
12281
|
+
"value",
|
|
12282
|
+
"included",
|
|
12283
|
+
"excluded",
|
|
12284
|
+
"total"
|
|
12285
|
+
]),
|
|
12286
|
+
/**
|
|
12287
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12288
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12289
|
+
*/
|
|
12290
|
+
empty: _enum([
|
|
12291
|
+
"null",
|
|
12292
|
+
"omit",
|
|
12293
|
+
"offline"
|
|
12294
|
+
])
|
|
12122
12295
|
})
|
|
12123
12296
|
]);
|
|
12124
12297
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
@@ -18595,7 +18768,8 @@ var CompositionProblemSchema = object({
|
|
|
18595
18768
|
"native-capability-replace",
|
|
18596
18769
|
"mixed-quantity",
|
|
18597
18770
|
"helper-mismatch",
|
|
18598
|
-
"member-constraint"
|
|
18771
|
+
"member-constraint",
|
|
18772
|
+
"retention"
|
|
18599
18773
|
]),
|
|
18600
18774
|
path: string(),
|
|
18601
18775
|
message: string()
|
|
@@ -18829,13 +19003,17 @@ Object.freeze({
|
|
|
18829
19003
|
latchedAt: {
|
|
18830
19004
|
kind: "fixed",
|
|
18831
19005
|
result: ["number", "null"]
|
|
19006
|
+
},
|
|
19007
|
+
schmitt: {
|
|
19008
|
+
kind: "fixed",
|
|
19009
|
+
result: ["boolean", "null"]
|
|
18832
19010
|
}
|
|
18833
19011
|
});
|
|
18834
19012
|
/**
|
|
18835
19013
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18836
19014
|
* Data, not a form default written into the block.
|
|
18837
19015
|
*/
|
|
18838
|
-
var NOW = {
|
|
19016
|
+
var NOW$2 = {
|
|
18839
19017
|
fieldPath: "lastFetchedAt",
|
|
18840
19018
|
expr: "now"
|
|
18841
19019
|
};
|
|
@@ -18849,6 +19027,8 @@ function numeric(input) {
|
|
|
18849
19027
|
family: "numeric",
|
|
18850
19028
|
deviceType: DeviceType.Sensor,
|
|
18851
19029
|
memberDeviceType: DeviceType.Sensor,
|
|
19030
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19031
|
+
activeWhen: void 0,
|
|
18852
19032
|
commandCaps: [],
|
|
18853
19033
|
baseUnit: baseUnitOf(input.quantity),
|
|
18854
19034
|
aggregates: NUMERIC_AGGREGATES,
|
|
@@ -18864,6 +19044,8 @@ function binary(input) {
|
|
|
18864
19044
|
family: "binary",
|
|
18865
19045
|
deviceType: DeviceType.Sensor,
|
|
18866
19046
|
memberDeviceType: DeviceType.Sensor,
|
|
19047
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19048
|
+
activeWhen: void 0,
|
|
18867
19049
|
commandCaps: [],
|
|
18868
19050
|
quantity: "none",
|
|
18869
19051
|
baseUnit: void 0,
|
|
@@ -18881,7 +19063,7 @@ var GROUP_TEMPLATES = [
|
|
|
18881
19063
|
quantity: "temperature",
|
|
18882
19064
|
defaultAggregate: "mean",
|
|
18883
19065
|
empty: "null",
|
|
18884
|
-
companions: [NOW]
|
|
19066
|
+
companions: [NOW$2]
|
|
18885
19067
|
}),
|
|
18886
19068
|
numeric({
|
|
18887
19069
|
id: "humidity",
|
|
@@ -18892,7 +19074,7 @@ var GROUP_TEMPLATES = [
|
|
|
18892
19074
|
quantity: "humidity",
|
|
18893
19075
|
defaultAggregate: "mean",
|
|
18894
19076
|
empty: "null",
|
|
18895
|
-
companions: [NOW]
|
|
19077
|
+
companions: [NOW$2]
|
|
18896
19078
|
}),
|
|
18897
19079
|
numeric({
|
|
18898
19080
|
id: "pressure",
|
|
@@ -18903,7 +19085,7 @@ var GROUP_TEMPLATES = [
|
|
|
18903
19085
|
quantity: "pressure",
|
|
18904
19086
|
defaultAggregate: "mean",
|
|
18905
19087
|
empty: "null",
|
|
18906
|
-
companions: [NOW]
|
|
19088
|
+
companions: [NOW$2]
|
|
18907
19089
|
}),
|
|
18908
19090
|
numeric({
|
|
18909
19091
|
id: "illuminance",
|
|
@@ -18914,7 +19096,7 @@ var GROUP_TEMPLATES = [
|
|
|
18914
19096
|
quantity: "illuminance",
|
|
18915
19097
|
defaultAggregate: "mean",
|
|
18916
19098
|
empty: "null",
|
|
18917
|
-
companions: [NOW]
|
|
19099
|
+
companions: [NOW$2]
|
|
18918
19100
|
}),
|
|
18919
19101
|
numeric({
|
|
18920
19102
|
id: "power",
|
|
@@ -18925,7 +19107,7 @@ var GROUP_TEMPLATES = [
|
|
|
18925
19107
|
quantity: "power",
|
|
18926
19108
|
defaultAggregate: "sum",
|
|
18927
19109
|
empty: "omit",
|
|
18928
|
-
companions: [NOW]
|
|
19110
|
+
companions: [NOW$2]
|
|
18929
19111
|
}),
|
|
18930
19112
|
numeric({
|
|
18931
19113
|
id: "energy",
|
|
@@ -18936,7 +19118,7 @@ var GROUP_TEMPLATES = [
|
|
|
18936
19118
|
quantity: "energy",
|
|
18937
19119
|
defaultAggregate: "sum",
|
|
18938
19120
|
empty: "omit",
|
|
18939
|
-
companions: [NOW]
|
|
19121
|
+
companions: [NOW$2]
|
|
18940
19122
|
}),
|
|
18941
19123
|
numeric({
|
|
18942
19124
|
id: "battery",
|
|
@@ -18971,7 +19153,7 @@ var GROUP_TEMPLATES = [
|
|
|
18971
19153
|
quantity: "device",
|
|
18972
19154
|
defaultAggregate: "mean",
|
|
18973
19155
|
empty: "null",
|
|
18974
|
-
companions: [NOW]
|
|
19156
|
+
companions: [NOW$2]
|
|
18975
19157
|
}),
|
|
18976
19158
|
binary({
|
|
18977
19159
|
id: "motion",
|
|
@@ -19065,6 +19247,11 @@ var GROUP_TEMPLATES = [
|
|
|
19065
19247
|
summary: "On when at least one switch is on, or when all of them are. Offline and unknown members are left out of that decision, never read as off, and still receive the command.",
|
|
19066
19248
|
deviceType: DeviceType.Switch,
|
|
19067
19249
|
outputCap: "switch",
|
|
19250
|
+
outputField: "on",
|
|
19251
|
+
member: {
|
|
19252
|
+
cap: "switch",
|
|
19253
|
+
fieldPath: "on"
|
|
19254
|
+
},
|
|
19068
19255
|
commandCaps: ["switch"]
|
|
19069
19256
|
}),
|
|
19070
19257
|
actuator({
|
|
@@ -19072,34 +19259,136 @@ var GROUP_TEMPLATES = [
|
|
|
19072
19259
|
summary: "On when at least one light is on, or when all of them are. Brightness and colour are offered only when every member has them. A command is not sent to a member that lacks it.",
|
|
19073
19260
|
deviceType: DeviceType.Light,
|
|
19074
19261
|
outputCap: "switch",
|
|
19262
|
+
outputField: "on",
|
|
19263
|
+
member: {
|
|
19264
|
+
cap: "switch",
|
|
19265
|
+
fieldPath: "on"
|
|
19266
|
+
},
|
|
19075
19267
|
commandCaps: [
|
|
19076
19268
|
"switch",
|
|
19077
19269
|
"brightness",
|
|
19078
19270
|
"color"
|
|
19079
19271
|
]
|
|
19272
|
+
}),
|
|
19273
|
+
actuator({
|
|
19274
|
+
id: "fan",
|
|
19275
|
+
summary: "On when at least one fan is on, or when all of them are. Speed, preset, direction and oscillation are offered only when every fan has them. A command is not sent to a fan that lacks it.",
|
|
19276
|
+
deviceType: DeviceType.Fan,
|
|
19277
|
+
outputCap: "switch",
|
|
19278
|
+
outputField: "on",
|
|
19279
|
+
member: {
|
|
19280
|
+
cap: "switch",
|
|
19281
|
+
fieldPath: "on"
|
|
19282
|
+
},
|
|
19283
|
+
commandCaps: ["switch", "fan-control"]
|
|
19284
|
+
}),
|
|
19285
|
+
actuator({
|
|
19286
|
+
id: "cover",
|
|
19287
|
+
summary: "Open when at least one cover is open or part-open, or only when all of them are. Position and tilt are offered only when every cover has them. A cover that reports nothing is left out, never read as closed.",
|
|
19288
|
+
deviceType: DeviceType.Cover,
|
|
19289
|
+
outputCap: "group-active",
|
|
19290
|
+
outputField: "active",
|
|
19291
|
+
member: {
|
|
19292
|
+
cap: "cover",
|
|
19293
|
+
fieldPath: "state"
|
|
19294
|
+
},
|
|
19295
|
+
activeWhen: [
|
|
19296
|
+
"open",
|
|
19297
|
+
"opening",
|
|
19298
|
+
"stopped"
|
|
19299
|
+
],
|
|
19300
|
+
commandCaps: ["cover"]
|
|
19301
|
+
}),
|
|
19302
|
+
actuator({
|
|
19303
|
+
id: "valve",
|
|
19304
|
+
summary: "Open when at least one valve is open or part-open, or only when all of them are. Position is offered only when every valve has it. A valve that reports nothing is left out, never read as closed.",
|
|
19305
|
+
deviceType: DeviceType.Valve,
|
|
19306
|
+
outputCap: "group-active",
|
|
19307
|
+
outputField: "active",
|
|
19308
|
+
member: {
|
|
19309
|
+
cap: "valve",
|
|
19310
|
+
fieldPath: "state"
|
|
19311
|
+
},
|
|
19312
|
+
activeWhen: [
|
|
19313
|
+
"open",
|
|
19314
|
+
"opening",
|
|
19315
|
+
"stopped"
|
|
19316
|
+
],
|
|
19317
|
+
commandCaps: ["valve"]
|
|
19318
|
+
}),
|
|
19319
|
+
actuator({
|
|
19320
|
+
id: "lock",
|
|
19321
|
+
summary: "Locked when at least one lock is locked, or only when all of them are. A jammed or moving lock is not locked. Locking is one tap; unlocking the group needs a confirmation every time, and nothing is sent without it.",
|
|
19322
|
+
deviceType: DeviceType.Lock,
|
|
19323
|
+
outputCap: "group-active",
|
|
19324
|
+
outputField: "active",
|
|
19325
|
+
member: {
|
|
19326
|
+
cap: "lock-control",
|
|
19327
|
+
fieldPath: "state"
|
|
19328
|
+
},
|
|
19329
|
+
activeWhen: ["locked"],
|
|
19330
|
+
commandCaps: ["lock-control"]
|
|
19331
|
+
}),
|
|
19332
|
+
actuator({
|
|
19333
|
+
id: "media-player",
|
|
19334
|
+
summary: "Playing when at least one player is playing, or only when all of them are. Volume is offered only when every player has it. A player that reports nothing is left out, never read as stopped.",
|
|
19335
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19336
|
+
outputCap: "group-active",
|
|
19337
|
+
outputField: "active",
|
|
19338
|
+
member: {
|
|
19339
|
+
cap: "media-player",
|
|
19340
|
+
fieldPath: "state"
|
|
19341
|
+
},
|
|
19342
|
+
activeWhen: ["playing", "buffering"],
|
|
19343
|
+
commandCaps: ["media-player"]
|
|
19344
|
+
}),
|
|
19345
|
+
actuator({
|
|
19346
|
+
id: "climate",
|
|
19347
|
+
summary: "Running when at least one thermostat or air conditioner is not off, or only when all of them are. Target temperature and fan are offered only when every device has them. A device that reports nothing is left out, never read as off.",
|
|
19348
|
+
deviceType: DeviceType.Thermostat,
|
|
19349
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19350
|
+
outputCap: "group-active",
|
|
19351
|
+
outputField: "active",
|
|
19352
|
+
member: {
|
|
19353
|
+
cap: "climate-control",
|
|
19354
|
+
fieldPath: "mode"
|
|
19355
|
+
},
|
|
19356
|
+
activeWhen: [
|
|
19357
|
+
"heat",
|
|
19358
|
+
"cool",
|
|
19359
|
+
"auto",
|
|
19360
|
+
"heat_cool",
|
|
19361
|
+
"fan_only",
|
|
19362
|
+
"dry"
|
|
19363
|
+
],
|
|
19364
|
+
commandCaps: ["climate-control"]
|
|
19080
19365
|
})
|
|
19081
19366
|
];
|
|
19082
19367
|
function actuator(input) {
|
|
19083
19368
|
return {
|
|
19084
|
-
|
|
19369
|
+
id: input.id,
|
|
19370
|
+
summary: input.summary,
|
|
19371
|
+
deviceType: input.deviceType,
|
|
19372
|
+
outputCap: input.outputCap,
|
|
19373
|
+
outputField: input.outputField,
|
|
19374
|
+
commandCaps: input.commandCaps,
|
|
19085
19375
|
family: "actuator",
|
|
19086
19376
|
role: void 0,
|
|
19087
19377
|
memberDeviceType: input.deviceType,
|
|
19088
|
-
|
|
19378
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19379
|
+
activeWhen: input.activeWhen,
|
|
19089
19380
|
quantity: "none",
|
|
19090
19381
|
baseUnit: void 0,
|
|
19091
19382
|
aggregates: BINARY_AGGREGATES,
|
|
19092
19383
|
defaultAggregate: "any",
|
|
19093
19384
|
empty: "offline",
|
|
19094
|
-
accept: [
|
|
19095
|
-
cap: "switch",
|
|
19096
|
-
fieldPath: "on"
|
|
19097
|
-
}],
|
|
19385
|
+
accept: [input.member],
|
|
19098
19386
|
companions: [CHANGED]
|
|
19099
19387
|
};
|
|
19100
19388
|
}
|
|
19101
19389
|
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19102
19390
|
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19391
|
+
DeviceType.Camera;
|
|
19103
19392
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
19104
19393
|
/**
|
|
19105
19394
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -47278,7 +47567,20 @@ var NcRuleInputSchema = object({
|
|
|
47278
47567
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
47279
47568
|
* path does not run Zod defaults.
|
|
47280
47569
|
*/
|
|
47281
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
47570
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
47571
|
+
/**
|
|
47572
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
47573
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
47574
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
47575
|
+
* same mark the Library writes, and records whose notification it was and
|
|
47576
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
47577
|
+
*
|
|
47578
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
47579
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
47580
|
+
* authored before this field meant. An editor turns it off by writing
|
|
47581
|
+
* `false`, so it needs no `clear` key.
|
|
47582
|
+
*/
|
|
47583
|
+
askVerdict: boolean().optional()
|
|
47282
47584
|
});
|
|
47283
47585
|
/**
|
|
47284
47586
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -60997,7 +61299,17 @@ var groupCommandsCapability = {
|
|
|
60997
61299
|
scope: "device",
|
|
60998
61300
|
deviceNative: true,
|
|
60999
61301
|
mode: "singleton",
|
|
61000
|
-
deviceTypes: [
|
|
61302
|
+
deviceTypes: [
|
|
61303
|
+
DeviceType.Switch,
|
|
61304
|
+
DeviceType.Light,
|
|
61305
|
+
DeviceType.Fan,
|
|
61306
|
+
DeviceType.Cover,
|
|
61307
|
+
DeviceType.Valve,
|
|
61308
|
+
DeviceType.Lock,
|
|
61309
|
+
DeviceType.MediaPlayer,
|
|
61310
|
+
DeviceType.Thermostat,
|
|
61311
|
+
DeviceType.Climate
|
|
61312
|
+
],
|
|
61001
61313
|
methods: {},
|
|
61002
61314
|
status: {
|
|
61003
61315
|
schema: GroupCommandsSchema,
|
|
@@ -61015,6 +61327,49 @@ var groupCommandsCapability = {
|
|
|
61015
61327
|
history: "none"
|
|
61016
61328
|
};
|
|
61017
61329
|
/**
|
|
61330
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
61331
|
+
* included member is, or every included member is. What "active" means is the
|
|
61332
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
61333
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
61334
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
61335
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
61336
|
+
* empty included set takes the device offline, never `active: false`.
|
|
61337
|
+
*/
|
|
61338
|
+
var GroupActiveSchema = object({
|
|
61339
|
+
active: boolean().meta({ label: "Active" }),
|
|
61340
|
+
/** Ms epoch when the slice was last updated. */
|
|
61341
|
+
lastChangedAt: number()
|
|
61342
|
+
});
|
|
61343
|
+
var groupActiveCapability = {
|
|
61344
|
+
name: "group-active",
|
|
61345
|
+
scope: "device",
|
|
61346
|
+
deviceNative: true,
|
|
61347
|
+
mode: "singleton",
|
|
61348
|
+
deviceTypes: [
|
|
61349
|
+
DeviceType.Cover,
|
|
61350
|
+
DeviceType.Valve,
|
|
61351
|
+
DeviceType.Lock,
|
|
61352
|
+
DeviceType.MediaPlayer,
|
|
61353
|
+
DeviceType.Climate,
|
|
61354
|
+
DeviceType.Thermostat
|
|
61355
|
+
],
|
|
61356
|
+
methods: {},
|
|
61357
|
+
status: {
|
|
61358
|
+
schema: GroupActiveSchema,
|
|
61359
|
+
kind: "push"
|
|
61360
|
+
},
|
|
61361
|
+
runtimeState: GroupActiveSchema,
|
|
61362
|
+
/**
|
|
61363
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
61364
|
+
* next source event; a restored value would outlive the members it named.
|
|
61365
|
+
*
|
|
61366
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61367
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61368
|
+
*/
|
|
61369
|
+
durability: "session",
|
|
61370
|
+
history: "none"
|
|
61371
|
+
};
|
|
61372
|
+
/**
|
|
61018
61373
|
* How many members of a helper group answered (D944). Counts are integers,
|
|
61019
61374
|
* not measurements: zero included is a real count, never a stand-in reading.
|
|
61020
61375
|
* The reading itself stays on the output capability. History is none — the
|
|
@@ -61045,7 +61400,14 @@ var groupStatusCapability = {
|
|
|
61045
61400
|
deviceTypes: [
|
|
61046
61401
|
DeviceType.Sensor,
|
|
61047
61402
|
DeviceType.Switch,
|
|
61048
|
-
DeviceType.Light
|
|
61403
|
+
DeviceType.Light,
|
|
61404
|
+
DeviceType.Fan,
|
|
61405
|
+
DeviceType.Cover,
|
|
61406
|
+
DeviceType.Valve,
|
|
61407
|
+
DeviceType.Lock,
|
|
61408
|
+
DeviceType.MediaPlayer,
|
|
61409
|
+
DeviceType.Thermostat,
|
|
61410
|
+
DeviceType.Climate
|
|
61049
61411
|
],
|
|
61050
61412
|
methods: {},
|
|
61051
61413
|
status: {
|
|
@@ -62318,7 +62680,14 @@ var lockControlCapability = {
|
|
|
62318
62680
|
}),
|
|
62319
62681
|
unlock: method(object({
|
|
62320
62682
|
deviceId: number().int().nonnegative(),
|
|
62321
|
-
code: string().min(1).optional()
|
|
62683
|
+
code: string().min(1).optional(),
|
|
62684
|
+
/**
|
|
62685
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
62686
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
62687
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
62688
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
62689
|
+
*/
|
|
62690
|
+
confirm: boolean().optional()
|
|
62322
62691
|
}), _void(), {
|
|
62323
62692
|
kind: "mutation",
|
|
62324
62693
|
auth: "protected"
|
|
@@ -62355,6 +62724,44 @@ var lockControlCapability = {
|
|
|
62355
62724
|
volatileStateFields: ["lastChangedAt"]
|
|
62356
62725
|
};
|
|
62357
62726
|
/**
|
|
62727
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
62728
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
62729
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
62730
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
62731
|
+
*/
|
|
62732
|
+
var MeterStatusSchema = object({
|
|
62733
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
62734
|
+
lastFetchedAt: number()
|
|
62735
|
+
});
|
|
62736
|
+
var meterCapability = {
|
|
62737
|
+
name: "meter",
|
|
62738
|
+
scope: "device",
|
|
62739
|
+
deviceNative: true,
|
|
62740
|
+
mode: "singleton",
|
|
62741
|
+
deviceTypes: [DeviceType.Sensor],
|
|
62742
|
+
methods: {},
|
|
62743
|
+
status: {
|
|
62744
|
+
schema: MeterStatusSchema,
|
|
62745
|
+
kind: "push"
|
|
62746
|
+
},
|
|
62747
|
+
runtimeState: MeterStatusSchema,
|
|
62748
|
+
/**
|
|
62749
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
62750
|
+
* history integral. A restart shows it only until the history pass
|
|
62751
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
62752
|
+
*
|
|
62753
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
62754
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
62755
|
+
*/
|
|
62756
|
+
durability: "restored",
|
|
62757
|
+
history: { fields: { value: {
|
|
62758
|
+
kind: "counter",
|
|
62759
|
+
deadband: .001,
|
|
62760
|
+
minIntervalMs: 6e4
|
|
62761
|
+
} } },
|
|
62762
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
62763
|
+
};
|
|
62764
|
+
/**
|
|
62358
62765
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
62359
62766
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
62360
62767
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -68123,7 +68530,8 @@ var switchCapability = {
|
|
|
68123
68530
|
deviceTypes: [
|
|
68124
68531
|
DeviceType.Switch,
|
|
68125
68532
|
DeviceType.Siren,
|
|
68126
|
-
DeviceType.Light
|
|
68533
|
+
DeviceType.Light,
|
|
68534
|
+
DeviceType.Fan
|
|
68127
68535
|
],
|
|
68128
68536
|
methods: { setState: method(object({
|
|
68129
68537
|
deviceId: number(),
|
|
@@ -70373,6 +70781,7 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
|
|
|
70373
70781
|
if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
70374
70782
|
return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
|
|
70375
70783
|
}
|
|
70784
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
70376
70785
|
/**
|
|
70377
70786
|
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
70378
70787
|
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
@@ -71101,6 +71510,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
71101
71510
|
featureProbe: featureProbeCapability,
|
|
71102
71511
|
flood: floodCapability,
|
|
71103
71512
|
gas: gasCapability,
|
|
71513
|
+
groupActive: groupActiveCapability,
|
|
71104
71514
|
groupCommands: groupCommandsCapability,
|
|
71105
71515
|
groupStatus: groupStatusCapability,
|
|
71106
71516
|
heatingValve: heatingValveCapability,
|
|
@@ -71112,6 +71522,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
71112
71522
|
lawnMowerControl: lawnMowerControlCapability,
|
|
71113
71523
|
lockControl: lockControlCapability,
|
|
71114
71524
|
mediaPlayer: mediaPlayerCapability,
|
|
71525
|
+
meter: meterCapability,
|
|
71115
71526
|
motion: motionCapability,
|
|
71116
71527
|
motionTrigger: motionTriggerCapability,
|
|
71117
71528
|
motionZones: motionZonesCapability,
|
|
@@ -75594,6 +76005,13 @@ Object.freeze({
|
|
|
75594
76005
|
access: "view",
|
|
75595
76006
|
role: "viewer"
|
|
75596
76007
|
},
|
|
76008
|
+
"groupActive.getStatus": {
|
|
76009
|
+
capName: "group-active",
|
|
76010
|
+
capScope: "device",
|
|
76011
|
+
addonId: null,
|
|
76012
|
+
access: "view",
|
|
76013
|
+
role: "viewer"
|
|
76014
|
+
},
|
|
75597
76015
|
"groupCommands.getStatus": {
|
|
75598
76016
|
capName: "group-commands",
|
|
75599
76017
|
capScope: "device",
|
|
@@ -76560,6 +76978,13 @@ Object.freeze({
|
|
|
76560
76978
|
access: "create",
|
|
76561
76979
|
role: "admin"
|
|
76562
76980
|
},
|
|
76981
|
+
"meter.getStatus": {
|
|
76982
|
+
capName: "meter",
|
|
76983
|
+
capScope: "device",
|
|
76984
|
+
addonId: null,
|
|
76985
|
+
access: "view",
|
|
76986
|
+
role: "viewer"
|
|
76987
|
+
},
|
|
76563
76988
|
"metricsProvider.collectSnapshot": {
|
|
76564
76989
|
capName: "metrics-provider",
|
|
76565
76990
|
capScope: "system",
|
|
@@ -85462,6 +85887,10 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85462
85887
|
icon: "flame"
|
|
85463
85888
|
}]
|
|
85464
85889
|
},
|
|
85890
|
+
"group-active": {
|
|
85891
|
+
scope: "device",
|
|
85892
|
+
noun: t("Group state", "Stato del gruppo")
|
|
85893
|
+
},
|
|
85465
85894
|
"group-commands": {
|
|
85466
85895
|
scope: "device",
|
|
85467
85896
|
noun: t("Group command", "Comando di gruppo")
|
|
@@ -85518,6 +85947,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85518
85947
|
}],
|
|
85519
85948
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
85520
85949
|
},
|
|
85950
|
+
meter: {
|
|
85951
|
+
scope: "device",
|
|
85952
|
+
noun: t("Meter", "Contatore"),
|
|
85953
|
+
state: [{
|
|
85954
|
+
kind: "numeric",
|
|
85955
|
+
field: "value",
|
|
85956
|
+
quantity: t("the total", "il totale"),
|
|
85957
|
+
label: t("Total", "Totale"),
|
|
85958
|
+
icon: "gauge"
|
|
85959
|
+
}]
|
|
85960
|
+
},
|
|
85521
85961
|
"numeric-sensor": {
|
|
85522
85962
|
scope: "device",
|
|
85523
85963
|
noun: t("Sensor", "Sensore"),
|
|
@@ -87008,6 +87448,11 @@ Object.freeze({
|
|
|
87008
87448
|
form: "single",
|
|
87009
87449
|
optional: false
|
|
87010
87450
|
}],
|
|
87451
|
+
"groupActive.getStatus": [{
|
|
87452
|
+
name: "deviceId",
|
|
87453
|
+
form: "single",
|
|
87454
|
+
optional: false
|
|
87455
|
+
}],
|
|
87011
87456
|
"groupCommands.getStatus": [{
|
|
87012
87457
|
name: "deviceId",
|
|
87013
87458
|
form: "single",
|
|
@@ -87218,6 +87663,11 @@ Object.freeze({
|
|
|
87218
87663
|
form: "single",
|
|
87219
87664
|
optional: false
|
|
87220
87665
|
}],
|
|
87666
|
+
"meter.getStatus": [{
|
|
87667
|
+
name: "deviceId",
|
|
87668
|
+
form: "single",
|
|
87669
|
+
optional: false
|
|
87670
|
+
}],
|
|
87221
87671
|
"motion.getStatus": [{
|
|
87222
87672
|
name: "deviceId",
|
|
87223
87673
|
form: "single",
|
|
@@ -88825,7 +89275,6 @@ Object.freeze({
|
|
|
88825
89275
|
"network-access": "ingress",
|
|
88826
89276
|
"smtp-provider": "email"
|
|
88827
89277
|
});
|
|
88828
|
-
DeviceType.Camera;
|
|
88829
89278
|
/**
|
|
88830
89279
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
88831
89280
|
* `z.infer`, they do not restate the shape.
|