@camstack/addon-auth 1.2.168 → 1.2.170
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 +21 -0
- package/README.md +27 -0
- package/dist/{dist-BbOGRpqM.mjs → dist-E4y3Hyed.mjs} +1366 -447
- package/dist/{dist-BshY4Vgx.js → dist-hxTUn06g.js} +1366 -447
- package/dist/oidc/auth-oidc.addon.js +1 -1
- package/dist/oidc/auth-oidc.addon.mjs +1 -1
- package/dist/webauthn/_stub.js +1 -1
- package/dist/webauthn/{_virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-CPAnDMEb.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_auth_webauthn_widgets-Dbb4FfU4.mjs} +3 -3
- package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CjbhzhqS.mjs +26 -0
- package/dist/webauthn/auth-webauthn.addon.js +1 -1
- package/dist/webauthn/auth-webauthn.addon.mjs +1 -1
- package/dist/webauthn/{hostInit-D1o9L6oS.mjs → hostInit-Bc063UIg.mjs} +3 -3
- package/dist/webauthn/remoteEntry.js +1 -1
- package/package.json +4 -2
- package/dist/webauthn/_virtual_mf___mfe_internal__addon_auth_webauthn_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CNflp3NL.mjs +0 -26
|
@@ -32,7 +32,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
32
32
|
}) : target, mod));
|
|
33
33
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
34
34
|
require("node:crypto");
|
|
35
|
-
//#region ../types/dist/event-category-
|
|
35
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
36
36
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
37
37
|
EventCategory["SystemBoot"] = "system.boot";
|
|
38
38
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -358,6 +358,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
358
358
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
359
359
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
360
360
|
/**
|
|
361
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
362
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
363
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
364
|
+
*/
|
|
365
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
366
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
367
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
368
|
+
/**
|
|
361
369
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
362
370
|
* (a settings change via `setAgentInferenceDevices` /
|
|
363
371
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5600,7 +5608,7 @@ var ZodIssueCode = {
|
|
|
5600
5608
|
var ZodFirstPartyTypeKind;
|
|
5601
5609
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5602
5610
|
//#endregion
|
|
5603
|
-
//#region ../types/dist/sleep
|
|
5611
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5604
5612
|
/**
|
|
5605
5613
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5606
5614
|
* window to float samples (D455).
|
|
@@ -8328,6 +8336,99 @@ function defineEntryKind(name, spec) {
|
|
|
8328
8336
|
if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
|
|
8329
8337
|
return defined;
|
|
8330
8338
|
}
|
|
8339
|
+
var READING_QUANTITIES = [
|
|
8340
|
+
"temperature",
|
|
8341
|
+
"pressure",
|
|
8342
|
+
"speed",
|
|
8343
|
+
"precipitation",
|
|
8344
|
+
"precipitation-rate",
|
|
8345
|
+
"length",
|
|
8346
|
+
"area",
|
|
8347
|
+
"illuminance",
|
|
8348
|
+
"irradiance",
|
|
8349
|
+
"power",
|
|
8350
|
+
"energy",
|
|
8351
|
+
"voltage",
|
|
8352
|
+
"current",
|
|
8353
|
+
"apparent-power",
|
|
8354
|
+
"humidity",
|
|
8355
|
+
"percentage",
|
|
8356
|
+
"concentration-volume",
|
|
8357
|
+
"concentration-mass",
|
|
8358
|
+
"concentration-ppb",
|
|
8359
|
+
"volume",
|
|
8360
|
+
"duration",
|
|
8361
|
+
"duration-ms",
|
|
8362
|
+
"information",
|
|
8363
|
+
"sound-level",
|
|
8364
|
+
"signal-level",
|
|
8365
|
+
"colour-temperature",
|
|
8366
|
+
"angle",
|
|
8367
|
+
"bitrate",
|
|
8368
|
+
"rate",
|
|
8369
|
+
"mass",
|
|
8370
|
+
"index",
|
|
8371
|
+
"ratio",
|
|
8372
|
+
"count",
|
|
8373
|
+
"none",
|
|
8374
|
+
"device"
|
|
8375
|
+
];
|
|
8376
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8377
|
+
new Set(READING_QUANTITIES);
|
|
8378
|
+
/**
|
|
8379
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8380
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8381
|
+
*/
|
|
8382
|
+
var QUANTITY_BASE = {
|
|
8383
|
+
temperature: "°C",
|
|
8384
|
+
pressure: "hPa",
|
|
8385
|
+
speed: "m/s",
|
|
8386
|
+
precipitation: "mm",
|
|
8387
|
+
"precipitation-rate": "mm/h",
|
|
8388
|
+
length: "m",
|
|
8389
|
+
area: "m²",
|
|
8390
|
+
illuminance: "lx",
|
|
8391
|
+
irradiance: "W/m²",
|
|
8392
|
+
power: "W",
|
|
8393
|
+
energy: "kWh",
|
|
8394
|
+
voltage: "V",
|
|
8395
|
+
current: "A",
|
|
8396
|
+
"apparent-power": "VA",
|
|
8397
|
+
humidity: "%",
|
|
8398
|
+
percentage: "%",
|
|
8399
|
+
"concentration-volume": "ppm",
|
|
8400
|
+
"concentration-mass": "µg/m³",
|
|
8401
|
+
"concentration-ppb": "ppb",
|
|
8402
|
+
volume: "L",
|
|
8403
|
+
duration: "s",
|
|
8404
|
+
"duration-ms": "ms",
|
|
8405
|
+
information: "B",
|
|
8406
|
+
"sound-level": "dBFS",
|
|
8407
|
+
"signal-level": "dBm",
|
|
8408
|
+
"colour-temperature": "mired",
|
|
8409
|
+
angle: "°",
|
|
8410
|
+
bitrate: "kbps",
|
|
8411
|
+
rate: "fps",
|
|
8412
|
+
mass: "kg",
|
|
8413
|
+
index: "none",
|
|
8414
|
+
ratio: "none",
|
|
8415
|
+
count: "none",
|
|
8416
|
+
none: "none",
|
|
8417
|
+
device: "device"
|
|
8418
|
+
};
|
|
8419
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8420
|
+
function baseUnitOf(quantity) {
|
|
8421
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8422
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8423
|
+
return symbol;
|
|
8424
|
+
}
|
|
8425
|
+
function readingMeta(quantity, extras) {
|
|
8426
|
+
return {
|
|
8427
|
+
quantity,
|
|
8428
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8429
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8430
|
+
};
|
|
8431
|
+
}
|
|
8331
8432
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8332
8433
|
var CamProfileSchema = _enum([
|
|
8333
8434
|
"high",
|
|
@@ -8355,8 +8456,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8355
8456
|
"derived"
|
|
8356
8457
|
]);
|
|
8357
8458
|
var CamStreamResolutionSchema = object({
|
|
8358
|
-
width: number().int().positive(),
|
|
8359
|
-
height: number().int().positive()
|
|
8459
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8460
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8360
8461
|
});
|
|
8361
8462
|
var CameraStreamSchema = object({
|
|
8362
8463
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8870,6 +8971,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8870
8971
|
"filesystem-browse",
|
|
8871
8972
|
"flood",
|
|
8872
8973
|
"gas",
|
|
8974
|
+
"group-active",
|
|
8975
|
+
"group-commands",
|
|
8976
|
+
"group-status",
|
|
8873
8977
|
"heating-valve",
|
|
8874
8978
|
"humidifier",
|
|
8875
8979
|
"humidity-sensor",
|
|
@@ -8890,6 +8994,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8890
8994
|
"login-method",
|
|
8891
8995
|
"media-player",
|
|
8892
8996
|
"mesh-network",
|
|
8997
|
+
"meter",
|
|
8893
8998
|
"metrics-provider",
|
|
8894
8999
|
"model-convert",
|
|
8895
9000
|
"model-distributor",
|
|
@@ -8999,14 +9104,6 @@ Object.freeze({
|
|
|
8999
9104
|
{
|
|
9000
9105
|
"path": "aqi",
|
|
9001
9106
|
"valueType": "number"
|
|
9002
|
-
},
|
|
9003
|
-
{
|
|
9004
|
-
"path": "unit",
|
|
9005
|
-
"valueType": "string"
|
|
9006
|
-
},
|
|
9007
|
-
{
|
|
9008
|
-
"path": "precision",
|
|
9009
|
-
"valueType": "number"
|
|
9010
9107
|
}
|
|
9011
9108
|
],
|
|
9012
9109
|
"alarm-panel": [
|
|
@@ -9042,20 +9139,10 @@ Object.freeze({
|
|
|
9042
9139
|
"valueType": "boolean"
|
|
9043
9140
|
}
|
|
9044
9141
|
],
|
|
9045
|
-
"ambient-light-sensor": [
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
},
|
|
9050
|
-
{
|
|
9051
|
-
"path": "unit",
|
|
9052
|
-
"valueType": "string"
|
|
9053
|
-
},
|
|
9054
|
-
{
|
|
9055
|
-
"path": "precision",
|
|
9056
|
-
"valueType": "number"
|
|
9057
|
-
}
|
|
9058
|
-
],
|
|
9142
|
+
"ambient-light-sensor": [{
|
|
9143
|
+
"path": "lux",
|
|
9144
|
+
"valueType": "number"
|
|
9145
|
+
}],
|
|
9059
9146
|
"audio-metrics": [
|
|
9060
9147
|
{
|
|
9061
9148
|
"path": "ts",
|
|
@@ -9135,6 +9222,10 @@ Object.freeze({
|
|
|
9135
9222
|
"path": "lastUpdated",
|
|
9136
9223
|
"valueType": "number"
|
|
9137
9224
|
},
|
|
9225
|
+
{
|
|
9226
|
+
"path": "volts",
|
|
9227
|
+
"valueType": "number"
|
|
9228
|
+
},
|
|
9138
9229
|
{
|
|
9139
9230
|
"path": "lastContactAt",
|
|
9140
9231
|
"valueType": "number"
|
|
@@ -9377,10 +9468,6 @@ Object.freeze({
|
|
|
9377
9468
|
"datetime"
|
|
9378
9469
|
]
|
|
9379
9470
|
},
|
|
9380
|
-
{
|
|
9381
|
-
"path": "unit",
|
|
9382
|
-
"valueType": "string"
|
|
9383
|
-
},
|
|
9384
9471
|
{
|
|
9385
9472
|
"path": "min",
|
|
9386
9473
|
"valueType": "number"
|
|
@@ -9392,19 +9479,6 @@ Object.freeze({
|
|
|
9392
9479
|
{
|
|
9393
9480
|
"path": "step",
|
|
9394
9481
|
"valueType": "number"
|
|
9395
|
-
},
|
|
9396
|
-
{
|
|
9397
|
-
"path": "precision",
|
|
9398
|
-
"valueType": "number"
|
|
9399
|
-
},
|
|
9400
|
-
{
|
|
9401
|
-
"path": "format",
|
|
9402
|
-
"valueType": "enum",
|
|
9403
|
-
"enumValues": [
|
|
9404
|
-
"date",
|
|
9405
|
-
"time",
|
|
9406
|
-
"datetime"
|
|
9407
|
-
]
|
|
9408
9482
|
}
|
|
9409
9483
|
],
|
|
9410
9484
|
"cover": [
|
|
@@ -9645,13 +9719,8 @@ Object.freeze({
|
|
|
9645
9719
|
"path": "value",
|
|
9646
9720
|
"valueType": "string"
|
|
9647
9721
|
}, {
|
|
9648
|
-
"path": "
|
|
9649
|
-
"valueType": "
|
|
9650
|
-
"enumValues": [
|
|
9651
|
-
"date",
|
|
9652
|
-
"time",
|
|
9653
|
-
"datetime"
|
|
9654
|
-
]
|
|
9722
|
+
"path": "timestamp",
|
|
9723
|
+
"valueType": "boolean"
|
|
9655
9724
|
}],
|
|
9656
9725
|
"event-emitter": [
|
|
9657
9726
|
{
|
|
@@ -9724,6 +9793,24 @@ Object.freeze({
|
|
|
9724
9793
|
"path": "detected",
|
|
9725
9794
|
"valueType": "boolean"
|
|
9726
9795
|
}],
|
|
9796
|
+
"group-active": [{
|
|
9797
|
+
"path": "active",
|
|
9798
|
+
"valueType": "boolean"
|
|
9799
|
+
}],
|
|
9800
|
+
"group-status": [
|
|
9801
|
+
{
|
|
9802
|
+
"path": "included",
|
|
9803
|
+
"valueType": "number"
|
|
9804
|
+
},
|
|
9805
|
+
{
|
|
9806
|
+
"path": "excluded",
|
|
9807
|
+
"valueType": "number"
|
|
9808
|
+
},
|
|
9809
|
+
{
|
|
9810
|
+
"path": "total",
|
|
9811
|
+
"valueType": "number"
|
|
9812
|
+
}
|
|
9813
|
+
],
|
|
9727
9814
|
"heating-valve": [{
|
|
9728
9815
|
"path": "position",
|
|
9729
9816
|
"valueType": "number"
|
|
@@ -9758,20 +9845,10 @@ Object.freeze({
|
|
|
9758
9845
|
"valueType": "number"
|
|
9759
9846
|
}
|
|
9760
9847
|
],
|
|
9761
|
-
"humidity-sensor": [
|
|
9762
|
-
|
|
9763
|
-
|
|
9764
|
-
|
|
9765
|
-
},
|
|
9766
|
-
{
|
|
9767
|
-
"path": "unit",
|
|
9768
|
-
"valueType": "string"
|
|
9769
|
-
},
|
|
9770
|
-
{
|
|
9771
|
-
"path": "precision",
|
|
9772
|
-
"valueType": "number"
|
|
9773
|
-
}
|
|
9774
|
-
],
|
|
9848
|
+
"humidity-sensor": [{
|
|
9849
|
+
"path": "percent",
|
|
9850
|
+
"valueType": "number"
|
|
9851
|
+
}],
|
|
9775
9852
|
"image": [{
|
|
9776
9853
|
"path": "url",
|
|
9777
9854
|
"valueType": "string"
|
|
@@ -9979,6 +10056,10 @@ Object.freeze({
|
|
|
9979
10056
|
]
|
|
9980
10057
|
}
|
|
9981
10058
|
],
|
|
10059
|
+
"meter": [{
|
|
10060
|
+
"path": "value",
|
|
10061
|
+
"valueType": "number"
|
|
10062
|
+
}],
|
|
9982
10063
|
"motion": [
|
|
9983
10064
|
{
|
|
9984
10065
|
"path": "detected",
|
|
@@ -10110,20 +10191,10 @@ Object.freeze({
|
|
|
10110
10191
|
"valueType": "boolean"
|
|
10111
10192
|
}
|
|
10112
10193
|
],
|
|
10113
|
-
"numeric-sensor": [
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
},
|
|
10118
|
-
{
|
|
10119
|
-
"path": "unit",
|
|
10120
|
-
"valueType": "string"
|
|
10121
|
-
},
|
|
10122
|
-
{
|
|
10123
|
-
"path": "precision",
|
|
10124
|
-
"valueType": "number"
|
|
10125
|
-
}
|
|
10126
|
-
],
|
|
10194
|
+
"numeric-sensor": [{
|
|
10195
|
+
"path": "value",
|
|
10196
|
+
"valueType": "number"
|
|
10197
|
+
}],
|
|
10127
10198
|
"pet-feeder": [
|
|
10128
10199
|
{
|
|
10129
10200
|
"path": "foodLevel",
|
|
@@ -10215,14 +10286,6 @@ Object.freeze({
|
|
|
10215
10286
|
{
|
|
10216
10287
|
"path": "powerFactor",
|
|
10217
10288
|
"valueType": "number"
|
|
10218
|
-
},
|
|
10219
|
-
{
|
|
10220
|
-
"path": "unit",
|
|
10221
|
-
"valueType": "string"
|
|
10222
|
-
},
|
|
10223
|
-
{
|
|
10224
|
-
"path": "precision",
|
|
10225
|
-
"valueType": "number"
|
|
10226
10289
|
}
|
|
10227
10290
|
],
|
|
10228
10291
|
"presence": [
|
|
@@ -10251,20 +10314,10 @@ Object.freeze({
|
|
|
10251
10314
|
"valueType": "number"
|
|
10252
10315
|
}
|
|
10253
10316
|
],
|
|
10254
|
-
"pressure-sensor": [
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
},
|
|
10259
|
-
{
|
|
10260
|
-
"path": "unit",
|
|
10261
|
-
"valueType": "string"
|
|
10262
|
-
},
|
|
10263
|
-
{
|
|
10264
|
-
"path": "precision",
|
|
10265
|
-
"valueType": "number"
|
|
10266
|
-
}
|
|
10267
|
-
],
|
|
10317
|
+
"pressure-sensor": [{
|
|
10318
|
+
"path": "hpa",
|
|
10319
|
+
"valueType": "number"
|
|
10320
|
+
}],
|
|
10268
10321
|
"privacy-mask": [{
|
|
10269
10322
|
"path": "enabled",
|
|
10270
10323
|
"valueType": "boolean"
|
|
@@ -10575,20 +10628,10 @@ Object.freeze({
|
|
|
10575
10628
|
"path": "tampered",
|
|
10576
10629
|
"valueType": "boolean"
|
|
10577
10630
|
}],
|
|
10578
|
-
"temperature-sensor": [
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
},
|
|
10583
|
-
{
|
|
10584
|
-
"path": "unit",
|
|
10585
|
-
"valueType": "string"
|
|
10586
|
-
},
|
|
10587
|
-
{
|
|
10588
|
-
"path": "precision",
|
|
10589
|
-
"valueType": "number"
|
|
10590
|
-
}
|
|
10591
|
-
],
|
|
10631
|
+
"temperature-sensor": [{
|
|
10632
|
+
"path": "celsius",
|
|
10633
|
+
"valueType": "number"
|
|
10634
|
+
}],
|
|
10592
10635
|
"update": [
|
|
10593
10636
|
{
|
|
10594
10637
|
"path": "currentVersion",
|
|
@@ -10699,10 +10742,6 @@ Object.freeze({
|
|
|
10699
10742
|
"path": "temperature",
|
|
10700
10743
|
"valueType": "number"
|
|
10701
10744
|
},
|
|
10702
|
-
{
|
|
10703
|
-
"path": "temperatureUnit",
|
|
10704
|
-
"valueType": "string"
|
|
10705
|
-
},
|
|
10706
10745
|
{
|
|
10707
10746
|
"path": "humidity",
|
|
10708
10747
|
"valueType": "number"
|
|
@@ -10711,18 +10750,10 @@ Object.freeze({
|
|
|
10711
10750
|
"path": "pressure",
|
|
10712
10751
|
"valueType": "number"
|
|
10713
10752
|
},
|
|
10714
|
-
{
|
|
10715
|
-
"path": "pressureUnit",
|
|
10716
|
-
"valueType": "string"
|
|
10717
|
-
},
|
|
10718
10753
|
{
|
|
10719
10754
|
"path": "windSpeed",
|
|
10720
10755
|
"valueType": "number"
|
|
10721
10756
|
},
|
|
10722
|
-
{
|
|
10723
|
-
"path": "windSpeedUnit",
|
|
10724
|
-
"valueType": "string"
|
|
10725
|
-
},
|
|
10726
10757
|
{
|
|
10727
10758
|
"path": "windBearing",
|
|
10728
10759
|
"valueType": "number"
|
|
@@ -10772,7 +10803,7 @@ object({
|
|
|
10772
10803
|
params: record(string(), union([string(), number()])).optional()
|
|
10773
10804
|
});
|
|
10774
10805
|
//#endregion
|
|
10775
|
-
//#region ../types/dist/err-msg-
|
|
10806
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10776
10807
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10777
10808
|
DeviceType["Camera"] = "camera";
|
|
10778
10809
|
DeviceType["Hub"] = "hub";
|
|
@@ -10866,8 +10897,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10866
10897
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10867
10898
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10868
10899
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10869
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10900
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10901
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10870
10902
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10903
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10904
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10905
|
+
DeviceType["Washer"] = "washer";
|
|
10906
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10907
|
+
DeviceType["Dryer"] = "dryer";
|
|
10871
10908
|
return DeviceType;
|
|
10872
10909
|
}({});
|
|
10873
10910
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11125,7 +11162,7 @@ function errMsg(err) {
|
|
|
11125
11162
|
return String(err);
|
|
11126
11163
|
}
|
|
11127
11164
|
//#endregion
|
|
11128
|
-
//#region ../types/dist/composition-
|
|
11165
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11129
11166
|
/**
|
|
11130
11167
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11131
11168
|
*
|
|
@@ -11440,6 +11477,13 @@ var table = {
|
|
|
11440
11477
|
apply: () => {
|
|
11441
11478
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11442
11479
|
}
|
|
11480
|
+
},
|
|
11481
|
+
schmitt: {
|
|
11482
|
+
minArgs: 3,
|
|
11483
|
+
maxArgs: 5,
|
|
11484
|
+
apply: () => {
|
|
11485
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11486
|
+
}
|
|
11443
11487
|
}
|
|
11444
11488
|
};
|
|
11445
11489
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11880,15 +11924,232 @@ function validateExpressionSource(src) {
|
|
|
11880
11924
|
}
|
|
11881
11925
|
return null;
|
|
11882
11926
|
}
|
|
11883
|
-
/**
|
|
11884
|
-
|
|
11885
|
-
|
|
11886
|
-
|
|
11927
|
+
/**
|
|
11928
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11929
|
+
*
|
|
11930
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11931
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11932
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11933
|
+
*
|
|
11934
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11935
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11936
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11937
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11938
|
+
* can move later without moving the others.
|
|
11939
|
+
*/
|
|
11940
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11941
|
+
var APPLIANCE_KINDS = [
|
|
11942
|
+
"washer",
|
|
11943
|
+
"dryer",
|
|
11944
|
+
"dishwasher"
|
|
11945
|
+
];
|
|
11946
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11947
|
+
/**
|
|
11948
|
+
* Statistics and integrals over a history read (D944).
|
|
11949
|
+
*
|
|
11950
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11951
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11952
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11953
|
+
* as zero. A truncated read is not published.
|
|
11954
|
+
*/
|
|
11955
|
+
var STATISTIC_STATS = [
|
|
11956
|
+
"min",
|
|
11957
|
+
"max",
|
|
11958
|
+
"mean",
|
|
11959
|
+
"sum",
|
|
11960
|
+
"count",
|
|
11961
|
+
"change"
|
|
11962
|
+
];
|
|
11963
|
+
/**
|
|
11964
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11965
|
+
*
|
|
11966
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11967
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11968
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11969
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11970
|
+
*/
|
|
11971
|
+
var MINUTE_MS = 6e4;
|
|
11972
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11973
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11974
|
+
var ROLLING_SPANS = [
|
|
11975
|
+
"1h",
|
|
11976
|
+
"24h",
|
|
11977
|
+
"2d",
|
|
11978
|
+
"7d",
|
|
11979
|
+
"30d",
|
|
11980
|
+
"custom"
|
|
11981
|
+
];
|
|
11982
|
+
var CALENDAR_PERIODS = [
|
|
11983
|
+
"today",
|
|
11984
|
+
"yesterday",
|
|
11985
|
+
"this-week",
|
|
11986
|
+
"this-month"
|
|
11987
|
+
];
|
|
11988
|
+
var RESET_PERIODS = [
|
|
11989
|
+
"never",
|
|
11990
|
+
"daily",
|
|
11991
|
+
"weekly",
|
|
11992
|
+
"monthly"
|
|
11993
|
+
];
|
|
11994
|
+
5 * MINUTE_MS;
|
|
11995
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11996
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11997
|
+
var rollingWindowObject = object({
|
|
11998
|
+
kind: literal("rolling"),
|
|
11999
|
+
span: _enum(ROLLING_SPANS),
|
|
12000
|
+
customMinutes: number().int().min(5).optional()
|
|
12001
|
+
}).check((payload) => {
|
|
12002
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
12003
|
+
code: "custom",
|
|
12004
|
+
message: "a custom range needs a duration in minutes",
|
|
12005
|
+
path: ["customMinutes"],
|
|
12006
|
+
input: payload.value
|
|
12007
|
+
});
|
|
12008
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
12009
|
+
code: "custom",
|
|
12010
|
+
message: "only a custom range carries a duration",
|
|
12011
|
+
path: ["customMinutes"],
|
|
12012
|
+
input: payload.value
|
|
12013
|
+
});
|
|
12014
|
+
});
|
|
12015
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12016
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12017
|
+
kind: literal("calendar"),
|
|
12018
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12019
|
+
})]);
|
|
12020
|
+
/**
|
|
12021
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
12022
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
12023
|
+
* `composition.ts` (D659).
|
|
12024
|
+
*/
|
|
11887
12025
|
var CompositionSourceRefSchema = object({
|
|
11888
12026
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11889
12027
|
addonId: string().min(1),
|
|
11890
12028
|
stableId: string().min(1)
|
|
11891
12029
|
});
|
|
12030
|
+
var GROUP_TEMPLATE_IDS = [
|
|
12031
|
+
"temperature",
|
|
12032
|
+
"humidity",
|
|
12033
|
+
"pressure",
|
|
12034
|
+
"illuminance",
|
|
12035
|
+
"power",
|
|
12036
|
+
"energy",
|
|
12037
|
+
"battery",
|
|
12038
|
+
"numeric",
|
|
12039
|
+
"motion",
|
|
12040
|
+
"contact",
|
|
12041
|
+
"leak",
|
|
12042
|
+
"smoke",
|
|
12043
|
+
"occupancy",
|
|
12044
|
+
"binary",
|
|
12045
|
+
"switch",
|
|
12046
|
+
"light",
|
|
12047
|
+
"fan",
|
|
12048
|
+
"cover",
|
|
12049
|
+
"valve",
|
|
12050
|
+
"lock",
|
|
12051
|
+
"media-player",
|
|
12052
|
+
"climate"
|
|
12053
|
+
];
|
|
12054
|
+
var NUMERIC_AGGREGATES = [
|
|
12055
|
+
"mean",
|
|
12056
|
+
"median",
|
|
12057
|
+
"min",
|
|
12058
|
+
"max",
|
|
12059
|
+
"sum"
|
|
12060
|
+
];
|
|
12061
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12062
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12063
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12064
|
+
var AGGREGATE_REDUCERS = [
|
|
12065
|
+
"mean",
|
|
12066
|
+
"median",
|
|
12067
|
+
"min",
|
|
12068
|
+
"max",
|
|
12069
|
+
"sum",
|
|
12070
|
+
"any",
|
|
12071
|
+
"all"
|
|
12072
|
+
];
|
|
12073
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12074
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12075
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12076
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12077
|
+
var HelperMemberSchema = object({
|
|
12078
|
+
source: CompositionSourceRefSchema,
|
|
12079
|
+
cap: string().min(1),
|
|
12080
|
+
fieldPath: string().min(1)
|
|
12081
|
+
});
|
|
12082
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12083
|
+
object({
|
|
12084
|
+
kind: literal("group"),
|
|
12085
|
+
templateId: GroupTemplateIdSchema,
|
|
12086
|
+
aggregate: AggregateReducerSchema,
|
|
12087
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12088
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12089
|
+
active: ActiveCriterionSchema.optional()
|
|
12090
|
+
}),
|
|
12091
|
+
object({
|
|
12092
|
+
kind: literal("appliance"),
|
|
12093
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12094
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12095
|
+
thresholdWatts: number().positive(),
|
|
12096
|
+
startDwellMs: number().int().nonnegative(),
|
|
12097
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12098
|
+
member: HelperMemberSchema
|
|
12099
|
+
}),
|
|
12100
|
+
object({
|
|
12101
|
+
kind: literal("statistic"),
|
|
12102
|
+
stat: _enum(STATISTIC_STATS),
|
|
12103
|
+
window: StatisticWindowSchema,
|
|
12104
|
+
source: HelperMemberSchema
|
|
12105
|
+
}),
|
|
12106
|
+
object({
|
|
12107
|
+
kind: literal("integral"),
|
|
12108
|
+
reset: _enum(RESET_PERIODS),
|
|
12109
|
+
output: _enum(["energy", "meter"]),
|
|
12110
|
+
source: HelperMemberSchema
|
|
12111
|
+
}),
|
|
12112
|
+
object({
|
|
12113
|
+
kind: literal("threshold"),
|
|
12114
|
+
source: HelperMemberSchema,
|
|
12115
|
+
high: number(),
|
|
12116
|
+
low: number(),
|
|
12117
|
+
onForMs: number().int().nonnegative(),
|
|
12118
|
+
offForMs: number().int().nonnegative()
|
|
12119
|
+
}),
|
|
12120
|
+
object({
|
|
12121
|
+
kind: literal("arithmetic"),
|
|
12122
|
+
op: _enum([
|
|
12123
|
+
"sum",
|
|
12124
|
+
"difference",
|
|
12125
|
+
"ratio"
|
|
12126
|
+
]),
|
|
12127
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12128
|
+
}),
|
|
12129
|
+
object({
|
|
12130
|
+
kind: literal("expression"),
|
|
12131
|
+
expr: string().min(1),
|
|
12132
|
+
inputs: array(object({
|
|
12133
|
+
name: string().min(1),
|
|
12134
|
+
member: HelperMemberSchema
|
|
12135
|
+
})).min(1).max(64),
|
|
12136
|
+
output: _enum(["number", "boolean"])
|
|
12137
|
+
}),
|
|
12138
|
+
object({
|
|
12139
|
+
kind: literal("derivative"),
|
|
12140
|
+
window: RollingWindowSchema,
|
|
12141
|
+
per: _enum([
|
|
12142
|
+
"second",
|
|
12143
|
+
"minute",
|
|
12144
|
+
"hour"
|
|
12145
|
+
]),
|
|
12146
|
+
source: HelperMemberSchema
|
|
12147
|
+
})
|
|
12148
|
+
]);
|
|
12149
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12150
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12151
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12152
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11892
12153
|
/** One field of one capability of one source device. */
|
|
11893
12154
|
var CompositionFieldReadSchema = object({
|
|
11894
12155
|
source: CompositionSourceRefSchema,
|
|
@@ -11932,7 +12193,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11932
12193
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11933
12194
|
CompositionFromSourceSchema,
|
|
11934
12195
|
CompositionExpressionSourceSchema,
|
|
11935
|
-
CompositionCodeSourceSchema
|
|
12196
|
+
CompositionCodeSourceSchema,
|
|
12197
|
+
object({
|
|
12198
|
+
kind: literal("aggregate"),
|
|
12199
|
+
reducer: _enum([
|
|
12200
|
+
"mean",
|
|
12201
|
+
"median",
|
|
12202
|
+
"min",
|
|
12203
|
+
"max",
|
|
12204
|
+
"sum",
|
|
12205
|
+
"any",
|
|
12206
|
+
"all"
|
|
12207
|
+
]),
|
|
12208
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12209
|
+
/**
|
|
12210
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12211
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12212
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12213
|
+
*/
|
|
12214
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12215
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12216
|
+
publish: _enum([
|
|
12217
|
+
"value",
|
|
12218
|
+
"included",
|
|
12219
|
+
"excluded",
|
|
12220
|
+
"total"
|
|
12221
|
+
]),
|
|
12222
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12223
|
+
empty: _enum([
|
|
12224
|
+
"null",
|
|
12225
|
+
"omit",
|
|
12226
|
+
"offline"
|
|
12227
|
+
])
|
|
12228
|
+
}),
|
|
12229
|
+
object({
|
|
12230
|
+
kind: literal("series"),
|
|
12231
|
+
read: CompositionFieldReadSchema,
|
|
12232
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12233
|
+
publish: _enum([
|
|
12234
|
+
"value",
|
|
12235
|
+
"included",
|
|
12236
|
+
"excluded",
|
|
12237
|
+
"total"
|
|
12238
|
+
]),
|
|
12239
|
+
/**
|
|
12240
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12241
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12242
|
+
*/
|
|
12243
|
+
empty: _enum([
|
|
12244
|
+
"null",
|
|
12245
|
+
"omit",
|
|
12246
|
+
"offline"
|
|
12247
|
+
])
|
|
12248
|
+
})
|
|
11936
12249
|
]);
|
|
11937
12250
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11938
12251
|
kind: literal("forward"),
|
|
@@ -11978,7 +12291,13 @@ var CompositionSchema = object({
|
|
|
11978
12291
|
kind: literal("existing"),
|
|
11979
12292
|
device: CompositionSourceRefSchema
|
|
11980
12293
|
})]),
|
|
11981
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12294
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12295
|
+
/**
|
|
12296
|
+
* Present when the block is a helper template. Absent on a free
|
|
12297
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12298
|
+
* never the compiled features.
|
|
12299
|
+
*/
|
|
12300
|
+
helper: HelperSpecSchema.optional()
|
|
11982
12301
|
}).superRefine((composition, ctx) => {
|
|
11983
12302
|
const seen = /* @__PURE__ */ new Set();
|
|
11984
12303
|
composition.features.forEach((feature, index) => {
|
|
@@ -17461,7 +17780,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17461
17780
|
*/
|
|
17462
17781
|
interactiveConnectPath: string().min(1).optional(),
|
|
17463
17782
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17464
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17783
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17784
|
+
/**
|
|
17785
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17786
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17787
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17788
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17789
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17790
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17791
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17792
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17793
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17794
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17795
|
+
* offers it as the default path; the fields the session fills are
|
|
17796
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17797
|
+
*/
|
|
17798
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17465
17799
|
}))
|
|
17466
17800
|
});
|
|
17467
17801
|
var ListInputSchema = object({
|
|
@@ -18456,7 +18790,12 @@ var CompositionProblemSchema = object({
|
|
|
18456
18790
|
"item-field-reserved",
|
|
18457
18791
|
"target-missing",
|
|
18458
18792
|
"target-unreadable",
|
|
18459
|
-
"not-replaceable"
|
|
18793
|
+
"not-replaceable",
|
|
18794
|
+
"native-capability-replace",
|
|
18795
|
+
"mixed-quantity",
|
|
18796
|
+
"helper-mismatch",
|
|
18797
|
+
"member-constraint",
|
|
18798
|
+
"retention"
|
|
18460
18799
|
]),
|
|
18461
18800
|
path: string(),
|
|
18462
18801
|
message: string()
|
|
@@ -18477,7 +18816,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18477
18816
|
"null",
|
|
18478
18817
|
"offline",
|
|
18479
18818
|
"unknown",
|
|
18480
|
-
"release"
|
|
18819
|
+
"release",
|
|
18820
|
+
"omit"
|
|
18481
18821
|
]);
|
|
18482
18822
|
/**
|
|
18483
18823
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18514,9 +18854,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18514
18854
|
reads: array(CompositionFieldReadSchema)
|
|
18515
18855
|
});
|
|
18516
18856
|
/**
|
|
18517
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18518
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18519
|
-
*
|
|
18857
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18858
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18859
|
+
* Replacing a capability the device already serves is refused
|
|
18860
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18861
|
+
* wire for a claim the hub already holds.
|
|
18520
18862
|
*/
|
|
18521
18863
|
var CompositionFeatureModeSchema = _enum([
|
|
18522
18864
|
"new",
|
|
@@ -18687,8 +19029,392 @@ Object.freeze({
|
|
|
18687
19029
|
latchedAt: {
|
|
18688
19030
|
kind: "fixed",
|
|
18689
19031
|
result: ["number", "null"]
|
|
19032
|
+
},
|
|
19033
|
+
schmitt: {
|
|
19034
|
+
kind: "fixed",
|
|
19035
|
+
result: ["boolean", "null"]
|
|
18690
19036
|
}
|
|
18691
19037
|
});
|
|
19038
|
+
/**
|
|
19039
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19040
|
+
* Data, not a form default written into the block.
|
|
19041
|
+
*/
|
|
19042
|
+
var NOW$2 = {
|
|
19043
|
+
fieldPath: "lastFetchedAt",
|
|
19044
|
+
expr: "now"
|
|
19045
|
+
};
|
|
19046
|
+
var CHANGED = {
|
|
19047
|
+
fieldPath: "lastChangedAt",
|
|
19048
|
+
expr: "now"
|
|
19049
|
+
};
|
|
19050
|
+
function numeric(input) {
|
|
19051
|
+
return {
|
|
19052
|
+
...input,
|
|
19053
|
+
family: "numeric",
|
|
19054
|
+
deviceType: DeviceType.Sensor,
|
|
19055
|
+
memberDeviceType: DeviceType.Sensor,
|
|
19056
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19057
|
+
activeWhen: void 0,
|
|
19058
|
+
commandCaps: [],
|
|
19059
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
19060
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
19061
|
+
accept: [{
|
|
19062
|
+
cap: input.outputCap,
|
|
19063
|
+
fieldPath: input.outputField
|
|
19064
|
+
}]
|
|
19065
|
+
};
|
|
19066
|
+
}
|
|
19067
|
+
function binary(input) {
|
|
19068
|
+
return {
|
|
19069
|
+
...input,
|
|
19070
|
+
family: "binary",
|
|
19071
|
+
deviceType: DeviceType.Sensor,
|
|
19072
|
+
memberDeviceType: DeviceType.Sensor,
|
|
19073
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19074
|
+
activeWhen: void 0,
|
|
19075
|
+
commandCaps: [],
|
|
19076
|
+
quantity: "none",
|
|
19077
|
+
baseUnit: void 0,
|
|
19078
|
+
aggregates: BINARY_AGGREGATES,
|
|
19079
|
+
empty: "offline"
|
|
19080
|
+
};
|
|
19081
|
+
}
|
|
19082
|
+
var GROUP_TEMPLATES = [
|
|
19083
|
+
numeric({
|
|
19084
|
+
id: "temperature",
|
|
19085
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
19086
|
+
role: DeviceRole.TemperatureSensor,
|
|
19087
|
+
outputCap: "temperature-sensor",
|
|
19088
|
+
outputField: "celsius",
|
|
19089
|
+
quantity: "temperature",
|
|
19090
|
+
defaultAggregate: "mean",
|
|
19091
|
+
empty: "null",
|
|
19092
|
+
companions: [NOW$2]
|
|
19093
|
+
}),
|
|
19094
|
+
numeric({
|
|
19095
|
+
id: "humidity",
|
|
19096
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19097
|
+
role: DeviceRole.HumiditySensor,
|
|
19098
|
+
outputCap: "humidity-sensor",
|
|
19099
|
+
outputField: "percent",
|
|
19100
|
+
quantity: "humidity",
|
|
19101
|
+
defaultAggregate: "mean",
|
|
19102
|
+
empty: "null",
|
|
19103
|
+
companions: [NOW$2]
|
|
19104
|
+
}),
|
|
19105
|
+
numeric({
|
|
19106
|
+
id: "pressure",
|
|
19107
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
19108
|
+
role: DeviceRole.PressureSensor,
|
|
19109
|
+
outputCap: "pressure-sensor",
|
|
19110
|
+
outputField: "hpa",
|
|
19111
|
+
quantity: "pressure",
|
|
19112
|
+
defaultAggregate: "mean",
|
|
19113
|
+
empty: "null",
|
|
19114
|
+
companions: [NOW$2]
|
|
19115
|
+
}),
|
|
19116
|
+
numeric({
|
|
19117
|
+
id: "illuminance",
|
|
19118
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
19119
|
+
role: DeviceRole.AmbientLightSensor,
|
|
19120
|
+
outputCap: "ambient-light-sensor",
|
|
19121
|
+
outputField: "lux",
|
|
19122
|
+
quantity: "illuminance",
|
|
19123
|
+
defaultAggregate: "mean",
|
|
19124
|
+
empty: "null",
|
|
19125
|
+
companions: [NOW$2]
|
|
19126
|
+
}),
|
|
19127
|
+
numeric({
|
|
19128
|
+
id: "power",
|
|
19129
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
19130
|
+
role: DeviceRole.PowerSensor,
|
|
19131
|
+
outputCap: "power-meter",
|
|
19132
|
+
outputField: "watts",
|
|
19133
|
+
quantity: "power",
|
|
19134
|
+
defaultAggregate: "sum",
|
|
19135
|
+
empty: "omit",
|
|
19136
|
+
companions: [NOW$2]
|
|
19137
|
+
}),
|
|
19138
|
+
numeric({
|
|
19139
|
+
id: "energy",
|
|
19140
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
19141
|
+
role: DeviceRole.EnergySensor,
|
|
19142
|
+
outputCap: "power-meter",
|
|
19143
|
+
outputField: "kwhTotal",
|
|
19144
|
+
quantity: "energy",
|
|
19145
|
+
defaultAggregate: "sum",
|
|
19146
|
+
empty: "omit",
|
|
19147
|
+
companions: [NOW$2]
|
|
19148
|
+
}),
|
|
19149
|
+
numeric({
|
|
19150
|
+
id: "battery",
|
|
19151
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19152
|
+
role: DeviceRole.BatterySensor,
|
|
19153
|
+
outputCap: "battery",
|
|
19154
|
+
outputField: "percentage",
|
|
19155
|
+
quantity: "percentage",
|
|
19156
|
+
defaultAggregate: "mean",
|
|
19157
|
+
empty: "null",
|
|
19158
|
+
companions: [
|
|
19159
|
+
{
|
|
19160
|
+
fieldPath: "charging",
|
|
19161
|
+
expr: "\"unknown\""
|
|
19162
|
+
},
|
|
19163
|
+
{
|
|
19164
|
+
fieldPath: "sleeping",
|
|
19165
|
+
expr: "false"
|
|
19166
|
+
},
|
|
19167
|
+
{
|
|
19168
|
+
fieldPath: "lastUpdated",
|
|
19169
|
+
expr: "now"
|
|
19170
|
+
}
|
|
19171
|
+
]
|
|
19172
|
+
}),
|
|
19173
|
+
numeric({
|
|
19174
|
+
id: "numeric",
|
|
19175
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
19176
|
+
role: DeviceRole.NumericSensor,
|
|
19177
|
+
outputCap: "numeric-sensor",
|
|
19178
|
+
outputField: "value",
|
|
19179
|
+
quantity: "device",
|
|
19180
|
+
defaultAggregate: "mean",
|
|
19181
|
+
empty: "null",
|
|
19182
|
+
companions: [NOW$2]
|
|
19183
|
+
}),
|
|
19184
|
+
binary({
|
|
19185
|
+
id: "motion",
|
|
19186
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
19187
|
+
role: DeviceRole.MotionSensor,
|
|
19188
|
+
outputCap: "motion",
|
|
19189
|
+
outputField: "detected",
|
|
19190
|
+
defaultAggregate: "any",
|
|
19191
|
+
accept: [{
|
|
19192
|
+
cap: "motion",
|
|
19193
|
+
fieldPath: "detected"
|
|
19194
|
+
}],
|
|
19195
|
+
companions: [{
|
|
19196
|
+
fieldPath: "lastDetectedAt",
|
|
19197
|
+
expr: "null"
|
|
19198
|
+
}, {
|
|
19199
|
+
fieldPath: "autoClearAfterMs",
|
|
19200
|
+
expr: "null"
|
|
19201
|
+
}]
|
|
19202
|
+
}),
|
|
19203
|
+
binary({
|
|
19204
|
+
id: "contact",
|
|
19205
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
19206
|
+
role: DeviceRole.ContactSensor,
|
|
19207
|
+
outputCap: "contact",
|
|
19208
|
+
outputField: "entryOpen",
|
|
19209
|
+
defaultAggregate: "any",
|
|
19210
|
+
accept: [{
|
|
19211
|
+
cap: "contact",
|
|
19212
|
+
fieldPath: "entryOpen"
|
|
19213
|
+
}],
|
|
19214
|
+
companions: [CHANGED]
|
|
19215
|
+
}),
|
|
19216
|
+
binary({
|
|
19217
|
+
id: "leak",
|
|
19218
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
19219
|
+
role: DeviceRole.LeakSensor,
|
|
19220
|
+
outputCap: "flood",
|
|
19221
|
+
outputField: "flooded",
|
|
19222
|
+
defaultAggregate: "any",
|
|
19223
|
+
accept: [{
|
|
19224
|
+
cap: "flood",
|
|
19225
|
+
fieldPath: "flooded"
|
|
19226
|
+
}],
|
|
19227
|
+
companions: [CHANGED]
|
|
19228
|
+
}),
|
|
19229
|
+
binary({
|
|
19230
|
+
id: "smoke",
|
|
19231
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
19232
|
+
role: DeviceRole.SmokeSensor,
|
|
19233
|
+
outputCap: "smoke",
|
|
19234
|
+
outputField: "detected",
|
|
19235
|
+
defaultAggregate: "any",
|
|
19236
|
+
accept: [{
|
|
19237
|
+
cap: "smoke",
|
|
19238
|
+
fieldPath: "detected"
|
|
19239
|
+
}],
|
|
19240
|
+
companions: [CHANGED]
|
|
19241
|
+
}),
|
|
19242
|
+
binary({
|
|
19243
|
+
id: "occupancy",
|
|
19244
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
19245
|
+
role: DeviceRole.BinarySensor,
|
|
19246
|
+
outputCap: "binary",
|
|
19247
|
+
outputField: "on",
|
|
19248
|
+
defaultAggregate: "any",
|
|
19249
|
+
accept: [{
|
|
19250
|
+
cap: "motion",
|
|
19251
|
+
fieldPath: "detected"
|
|
19252
|
+
}, {
|
|
19253
|
+
cap: "binary",
|
|
19254
|
+
fieldPath: "on"
|
|
19255
|
+
}],
|
|
19256
|
+
companions: [CHANGED]
|
|
19257
|
+
}),
|
|
19258
|
+
binary({
|
|
19259
|
+
id: "binary",
|
|
19260
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
19261
|
+
role: DeviceRole.BinarySensor,
|
|
19262
|
+
outputCap: "binary",
|
|
19263
|
+
outputField: "on",
|
|
19264
|
+
defaultAggregate: "any",
|
|
19265
|
+
accept: [{
|
|
19266
|
+
cap: "binary",
|
|
19267
|
+
fieldPath: "on"
|
|
19268
|
+
}],
|
|
19269
|
+
companions: [CHANGED]
|
|
19270
|
+
}),
|
|
19271
|
+
actuator({
|
|
19272
|
+
id: "switch",
|
|
19273
|
+
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.",
|
|
19274
|
+
deviceType: DeviceType.Switch,
|
|
19275
|
+
outputCap: "switch",
|
|
19276
|
+
outputField: "on",
|
|
19277
|
+
member: {
|
|
19278
|
+
cap: "switch",
|
|
19279
|
+
fieldPath: "on"
|
|
19280
|
+
},
|
|
19281
|
+
commandCaps: ["switch"]
|
|
19282
|
+
}),
|
|
19283
|
+
actuator({
|
|
19284
|
+
id: "light",
|
|
19285
|
+
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.",
|
|
19286
|
+
deviceType: DeviceType.Light,
|
|
19287
|
+
outputCap: "switch",
|
|
19288
|
+
outputField: "on",
|
|
19289
|
+
member: {
|
|
19290
|
+
cap: "switch",
|
|
19291
|
+
fieldPath: "on"
|
|
19292
|
+
},
|
|
19293
|
+
commandCaps: [
|
|
19294
|
+
"switch",
|
|
19295
|
+
"brightness",
|
|
19296
|
+
"color"
|
|
19297
|
+
]
|
|
19298
|
+
}),
|
|
19299
|
+
actuator({
|
|
19300
|
+
id: "fan",
|
|
19301
|
+
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.",
|
|
19302
|
+
deviceType: DeviceType.Fan,
|
|
19303
|
+
outputCap: "switch",
|
|
19304
|
+
outputField: "on",
|
|
19305
|
+
member: {
|
|
19306
|
+
cap: "switch",
|
|
19307
|
+
fieldPath: "on"
|
|
19308
|
+
},
|
|
19309
|
+
commandCaps: ["switch", "fan-control"]
|
|
19310
|
+
}),
|
|
19311
|
+
actuator({
|
|
19312
|
+
id: "cover",
|
|
19313
|
+
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.",
|
|
19314
|
+
deviceType: DeviceType.Cover,
|
|
19315
|
+
outputCap: "group-active",
|
|
19316
|
+
outputField: "active",
|
|
19317
|
+
member: {
|
|
19318
|
+
cap: "cover",
|
|
19319
|
+
fieldPath: "state"
|
|
19320
|
+
},
|
|
19321
|
+
activeWhen: [
|
|
19322
|
+
"open",
|
|
19323
|
+
"opening",
|
|
19324
|
+
"stopped"
|
|
19325
|
+
],
|
|
19326
|
+
commandCaps: ["cover"]
|
|
19327
|
+
}),
|
|
19328
|
+
actuator({
|
|
19329
|
+
id: "valve",
|
|
19330
|
+
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.",
|
|
19331
|
+
deviceType: DeviceType.Valve,
|
|
19332
|
+
outputCap: "group-active",
|
|
19333
|
+
outputField: "active",
|
|
19334
|
+
member: {
|
|
19335
|
+
cap: "valve",
|
|
19336
|
+
fieldPath: "state"
|
|
19337
|
+
},
|
|
19338
|
+
activeWhen: [
|
|
19339
|
+
"open",
|
|
19340
|
+
"opening",
|
|
19341
|
+
"stopped"
|
|
19342
|
+
],
|
|
19343
|
+
commandCaps: ["valve"]
|
|
19344
|
+
}),
|
|
19345
|
+
actuator({
|
|
19346
|
+
id: "lock",
|
|
19347
|
+
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.",
|
|
19348
|
+
deviceType: DeviceType.Lock,
|
|
19349
|
+
outputCap: "group-active",
|
|
19350
|
+
outputField: "active",
|
|
19351
|
+
member: {
|
|
19352
|
+
cap: "lock-control",
|
|
19353
|
+
fieldPath: "state"
|
|
19354
|
+
},
|
|
19355
|
+
activeWhen: ["locked"],
|
|
19356
|
+
commandCaps: ["lock-control"]
|
|
19357
|
+
}),
|
|
19358
|
+
actuator({
|
|
19359
|
+
id: "media-player",
|
|
19360
|
+
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.",
|
|
19361
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19362
|
+
outputCap: "group-active",
|
|
19363
|
+
outputField: "active",
|
|
19364
|
+
member: {
|
|
19365
|
+
cap: "media-player",
|
|
19366
|
+
fieldPath: "state"
|
|
19367
|
+
},
|
|
19368
|
+
activeWhen: ["playing", "buffering"],
|
|
19369
|
+
commandCaps: ["media-player"]
|
|
19370
|
+
}),
|
|
19371
|
+
actuator({
|
|
19372
|
+
id: "climate",
|
|
19373
|
+
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.",
|
|
19374
|
+
deviceType: DeviceType.Thermostat,
|
|
19375
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19376
|
+
outputCap: "group-active",
|
|
19377
|
+
outputField: "active",
|
|
19378
|
+
member: {
|
|
19379
|
+
cap: "climate-control",
|
|
19380
|
+
fieldPath: "mode"
|
|
19381
|
+
},
|
|
19382
|
+
activeWhen: [
|
|
19383
|
+
"heat",
|
|
19384
|
+
"cool",
|
|
19385
|
+
"auto",
|
|
19386
|
+
"heat_cool",
|
|
19387
|
+
"fan_only",
|
|
19388
|
+
"dry"
|
|
19389
|
+
],
|
|
19390
|
+
commandCaps: ["climate-control"]
|
|
19391
|
+
})
|
|
19392
|
+
];
|
|
19393
|
+
function actuator(input) {
|
|
19394
|
+
return {
|
|
19395
|
+
id: input.id,
|
|
19396
|
+
summary: input.summary,
|
|
19397
|
+
deviceType: input.deviceType,
|
|
19398
|
+
outputCap: input.outputCap,
|
|
19399
|
+
outputField: input.outputField,
|
|
19400
|
+
commandCaps: input.commandCaps,
|
|
19401
|
+
family: "actuator",
|
|
19402
|
+
role: void 0,
|
|
19403
|
+
memberDeviceType: input.deviceType,
|
|
19404
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19405
|
+
activeWhen: input.activeWhen,
|
|
19406
|
+
quantity: "none",
|
|
19407
|
+
baseUnit: void 0,
|
|
19408
|
+
aggregates: BINARY_AGGREGATES,
|
|
19409
|
+
defaultAggregate: "any",
|
|
19410
|
+
empty: "offline",
|
|
19411
|
+
accept: [input.member],
|
|
19412
|
+
companions: [CHANGED]
|
|
19413
|
+
};
|
|
19414
|
+
}
|
|
19415
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19416
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19417
|
+
DeviceType.Camera;
|
|
18692
19418
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18693
19419
|
/**
|
|
18694
19420
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20402,12 +21128,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
20402
21128
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20403
21129
|
* in-place so dispatch keeps working.
|
|
20404
21130
|
*
|
|
20405
|
-
* **
|
|
20406
|
-
*
|
|
20407
|
-
*
|
|
20408
|
-
*
|
|
20409
|
-
* (`ha-domain-mapping`)
|
|
20410
|
-
* stored after that point.
|
|
21131
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
21132
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
21133
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
21134
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
21135
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
21136
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20411
21137
|
*
|
|
20412
21138
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20413
21139
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20421,6 +21147,14 @@ var SourceInfoSchema = object({
|
|
|
20421
21147
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20422
21148
|
* Used to detect rename when `id` changes. */
|
|
20423
21149
|
uniqueId: string().optional(),
|
|
21150
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
21151
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
21152
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
21153
|
+
dateTimeShape: _enum([
|
|
21154
|
+
"date",
|
|
21155
|
+
"time",
|
|
21156
|
+
"datetime"
|
|
21157
|
+
]).optional(),
|
|
20424
21158
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20425
21159
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20426
21160
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41351,7 +42085,8 @@ method(object({
|
|
|
41351
42085
|
"enum"
|
|
41352
42086
|
]),
|
|
41353
42087
|
enumValues: array(string()).optional(),
|
|
41354
|
-
item: boolean().optional()
|
|
42088
|
+
item: boolean().optional(),
|
|
42089
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41355
42090
|
})).readonly(),
|
|
41356
42091
|
itemArray: object({
|
|
41357
42092
|
path: string(),
|
|
@@ -43720,7 +44455,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43720
44455
|
});
|
|
43721
44456
|
/**
|
|
43722
44457
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43723
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44458
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43724
44459
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43725
44460
|
* the originating provider config (mode + sourcePort) so the
|
|
43726
44461
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -45159,8 +45894,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
45159
45894
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
45160
45895
|
var MaskGridShapeSchema = object({
|
|
45161
45896
|
kind: literal("grid"),
|
|
45162
|
-
gridWidth: number(),
|
|
45163
|
-
gridHeight: number(),
|
|
45897
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45898
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
45164
45899
|
cells: array(boolean())
|
|
45165
45900
|
});
|
|
45166
45901
|
discriminatedUnion("kind", [
|
|
@@ -45272,6 +46007,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45272
46007
|
"detection-blind",
|
|
45273
46008
|
"motion-noisy",
|
|
45274
46009
|
"motion-calm",
|
|
46010
|
+
"package-llm-silent",
|
|
46011
|
+
"package-llm-answered",
|
|
45275
46012
|
"recording-stalled",
|
|
45276
46013
|
"recording-healthy",
|
|
45277
46014
|
"recording-degraded",
|
|
@@ -46361,7 +47098,20 @@ var NcRuleInputSchema = object({
|
|
|
46361
47098
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46362
47099
|
* path does not run Zod defaults.
|
|
46363
47100
|
*/
|
|
46364
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
47101
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
47102
|
+
/**
|
|
47103
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
47104
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
47105
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
47106
|
+
* same mark the Library writes, and records whose notification it was and
|
|
47107
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
47108
|
+
*
|
|
47109
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
47110
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
47111
|
+
* authored before this field meant. An editor turns it off by writing
|
|
47112
|
+
* `false`, so it needs no `clear` key.
|
|
47113
|
+
*/
|
|
47114
|
+
askVerdict: boolean().optional()
|
|
46365
47115
|
});
|
|
46366
47116
|
/**
|
|
46367
47117
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56337,6 +57087,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56337
57087
|
deprecated: string().optional(),
|
|
56338
57088
|
distTags: array(string()).readonly()
|
|
56339
57089
|
});
|
|
57090
|
+
/**
|
|
57091
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
57092
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
57093
|
+
* tarball failure — never an empty string standing in for either.
|
|
57094
|
+
*/
|
|
57095
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
57096
|
+
object({
|
|
57097
|
+
status: literal("ok"),
|
|
57098
|
+
markdown: string()
|
|
57099
|
+
}),
|
|
57100
|
+
object({ status: literal("missing") }),
|
|
57101
|
+
object({
|
|
57102
|
+
status: literal("error"),
|
|
57103
|
+
message: string()
|
|
57104
|
+
})
|
|
57105
|
+
]);
|
|
57106
|
+
var PackageDocsSchema = object({
|
|
57107
|
+
name: string(),
|
|
57108
|
+
version: string(),
|
|
57109
|
+
readme: PackageDocBodySchema,
|
|
57110
|
+
changelog: PackageDocBodySchema
|
|
57111
|
+
});
|
|
56340
57112
|
var SearchResultSchema = object({
|
|
56341
57113
|
name: string(),
|
|
56342
57114
|
version: string(),
|
|
@@ -56555,7 +57327,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56555
57327
|
}), object({ success: literal(true) }), {
|
|
56556
57328
|
kind: "mutation",
|
|
56557
57329
|
auth: "admin"
|
|
56558
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57330
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57331
|
+
name: string().min(1),
|
|
57332
|
+
version: string().min(1).optional()
|
|
57333
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56559
57334
|
kind: "mutation",
|
|
56560
57335
|
auth: "admin"
|
|
56561
57336
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56605,46 +57380,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56605
57380
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56606
57381
|
object({
|
|
56607
57382
|
/** Carbon dioxide concentration in ppm. */
|
|
56608
|
-
co2Ppm: number().min(0).optional(),
|
|
57383
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56609
57384
|
/** Total volatile organic compounds in ppb. */
|
|
56610
|
-
vocPpb: number().min(0).optional(),
|
|
57385
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56611
57386
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56612
|
-
pm25: number().min(0).optional(),
|
|
57387
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56613
57388
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56614
|
-
pm10: number().min(0).optional(),
|
|
57389
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56615
57390
|
/** Composite AQI value (typically 0..500). */
|
|
56616
|
-
aqi: number().optional(),
|
|
57391
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56617
57392
|
/** Ms epoch when the slice was last updated. */
|
|
56618
|
-
lastFetchedAt: number()
|
|
56619
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56620
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56621
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56622
|
-
* per slice is unambiguous. */
|
|
56623
|
-
unit: string().optional(),
|
|
56624
|
-
/** Suggested decimal places for numeric display.
|
|
56625
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56626
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56627
|
-
* auto-formatting when absent. */
|
|
56628
|
-
precision: number().int().min(0).max(10).optional()
|
|
57393
|
+
lastFetchedAt: number()
|
|
56629
57394
|
});
|
|
56630
57395
|
DeviceType.Sensor;
|
|
56631
57396
|
object({
|
|
56632
|
-
/** Current illuminance in lux (lx). */
|
|
56633
|
-
lux: number().min(0).meta({
|
|
56634
|
-
|
|
57397
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57398
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57399
|
+
precision: 0,
|
|
56635
57400
|
label: "Illuminance"
|
|
56636
|
-
}),
|
|
57401
|
+
})),
|
|
56637
57402
|
/** Ms epoch when the slice was last updated. */
|
|
56638
|
-
lastFetchedAt: number()
|
|
56639
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56640
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56641
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56642
|
-
unit: string().optional(),
|
|
56643
|
-
/** Suggested decimal places for numeric display.
|
|
56644
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56645
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56646
|
-
* auto-formatting when absent. */
|
|
56647
|
-
precision: number().int().min(0).max(10).optional()
|
|
57403
|
+
lastFetchedAt: number()
|
|
56648
57404
|
});
|
|
56649
57405
|
DeviceType.Sensor;
|
|
56650
57406
|
/**
|
|
@@ -56789,10 +57545,7 @@ var BatteryStatusSchema = object({
|
|
|
56789
57545
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56790
57546
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56791
57547
|
*/
|
|
56792
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56793
|
-
unit: "%",
|
|
56794
|
-
label: "Charge"
|
|
56795
|
-
}),
|
|
57548
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56796
57549
|
/**
|
|
56797
57550
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56798
57551
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56819,7 +57572,14 @@ var BatteryStatusSchema = object({
|
|
|
56819
57572
|
*/
|
|
56820
57573
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56821
57574
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56822
|
-
lastUpdated: number(),
|
|
57575
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57576
|
+
/**
|
|
57577
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57578
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57579
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57580
|
+
* `numeric-sensor` on the same device.
|
|
57581
|
+
*/
|
|
57582
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56823
57583
|
/**
|
|
56824
57584
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56825
57585
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56859,7 +57619,7 @@ var BatteryStatusSchema = object({
|
|
|
56859
57619
|
*/
|
|
56860
57620
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56861
57621
|
});
|
|
56862
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57622
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56863
57623
|
method(object({
|
|
56864
57624
|
deviceId: number(),
|
|
56865
57625
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56879,7 +57639,7 @@ object({
|
|
|
56879
57639
|
DeviceType.Sensor;
|
|
56880
57640
|
object({
|
|
56881
57641
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56882
|
-
percentage: number().min(0).max(100),
|
|
57642
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56883
57643
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56884
57644
|
lastChangedAt: number()
|
|
56885
57645
|
});
|
|
@@ -57264,21 +58024,21 @@ object({
|
|
|
57264
58024
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57265
58025
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57266
58026
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57267
|
-
target: number().nullable(),
|
|
58027
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57268
58028
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57269
58029
|
* in `heat_cool` mode. */
|
|
57270
|
-
targetHigh: number().nullable(),
|
|
58030
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57271
58031
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57272
58032
|
* in `heat_cool` mode. */
|
|
57273
|
-
targetLow: number().nullable(),
|
|
58033
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57274
58034
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57275
58035
|
* humidity control. */
|
|
57276
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58036
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57277
58037
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57278
58038
|
* the device's internal sensor. */
|
|
57279
|
-
currentTemp: number().nullable(),
|
|
58039
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57280
58040
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57281
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58041
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57282
58042
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57283
58043
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57284
58044
|
swingVertical: boolean().nullable(),
|
|
@@ -57286,11 +58046,11 @@ object({
|
|
|
57286
58046
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57287
58047
|
swingHorizontal: boolean().nullable(),
|
|
57288
58048
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57289
|
-
minTemp: number().nullable().optional(),
|
|
58049
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57290
58050
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57291
|
-
maxTemp: number().nullable().optional(),
|
|
58051
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57292
58052
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57293
|
-
tempStep: number().positive().nullable().optional(),
|
|
58053
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57294
58054
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57295
58055
|
lastFetchedAt: number()
|
|
57296
58056
|
});
|
|
@@ -57369,17 +58129,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
57369
58129
|
* modes to expose in the picker without a slice fetch.
|
|
57370
58130
|
*/
|
|
57371
58131
|
var RgbTripletSchema = object({
|
|
57372
|
-
r: number().int().min(0).max(255),
|
|
57373
|
-
g: number().int().min(0).max(255),
|
|
57374
|
-
b: number().int().min(0).max(255)
|
|
58132
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58133
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58134
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57375
58135
|
});
|
|
57376
58136
|
var HsvTripletSchema = object({
|
|
57377
58137
|
/** Hue in degrees, 0..360. */
|
|
57378
|
-
h: number().min(0).max(360),
|
|
58138
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57379
58139
|
/** Saturation as 0..100 inclusive. */
|
|
57380
|
-
s: number().min(0).max(100),
|
|
58140
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57381
58141
|
/** Value/brightness as 0..100 inclusive. */
|
|
57382
|
-
v: number().min(0).max(100)
|
|
58142
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57383
58143
|
});
|
|
57384
58144
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57385
58145
|
object({
|
|
@@ -57408,7 +58168,7 @@ object({
|
|
|
57408
58168
|
/** Populated when `mode === 'hsv'`. */
|
|
57409
58169
|
hsv: HsvTripletSchema.optional(),
|
|
57410
58170
|
/** Populated when `mode === 'mired'`. */
|
|
57411
|
-
mireds: number().int().optional(),
|
|
58171
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57412
58172
|
/** Ms epoch of the last operator-driven change. */
|
|
57413
58173
|
lastChangedAt: number()
|
|
57414
58174
|
});
|
|
@@ -57532,18 +58292,12 @@ _enum([
|
|
|
57532
58292
|
"empty",
|
|
57533
58293
|
"full"
|
|
57534
58294
|
]);
|
|
57535
|
-
/**
|
|
57536
|
-
|
|
57537
|
-
|
|
57538
|
-
"days",
|
|
57539
|
-
"hours",
|
|
57540
|
-
"cycles"
|
|
57541
|
-
]);
|
|
57542
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57543
|
-
* days). `value` null = unknown (D393). */
|
|
58295
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58296
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58297
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57544
58298
|
var ConsumableRemainingSchema = object({
|
|
57545
|
-
value: number().min(0).nullable(),
|
|
57546
|
-
|
|
58299
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58300
|
+
kind: ConsumableRemainingKindSchema
|
|
57547
58301
|
});
|
|
57548
58302
|
var ConsumablesStatusSchema = object({
|
|
57549
58303
|
items: array(object({
|
|
@@ -57552,7 +58306,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57552
58306
|
/** Display name. */
|
|
57553
58307
|
label: string().min(1),
|
|
57554
58308
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57555
|
-
level: number().min(0).max(100).nullable(),
|
|
58309
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57556
58310
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57557
58311
|
status: ConsumableStatusSchema.nullable(),
|
|
57558
58312
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57569,7 +58323,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57569
58323
|
})),
|
|
57570
58324
|
lastChangedAt: number()
|
|
57571
58325
|
});
|
|
57572
|
-
Object.values(DeviceType), [...
|
|
58326
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57573
58327
|
Object.values(DeviceType), method(object({
|
|
57574
58328
|
deviceId: number().int().nonnegative(),
|
|
57575
58329
|
key: string().min(1)
|
|
@@ -57594,39 +58348,17 @@ object({
|
|
|
57594
58348
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57595
58349
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57596
58350
|
* or time-only — HA accepts all three forms). */
|
|
57597
|
-
value: union([number(), string()]),
|
|
58351
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57598
58352
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57599
58353
|
options: array(string()),
|
|
57600
58354
|
/** Ms epoch when the slice was last updated. */
|
|
57601
58355
|
lastChangedAt: number(),
|
|
57602
|
-
/**
|
|
57603
|
-
|
|
57604
|
-
|
|
57605
|
-
|
|
57606
|
-
/**
|
|
57607
|
-
|
|
57608
|
-
min: number().optional(),
|
|
57609
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57610
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57611
|
-
max: number().optional(),
|
|
57612
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57613
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57614
|
-
step: number().optional(),
|
|
57615
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57616
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57617
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57618
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57619
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57620
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57621
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57622
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57623
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57624
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57625
|
-
format: _enum([
|
|
57626
|
-
"date",
|
|
57627
|
-
"time",
|
|
57628
|
-
"datetime"
|
|
57629
|
-
]).optional()
|
|
58356
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58357
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58358
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58359
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58360
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58361
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57630
58362
|
});
|
|
57631
58363
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57632
58364
|
object({
|
|
@@ -57664,9 +58396,9 @@ object({
|
|
|
57664
58396
|
]),
|
|
57665
58397
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57666
58398
|
* no intermediate position surface. */
|
|
57667
|
-
position: number().min(0).max(100).nullable(),
|
|
58399
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57668
58400
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57669
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58401
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57670
58402
|
/** Ms epoch when the slice was last updated. */
|
|
57671
58403
|
lastChangedAt: number()
|
|
57672
58404
|
});
|
|
@@ -57724,9 +58456,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57724
58456
|
object({
|
|
57725
58457
|
mode: DayNightModeSchema,
|
|
57726
58458
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57727
|
-
sensitivity: number().optional(),
|
|
58459
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57728
58460
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57729
|
-
switchDelaySec: number().optional(),
|
|
58461
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57730
58462
|
lastFetchedAt: number()
|
|
57731
58463
|
});
|
|
57732
58464
|
/**
|
|
@@ -57881,11 +58613,11 @@ object({
|
|
|
57881
58613
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57882
58614
|
availablePrograms: array(string()),
|
|
57883
58615
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57884
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58616
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57885
58617
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57886
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58618
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57887
58619
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57888
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58620
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57889
58621
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57890
58622
|
doorOpen: boolean().nullable(),
|
|
57891
58623
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57909,7 +58641,7 @@ object({
|
|
|
57909
58641
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57910
58642
|
machineCareDue: boolean().nullable(),
|
|
57911
58643
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57912
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58644
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57913
58645
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57914
58646
|
halfLoad: boolean().nullable(),
|
|
57915
58647
|
hygienePlus: boolean().nullable(),
|
|
@@ -57924,7 +58656,7 @@ object({
|
|
|
57924
58656
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57925
58657
|
activeEvents: array(string()),
|
|
57926
58658
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57927
|
-
errorCode: number().nullable(),
|
|
58659
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57928
58660
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57929
58661
|
errorLabel: string().nullable(),
|
|
57930
58662
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58070,24 +58802,14 @@ object({
|
|
|
58070
58802
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58071
58803
|
lastPressedAt: number().nullable(),
|
|
58072
58804
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58073
|
-
pressCountSinceStart: number()
|
|
58805
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58074
58806
|
});
|
|
58075
58807
|
object({
|
|
58076
58808
|
deviceId: number(),
|
|
58077
58809
|
timestamp: number()
|
|
58078
58810
|
});
|
|
58079
58811
|
DeviceType.Button, DeviceType.Camera;
|
|
58080
|
-
|
|
58081
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
58082
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
58083
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
58084
|
-
* The option set is stable across observations; it is persisted in the
|
|
58085
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
58086
|
-
* stored in `sourceInfo`.
|
|
58087
|
-
*/
|
|
58088
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
58089
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
58090
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58812
|
+
_enum([
|
|
58091
58813
|
"date",
|
|
58092
58814
|
"time",
|
|
58093
58815
|
"datetime"
|
|
@@ -58095,12 +58817,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
58095
58817
|
object({
|
|
58096
58818
|
value: string(),
|
|
58097
58819
|
/**
|
|
58098
|
-
* Set
|
|
58099
|
-
* as
|
|
58100
|
-
*
|
|
58101
|
-
* a time-only sensor → `'time'`.
|
|
58820
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58821
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58822
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
58102
58823
|
*/
|
|
58103
|
-
|
|
58824
|
+
timestamp: boolean().optional(),
|
|
58104
58825
|
/** Ms epoch when the slice was last updated. */
|
|
58105
58826
|
lastFetchedAt: number()
|
|
58106
58827
|
});
|
|
@@ -58119,13 +58840,13 @@ var EventFireSchema = object({
|
|
|
58119
58840
|
deviceId: number(),
|
|
58120
58841
|
eventType: string(),
|
|
58121
58842
|
data: record(string(), unknown()).nullable(),
|
|
58122
|
-
timestamp: number(),
|
|
58123
|
-
seq: number()
|
|
58843
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58844
|
+
seq: number().meta(readingMeta("count"))
|
|
58124
58845
|
});
|
|
58125
58846
|
object({
|
|
58126
58847
|
eventTypes: array(string()),
|
|
58127
58848
|
lastEvent: EventFireSchema.nullable(),
|
|
58128
|
-
eventCountSinceStart: number()
|
|
58849
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
58129
58850
|
});
|
|
58130
58851
|
DeviceType.EventEmitter;
|
|
58131
58852
|
var IdentitySchema = object({
|
|
@@ -58514,10 +59235,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58514
59235
|
object({
|
|
58515
59236
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58516
59237
|
* speed surface (single-speed fan). */
|
|
58517
|
-
percentage: number().min(0).max(100).nullable(),
|
|
59238
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58518
59239
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58519
59240
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58520
|
-
percentageStep: number().positive().optional(),
|
|
59241
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
58521
59242
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
58522
59243
|
* — empty string when no preset is active or supported. */
|
|
58523
59244
|
preset: string(),
|
|
@@ -58599,7 +59320,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58599
59320
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58600
59321
|
model: string().nullable(),
|
|
58601
59322
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58602
|
-
channelCount: number().nullable(),
|
|
59323
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58603
59324
|
/**
|
|
58604
59325
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58605
59326
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58631,9 +59352,45 @@ object({
|
|
|
58631
59352
|
lastChangedAt: number()
|
|
58632
59353
|
});
|
|
58633
59354
|
DeviceType.Sensor;
|
|
59355
|
+
object({
|
|
59356
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
59357
|
+
results: array(object({
|
|
59358
|
+
deviceId: number().int().nonnegative(),
|
|
59359
|
+
cap: string().min(1),
|
|
59360
|
+
method: string().min(1),
|
|
59361
|
+
ok: boolean(),
|
|
59362
|
+
error: string().optional(),
|
|
59363
|
+
/** Ms epoch of the attempt. */
|
|
59364
|
+
at: number()
|
|
59365
|
+
})) });
|
|
59366
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
59367
|
+
object({
|
|
59368
|
+
active: boolean().meta({ label: "Active" }),
|
|
59369
|
+
/** Ms epoch when the slice was last updated. */
|
|
59370
|
+
lastChangedAt: number()
|
|
59371
|
+
});
|
|
59372
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
59373
|
+
object({
|
|
59374
|
+
/** Members whose current value entered the aggregate. */
|
|
59375
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
59376
|
+
precision: 0,
|
|
59377
|
+
label: "Reporting"
|
|
59378
|
+
})),
|
|
59379
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
59380
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
59381
|
+
precision: 0,
|
|
59382
|
+
label: "Excluded"
|
|
59383
|
+
})),
|
|
59384
|
+
/** `included` + `excluded`. */
|
|
59385
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
59386
|
+
precision: 0,
|
|
59387
|
+
label: "Members"
|
|
59388
|
+
}))
|
|
59389
|
+
});
|
|
59390
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58634
59391
|
object({
|
|
58635
59392
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58636
|
-
position: number().min(0).max(100).nullable(),
|
|
59393
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58637
59394
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58638
59395
|
lastFetchedAt: number()
|
|
58639
59396
|
});
|
|
@@ -58642,9 +59399,9 @@ object({
|
|
|
58642
59399
|
/** Whether the humidifier is currently on. */
|
|
58643
59400
|
on: boolean(),
|
|
58644
59401
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58645
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59402
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58646
59403
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58647
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59404
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58648
59405
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58649
59406
|
* device has no mode surface. */
|
|
58650
59407
|
mode: string().nullable(),
|
|
@@ -58654,9 +59411,9 @@ object({
|
|
|
58654
59411
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58655
59412
|
action: string().nullable(),
|
|
58656
59413
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58657
|
-
minHumidity: number().nullable(),
|
|
59414
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58658
59415
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58659
|
-
maxHumidity: number().nullable(),
|
|
59416
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58660
59417
|
/** Ms epoch when the slice was last updated. */
|
|
58661
59418
|
lastChangedAt: number()
|
|
58662
59419
|
});
|
|
@@ -58680,22 +59437,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58680
59437
|
auth: "protected"
|
|
58681
59438
|
});
|
|
58682
59439
|
object({
|
|
58683
|
-
/** Current relative humidity, 0..100. */
|
|
58684
|
-
percent: number().min(0).max(100).meta({
|
|
58685
|
-
|
|
59440
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59441
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59442
|
+
precision: 0,
|
|
58686
59443
|
label: "Humidity"
|
|
58687
|
-
}),
|
|
59444
|
+
})),
|
|
58688
59445
|
/** Ms epoch when the slice was last updated. */
|
|
58689
|
-
lastFetchedAt: number()
|
|
58690
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58691
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58692
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58693
|
-
unit: string().optional(),
|
|
58694
|
-
/** Suggested decimal places for numeric display.
|
|
58695
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58696
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58697
|
-
* auto-formatting when absent. */
|
|
58698
|
-
precision: number().int().min(0).max(10).optional()
|
|
59446
|
+
lastFetchedAt: number()
|
|
58699
59447
|
});
|
|
58700
59448
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58701
59449
|
object({
|
|
@@ -58703,7 +59451,7 @@ object({
|
|
|
58703
59451
|
* entity exposes no `entity_picture` (yet). */
|
|
58704
59452
|
url: string().nullable(),
|
|
58705
59453
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58706
|
-
lastUpdated: number().nullable()
|
|
59454
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58707
59455
|
});
|
|
58708
59456
|
DeviceType.Image;
|
|
58709
59457
|
/**
|
|
@@ -58759,19 +59507,19 @@ var NormalizedRangeSchema = object({
|
|
|
58759
59507
|
});
|
|
58760
59508
|
object({
|
|
58761
59509
|
/** Normalized 0–100. */
|
|
58762
|
-
brightness: number().optional(),
|
|
59510
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58763
59511
|
/** Normalized 0–100. */
|
|
58764
|
-
contrast: number().optional(),
|
|
59512
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58765
59513
|
/** Normalized 0–100. */
|
|
58766
|
-
saturation: number().optional(),
|
|
59514
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58767
59515
|
/** Normalized 0–100. */
|
|
58768
|
-
sharpness: number().optional(),
|
|
59516
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58769
59517
|
mirror: boolean().optional(),
|
|
58770
59518
|
flip: boolean().optional(),
|
|
58771
59519
|
rotate: ImageRotateSchema.optional(),
|
|
58772
59520
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58773
59521
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58774
|
-
warmth: number().optional(),
|
|
59522
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58775
59523
|
exposureMode: ExposureModeSchema.optional(),
|
|
58776
59524
|
backlightMode: BacklightModeSchema.optional(),
|
|
58777
59525
|
lastFetchedAt: number()
|
|
@@ -59016,10 +59764,10 @@ var IntercomAbilitySchema = object({
|
|
|
59016
59764
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
59017
59765
|
codecs: array(string()),
|
|
59018
59766
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
59019
|
-
sampleRate: number(),
|
|
59767
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
59020
59768
|
duplex: _enum(["half", "full"]),
|
|
59021
59769
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
59022
|
-
maxBacklogMs: number()
|
|
59770
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
59023
59771
|
});
|
|
59024
59772
|
var IntercomStatusSchema = object({
|
|
59025
59773
|
/** True while a talk session is open. */
|
|
@@ -59130,13 +59878,13 @@ object({
|
|
|
59130
59878
|
activity: LawnMowerActivitySchema,
|
|
59131
59879
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
59132
59880
|
* reading. */
|
|
59133
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59881
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59134
59882
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
59135
59883
|
* task is active / progress is unavailable. */
|
|
59136
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59884
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59137
59885
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
59138
59886
|
* or null when unknown. */
|
|
59139
|
-
currentCode: number().nullable(),
|
|
59887
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
59140
59888
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
59141
59889
|
currentCodeLabel: string().nullable(),
|
|
59142
59890
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -59546,7 +60294,14 @@ DeviceType.Lock, method(object({
|
|
|
59546
60294
|
auth: "protected"
|
|
59547
60295
|
}), method(object({
|
|
59548
60296
|
deviceId: number().int().nonnegative(),
|
|
59549
|
-
code: string().min(1).optional()
|
|
60297
|
+
code: string().min(1).optional(),
|
|
60298
|
+
/**
|
|
60299
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
60300
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
60301
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
60302
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
60303
|
+
*/
|
|
60304
|
+
confirm: boolean().optional()
|
|
59550
60305
|
}), _void(), {
|
|
59551
60306
|
kind: "mutation",
|
|
59552
60307
|
auth: "protected"
|
|
@@ -59554,6 +60309,11 @@ DeviceType.Lock, method(object({
|
|
|
59554
60309
|
kind: "mutation",
|
|
59555
60310
|
auth: "protected"
|
|
59556
60311
|
});
|
|
60312
|
+
object({
|
|
60313
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
60314
|
+
lastFetchedAt: number()
|
|
60315
|
+
});
|
|
60316
|
+
DeviceType.Sensor;
|
|
59557
60317
|
/**
|
|
59558
60318
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59559
60319
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59598,7 +60358,7 @@ object({
|
|
|
59598
60358
|
state: MediaPlayerStateSchema,
|
|
59599
60359
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59600
60360
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59601
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
60361
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59602
60362
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59603
60363
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59604
60364
|
isMuted: boolean().nullable(),
|
|
@@ -59611,10 +60371,10 @@ object({
|
|
|
59611
60371
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59612
60372
|
/** Current playback position in ms. Null when not seekable or
|
|
59613
60373
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59614
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
60374
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59615
60375
|
/** Total duration of the current media in ms. Null when unknown
|
|
59616
60376
|
* (live stream) or nothing is playing. */
|
|
59617
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
60377
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59618
60378
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59619
60379
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59620
60380
|
shuffle: boolean().nullable(),
|
|
@@ -59914,7 +60674,7 @@ object({
|
|
|
59914
60674
|
* it, every provider seeded it at boot, and every session left it
|
|
59915
60675
|
* `detected: true` after its detach.
|
|
59916
60676
|
*/
|
|
59917
|
-
autoClearAfterMs: number().nullable()
|
|
60677
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59918
60678
|
});
|
|
59919
60679
|
/**
|
|
59920
60680
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59964,7 +60724,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59964
60724
|
});
|
|
59965
60725
|
object({
|
|
59966
60726
|
enabled: boolean(),
|
|
59967
|
-
sensitivity: number(),
|
|
60727
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59968
60728
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59969
60729
|
regions: array(MotionZoneRegionSchema),
|
|
59970
60730
|
lastFetchedAt: number()
|
|
@@ -60268,7 +61028,7 @@ var NavigationStatusSchema = object({
|
|
|
60268
61028
|
following: boolean(),
|
|
60269
61029
|
flash: boolean(),
|
|
60270
61030
|
lightMode: NavigationLightModeSchema,
|
|
60271
|
-
lightLevel: number().min(40).max(100),
|
|
61031
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
60272
61032
|
/** Ms epoch when the slice was last updated. */
|
|
60273
61033
|
lastChangedAt: number()
|
|
60274
61034
|
});
|
|
@@ -60314,13 +61074,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
60314
61074
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
60315
61075
|
* SKIP a null rather than coerce it.
|
|
60316
61076
|
*/
|
|
60317
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
61077
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60318
61078
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
60319
|
-
rssiDbm: number().optional(),
|
|
61079
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
60320
61080
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
60321
61081
|
ssid: string().optional(),
|
|
60322
61082
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
60323
|
-
lastUpdated: number()
|
|
61083
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
60324
61084
|
});
|
|
60325
61085
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
60326
61086
|
deviceId: number(),
|
|
@@ -60639,7 +61399,7 @@ object({
|
|
|
60639
61399
|
lastError: string().nullable(),
|
|
60640
61400
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60641
61401
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60642
|
-
queueDepth: number().int().nonnegative(),
|
|
61402
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60643
61403
|
/** Per-feature capability matrix — authoritative source for the
|
|
60644
61404
|
* compose-form field gating. */
|
|
60645
61405
|
supports: NotifierSupportsSchema
|
|
@@ -60689,15 +61449,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60689
61449
|
acceptedAt: number()
|
|
60690
61450
|
});
|
|
60691
61451
|
object({
|
|
60692
|
-
|
|
60693
|
-
|
|
60694
|
-
* Populated live from the upstream source on each state push.
|
|
60695
|
-
* Absent for unitless sensors. */
|
|
60696
|
-
unit: string().optional(),
|
|
60697
|
-
/** Suggested decimal places for numeric display.
|
|
60698
|
-
* Populated live from the upstream source when provided.
|
|
60699
|
-
* Falls back to auto-formatting when absent. */
|
|
60700
|
-
precision: number().int().min(0).max(10).optional(),
|
|
61452
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
61453
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60701
61454
|
/** Ms epoch when the slice was last updated. */
|
|
60702
61455
|
lastFetchedAt: number()
|
|
60703
61456
|
});
|
|
@@ -60987,23 +61740,26 @@ object({
|
|
|
60987
61740
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60988
61741
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60989
61742
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60990
|
-
foodLevel: number().nullable(),
|
|
61743
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60991
61744
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60992
61745
|
* single-hopper models. */
|
|
60993
|
-
food1: number().nullable(),
|
|
61746
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60994
61747
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60995
61748
|
* single-hopper models. */
|
|
60996
|
-
food2: number().nullable(),
|
|
61749
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60997
61750
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60998
61751
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60999
61752
|
* below the feeder's low threshold. */
|
|
61000
61753
|
lowFood: boolean(),
|
|
61001
61754
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
61002
61755
|
* device has no battery reading. */
|
|
61003
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
61004
|
-
/**
|
|
61005
|
-
*
|
|
61006
|
-
|
|
61756
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61757
|
+
/**
|
|
61758
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61759
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61760
|
+
* model has no desiccant sensor.
|
|
61761
|
+
*/
|
|
61762
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
61007
61763
|
/** True while a feed is in progress. */
|
|
61008
61764
|
feeding: boolean(),
|
|
61009
61765
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -61014,7 +61770,7 @@ object({
|
|
|
61014
61770
|
* with `errorCode` for consumers that want the raw integer. */
|
|
61015
61771
|
error: string().nullable(),
|
|
61016
61772
|
/** Raw device error code (0 / null = no error). */
|
|
61017
|
-
errorCode: number().nullable(),
|
|
61773
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
61018
61774
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
61019
61775
|
isDualHopper: boolean(),
|
|
61020
61776
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -61024,7 +61780,7 @@ object({
|
|
|
61024
61780
|
/** Play a chime when dispensing. */
|
|
61025
61781
|
feedSound: boolean(),
|
|
61026
61782
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
61027
|
-
volume: number(),
|
|
61783
|
+
volume: number().meta(readingMeta("none")),
|
|
61028
61784
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
61029
61785
|
lastFetchedAt: number()
|
|
61030
61786
|
});
|
|
@@ -61461,38 +62217,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61461
62217
|
});
|
|
61462
62218
|
object({
|
|
61463
62219
|
/** Instantaneous power draw in watts. */
|
|
61464
|
-
watts: number().optional().meta({
|
|
61465
|
-
unit: "W",
|
|
61466
|
-
label: "Power"
|
|
61467
|
-
}),
|
|
62220
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61468
62221
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61469
|
-
kwhTotal: number().optional().meta({
|
|
61470
|
-
unit: "kWh",
|
|
61471
|
-
label: "Energy"
|
|
61472
|
-
}),
|
|
62222
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61473
62223
|
/** Voltage in volts. */
|
|
61474
|
-
volts: number().optional(),
|
|
62224
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61475
62225
|
/** Current in amperes. */
|
|
61476
|
-
amps: number().optional(),
|
|
61477
|
-
/** Apparent power in volt-amperes
|
|
61478
|
-
va: number().optional(),
|
|
62226
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
62227
|
+
/** Apparent power in volt-amperes. */
|
|
62228
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61479
62229
|
/** Power factor (0..1) if reported. */
|
|
61480
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
62230
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61481
62231
|
/** Ms epoch when the slice was last updated. */
|
|
61482
|
-
lastFetchedAt: number()
|
|
61483
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
61484
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
61485
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
61486
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
61487
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
61488
|
-
unit: string().optional(),
|
|
61489
|
-
/** Suggested decimal places for numeric display.
|
|
61490
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61491
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61492
|
-
* auto-formatting when absent. */
|
|
61493
|
-
precision: number().int().min(0).max(10).optional()
|
|
62232
|
+
lastFetchedAt: number()
|
|
61494
62233
|
});
|
|
61495
|
-
|
|
62234
|
+
[
|
|
62235
|
+
DeviceType.Sensor,
|
|
62236
|
+
DeviceType.Switch,
|
|
62237
|
+
DeviceType.Light,
|
|
62238
|
+
DeviceType.Fan,
|
|
62239
|
+
DeviceType.Climate,
|
|
62240
|
+
DeviceType.Thermostat,
|
|
62241
|
+
DeviceType.Humidifier,
|
|
62242
|
+
DeviceType.WaterHeater,
|
|
62243
|
+
DeviceType.MediaPlayer,
|
|
62244
|
+
DeviceType.Washer,
|
|
62245
|
+
DeviceType.Dryer,
|
|
62246
|
+
DeviceType.Dishwasher,
|
|
62247
|
+
DeviceType.Vacuum,
|
|
62248
|
+
DeviceType.LawnMower,
|
|
62249
|
+
DeviceType.PetFeeder
|
|
62250
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61496
62251
|
/**
|
|
61497
62252
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61498
62253
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61511,11 +62266,11 @@ DeviceType.Sensor;
|
|
|
61511
62266
|
*/
|
|
61512
62267
|
var GpsLocationSchema = object({
|
|
61513
62268
|
/** Latitude in decimal degrees, -90..90. */
|
|
61514
|
-
latitude: number().min(-90).max(90),
|
|
62269
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
61515
62270
|
/** Longitude in decimal degrees, -180..180. */
|
|
61516
|
-
longitude: number().min(-180).max(180),
|
|
62271
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
61517
62272
|
/** Reported accuracy in meters (lower = better). */
|
|
61518
|
-
accuracyMeters: number().nonnegative()
|
|
62273
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
61519
62274
|
});
|
|
61520
62275
|
object({
|
|
61521
62276
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -61527,25 +62282,16 @@ object({
|
|
|
61527
62282
|
gps: GpsLocationSchema.nullable(),
|
|
61528
62283
|
/** Optional battery level of the tracking device (0..100). Null
|
|
61529
62284
|
* when not reported. */
|
|
61530
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
62285
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61531
62286
|
/** Ms epoch when the slice was last updated. */
|
|
61532
62287
|
lastChangedAt: number()
|
|
61533
62288
|
});
|
|
61534
62289
|
DeviceType.Presence;
|
|
61535
62290
|
object({
|
|
61536
|
-
/** Current pressure in hPa. */
|
|
61537
|
-
hpa: number(),
|
|
62291
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
62292
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61538
62293
|
/** Ms epoch when the slice was last updated. */
|
|
61539
|
-
lastFetchedAt: number()
|
|
61540
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61541
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61542
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61543
|
-
unit: string().optional(),
|
|
61544
|
-
/** Suggested decimal places for numeric display.
|
|
61545
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61546
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61547
|
-
* auto-formatting when absent. */
|
|
61548
|
-
precision: number().int().min(0).max(10).optional()
|
|
62294
|
+
lastFetchedAt: number()
|
|
61549
62295
|
});
|
|
61550
62296
|
DeviceType.Sensor;
|
|
61551
62297
|
/**
|
|
@@ -61878,8 +62624,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61878
62624
|
}), _void(), { kind: "mutation" });
|
|
61879
62625
|
var PtzAutotrackSettingsSchema = object({
|
|
61880
62626
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61881
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61882
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62627
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62628
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61883
62629
|
});
|
|
61884
62630
|
/**
|
|
61885
62631
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61936,7 +62682,7 @@ object({
|
|
|
61936
62682
|
/** null = unknown — never coerced to false (D393). */
|
|
61937
62683
|
running: boolean().nullable(),
|
|
61938
62684
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61939
|
-
since: number().nullable(),
|
|
62685
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61940
62686
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61941
62687
|
phase: string().nullable(),
|
|
61942
62688
|
/** null until a reading has been published (D393). */
|
|
@@ -61948,7 +62694,7 @@ object({
|
|
|
61948
62694
|
phase: string().nullable()
|
|
61949
62695
|
});
|
|
61950
62696
|
Object.values(DeviceType);
|
|
61951
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62697
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61952
62698
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61953
62699
|
kind: "mutation",
|
|
61954
62700
|
auth: "admin"
|
|
@@ -63134,9 +63880,9 @@ var RecordTriggerSchema = _enum([
|
|
|
63134
63880
|
*/
|
|
63135
63881
|
var RecordWindowSchema = object({
|
|
63136
63882
|
trigger: RecordTriggerSchema,
|
|
63137
|
-
day: number().int().min(0).max(6),
|
|
63138
|
-
startMinute: number().int().min(0).max(1439),
|
|
63139
|
-
endMinute: number().int().min(1).max(1440)
|
|
63883
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63884
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63885
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
63140
63886
|
});
|
|
63141
63887
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
63142
63888
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -63205,10 +63951,10 @@ object({
|
|
|
63205
63951
|
/** Master "record to the card at all" switch. */
|
|
63206
63952
|
enabled: boolean().nullable(),
|
|
63207
63953
|
overwriteWhenFull: boolean().nullable(),
|
|
63208
|
-
preRecordSec: number().nullable(),
|
|
63209
|
-
postRecordSec: number().nullable(),
|
|
63954
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63955
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63210
63956
|
/** Length of one recorded file, in minutes. */
|
|
63211
|
-
segmentMinutes: number().nullable(),
|
|
63957
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
63212
63958
|
/** The primary track's weekly windows, flattened. */
|
|
63213
63959
|
windows: array(RecordWindowSchema),
|
|
63214
63960
|
/**
|
|
@@ -63224,7 +63970,7 @@ object({
|
|
|
63224
63970
|
* provider reporting a non-zero count also reports the schedule as not
|
|
63225
63971
|
* writable.
|
|
63226
63972
|
*/
|
|
63227
|
-
unreadableWindows: number(),
|
|
63973
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
63228
63974
|
/**
|
|
63229
63975
|
* The camera is scheduled to record and has NO usable storage.
|
|
63230
63976
|
*
|
|
@@ -63861,7 +64607,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63861
64607
|
url: string().optional(),
|
|
63862
64608
|
codec: string().optional(),
|
|
63863
64609
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63864
|
-
fps: number().positive().optional(),
|
|
64610
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63865
64611
|
label: string().optional(),
|
|
63866
64612
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63867
64613
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63891,18 +64637,18 @@ var StreamProfileSchema = _enum([
|
|
|
63891
64637
|
]);
|
|
63892
64638
|
/** The current encoding config of one stream profile. */
|
|
63893
64639
|
var StreamProfileConfigSchema = object({
|
|
63894
|
-
width: number(),
|
|
63895
|
-
height: number(),
|
|
64640
|
+
width: number().meta(readingMeta("none")),
|
|
64641
|
+
height: number().meta(readingMeta("none")),
|
|
63896
64642
|
codec: _enum(["h264", "h265"]),
|
|
63897
|
-
framerate: number(),
|
|
63898
|
-
bitrate: number(),
|
|
64643
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64644
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63899
64645
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63900
64646
|
encoderProfile: _enum([
|
|
63901
64647
|
"high",
|
|
63902
64648
|
"main",
|
|
63903
64649
|
"baseline"
|
|
63904
64650
|
]).optional(),
|
|
63905
|
-
gop: number().optional(),
|
|
64651
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63906
64652
|
/**
|
|
63907
64653
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63908
64654
|
*
|
|
@@ -63987,7 +64733,7 @@ object({
|
|
|
63987
64733
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63988
64734
|
lastChangedAt: number()
|
|
63989
64735
|
});
|
|
63990
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64736
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63991
64737
|
deviceId: number(),
|
|
63992
64738
|
on: boolean()
|
|
63993
64739
|
}), _void(), {
|
|
@@ -64545,23 +65291,13 @@ object({
|
|
|
64545
65291
|
});
|
|
64546
65292
|
DeviceType.Sensor;
|
|
64547
65293
|
object({
|
|
64548
|
-
/** Current temperature in Celsius. */
|
|
64549
|
-
celsius: number().meta({
|
|
64550
|
-
|
|
65294
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
65295
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
65296
|
+
precision: 1,
|
|
64551
65297
|
label: "Temperature"
|
|
64552
|
-
}),
|
|
65298
|
+
})),
|
|
64553
65299
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64554
|
-
lastFetchedAt: number()
|
|
64555
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64556
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64557
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64558
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64559
|
-
unit: string().optional(),
|
|
64560
|
-
/** Suggested decimal places for numeric display.
|
|
64561
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64562
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64563
|
-
* auto-formatting when absent. */
|
|
64564
|
-
precision: number().int().min(0).max(10).optional()
|
|
65300
|
+
lastFetchedAt: number()
|
|
64565
65301
|
});
|
|
64566
65302
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64567
65303
|
/**
|
|
@@ -64813,16 +65549,16 @@ object({
|
|
|
64813
65549
|
]),
|
|
64814
65550
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64815
65551
|
* reading. */
|
|
64816
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65552
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64817
65553
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64818
65554
|
* the vacuum has no speed control. */
|
|
64819
65555
|
fanSpeed: string().nullable(),
|
|
64820
65556
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64821
65557
|
availableFanSpeeds: array(string()),
|
|
64822
65558
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64823
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65559
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64824
65560
|
/** Current error code (0 / null = no error). */
|
|
64825
|
-
errorCode: number().nullable(),
|
|
65561
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64826
65562
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64827
65563
|
errorLabel: string().nullable(),
|
|
64828
65564
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64861,7 +65597,7 @@ object({
|
|
|
64861
65597
|
]),
|
|
64862
65598
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64863
65599
|
* intermediate position surface. */
|
|
64864
|
-
position: number().min(0).max(100).nullable(),
|
|
65600
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64865
65601
|
/** Ms epoch when the slice was last updated. */
|
|
64866
65602
|
lastChangedAt: number()
|
|
64867
65603
|
});
|
|
@@ -64889,9 +65625,9 @@ object({
|
|
|
64889
65625
|
DeviceType.Sensor;
|
|
64890
65626
|
object({
|
|
64891
65627
|
/** Current measured temperature. Null when not reported. */
|
|
64892
|
-
currentTemp: number().nullable(),
|
|
65628
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64893
65629
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64894
|
-
targetTemp: number().nullable(),
|
|
65630
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64895
65631
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64896
65632
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64897
65633
|
* device reports an unknown state. */
|
|
@@ -64902,9 +65638,9 @@ object({
|
|
|
64902
65638
|
* has no away surface. */
|
|
64903
65639
|
away: boolean().nullable(),
|
|
64904
65640
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64905
|
-
minTemp: number().nullable(),
|
|
65641
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64906
65642
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64907
|
-
maxTemp: number().nullable(),
|
|
65643
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64908
65644
|
/** Ms epoch when the slice was last updated. */
|
|
64909
65645
|
lastChangedAt: number()
|
|
64910
65646
|
});
|
|
@@ -64928,25 +65664,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64928
65664
|
auth: "protected"
|
|
64929
65665
|
});
|
|
64930
65666
|
object({
|
|
64931
|
-
/** Verbatim
|
|
64932
|
-
* when no condition has been reported yet. */
|
|
65667
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64933
65668
|
condition: string().nullable(),
|
|
64934
|
-
/** Current temperature in
|
|
64935
|
-
temperature: number().nullable(),
|
|
64936
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64937
|
-
temperatureUnit: string().nullable(),
|
|
65669
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65670
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64938
65671
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64939
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64940
|
-
/** Barometric pressure in
|
|
64941
|
-
pressure: number().nullable(),
|
|
64942
|
-
/**
|
|
64943
|
-
|
|
64944
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64945
|
-
windSpeed: number().nullable(),
|
|
64946
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64947
|
-
windSpeedUnit: string().nullable(),
|
|
65672
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65673
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65674
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65675
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65676
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64948
65677
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64949
|
-
windBearing: number().nullable(),
|
|
65678
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64950
65679
|
/** Ms epoch when the slice was last updated. */
|
|
64951
65680
|
lastFetchedAt: number()
|
|
64952
65681
|
});
|
|
@@ -65696,8 +66425,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65696
66425
|
kind: "mutation",
|
|
65697
66426
|
auth: "admin"
|
|
65698
66427
|
});
|
|
66428
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65699
66429
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65700
|
-
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;
|
|
66430
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, 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.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
65701
66431
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65702
66432
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65703
66433
|
new Set(CAP_NAMES);
|
|
@@ -65750,7 +66480,7 @@ var AccessoryKind = {
|
|
|
65750
66480
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65751
66481
|
};
|
|
65752
66482
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65753
|
-
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;
|
|
66483
|
+
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;
|
|
65754
66484
|
new Set(Object.values(DeviceType));
|
|
65755
66485
|
Object.freeze({
|
|
65756
66486
|
"accessories.getStatus": {
|
|
@@ -65858,6 +66588,13 @@ Object.freeze({
|
|
|
65858
66588
|
access: "view",
|
|
65859
66589
|
role: "admin"
|
|
65860
66590
|
},
|
|
66591
|
+
"addons.getPackageDocs": {
|
|
66592
|
+
capName: "addons",
|
|
66593
|
+
capScope: "system",
|
|
66594
|
+
addonId: null,
|
|
66595
|
+
access: "view",
|
|
66596
|
+
role: "admin"
|
|
66597
|
+
},
|
|
65861
66598
|
"addons.getVersions": {
|
|
65862
66599
|
capName: "addons",
|
|
65863
66600
|
capScope: "system",
|
|
@@ -68966,6 +69703,27 @@ Object.freeze({
|
|
|
68966
69703
|
access: "view",
|
|
68967
69704
|
role: "viewer"
|
|
68968
69705
|
},
|
|
69706
|
+
"groupActive.getStatus": {
|
|
69707
|
+
capName: "group-active",
|
|
69708
|
+
capScope: "device",
|
|
69709
|
+
addonId: null,
|
|
69710
|
+
access: "view",
|
|
69711
|
+
role: "viewer"
|
|
69712
|
+
},
|
|
69713
|
+
"groupCommands.getStatus": {
|
|
69714
|
+
capName: "group-commands",
|
|
69715
|
+
capScope: "device",
|
|
69716
|
+
addonId: null,
|
|
69717
|
+
access: "view",
|
|
69718
|
+
role: "viewer"
|
|
69719
|
+
},
|
|
69720
|
+
"groupStatus.getStatus": {
|
|
69721
|
+
capName: "group-status",
|
|
69722
|
+
capScope: "device",
|
|
69723
|
+
addonId: null,
|
|
69724
|
+
access: "view",
|
|
69725
|
+
role: "viewer"
|
|
69726
|
+
},
|
|
68969
69727
|
"heatingValve.getStatus": {
|
|
68970
69728
|
capName: "heating-valve",
|
|
68971
69729
|
capScope: "device",
|
|
@@ -69918,6 +70676,13 @@ Object.freeze({
|
|
|
69918
70676
|
access: "create",
|
|
69919
70677
|
role: "admin"
|
|
69920
70678
|
},
|
|
70679
|
+
"meter.getStatus": {
|
|
70680
|
+
capName: "meter",
|
|
70681
|
+
capScope: "device",
|
|
70682
|
+
addonId: null,
|
|
70683
|
+
access: "view",
|
|
70684
|
+
role: "viewer"
|
|
70685
|
+
},
|
|
69921
70686
|
"metricsProvider.collectSnapshot": {
|
|
69922
70687
|
capName: "metrics-provider",
|
|
69923
70688
|
capScope: "system",
|
|
@@ -78016,7 +78781,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
78016
78781
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
78017
78782
|
icon: "square"
|
|
78018
78783
|
}
|
|
78019
|
-
}
|
|
78784
|
+
},
|
|
78785
|
+
overrides: { byType: {
|
|
78786
|
+
[DeviceType.Washer]: {
|
|
78787
|
+
state: { running: {
|
|
78788
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78789
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78790
|
+
} },
|
|
78791
|
+
events: {
|
|
78792
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78793
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78794
|
+
}
|
|
78795
|
+
},
|
|
78796
|
+
[DeviceType.Dryer]: {
|
|
78797
|
+
state: { running: {
|
|
78798
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78799
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78800
|
+
} },
|
|
78801
|
+
events: {
|
|
78802
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78803
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78804
|
+
}
|
|
78805
|
+
},
|
|
78806
|
+
[DeviceType.Dishwasher]: {
|
|
78807
|
+
state: { running: {
|
|
78808
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78809
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78810
|
+
} },
|
|
78811
|
+
events: {
|
|
78812
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78813
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78814
|
+
}
|
|
78815
|
+
}
|
|
78816
|
+
} }
|
|
78020
78817
|
},
|
|
78021
78818
|
update: {
|
|
78022
78819
|
scope: "device",
|
|
@@ -78788,6 +79585,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78788
79585
|
icon: "flame"
|
|
78789
79586
|
}]
|
|
78790
79587
|
},
|
|
79588
|
+
"group-active": {
|
|
79589
|
+
scope: "device",
|
|
79590
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79591
|
+
},
|
|
79592
|
+
"group-commands": {
|
|
79593
|
+
scope: "device",
|
|
79594
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79595
|
+
},
|
|
79596
|
+
"group-status": {
|
|
79597
|
+
scope: "device",
|
|
79598
|
+
noun: t("Group", "Gruppo"),
|
|
79599
|
+
state: [
|
|
79600
|
+
{
|
|
79601
|
+
kind: "numeric",
|
|
79602
|
+
field: "included",
|
|
79603
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79604
|
+
label: t("Reporting", "Rispondono"),
|
|
79605
|
+
icon: "users"
|
|
79606
|
+
},
|
|
79607
|
+
{
|
|
79608
|
+
kind: "numeric",
|
|
79609
|
+
field: "excluded",
|
|
79610
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79611
|
+
label: t("Excluded", "Esclusi"),
|
|
79612
|
+
icon: "users"
|
|
79613
|
+
},
|
|
79614
|
+
{
|
|
79615
|
+
kind: "numeric",
|
|
79616
|
+
field: "total",
|
|
79617
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79618
|
+
label: t("Members", "Membri"),
|
|
79619
|
+
icon: "sigma"
|
|
79620
|
+
}
|
|
79621
|
+
]
|
|
79622
|
+
},
|
|
78791
79623
|
"humidity-sensor": {
|
|
78792
79624
|
scope: "device",
|
|
78793
79625
|
noun: t("Humidity", "Umidità"),
|
|
@@ -78813,6 +79645,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78813
79645
|
}],
|
|
78814
79646
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78815
79647
|
},
|
|
79648
|
+
meter: {
|
|
79649
|
+
scope: "device",
|
|
79650
|
+
noun: t("Meter", "Contatore"),
|
|
79651
|
+
state: [{
|
|
79652
|
+
kind: "numeric",
|
|
79653
|
+
field: "value",
|
|
79654
|
+
quantity: t("the total", "il totale"),
|
|
79655
|
+
label: t("Total", "Totale"),
|
|
79656
|
+
icon: "gauge"
|
|
79657
|
+
}]
|
|
79658
|
+
},
|
|
78816
79659
|
"numeric-sensor": {
|
|
78817
79660
|
scope: "device",
|
|
78818
79661
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78821,7 +79664,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78821
79664
|
field: "value",
|
|
78822
79665
|
quantity: t("the reading", "il valore"),
|
|
78823
79666
|
label: t("Reading", "Valore"),
|
|
78824
|
-
unitField: "unit",
|
|
78825
79667
|
icon: "gauge"
|
|
78826
79668
|
}]
|
|
78827
79669
|
},
|
|
@@ -78957,7 +79799,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78957
79799
|
field: "temperature",
|
|
78958
79800
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78959
79801
|
label: t("Temperature", "Temperatura"),
|
|
78960
|
-
|
|
79802
|
+
unit: "°C",
|
|
78961
79803
|
icon: "thermometer"
|
|
78962
79804
|
},
|
|
78963
79805
|
{
|
|
@@ -78973,7 +79815,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78973
79815
|
field: "windSpeed",
|
|
78974
79816
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78975
79817
|
label: t("Wind", "Vento"),
|
|
78976
|
-
|
|
79818
|
+
unit: "m/s",
|
|
78977
79819
|
icon: "wind"
|
|
78978
79820
|
},
|
|
78979
79821
|
{
|
|
@@ -78981,7 +79823,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78981
79823
|
field: "pressure",
|
|
78982
79824
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78983
79825
|
label: t("Pressure", "Pressione"),
|
|
78984
|
-
|
|
79826
|
+
unit: "hPa",
|
|
78985
79827
|
icon: "gauge"
|
|
78986
79828
|
}
|
|
78987
79829
|
]
|
|
@@ -79286,8 +80128,47 @@ function projectAction(cap, action) {
|
|
|
79286
80128
|
};
|
|
79287
80129
|
}
|
|
79288
80130
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
79289
|
-
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;
|
|
80131
|
+
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;
|
|
79290
80132
|
DeviceFeature.BatteryOperated;
|
|
80133
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
80134
|
+
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.";
|
|
80135
|
+
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.";
|
|
80136
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
80137
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
80138
|
+
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.";
|
|
80139
|
+
function withheld(reason) {
|
|
80140
|
+
return {
|
|
80141
|
+
[DeviceType.Washer]: {
|
|
80142
|
+
exported: false,
|
|
80143
|
+
reason
|
|
80144
|
+
},
|
|
80145
|
+
[DeviceType.Dryer]: {
|
|
80146
|
+
exported: false,
|
|
80147
|
+
reason
|
|
80148
|
+
},
|
|
80149
|
+
[DeviceType.Dishwasher]: {
|
|
80150
|
+
exported: false,
|
|
80151
|
+
reason
|
|
80152
|
+
}
|
|
80153
|
+
};
|
|
80154
|
+
}
|
|
80155
|
+
function offered(received) {
|
|
80156
|
+
return {
|
|
80157
|
+
[DeviceType.Washer]: {
|
|
80158
|
+
exported: true,
|
|
80159
|
+
as: received
|
|
80160
|
+
},
|
|
80161
|
+
[DeviceType.Dryer]: {
|
|
80162
|
+
exported: true,
|
|
80163
|
+
as: received
|
|
80164
|
+
},
|
|
80165
|
+
[DeviceType.Dishwasher]: {
|
|
80166
|
+
exported: true,
|
|
80167
|
+
as: received
|
|
80168
|
+
}
|
|
80169
|
+
};
|
|
80170
|
+
}
|
|
80171
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
79291
80172
|
Object.freeze({
|
|
79292
80173
|
"accessories.getStatus": [{
|
|
79293
80174
|
name: "deviceId",
|
|
@@ -80254,6 +81135,21 @@ Object.freeze({
|
|
|
80254
81135
|
form: "single",
|
|
80255
81136
|
optional: false
|
|
80256
81137
|
}],
|
|
81138
|
+
"groupActive.getStatus": [{
|
|
81139
|
+
name: "deviceId",
|
|
81140
|
+
form: "single",
|
|
81141
|
+
optional: false
|
|
81142
|
+
}],
|
|
81143
|
+
"groupCommands.getStatus": [{
|
|
81144
|
+
name: "deviceId",
|
|
81145
|
+
form: "single",
|
|
81146
|
+
optional: false
|
|
81147
|
+
}],
|
|
81148
|
+
"groupStatus.getStatus": [{
|
|
81149
|
+
name: "deviceId",
|
|
81150
|
+
form: "single",
|
|
81151
|
+
optional: false
|
|
81152
|
+
}],
|
|
80257
81153
|
"heatingValve.getStatus": [{
|
|
80258
81154
|
name: "deviceId",
|
|
80259
81155
|
form: "single",
|
|
@@ -80454,6 +81350,11 @@ Object.freeze({
|
|
|
80454
81350
|
form: "single",
|
|
80455
81351
|
optional: false
|
|
80456
81352
|
}],
|
|
81353
|
+
"meter.getStatus": [{
|
|
81354
|
+
name: "deviceId",
|
|
81355
|
+
form: "single",
|
|
81356
|
+
optional: false
|
|
81357
|
+
}],
|
|
80457
81358
|
"motion.getStatus": [{
|
|
80458
81359
|
name: "deviceId",
|
|
80459
81360
|
form: "single",
|
|
@@ -82061,7 +82962,6 @@ Object.freeze({
|
|
|
82061
82962
|
"network-access": "ingress",
|
|
82062
82963
|
"smtp-provider": "email"
|
|
82063
82964
|
});
|
|
82064
|
-
DeviceType.Camera;
|
|
82065
82965
|
/**
|
|
82066
82966
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
82067
82967
|
* `z.infer`, they do not restate the shape.
|
|
@@ -82238,6 +83138,8 @@ new Map(Object.entries({
|
|
|
82238
83138
|
"detection-blind": "device-events",
|
|
82239
83139
|
"motion-noisy": "device-events",
|
|
82240
83140
|
"motion-calm": "device-events",
|
|
83141
|
+
"package-llm-silent": "device-events",
|
|
83142
|
+
"package-llm-answered": "device-events",
|
|
82241
83143
|
"recording-stalled": "device-events",
|
|
82242
83144
|
"recording-healthy": "device-events",
|
|
82243
83145
|
"recording-degraded": "device-events",
|
|
@@ -82321,6 +83223,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
82321
83223
|
label: "Motion without a subject",
|
|
82322
83224
|
kinds: ["motion-noisy", "motion-calm"]
|
|
82323
83225
|
},
|
|
83226
|
+
{
|
|
83227
|
+
id: "package-llm",
|
|
83228
|
+
family: "device-events",
|
|
83229
|
+
label: "Package confirm",
|
|
83230
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
83231
|
+
},
|
|
82324
83232
|
{
|
|
82325
83233
|
id: "recording",
|
|
82326
83234
|
family: "device-events",
|
|
@@ -82502,6 +83410,8 @@ var DEVICE_EVENTS = [
|
|
|
82502
83410
|
"detection-blind",
|
|
82503
83411
|
"motion-noisy",
|
|
82504
83412
|
"motion-calm",
|
|
83413
|
+
"package-llm-silent",
|
|
83414
|
+
"package-llm-answered",
|
|
82505
83415
|
"recording-stalled",
|
|
82506
83416
|
"recording-healthy",
|
|
82507
83417
|
"recording-degraded",
|
|
@@ -82770,6 +83680,15 @@ new Map([
|
|
|
82770
83680
|
snapshotLabel: "Cameras with constant motion now",
|
|
82771
83681
|
snapshotSection: null
|
|
82772
83682
|
},
|
|
83683
|
+
{
|
|
83684
|
+
id: "package-llm-confirm",
|
|
83685
|
+
family: "device-events",
|
|
83686
|
+
label: "Package confirm (not answering / answering again)",
|
|
83687
|
+
bad: ["package-llm-silent"],
|
|
83688
|
+
recovery: ["package-llm-answered"],
|
|
83689
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
83690
|
+
snapshotSection: null
|
|
83691
|
+
},
|
|
82773
83692
|
{
|
|
82774
83693
|
id: "recording-health",
|
|
82775
83694
|
family: "device-events",
|