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