@camstack/addon-pipeline 1.2.628 → 1.2.630
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 +12 -0
- package/README.md +35 -0
- package/dist/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-D2oFV46F.js → custom-model-catalog-CsHQljey.js} +2 -2
- package/dist/{custom-model-catalog-Bu1Lc-iF.mjs → custom-model-catalog-qwNT0qE-.mjs} +2 -2
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-DNW4WfVK.mjs → dist-C56NTN3j.mjs} +1061 -24
- package/dist/{dist-BjySFF52.js → dist-M09KjuSx.js} +1061 -24
- package/dist/{model-catalogs-CwuCl3IY.js → model-catalogs-BmZHxpaD.js} +1 -1
- package/dist/{model-catalogs-CCHnV0wA.mjs → model-catalogs-vPj_kgtX.mjs} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-CLDkYxRi.js → node-C0CzsJ0N.js} +1 -1
- package/dist/{node-CiT7lJCO.mjs → node-CdsOgsyN.mjs} +1 -1
- package/dist/pipeline-runner/index.js +3 -3
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/{process-memory-D5WNQP42.js → process-memory-BURe-pwd.js} +1 -1
- package/dist/{process-memory-6dtW_uwK.mjs → process-memory-DAhr_IbO.mjs} +1 -1
- package/dist/recorder/index.js +2 -2
- package/dist/recorder/index.mjs +2 -2
- package/dist/{segment-demux-js-DDI4hgPB.js → segment-demux-js-B391lmQZ.js} +1 -1
- package/dist/{segment-demux-js-CL6CBu1v.mjs → segment-demux-js-CobIINvd.mjs} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DrEPZZ6A.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Bxan5418.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-inxALjZf.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-wSzIkKI-.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-CsSJvo8w.mjs → hostInit-CmFod5rw.mjs} +2 -2
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +4 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-aLQXb88Y.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CEiM-boT.mjs +0 -26
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
let node_crypto = require("node:crypto");
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -325,6 +325,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
325
325
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
326
326
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
327
327
|
/**
|
|
328
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
329
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
330
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
331
|
+
*/
|
|
332
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
333
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
334
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
335
|
+
/**
|
|
328
336
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
329
337
|
* (a settings change via `setAgentInferenceDevices` /
|
|
330
338
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5567,7 +5575,7 @@ var ZodIssueCode = {
|
|
|
5567
5575
|
var ZodFirstPartyTypeKind;
|
|
5568
5576
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5569
5577
|
//#endregion
|
|
5570
|
-
//#region ../types/dist/sleep
|
|
5578
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5571
5579
|
/**
|
|
5572
5580
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5573
5581
|
* window to float samples (D455).
|
|
@@ -8354,6 +8362,53 @@ var READING_QUANTITIES = [
|
|
|
8354
8362
|
];
|
|
8355
8363
|
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8356
8364
|
new Set(READING_QUANTITIES);
|
|
8365
|
+
/**
|
|
8366
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8367
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8368
|
+
*/
|
|
8369
|
+
var QUANTITY_BASE = {
|
|
8370
|
+
temperature: "°C",
|
|
8371
|
+
pressure: "hPa",
|
|
8372
|
+
speed: "m/s",
|
|
8373
|
+
precipitation: "mm",
|
|
8374
|
+
"precipitation-rate": "mm/h",
|
|
8375
|
+
length: "m",
|
|
8376
|
+
area: "m²",
|
|
8377
|
+
illuminance: "lx",
|
|
8378
|
+
irradiance: "W/m²",
|
|
8379
|
+
power: "W",
|
|
8380
|
+
energy: "kWh",
|
|
8381
|
+
voltage: "V",
|
|
8382
|
+
current: "A",
|
|
8383
|
+
"apparent-power": "VA",
|
|
8384
|
+
humidity: "%",
|
|
8385
|
+
percentage: "%",
|
|
8386
|
+
"concentration-volume": "ppm",
|
|
8387
|
+
"concentration-mass": "µg/m³",
|
|
8388
|
+
"concentration-ppb": "ppb",
|
|
8389
|
+
volume: "L",
|
|
8390
|
+
duration: "s",
|
|
8391
|
+
"duration-ms": "ms",
|
|
8392
|
+
information: "B",
|
|
8393
|
+
"sound-level": "dBFS",
|
|
8394
|
+
"signal-level": "dBm",
|
|
8395
|
+
"colour-temperature": "mired",
|
|
8396
|
+
angle: "°",
|
|
8397
|
+
bitrate: "kbps",
|
|
8398
|
+
rate: "fps",
|
|
8399
|
+
mass: "kg",
|
|
8400
|
+
index: "none",
|
|
8401
|
+
ratio: "none",
|
|
8402
|
+
count: "none",
|
|
8403
|
+
none: "none",
|
|
8404
|
+
device: "device"
|
|
8405
|
+
};
|
|
8406
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8407
|
+
function baseUnitOf(quantity) {
|
|
8408
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8409
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8410
|
+
return symbol;
|
|
8411
|
+
}
|
|
8357
8412
|
function readingMeta(quantity, extras) {
|
|
8358
8413
|
return {
|
|
8359
8414
|
quantity,
|
|
@@ -9052,6 +9107,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
9052
9107
|
"filesystem-browse",
|
|
9053
9108
|
"flood",
|
|
9054
9109
|
"gas",
|
|
9110
|
+
"group-active",
|
|
9111
|
+
"group-commands",
|
|
9112
|
+
"group-status",
|
|
9055
9113
|
"heating-valve",
|
|
9056
9114
|
"humidifier",
|
|
9057
9115
|
"humidity-sensor",
|
|
@@ -9072,6 +9130,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9072
9130
|
"login-method",
|
|
9073
9131
|
"media-player",
|
|
9074
9132
|
"mesh-network",
|
|
9133
|
+
"meter",
|
|
9075
9134
|
"metrics-provider",
|
|
9076
9135
|
"model-convert",
|
|
9077
9136
|
"model-distributor",
|
|
@@ -9870,6 +9929,24 @@ Object.freeze({
|
|
|
9870
9929
|
"path": "detected",
|
|
9871
9930
|
"valueType": "boolean"
|
|
9872
9931
|
}],
|
|
9932
|
+
"group-active": [{
|
|
9933
|
+
"path": "active",
|
|
9934
|
+
"valueType": "boolean"
|
|
9935
|
+
}],
|
|
9936
|
+
"group-status": [
|
|
9937
|
+
{
|
|
9938
|
+
"path": "included",
|
|
9939
|
+
"valueType": "number"
|
|
9940
|
+
},
|
|
9941
|
+
{
|
|
9942
|
+
"path": "excluded",
|
|
9943
|
+
"valueType": "number"
|
|
9944
|
+
},
|
|
9945
|
+
{
|
|
9946
|
+
"path": "total",
|
|
9947
|
+
"valueType": "number"
|
|
9948
|
+
}
|
|
9949
|
+
],
|
|
9873
9950
|
"heating-valve": [{
|
|
9874
9951
|
"path": "position",
|
|
9875
9952
|
"valueType": "number"
|
|
@@ -10115,6 +10192,10 @@ Object.freeze({
|
|
|
10115
10192
|
]
|
|
10116
10193
|
}
|
|
10117
10194
|
],
|
|
10195
|
+
"meter": [{
|
|
10196
|
+
"path": "value",
|
|
10197
|
+
"valueType": "number"
|
|
10198
|
+
}],
|
|
10118
10199
|
"motion": [
|
|
10119
10200
|
{
|
|
10120
10201
|
"path": "detected",
|
|
@@ -11010,7 +11091,7 @@ function sleep(ms) {
|
|
|
11010
11091
|
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
11011
11092
|
}
|
|
11012
11093
|
//#endregion
|
|
11013
|
-
//#region ../types/dist/err-msg-
|
|
11094
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
11014
11095
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
11015
11096
|
DeviceType["Camera"] = "camera";
|
|
11016
11097
|
DeviceType["Hub"] = "hub";
|
|
@@ -11104,8 +11185,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
11104
11185
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11105
11186
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
11106
11187
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
11107
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
11188
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
11189
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
11108
11190
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
11191
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
11192
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
11193
|
+
DeviceType["Washer"] = "washer";
|
|
11194
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
11195
|
+
DeviceType["Dryer"] = "dryer";
|
|
11109
11196
|
return DeviceType;
|
|
11110
11197
|
}({});
|
|
11111
11198
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11363,7 +11450,7 @@ function errMsg(err) {
|
|
|
11363
11450
|
return String(err);
|
|
11364
11451
|
}
|
|
11365
11452
|
//#endregion
|
|
11366
|
-
//#region ../types/dist/composition-
|
|
11453
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11367
11454
|
var AUDIO_ENCODER_BY_CODEC = {
|
|
11368
11455
|
opus: "libopus",
|
|
11369
11456
|
aac: "aac",
|
|
@@ -12514,6 +12601,13 @@ var table = {
|
|
|
12514
12601
|
apply: () => {
|
|
12515
12602
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
12516
12603
|
}
|
|
12604
|
+
},
|
|
12605
|
+
schmitt: {
|
|
12606
|
+
minArgs: 3,
|
|
12607
|
+
maxArgs: 5,
|
|
12608
|
+
apply: () => {
|
|
12609
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
12610
|
+
}
|
|
12517
12611
|
}
|
|
12518
12612
|
};
|
|
12519
12613
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -12954,15 +13048,232 @@ function validateExpressionSource(src) {
|
|
|
12954
13048
|
}
|
|
12955
13049
|
return null;
|
|
12956
13050
|
}
|
|
12957
|
-
/**
|
|
12958
|
-
|
|
12959
|
-
|
|
12960
|
-
|
|
13051
|
+
/**
|
|
13052
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
13053
|
+
*
|
|
13054
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
13055
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
13056
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
13057
|
+
*
|
|
13058
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
13059
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
13060
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
13061
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
13062
|
+
* can move later without moving the others.
|
|
13063
|
+
*/
|
|
13064
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
13065
|
+
var APPLIANCE_KINDS = [
|
|
13066
|
+
"washer",
|
|
13067
|
+
"dryer",
|
|
13068
|
+
"dishwasher"
|
|
13069
|
+
];
|
|
13070
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
13071
|
+
/**
|
|
13072
|
+
* Statistics and integrals over a history read (D944).
|
|
13073
|
+
*
|
|
13074
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
13075
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
13076
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
13077
|
+
* as zero. A truncated read is not published.
|
|
13078
|
+
*/
|
|
13079
|
+
var STATISTIC_STATS = [
|
|
13080
|
+
"min",
|
|
13081
|
+
"max",
|
|
13082
|
+
"mean",
|
|
13083
|
+
"sum",
|
|
13084
|
+
"count",
|
|
13085
|
+
"change"
|
|
13086
|
+
];
|
|
13087
|
+
/**
|
|
13088
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
13089
|
+
*
|
|
13090
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
13091
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
13092
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
13093
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
13094
|
+
*/
|
|
13095
|
+
var MINUTE_MS = 6e4;
|
|
13096
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
13097
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
13098
|
+
var ROLLING_SPANS = [
|
|
13099
|
+
"1h",
|
|
13100
|
+
"24h",
|
|
13101
|
+
"2d",
|
|
13102
|
+
"7d",
|
|
13103
|
+
"30d",
|
|
13104
|
+
"custom"
|
|
13105
|
+
];
|
|
13106
|
+
var CALENDAR_PERIODS = [
|
|
13107
|
+
"today",
|
|
13108
|
+
"yesterday",
|
|
13109
|
+
"this-week",
|
|
13110
|
+
"this-month"
|
|
13111
|
+
];
|
|
13112
|
+
var RESET_PERIODS = [
|
|
13113
|
+
"never",
|
|
13114
|
+
"daily",
|
|
13115
|
+
"weekly",
|
|
13116
|
+
"monthly"
|
|
13117
|
+
];
|
|
13118
|
+
5 * MINUTE_MS;
|
|
13119
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
13120
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
13121
|
+
var rollingWindowObject = object({
|
|
13122
|
+
kind: literal("rolling"),
|
|
13123
|
+
span: _enum(ROLLING_SPANS),
|
|
13124
|
+
customMinutes: number().int().min(5).optional()
|
|
13125
|
+
}).check((payload) => {
|
|
13126
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
13127
|
+
code: "custom",
|
|
13128
|
+
message: "a custom range needs a duration in minutes",
|
|
13129
|
+
path: ["customMinutes"],
|
|
13130
|
+
input: payload.value
|
|
13131
|
+
});
|
|
13132
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
13133
|
+
code: "custom",
|
|
13134
|
+
message: "only a custom range carries a duration",
|
|
13135
|
+
path: ["customMinutes"],
|
|
13136
|
+
input: payload.value
|
|
13137
|
+
});
|
|
13138
|
+
});
|
|
13139
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
13140
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
13141
|
+
kind: literal("calendar"),
|
|
13142
|
+
period: _enum(CALENDAR_PERIODS)
|
|
13143
|
+
})]);
|
|
13144
|
+
/**
|
|
13145
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
13146
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
13147
|
+
* `composition.ts` (D659).
|
|
13148
|
+
*/
|
|
12961
13149
|
var CompositionSourceRefSchema = object({
|
|
12962
13150
|
/** The owning addon; `stableId` is unique only within it. */
|
|
12963
13151
|
addonId: string().min(1),
|
|
12964
13152
|
stableId: string().min(1)
|
|
12965
13153
|
});
|
|
13154
|
+
var GROUP_TEMPLATE_IDS = [
|
|
13155
|
+
"temperature",
|
|
13156
|
+
"humidity",
|
|
13157
|
+
"pressure",
|
|
13158
|
+
"illuminance",
|
|
13159
|
+
"power",
|
|
13160
|
+
"energy",
|
|
13161
|
+
"battery",
|
|
13162
|
+
"numeric",
|
|
13163
|
+
"motion",
|
|
13164
|
+
"contact",
|
|
13165
|
+
"leak",
|
|
13166
|
+
"smoke",
|
|
13167
|
+
"occupancy",
|
|
13168
|
+
"binary",
|
|
13169
|
+
"switch",
|
|
13170
|
+
"light",
|
|
13171
|
+
"fan",
|
|
13172
|
+
"cover",
|
|
13173
|
+
"valve",
|
|
13174
|
+
"lock",
|
|
13175
|
+
"media-player",
|
|
13176
|
+
"climate"
|
|
13177
|
+
];
|
|
13178
|
+
var NUMERIC_AGGREGATES = [
|
|
13179
|
+
"mean",
|
|
13180
|
+
"median",
|
|
13181
|
+
"min",
|
|
13182
|
+
"max",
|
|
13183
|
+
"sum"
|
|
13184
|
+
];
|
|
13185
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
13186
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
13187
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
13188
|
+
var AGGREGATE_REDUCERS = [
|
|
13189
|
+
"mean",
|
|
13190
|
+
"median",
|
|
13191
|
+
"min",
|
|
13192
|
+
"max",
|
|
13193
|
+
"sum",
|
|
13194
|
+
"any",
|
|
13195
|
+
"all"
|
|
13196
|
+
];
|
|
13197
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
13198
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
13199
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
13200
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
13201
|
+
var HelperMemberSchema = object({
|
|
13202
|
+
source: CompositionSourceRefSchema,
|
|
13203
|
+
cap: string().min(1),
|
|
13204
|
+
fieldPath: string().min(1)
|
|
13205
|
+
});
|
|
13206
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
13207
|
+
object({
|
|
13208
|
+
kind: literal("group"),
|
|
13209
|
+
templateId: GroupTemplateIdSchema,
|
|
13210
|
+
aggregate: AggregateReducerSchema,
|
|
13211
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
13212
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
13213
|
+
active: ActiveCriterionSchema.optional()
|
|
13214
|
+
}),
|
|
13215
|
+
object({
|
|
13216
|
+
kind: literal("appliance"),
|
|
13217
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
13218
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
13219
|
+
thresholdWatts: number().positive(),
|
|
13220
|
+
startDwellMs: number().int().nonnegative(),
|
|
13221
|
+
stopDwellMs: number().int().nonnegative(),
|
|
13222
|
+
member: HelperMemberSchema
|
|
13223
|
+
}),
|
|
13224
|
+
object({
|
|
13225
|
+
kind: literal("statistic"),
|
|
13226
|
+
stat: _enum(STATISTIC_STATS),
|
|
13227
|
+
window: StatisticWindowSchema,
|
|
13228
|
+
source: HelperMemberSchema
|
|
13229
|
+
}),
|
|
13230
|
+
object({
|
|
13231
|
+
kind: literal("integral"),
|
|
13232
|
+
reset: _enum(RESET_PERIODS),
|
|
13233
|
+
output: _enum(["energy", "meter"]),
|
|
13234
|
+
source: HelperMemberSchema
|
|
13235
|
+
}),
|
|
13236
|
+
object({
|
|
13237
|
+
kind: literal("threshold"),
|
|
13238
|
+
source: HelperMemberSchema,
|
|
13239
|
+
high: number(),
|
|
13240
|
+
low: number(),
|
|
13241
|
+
onForMs: number().int().nonnegative(),
|
|
13242
|
+
offForMs: number().int().nonnegative()
|
|
13243
|
+
}),
|
|
13244
|
+
object({
|
|
13245
|
+
kind: literal("arithmetic"),
|
|
13246
|
+
op: _enum([
|
|
13247
|
+
"sum",
|
|
13248
|
+
"difference",
|
|
13249
|
+
"ratio"
|
|
13250
|
+
]),
|
|
13251
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
13252
|
+
}),
|
|
13253
|
+
object({
|
|
13254
|
+
kind: literal("expression"),
|
|
13255
|
+
expr: string().min(1),
|
|
13256
|
+
inputs: array(object({
|
|
13257
|
+
name: string().min(1),
|
|
13258
|
+
member: HelperMemberSchema
|
|
13259
|
+
})).min(1).max(64),
|
|
13260
|
+
output: _enum(["number", "boolean"])
|
|
13261
|
+
}),
|
|
13262
|
+
object({
|
|
13263
|
+
kind: literal("derivative"),
|
|
13264
|
+
window: RollingWindowSchema,
|
|
13265
|
+
per: _enum([
|
|
13266
|
+
"second",
|
|
13267
|
+
"minute",
|
|
13268
|
+
"hour"
|
|
13269
|
+
]),
|
|
13270
|
+
source: HelperMemberSchema
|
|
13271
|
+
})
|
|
13272
|
+
]);
|
|
13273
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
13274
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
13275
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
13276
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
12966
13277
|
/** One field of one capability of one source device. */
|
|
12967
13278
|
var CompositionFieldReadSchema = object({
|
|
12968
13279
|
source: CompositionSourceRefSchema,
|
|
@@ -13006,7 +13317,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
13006
13317
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
13007
13318
|
CompositionFromSourceSchema,
|
|
13008
13319
|
CompositionExpressionSourceSchema,
|
|
13009
|
-
CompositionCodeSourceSchema
|
|
13320
|
+
CompositionCodeSourceSchema,
|
|
13321
|
+
object({
|
|
13322
|
+
kind: literal("aggregate"),
|
|
13323
|
+
reducer: _enum([
|
|
13324
|
+
"mean",
|
|
13325
|
+
"median",
|
|
13326
|
+
"min",
|
|
13327
|
+
"max",
|
|
13328
|
+
"sum",
|
|
13329
|
+
"any",
|
|
13330
|
+
"all"
|
|
13331
|
+
]),
|
|
13332
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
13333
|
+
/**
|
|
13334
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
13335
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
13336
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
13337
|
+
*/
|
|
13338
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
13339
|
+
/** `value` is the reading; the others are the member counts. */
|
|
13340
|
+
publish: _enum([
|
|
13341
|
+
"value",
|
|
13342
|
+
"included",
|
|
13343
|
+
"excluded",
|
|
13344
|
+
"total"
|
|
13345
|
+
]),
|
|
13346
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
13347
|
+
empty: _enum([
|
|
13348
|
+
"null",
|
|
13349
|
+
"omit",
|
|
13350
|
+
"offline"
|
|
13351
|
+
])
|
|
13352
|
+
}),
|
|
13353
|
+
object({
|
|
13354
|
+
kind: literal("series"),
|
|
13355
|
+
read: CompositionFieldReadSchema,
|
|
13356
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
13357
|
+
publish: _enum([
|
|
13358
|
+
"value",
|
|
13359
|
+
"included",
|
|
13360
|
+
"excluded",
|
|
13361
|
+
"total"
|
|
13362
|
+
]),
|
|
13363
|
+
/**
|
|
13364
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
13365
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
13366
|
+
*/
|
|
13367
|
+
empty: _enum([
|
|
13368
|
+
"null",
|
|
13369
|
+
"omit",
|
|
13370
|
+
"offline"
|
|
13371
|
+
])
|
|
13372
|
+
})
|
|
13010
13373
|
]);
|
|
13011
13374
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
13012
13375
|
kind: literal("forward"),
|
|
@@ -13052,7 +13415,13 @@ var CompositionSchema = object({
|
|
|
13052
13415
|
kind: literal("existing"),
|
|
13053
13416
|
device: CompositionSourceRefSchema
|
|
13054
13417
|
})]),
|
|
13055
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
13418
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
13419
|
+
/**
|
|
13420
|
+
* Present when the block is a helper template. Absent on a free
|
|
13421
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
13422
|
+
* never the compiled features.
|
|
13423
|
+
*/
|
|
13424
|
+
helper: HelperSpecSchema.optional()
|
|
13056
13425
|
}).superRefine((composition, ctx) => {
|
|
13057
13426
|
const seen = /* @__PURE__ */ new Set();
|
|
13058
13427
|
composition.features.forEach((feature, index) => {
|
|
@@ -20983,7 +21352,11 @@ var CompositionProblemSchema = object({
|
|
|
20983
21352
|
"target-missing",
|
|
20984
21353
|
"target-unreadable",
|
|
20985
21354
|
"not-replaceable",
|
|
20986
|
-
"native-capability-replace"
|
|
21355
|
+
"native-capability-replace",
|
|
21356
|
+
"mixed-quantity",
|
|
21357
|
+
"helper-mismatch",
|
|
21358
|
+
"member-constraint",
|
|
21359
|
+
"retention"
|
|
20987
21360
|
]),
|
|
20988
21361
|
path: string(),
|
|
20989
21362
|
message: string()
|
|
@@ -21004,7 +21377,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
21004
21377
|
"null",
|
|
21005
21378
|
"offline",
|
|
21006
21379
|
"unknown",
|
|
21007
|
-
"release"
|
|
21380
|
+
"release",
|
|
21381
|
+
"omit"
|
|
21008
21382
|
]);
|
|
21009
21383
|
/**
|
|
21010
21384
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -21216,8 +21590,392 @@ Object.freeze({
|
|
|
21216
21590
|
latchedAt: {
|
|
21217
21591
|
kind: "fixed",
|
|
21218
21592
|
result: ["number", "null"]
|
|
21593
|
+
},
|
|
21594
|
+
schmitt: {
|
|
21595
|
+
kind: "fixed",
|
|
21596
|
+
result: ["boolean", "null"]
|
|
21219
21597
|
}
|
|
21220
21598
|
});
|
|
21599
|
+
/**
|
|
21600
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
21601
|
+
* Data, not a form default written into the block.
|
|
21602
|
+
*/
|
|
21603
|
+
var NOW$2 = {
|
|
21604
|
+
fieldPath: "lastFetchedAt",
|
|
21605
|
+
expr: "now"
|
|
21606
|
+
};
|
|
21607
|
+
var CHANGED = {
|
|
21608
|
+
fieldPath: "lastChangedAt",
|
|
21609
|
+
expr: "now"
|
|
21610
|
+
};
|
|
21611
|
+
function numeric(input) {
|
|
21612
|
+
return {
|
|
21613
|
+
...input,
|
|
21614
|
+
family: "numeric",
|
|
21615
|
+
deviceType: DeviceType.Sensor,
|
|
21616
|
+
memberDeviceType: DeviceType.Sensor,
|
|
21617
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
21618
|
+
activeWhen: void 0,
|
|
21619
|
+
commandCaps: [],
|
|
21620
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
21621
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
21622
|
+
accept: [{
|
|
21623
|
+
cap: input.outputCap,
|
|
21624
|
+
fieldPath: input.outputField
|
|
21625
|
+
}]
|
|
21626
|
+
};
|
|
21627
|
+
}
|
|
21628
|
+
function binary(input) {
|
|
21629
|
+
return {
|
|
21630
|
+
...input,
|
|
21631
|
+
family: "binary",
|
|
21632
|
+
deviceType: DeviceType.Sensor,
|
|
21633
|
+
memberDeviceType: DeviceType.Sensor,
|
|
21634
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
21635
|
+
activeWhen: void 0,
|
|
21636
|
+
commandCaps: [],
|
|
21637
|
+
quantity: "none",
|
|
21638
|
+
baseUnit: void 0,
|
|
21639
|
+
aggregates: BINARY_AGGREGATES,
|
|
21640
|
+
empty: "offline"
|
|
21641
|
+
};
|
|
21642
|
+
}
|
|
21643
|
+
var GROUP_TEMPLATES = [
|
|
21644
|
+
numeric({
|
|
21645
|
+
id: "temperature",
|
|
21646
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
21647
|
+
role: DeviceRole.TemperatureSensor,
|
|
21648
|
+
outputCap: "temperature-sensor",
|
|
21649
|
+
outputField: "celsius",
|
|
21650
|
+
quantity: "temperature",
|
|
21651
|
+
defaultAggregate: "mean",
|
|
21652
|
+
empty: "null",
|
|
21653
|
+
companions: [NOW$2]
|
|
21654
|
+
}),
|
|
21655
|
+
numeric({
|
|
21656
|
+
id: "humidity",
|
|
21657
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
21658
|
+
role: DeviceRole.HumiditySensor,
|
|
21659
|
+
outputCap: "humidity-sensor",
|
|
21660
|
+
outputField: "percent",
|
|
21661
|
+
quantity: "humidity",
|
|
21662
|
+
defaultAggregate: "mean",
|
|
21663
|
+
empty: "null",
|
|
21664
|
+
companions: [NOW$2]
|
|
21665
|
+
}),
|
|
21666
|
+
numeric({
|
|
21667
|
+
id: "pressure",
|
|
21668
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
21669
|
+
role: DeviceRole.PressureSensor,
|
|
21670
|
+
outputCap: "pressure-sensor",
|
|
21671
|
+
outputField: "hpa",
|
|
21672
|
+
quantity: "pressure",
|
|
21673
|
+
defaultAggregate: "mean",
|
|
21674
|
+
empty: "null",
|
|
21675
|
+
companions: [NOW$2]
|
|
21676
|
+
}),
|
|
21677
|
+
numeric({
|
|
21678
|
+
id: "illuminance",
|
|
21679
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
21680
|
+
role: DeviceRole.AmbientLightSensor,
|
|
21681
|
+
outputCap: "ambient-light-sensor",
|
|
21682
|
+
outputField: "lux",
|
|
21683
|
+
quantity: "illuminance",
|
|
21684
|
+
defaultAggregate: "mean",
|
|
21685
|
+
empty: "null",
|
|
21686
|
+
companions: [NOW$2]
|
|
21687
|
+
}),
|
|
21688
|
+
numeric({
|
|
21689
|
+
id: "power",
|
|
21690
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
21691
|
+
role: DeviceRole.PowerSensor,
|
|
21692
|
+
outputCap: "power-meter",
|
|
21693
|
+
outputField: "watts",
|
|
21694
|
+
quantity: "power",
|
|
21695
|
+
defaultAggregate: "sum",
|
|
21696
|
+
empty: "omit",
|
|
21697
|
+
companions: [NOW$2]
|
|
21698
|
+
}),
|
|
21699
|
+
numeric({
|
|
21700
|
+
id: "energy",
|
|
21701
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
21702
|
+
role: DeviceRole.EnergySensor,
|
|
21703
|
+
outputCap: "power-meter",
|
|
21704
|
+
outputField: "kwhTotal",
|
|
21705
|
+
quantity: "energy",
|
|
21706
|
+
defaultAggregate: "sum",
|
|
21707
|
+
empty: "omit",
|
|
21708
|
+
companions: [NOW$2]
|
|
21709
|
+
}),
|
|
21710
|
+
numeric({
|
|
21711
|
+
id: "battery",
|
|
21712
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
21713
|
+
role: DeviceRole.BatterySensor,
|
|
21714
|
+
outputCap: "battery",
|
|
21715
|
+
outputField: "percentage",
|
|
21716
|
+
quantity: "percentage",
|
|
21717
|
+
defaultAggregate: "mean",
|
|
21718
|
+
empty: "null",
|
|
21719
|
+
companions: [
|
|
21720
|
+
{
|
|
21721
|
+
fieldPath: "charging",
|
|
21722
|
+
expr: "\"unknown\""
|
|
21723
|
+
},
|
|
21724
|
+
{
|
|
21725
|
+
fieldPath: "sleeping",
|
|
21726
|
+
expr: "false"
|
|
21727
|
+
},
|
|
21728
|
+
{
|
|
21729
|
+
fieldPath: "lastUpdated",
|
|
21730
|
+
expr: "now"
|
|
21731
|
+
}
|
|
21732
|
+
]
|
|
21733
|
+
}),
|
|
21734
|
+
numeric({
|
|
21735
|
+
id: "numeric",
|
|
21736
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
21737
|
+
role: DeviceRole.NumericSensor,
|
|
21738
|
+
outputCap: "numeric-sensor",
|
|
21739
|
+
outputField: "value",
|
|
21740
|
+
quantity: "device",
|
|
21741
|
+
defaultAggregate: "mean",
|
|
21742
|
+
empty: "null",
|
|
21743
|
+
companions: [NOW$2]
|
|
21744
|
+
}),
|
|
21745
|
+
binary({
|
|
21746
|
+
id: "motion",
|
|
21747
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
21748
|
+
role: DeviceRole.MotionSensor,
|
|
21749
|
+
outputCap: "motion",
|
|
21750
|
+
outputField: "detected",
|
|
21751
|
+
defaultAggregate: "any",
|
|
21752
|
+
accept: [{
|
|
21753
|
+
cap: "motion",
|
|
21754
|
+
fieldPath: "detected"
|
|
21755
|
+
}],
|
|
21756
|
+
companions: [{
|
|
21757
|
+
fieldPath: "lastDetectedAt",
|
|
21758
|
+
expr: "null"
|
|
21759
|
+
}, {
|
|
21760
|
+
fieldPath: "autoClearAfterMs",
|
|
21761
|
+
expr: "null"
|
|
21762
|
+
}]
|
|
21763
|
+
}),
|
|
21764
|
+
binary({
|
|
21765
|
+
id: "contact",
|
|
21766
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
21767
|
+
role: DeviceRole.ContactSensor,
|
|
21768
|
+
outputCap: "contact",
|
|
21769
|
+
outputField: "entryOpen",
|
|
21770
|
+
defaultAggregate: "any",
|
|
21771
|
+
accept: [{
|
|
21772
|
+
cap: "contact",
|
|
21773
|
+
fieldPath: "entryOpen"
|
|
21774
|
+
}],
|
|
21775
|
+
companions: [CHANGED]
|
|
21776
|
+
}),
|
|
21777
|
+
binary({
|
|
21778
|
+
id: "leak",
|
|
21779
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
21780
|
+
role: DeviceRole.LeakSensor,
|
|
21781
|
+
outputCap: "flood",
|
|
21782
|
+
outputField: "flooded",
|
|
21783
|
+
defaultAggregate: "any",
|
|
21784
|
+
accept: [{
|
|
21785
|
+
cap: "flood",
|
|
21786
|
+
fieldPath: "flooded"
|
|
21787
|
+
}],
|
|
21788
|
+
companions: [CHANGED]
|
|
21789
|
+
}),
|
|
21790
|
+
binary({
|
|
21791
|
+
id: "smoke",
|
|
21792
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
21793
|
+
role: DeviceRole.SmokeSensor,
|
|
21794
|
+
outputCap: "smoke",
|
|
21795
|
+
outputField: "detected",
|
|
21796
|
+
defaultAggregate: "any",
|
|
21797
|
+
accept: [{
|
|
21798
|
+
cap: "smoke",
|
|
21799
|
+
fieldPath: "detected"
|
|
21800
|
+
}],
|
|
21801
|
+
companions: [CHANGED]
|
|
21802
|
+
}),
|
|
21803
|
+
binary({
|
|
21804
|
+
id: "occupancy",
|
|
21805
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
21806
|
+
role: DeviceRole.BinarySensor,
|
|
21807
|
+
outputCap: "binary",
|
|
21808
|
+
outputField: "on",
|
|
21809
|
+
defaultAggregate: "any",
|
|
21810
|
+
accept: [{
|
|
21811
|
+
cap: "motion",
|
|
21812
|
+
fieldPath: "detected"
|
|
21813
|
+
}, {
|
|
21814
|
+
cap: "binary",
|
|
21815
|
+
fieldPath: "on"
|
|
21816
|
+
}],
|
|
21817
|
+
companions: [CHANGED]
|
|
21818
|
+
}),
|
|
21819
|
+
binary({
|
|
21820
|
+
id: "binary",
|
|
21821
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
21822
|
+
role: DeviceRole.BinarySensor,
|
|
21823
|
+
outputCap: "binary",
|
|
21824
|
+
outputField: "on",
|
|
21825
|
+
defaultAggregate: "any",
|
|
21826
|
+
accept: [{
|
|
21827
|
+
cap: "binary",
|
|
21828
|
+
fieldPath: "on"
|
|
21829
|
+
}],
|
|
21830
|
+
companions: [CHANGED]
|
|
21831
|
+
}),
|
|
21832
|
+
actuator({
|
|
21833
|
+
id: "switch",
|
|
21834
|
+
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.",
|
|
21835
|
+
deviceType: DeviceType.Switch,
|
|
21836
|
+
outputCap: "switch",
|
|
21837
|
+
outputField: "on",
|
|
21838
|
+
member: {
|
|
21839
|
+
cap: "switch",
|
|
21840
|
+
fieldPath: "on"
|
|
21841
|
+
},
|
|
21842
|
+
commandCaps: ["switch"]
|
|
21843
|
+
}),
|
|
21844
|
+
actuator({
|
|
21845
|
+
id: "light",
|
|
21846
|
+
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.",
|
|
21847
|
+
deviceType: DeviceType.Light,
|
|
21848
|
+
outputCap: "switch",
|
|
21849
|
+
outputField: "on",
|
|
21850
|
+
member: {
|
|
21851
|
+
cap: "switch",
|
|
21852
|
+
fieldPath: "on"
|
|
21853
|
+
},
|
|
21854
|
+
commandCaps: [
|
|
21855
|
+
"switch",
|
|
21856
|
+
"brightness",
|
|
21857
|
+
"color"
|
|
21858
|
+
]
|
|
21859
|
+
}),
|
|
21860
|
+
actuator({
|
|
21861
|
+
id: "fan",
|
|
21862
|
+
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.",
|
|
21863
|
+
deviceType: DeviceType.Fan,
|
|
21864
|
+
outputCap: "switch",
|
|
21865
|
+
outputField: "on",
|
|
21866
|
+
member: {
|
|
21867
|
+
cap: "switch",
|
|
21868
|
+
fieldPath: "on"
|
|
21869
|
+
},
|
|
21870
|
+
commandCaps: ["switch", "fan-control"]
|
|
21871
|
+
}),
|
|
21872
|
+
actuator({
|
|
21873
|
+
id: "cover",
|
|
21874
|
+
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.",
|
|
21875
|
+
deviceType: DeviceType.Cover,
|
|
21876
|
+
outputCap: "group-active",
|
|
21877
|
+
outputField: "active",
|
|
21878
|
+
member: {
|
|
21879
|
+
cap: "cover",
|
|
21880
|
+
fieldPath: "state"
|
|
21881
|
+
},
|
|
21882
|
+
activeWhen: [
|
|
21883
|
+
"open",
|
|
21884
|
+
"opening",
|
|
21885
|
+
"stopped"
|
|
21886
|
+
],
|
|
21887
|
+
commandCaps: ["cover"]
|
|
21888
|
+
}),
|
|
21889
|
+
actuator({
|
|
21890
|
+
id: "valve",
|
|
21891
|
+
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.",
|
|
21892
|
+
deviceType: DeviceType.Valve,
|
|
21893
|
+
outputCap: "group-active",
|
|
21894
|
+
outputField: "active",
|
|
21895
|
+
member: {
|
|
21896
|
+
cap: "valve",
|
|
21897
|
+
fieldPath: "state"
|
|
21898
|
+
},
|
|
21899
|
+
activeWhen: [
|
|
21900
|
+
"open",
|
|
21901
|
+
"opening",
|
|
21902
|
+
"stopped"
|
|
21903
|
+
],
|
|
21904
|
+
commandCaps: ["valve"]
|
|
21905
|
+
}),
|
|
21906
|
+
actuator({
|
|
21907
|
+
id: "lock",
|
|
21908
|
+
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.",
|
|
21909
|
+
deviceType: DeviceType.Lock,
|
|
21910
|
+
outputCap: "group-active",
|
|
21911
|
+
outputField: "active",
|
|
21912
|
+
member: {
|
|
21913
|
+
cap: "lock-control",
|
|
21914
|
+
fieldPath: "state"
|
|
21915
|
+
},
|
|
21916
|
+
activeWhen: ["locked"],
|
|
21917
|
+
commandCaps: ["lock-control"]
|
|
21918
|
+
}),
|
|
21919
|
+
actuator({
|
|
21920
|
+
id: "media-player",
|
|
21921
|
+
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.",
|
|
21922
|
+
deviceType: DeviceType.MediaPlayer,
|
|
21923
|
+
outputCap: "group-active",
|
|
21924
|
+
outputField: "active",
|
|
21925
|
+
member: {
|
|
21926
|
+
cap: "media-player",
|
|
21927
|
+
fieldPath: "state"
|
|
21928
|
+
},
|
|
21929
|
+
activeWhen: ["playing", "buffering"],
|
|
21930
|
+
commandCaps: ["media-player"]
|
|
21931
|
+
}),
|
|
21932
|
+
actuator({
|
|
21933
|
+
id: "climate",
|
|
21934
|
+
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.",
|
|
21935
|
+
deviceType: DeviceType.Thermostat,
|
|
21936
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
21937
|
+
outputCap: "group-active",
|
|
21938
|
+
outputField: "active",
|
|
21939
|
+
member: {
|
|
21940
|
+
cap: "climate-control",
|
|
21941
|
+
fieldPath: "mode"
|
|
21942
|
+
},
|
|
21943
|
+
activeWhen: [
|
|
21944
|
+
"heat",
|
|
21945
|
+
"cool",
|
|
21946
|
+
"auto",
|
|
21947
|
+
"heat_cool",
|
|
21948
|
+
"fan_only",
|
|
21949
|
+
"dry"
|
|
21950
|
+
],
|
|
21951
|
+
commandCaps: ["climate-control"]
|
|
21952
|
+
})
|
|
21953
|
+
];
|
|
21954
|
+
function actuator(input) {
|
|
21955
|
+
return {
|
|
21956
|
+
id: input.id,
|
|
21957
|
+
summary: input.summary,
|
|
21958
|
+
deviceType: input.deviceType,
|
|
21959
|
+
outputCap: input.outputCap,
|
|
21960
|
+
outputField: input.outputField,
|
|
21961
|
+
commandCaps: input.commandCaps,
|
|
21962
|
+
family: "actuator",
|
|
21963
|
+
role: void 0,
|
|
21964
|
+
memberDeviceType: input.deviceType,
|
|
21965
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
21966
|
+
activeWhen: input.activeWhen,
|
|
21967
|
+
quantity: "none",
|
|
21968
|
+
baseUnit: void 0,
|
|
21969
|
+
aggregates: BINARY_AGGREGATES,
|
|
21970
|
+
defaultAggregate: "any",
|
|
21971
|
+
empty: "offline",
|
|
21972
|
+
accept: [input.member],
|
|
21973
|
+
companions: [CHANGED]
|
|
21974
|
+
};
|
|
21975
|
+
}
|
|
21976
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
21977
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
21978
|
+
DeviceType.Camera;
|
|
21221
21979
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
21222
21980
|
/**
|
|
21223
21981
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -48229,6 +48987,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
48229
48987
|
"detection-blind",
|
|
48230
48988
|
"motion-noisy",
|
|
48231
48989
|
"motion-calm",
|
|
48990
|
+
"package-llm-silent",
|
|
48991
|
+
"package-llm-answered",
|
|
48232
48992
|
"recording-stalled",
|
|
48233
48993
|
"recording-healthy",
|
|
48234
48994
|
"recording-degraded",
|
|
@@ -49318,7 +50078,20 @@ var NcRuleInputSchema = object({
|
|
|
49318
50078
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
49319
50079
|
* path does not run Zod defaults.
|
|
49320
50080
|
*/
|
|
49321
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
50081
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
50082
|
+
/**
|
|
50083
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
50084
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
50085
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
50086
|
+
* same mark the Library writes, and records whose notification it was and
|
|
50087
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
50088
|
+
*
|
|
50089
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
50090
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
50091
|
+
* authored before this field meant. An editor turns it off by writing
|
|
50092
|
+
* `false`, so it needs no `clear` key.
|
|
50093
|
+
*/
|
|
50094
|
+
askVerdict: boolean().optional()
|
|
49322
50095
|
});
|
|
49323
50096
|
/**
|
|
49324
50097
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -60083,6 +60856,28 @@ var PackageVersionInfoSchema = object({
|
|
|
60083
60856
|
deprecated: string().optional(),
|
|
60084
60857
|
distTags: array(string()).readonly()
|
|
60085
60858
|
});
|
|
60859
|
+
/**
|
|
60860
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
60861
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
60862
|
+
* tarball failure — never an empty string standing in for either.
|
|
60863
|
+
*/
|
|
60864
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
60865
|
+
object({
|
|
60866
|
+
status: literal("ok"),
|
|
60867
|
+
markdown: string()
|
|
60868
|
+
}),
|
|
60869
|
+
object({ status: literal("missing") }),
|
|
60870
|
+
object({
|
|
60871
|
+
status: literal("error"),
|
|
60872
|
+
message: string()
|
|
60873
|
+
})
|
|
60874
|
+
]);
|
|
60875
|
+
var PackageDocsSchema = object({
|
|
60876
|
+
name: string(),
|
|
60877
|
+
version: string(),
|
|
60878
|
+
readme: PackageDocBodySchema,
|
|
60879
|
+
changelog: PackageDocBodySchema
|
|
60880
|
+
});
|
|
60086
60881
|
var SearchResultSchema = object({
|
|
60087
60882
|
name: string(),
|
|
60088
60883
|
version: string(),
|
|
@@ -60301,7 +61096,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
60301
61096
|
}), object({ success: literal(true) }), {
|
|
60302
61097
|
kind: "mutation",
|
|
60303
61098
|
auth: "admin"
|
|
60304
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
61099
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
61100
|
+
name: string().min(1),
|
|
61101
|
+
version: string().min(1).optional()
|
|
61102
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
60305
61103
|
kind: "mutation",
|
|
60306
61104
|
auth: "admin"
|
|
60307
61105
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -62467,6 +63265,42 @@ object({
|
|
|
62467
63265
|
lastChangedAt: number()
|
|
62468
63266
|
});
|
|
62469
63267
|
DeviceType.Sensor;
|
|
63268
|
+
object({
|
|
63269
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
63270
|
+
results: array(object({
|
|
63271
|
+
deviceId: number().int().nonnegative(),
|
|
63272
|
+
cap: string().min(1),
|
|
63273
|
+
method: string().min(1),
|
|
63274
|
+
ok: boolean(),
|
|
63275
|
+
error: string().optional(),
|
|
63276
|
+
/** Ms epoch of the attempt. */
|
|
63277
|
+
at: number()
|
|
63278
|
+
})) });
|
|
63279
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
63280
|
+
object({
|
|
63281
|
+
active: boolean().meta({ label: "Active" }),
|
|
63282
|
+
/** Ms epoch when the slice was last updated. */
|
|
63283
|
+
lastChangedAt: number()
|
|
63284
|
+
});
|
|
63285
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
63286
|
+
object({
|
|
63287
|
+
/** Members whose current value entered the aggregate. */
|
|
63288
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
63289
|
+
precision: 0,
|
|
63290
|
+
label: "Reporting"
|
|
63291
|
+
})),
|
|
63292
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
63293
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
63294
|
+
precision: 0,
|
|
63295
|
+
label: "Excluded"
|
|
63296
|
+
})),
|
|
63297
|
+
/** `included` + `excluded`. */
|
|
63298
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
63299
|
+
precision: 0,
|
|
63300
|
+
label: "Members"
|
|
63301
|
+
}))
|
|
63302
|
+
});
|
|
63303
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
62470
63304
|
object({
|
|
62471
63305
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
62472
63306
|
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
@@ -63373,7 +64207,14 @@ DeviceType.Lock, method(object({
|
|
|
63373
64207
|
auth: "protected"
|
|
63374
64208
|
}), method(object({
|
|
63375
64209
|
deviceId: number().int().nonnegative(),
|
|
63376
|
-
code: string().min(1).optional()
|
|
64210
|
+
code: string().min(1).optional(),
|
|
64211
|
+
/**
|
|
64212
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
64213
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
64214
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
64215
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
64216
|
+
*/
|
|
64217
|
+
confirm: boolean().optional()
|
|
63377
64218
|
}), _void(), {
|
|
63378
64219
|
kind: "mutation",
|
|
63379
64220
|
auth: "protected"
|
|
@@ -63381,6 +64222,11 @@ DeviceType.Lock, method(object({
|
|
|
63381
64222
|
kind: "mutation",
|
|
63382
64223
|
auth: "protected"
|
|
63383
64224
|
});
|
|
64225
|
+
object({
|
|
64226
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
64227
|
+
lastFetchedAt: number()
|
|
64228
|
+
});
|
|
64229
|
+
DeviceType.Sensor;
|
|
63384
64230
|
/**
|
|
63385
64231
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
63386
64232
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -65298,7 +66144,7 @@ object({
|
|
|
65298
66144
|
/** Ms epoch when the slice was last updated. */
|
|
65299
66145
|
lastFetchedAt: number()
|
|
65300
66146
|
});
|
|
65301
|
-
DeviceType.Sensor;
|
|
66147
|
+
DeviceType.Sensor, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
65302
66148
|
/**
|
|
65303
66149
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
65304
66150
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -65745,7 +66591,7 @@ object({
|
|
|
65745
66591
|
phase: string().nullable()
|
|
65746
66592
|
});
|
|
65747
66593
|
Object.values(DeviceType);
|
|
65748
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
66594
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
65749
66595
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
65750
66596
|
kind: "mutation",
|
|
65751
66597
|
auth: "admin"
|
|
@@ -68308,7 +69154,7 @@ object({
|
|
|
68308
69154
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
68309
69155
|
lastChangedAt: number()
|
|
68310
69156
|
});
|
|
68311
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
69157
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
68312
69158
|
deviceId: number(),
|
|
68313
69159
|
on: boolean()
|
|
68314
69160
|
}), _void(), {
|
|
@@ -70040,8 +70886,9 @@ function dominantClipLabels(events) {
|
|
|
70040
70886
|
}
|
|
70041
70887
|
return [...counts.entries()].toSorted((x, y) => y[1] - x[1]).slice(0, 3).map(([name]) => name);
|
|
70042
70888
|
}
|
|
70889
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
70043
70890
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
70044
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
70891
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
70045
70892
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
70046
70893
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
70047
70894
|
new Set(CAP_NAMES);
|
|
@@ -70112,7 +70959,7 @@ function deriveBatteryPresence(input) {
|
|
|
70112
70959
|
const budget = input.unreachableAfterMs ?? 216e5;
|
|
70113
70960
|
return input.nowMs - lastContactAt > budget ? "unreachable" : "sleeping";
|
|
70114
70961
|
}
|
|
70115
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
70962
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
70116
70963
|
new Set(Object.values(DeviceType));
|
|
70117
70964
|
Object.freeze({
|
|
70118
70965
|
"accessories.getStatus": {
|
|
@@ -70220,6 +71067,13 @@ Object.freeze({
|
|
|
70220
71067
|
access: "view",
|
|
70221
71068
|
role: "admin"
|
|
70222
71069
|
},
|
|
71070
|
+
"addons.getPackageDocs": {
|
|
71071
|
+
capName: "addons",
|
|
71072
|
+
capScope: "system",
|
|
71073
|
+
addonId: null,
|
|
71074
|
+
access: "view",
|
|
71075
|
+
role: "admin"
|
|
71076
|
+
},
|
|
70223
71077
|
"addons.getVersions": {
|
|
70224
71078
|
capName: "addons",
|
|
70225
71079
|
capScope: "system",
|
|
@@ -73328,6 +74182,27 @@ Object.freeze({
|
|
|
73328
74182
|
access: "view",
|
|
73329
74183
|
role: "viewer"
|
|
73330
74184
|
},
|
|
74185
|
+
"groupActive.getStatus": {
|
|
74186
|
+
capName: "group-active",
|
|
74187
|
+
capScope: "device",
|
|
74188
|
+
addonId: null,
|
|
74189
|
+
access: "view",
|
|
74190
|
+
role: "viewer"
|
|
74191
|
+
},
|
|
74192
|
+
"groupCommands.getStatus": {
|
|
74193
|
+
capName: "group-commands",
|
|
74194
|
+
capScope: "device",
|
|
74195
|
+
addonId: null,
|
|
74196
|
+
access: "view",
|
|
74197
|
+
role: "viewer"
|
|
74198
|
+
},
|
|
74199
|
+
"groupStatus.getStatus": {
|
|
74200
|
+
capName: "group-status",
|
|
74201
|
+
capScope: "device",
|
|
74202
|
+
addonId: null,
|
|
74203
|
+
access: "view",
|
|
74204
|
+
role: "viewer"
|
|
74205
|
+
},
|
|
73331
74206
|
"heatingValve.getStatus": {
|
|
73332
74207
|
capName: "heating-valve",
|
|
73333
74208
|
capScope: "device",
|
|
@@ -74280,6 +75155,13 @@ Object.freeze({
|
|
|
74280
75155
|
access: "create",
|
|
74281
75156
|
role: "admin"
|
|
74282
75157
|
},
|
|
75158
|
+
"meter.getStatus": {
|
|
75159
|
+
capName: "meter",
|
|
75160
|
+
capScope: "device",
|
|
75161
|
+
addonId: null,
|
|
75162
|
+
access: "view",
|
|
75163
|
+
role: "viewer"
|
|
75164
|
+
},
|
|
74283
75165
|
"metricsProvider.collectSnapshot": {
|
|
74284
75166
|
capName: "metrics-provider",
|
|
74285
75167
|
capScope: "system",
|
|
@@ -82378,7 +83260,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
82378
83260
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
82379
83261
|
icon: "square"
|
|
82380
83262
|
}
|
|
82381
|
-
}
|
|
83263
|
+
},
|
|
83264
|
+
overrides: { byType: {
|
|
83265
|
+
[DeviceType.Washer]: {
|
|
83266
|
+
state: { running: {
|
|
83267
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
83268
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
83269
|
+
} },
|
|
83270
|
+
events: {
|
|
83271
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
83272
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
83273
|
+
}
|
|
83274
|
+
},
|
|
83275
|
+
[DeviceType.Dryer]: {
|
|
83276
|
+
state: { running: {
|
|
83277
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
83278
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
83279
|
+
} },
|
|
83280
|
+
events: {
|
|
83281
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
83282
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
83283
|
+
}
|
|
83284
|
+
},
|
|
83285
|
+
[DeviceType.Dishwasher]: {
|
|
83286
|
+
state: { running: {
|
|
83287
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
83288
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
83289
|
+
} },
|
|
83290
|
+
events: {
|
|
83291
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
83292
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
83293
|
+
}
|
|
83294
|
+
}
|
|
83295
|
+
} }
|
|
82382
83296
|
},
|
|
82383
83297
|
update: {
|
|
82384
83298
|
scope: "device",
|
|
@@ -83150,6 +84064,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83150
84064
|
icon: "flame"
|
|
83151
84065
|
}]
|
|
83152
84066
|
},
|
|
84067
|
+
"group-active": {
|
|
84068
|
+
scope: "device",
|
|
84069
|
+
noun: t("Group state", "Stato del gruppo")
|
|
84070
|
+
},
|
|
84071
|
+
"group-commands": {
|
|
84072
|
+
scope: "device",
|
|
84073
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84074
|
+
},
|
|
84075
|
+
"group-status": {
|
|
84076
|
+
scope: "device",
|
|
84077
|
+
noun: t("Group", "Gruppo"),
|
|
84078
|
+
state: [
|
|
84079
|
+
{
|
|
84080
|
+
kind: "numeric",
|
|
84081
|
+
field: "included",
|
|
84082
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84083
|
+
label: t("Reporting", "Rispondono"),
|
|
84084
|
+
icon: "users"
|
|
84085
|
+
},
|
|
84086
|
+
{
|
|
84087
|
+
kind: "numeric",
|
|
84088
|
+
field: "excluded",
|
|
84089
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84090
|
+
label: t("Excluded", "Esclusi"),
|
|
84091
|
+
icon: "users"
|
|
84092
|
+
},
|
|
84093
|
+
{
|
|
84094
|
+
kind: "numeric",
|
|
84095
|
+
field: "total",
|
|
84096
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84097
|
+
label: t("Members", "Membri"),
|
|
84098
|
+
icon: "sigma"
|
|
84099
|
+
}
|
|
84100
|
+
]
|
|
84101
|
+
},
|
|
83153
84102
|
"humidity-sensor": {
|
|
83154
84103
|
scope: "device",
|
|
83155
84104
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83175,6 +84124,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83175
84124
|
}],
|
|
83176
84125
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
83177
84126
|
},
|
|
84127
|
+
meter: {
|
|
84128
|
+
scope: "device",
|
|
84129
|
+
noun: t("Meter", "Contatore"),
|
|
84130
|
+
state: [{
|
|
84131
|
+
kind: "numeric",
|
|
84132
|
+
field: "value",
|
|
84133
|
+
quantity: t("the total", "il totale"),
|
|
84134
|
+
label: t("Total", "Totale"),
|
|
84135
|
+
icon: "gauge"
|
|
84136
|
+
}]
|
|
84137
|
+
},
|
|
83178
84138
|
"numeric-sensor": {
|
|
83179
84139
|
scope: "device",
|
|
83180
84140
|
noun: t("Sensor", "Sensore"),
|
|
@@ -83647,8 +84607,47 @@ function projectAction(cap, action) {
|
|
|
83647
84607
|
};
|
|
83648
84608
|
}
|
|
83649
84609
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
83650
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
84610
|
+
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer;
|
|
83651
84611
|
DeviceFeature.BatteryOperated;
|
|
84612
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
84613
|
+
var HA_AS = "a power sensor (device_class power). Home Assistant has no laundry domain. running-state stays unexported until a null reading can be published as unavailable.";
|
|
84614
|
+
var HOMEKIT_REASON = "HomeKit has no laundry-appliance service. The export tab would pair an accessory with nothing on it: running-state is withheld until a null reading can be unavailable, and power is not a HomeKit service this export honours.";
|
|
84615
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
84616
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
84617
|
+
var MATTER_REASON = "No Matter export is built. The closest device types are Laundry Washer (0x0073) and Laundry Dryer (0x0074); a power threshold is not the Laundry Washer Mode cluster.";
|
|
84618
|
+
function withheld(reason) {
|
|
84619
|
+
return {
|
|
84620
|
+
[DeviceType.Washer]: {
|
|
84621
|
+
exported: false,
|
|
84622
|
+
reason
|
|
84623
|
+
},
|
|
84624
|
+
[DeviceType.Dryer]: {
|
|
84625
|
+
exported: false,
|
|
84626
|
+
reason
|
|
84627
|
+
},
|
|
84628
|
+
[DeviceType.Dishwasher]: {
|
|
84629
|
+
exported: false,
|
|
84630
|
+
reason
|
|
84631
|
+
}
|
|
84632
|
+
};
|
|
84633
|
+
}
|
|
84634
|
+
function offered(received) {
|
|
84635
|
+
return {
|
|
84636
|
+
[DeviceType.Washer]: {
|
|
84637
|
+
exported: true,
|
|
84638
|
+
as: received
|
|
84639
|
+
},
|
|
84640
|
+
[DeviceType.Dryer]: {
|
|
84641
|
+
exported: true,
|
|
84642
|
+
as: received
|
|
84643
|
+
},
|
|
84644
|
+
[DeviceType.Dishwasher]: {
|
|
84645
|
+
exported: true,
|
|
84646
|
+
as: received
|
|
84647
|
+
}
|
|
84648
|
+
};
|
|
84649
|
+
}
|
|
84650
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
83652
84651
|
Object.freeze({
|
|
83653
84652
|
"accessories.getStatus": [{
|
|
83654
84653
|
name: "deviceId",
|
|
@@ -84615,6 +85614,21 @@ Object.freeze({
|
|
|
84615
85614
|
form: "single",
|
|
84616
85615
|
optional: false
|
|
84617
85616
|
}],
|
|
85617
|
+
"groupActive.getStatus": [{
|
|
85618
|
+
name: "deviceId",
|
|
85619
|
+
form: "single",
|
|
85620
|
+
optional: false
|
|
85621
|
+
}],
|
|
85622
|
+
"groupCommands.getStatus": [{
|
|
85623
|
+
name: "deviceId",
|
|
85624
|
+
form: "single",
|
|
85625
|
+
optional: false
|
|
85626
|
+
}],
|
|
85627
|
+
"groupStatus.getStatus": [{
|
|
85628
|
+
name: "deviceId",
|
|
85629
|
+
form: "single",
|
|
85630
|
+
optional: false
|
|
85631
|
+
}],
|
|
84618
85632
|
"heatingValve.getStatus": [{
|
|
84619
85633
|
name: "deviceId",
|
|
84620
85634
|
form: "single",
|
|
@@ -84815,6 +85829,11 @@ Object.freeze({
|
|
|
84815
85829
|
form: "single",
|
|
84816
85830
|
optional: false
|
|
84817
85831
|
}],
|
|
85832
|
+
"meter.getStatus": [{
|
|
85833
|
+
name: "deviceId",
|
|
85834
|
+
form: "single",
|
|
85835
|
+
optional: false
|
|
85836
|
+
}],
|
|
84818
85837
|
"motion.getStatus": [{
|
|
84819
85838
|
name: "deviceId",
|
|
84820
85839
|
form: "single",
|
|
@@ -86422,7 +87441,6 @@ Object.freeze({
|
|
|
86422
87441
|
"network-access": "ingress",
|
|
86423
87442
|
"smtp-provider": "email"
|
|
86424
87443
|
});
|
|
86425
|
-
DeviceType.Camera;
|
|
86426
87444
|
/**
|
|
86427
87445
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
86428
87446
|
* `z.infer`, they do not restate the shape.
|
|
@@ -86649,6 +87667,8 @@ new Map(Object.entries({
|
|
|
86649
87667
|
"detection-blind": "device-events",
|
|
86650
87668
|
"motion-noisy": "device-events",
|
|
86651
87669
|
"motion-calm": "device-events",
|
|
87670
|
+
"package-llm-silent": "device-events",
|
|
87671
|
+
"package-llm-answered": "device-events",
|
|
86652
87672
|
"recording-stalled": "device-events",
|
|
86653
87673
|
"recording-healthy": "device-events",
|
|
86654
87674
|
"recording-degraded": "device-events",
|
|
@@ -86732,6 +87752,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
86732
87752
|
label: "Motion without a subject",
|
|
86733
87753
|
kinds: ["motion-noisy", "motion-calm"]
|
|
86734
87754
|
},
|
|
87755
|
+
{
|
|
87756
|
+
id: "package-llm",
|
|
87757
|
+
family: "device-events",
|
|
87758
|
+
label: "Package confirm",
|
|
87759
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
87760
|
+
},
|
|
86735
87761
|
{
|
|
86736
87762
|
id: "recording",
|
|
86737
87763
|
family: "device-events",
|
|
@@ -86913,6 +87939,8 @@ var DEVICE_EVENTS = [
|
|
|
86913
87939
|
"detection-blind",
|
|
86914
87940
|
"motion-noisy",
|
|
86915
87941
|
"motion-calm",
|
|
87942
|
+
"package-llm-silent",
|
|
87943
|
+
"package-llm-answered",
|
|
86916
87944
|
"recording-stalled",
|
|
86917
87945
|
"recording-healthy",
|
|
86918
87946
|
"recording-degraded",
|
|
@@ -87181,6 +88209,15 @@ new Map([
|
|
|
87181
88209
|
snapshotLabel: "Cameras with constant motion now",
|
|
87182
88210
|
snapshotSection: null
|
|
87183
88211
|
},
|
|
88212
|
+
{
|
|
88213
|
+
id: "package-llm-confirm",
|
|
88214
|
+
family: "device-events",
|
|
88215
|
+
label: "Package confirm (not answering / answering again)",
|
|
88216
|
+
bad: ["package-llm-silent"],
|
|
88217
|
+
recovery: ["package-llm-answered"],
|
|
88218
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88219
|
+
snapshotSection: null
|
|
88220
|
+
},
|
|
87184
88221
|
{
|
|
87185
88222
|
id: "recording-health",
|
|
87186
88223
|
family: "device-events",
|