@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region ../types/dist/event-category-
|
|
1
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
2
2
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
3
3
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4
4
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -324,6 +324,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
324
324
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
325
325
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
326
326
|
/**
|
|
327
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
328
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
329
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
330
|
+
*/
|
|
331
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
332
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
333
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
334
|
+
/**
|
|
327
335
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
328
336
|
* (a settings change via `setAgentInferenceDevices` /
|
|
329
337
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5566,7 +5574,7 @@ var ZodIssueCode = {
|
|
|
5566
5574
|
var ZodFirstPartyTypeKind;
|
|
5567
5575
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5568
5576
|
//#endregion
|
|
5569
|
-
//#region ../types/dist/sleep
|
|
5577
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5570
5578
|
/**
|
|
5571
5579
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5572
5580
|
* window to float samples (D455).
|
|
@@ -8294,6 +8302,99 @@ function defineEntryKind(name, spec) {
|
|
|
8294
8302
|
if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
|
|
8295
8303
|
return defined;
|
|
8296
8304
|
}
|
|
8305
|
+
var READING_QUANTITIES = [
|
|
8306
|
+
"temperature",
|
|
8307
|
+
"pressure",
|
|
8308
|
+
"speed",
|
|
8309
|
+
"precipitation",
|
|
8310
|
+
"precipitation-rate",
|
|
8311
|
+
"length",
|
|
8312
|
+
"area",
|
|
8313
|
+
"illuminance",
|
|
8314
|
+
"irradiance",
|
|
8315
|
+
"power",
|
|
8316
|
+
"energy",
|
|
8317
|
+
"voltage",
|
|
8318
|
+
"current",
|
|
8319
|
+
"apparent-power",
|
|
8320
|
+
"humidity",
|
|
8321
|
+
"percentage",
|
|
8322
|
+
"concentration-volume",
|
|
8323
|
+
"concentration-mass",
|
|
8324
|
+
"concentration-ppb",
|
|
8325
|
+
"volume",
|
|
8326
|
+
"duration",
|
|
8327
|
+
"duration-ms",
|
|
8328
|
+
"information",
|
|
8329
|
+
"sound-level",
|
|
8330
|
+
"signal-level",
|
|
8331
|
+
"colour-temperature",
|
|
8332
|
+
"angle",
|
|
8333
|
+
"bitrate",
|
|
8334
|
+
"rate",
|
|
8335
|
+
"mass",
|
|
8336
|
+
"index",
|
|
8337
|
+
"ratio",
|
|
8338
|
+
"count",
|
|
8339
|
+
"none",
|
|
8340
|
+
"device"
|
|
8341
|
+
];
|
|
8342
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8343
|
+
new Set(READING_QUANTITIES);
|
|
8344
|
+
/**
|
|
8345
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8346
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8347
|
+
*/
|
|
8348
|
+
var QUANTITY_BASE = {
|
|
8349
|
+
temperature: "°C",
|
|
8350
|
+
pressure: "hPa",
|
|
8351
|
+
speed: "m/s",
|
|
8352
|
+
precipitation: "mm",
|
|
8353
|
+
"precipitation-rate": "mm/h",
|
|
8354
|
+
length: "m",
|
|
8355
|
+
area: "m²",
|
|
8356
|
+
illuminance: "lx",
|
|
8357
|
+
irradiance: "W/m²",
|
|
8358
|
+
power: "W",
|
|
8359
|
+
energy: "kWh",
|
|
8360
|
+
voltage: "V",
|
|
8361
|
+
current: "A",
|
|
8362
|
+
"apparent-power": "VA",
|
|
8363
|
+
humidity: "%",
|
|
8364
|
+
percentage: "%",
|
|
8365
|
+
"concentration-volume": "ppm",
|
|
8366
|
+
"concentration-mass": "µg/m³",
|
|
8367
|
+
"concentration-ppb": "ppb",
|
|
8368
|
+
volume: "L",
|
|
8369
|
+
duration: "s",
|
|
8370
|
+
"duration-ms": "ms",
|
|
8371
|
+
information: "B",
|
|
8372
|
+
"sound-level": "dBFS",
|
|
8373
|
+
"signal-level": "dBm",
|
|
8374
|
+
"colour-temperature": "mired",
|
|
8375
|
+
angle: "°",
|
|
8376
|
+
bitrate: "kbps",
|
|
8377
|
+
rate: "fps",
|
|
8378
|
+
mass: "kg",
|
|
8379
|
+
index: "none",
|
|
8380
|
+
ratio: "none",
|
|
8381
|
+
count: "none",
|
|
8382
|
+
none: "none",
|
|
8383
|
+
device: "device"
|
|
8384
|
+
};
|
|
8385
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8386
|
+
function baseUnitOf(quantity) {
|
|
8387
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8388
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8389
|
+
return symbol;
|
|
8390
|
+
}
|
|
8391
|
+
function readingMeta(quantity, extras) {
|
|
8392
|
+
return {
|
|
8393
|
+
quantity,
|
|
8394
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8395
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8396
|
+
};
|
|
8397
|
+
}
|
|
8297
8398
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8298
8399
|
var CamProfileSchema = _enum([
|
|
8299
8400
|
"high",
|
|
@@ -8321,8 +8422,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8321
8422
|
"derived"
|
|
8322
8423
|
]);
|
|
8323
8424
|
var CamStreamResolutionSchema = object({
|
|
8324
|
-
width: number().int().positive(),
|
|
8325
|
-
height: number().int().positive()
|
|
8425
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8426
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8326
8427
|
});
|
|
8327
8428
|
var CameraStreamSchema = object({
|
|
8328
8429
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8836,6 +8937,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8836
8937
|
"filesystem-browse",
|
|
8837
8938
|
"flood",
|
|
8838
8939
|
"gas",
|
|
8940
|
+
"group-active",
|
|
8941
|
+
"group-commands",
|
|
8942
|
+
"group-status",
|
|
8839
8943
|
"heating-valve",
|
|
8840
8944
|
"humidifier",
|
|
8841
8945
|
"humidity-sensor",
|
|
@@ -8856,6 +8960,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8856
8960
|
"login-method",
|
|
8857
8961
|
"media-player",
|
|
8858
8962
|
"mesh-network",
|
|
8963
|
+
"meter",
|
|
8859
8964
|
"metrics-provider",
|
|
8860
8965
|
"model-convert",
|
|
8861
8966
|
"model-distributor",
|
|
@@ -8965,14 +9070,6 @@ Object.freeze({
|
|
|
8965
9070
|
{
|
|
8966
9071
|
"path": "aqi",
|
|
8967
9072
|
"valueType": "number"
|
|
8968
|
-
},
|
|
8969
|
-
{
|
|
8970
|
-
"path": "unit",
|
|
8971
|
-
"valueType": "string"
|
|
8972
|
-
},
|
|
8973
|
-
{
|
|
8974
|
-
"path": "precision",
|
|
8975
|
-
"valueType": "number"
|
|
8976
9073
|
}
|
|
8977
9074
|
],
|
|
8978
9075
|
"alarm-panel": [
|
|
@@ -9008,20 +9105,10 @@ Object.freeze({
|
|
|
9008
9105
|
"valueType": "boolean"
|
|
9009
9106
|
}
|
|
9010
9107
|
],
|
|
9011
|
-
"ambient-light-sensor": [
|
|
9012
|
-
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
},
|
|
9016
|
-
{
|
|
9017
|
-
"path": "unit",
|
|
9018
|
-
"valueType": "string"
|
|
9019
|
-
},
|
|
9020
|
-
{
|
|
9021
|
-
"path": "precision",
|
|
9022
|
-
"valueType": "number"
|
|
9023
|
-
}
|
|
9024
|
-
],
|
|
9108
|
+
"ambient-light-sensor": [{
|
|
9109
|
+
"path": "lux",
|
|
9110
|
+
"valueType": "number"
|
|
9111
|
+
}],
|
|
9025
9112
|
"audio-metrics": [
|
|
9026
9113
|
{
|
|
9027
9114
|
"path": "ts",
|
|
@@ -9101,6 +9188,10 @@ Object.freeze({
|
|
|
9101
9188
|
"path": "lastUpdated",
|
|
9102
9189
|
"valueType": "number"
|
|
9103
9190
|
},
|
|
9191
|
+
{
|
|
9192
|
+
"path": "volts",
|
|
9193
|
+
"valueType": "number"
|
|
9194
|
+
},
|
|
9104
9195
|
{
|
|
9105
9196
|
"path": "lastContactAt",
|
|
9106
9197
|
"valueType": "number"
|
|
@@ -9343,10 +9434,6 @@ Object.freeze({
|
|
|
9343
9434
|
"datetime"
|
|
9344
9435
|
]
|
|
9345
9436
|
},
|
|
9346
|
-
{
|
|
9347
|
-
"path": "unit",
|
|
9348
|
-
"valueType": "string"
|
|
9349
|
-
},
|
|
9350
9437
|
{
|
|
9351
9438
|
"path": "min",
|
|
9352
9439
|
"valueType": "number"
|
|
@@ -9358,19 +9445,6 @@ Object.freeze({
|
|
|
9358
9445
|
{
|
|
9359
9446
|
"path": "step",
|
|
9360
9447
|
"valueType": "number"
|
|
9361
|
-
},
|
|
9362
|
-
{
|
|
9363
|
-
"path": "precision",
|
|
9364
|
-
"valueType": "number"
|
|
9365
|
-
},
|
|
9366
|
-
{
|
|
9367
|
-
"path": "format",
|
|
9368
|
-
"valueType": "enum",
|
|
9369
|
-
"enumValues": [
|
|
9370
|
-
"date",
|
|
9371
|
-
"time",
|
|
9372
|
-
"datetime"
|
|
9373
|
-
]
|
|
9374
9448
|
}
|
|
9375
9449
|
],
|
|
9376
9450
|
"cover": [
|
|
@@ -9611,13 +9685,8 @@ Object.freeze({
|
|
|
9611
9685
|
"path": "value",
|
|
9612
9686
|
"valueType": "string"
|
|
9613
9687
|
}, {
|
|
9614
|
-
"path": "
|
|
9615
|
-
"valueType": "
|
|
9616
|
-
"enumValues": [
|
|
9617
|
-
"date",
|
|
9618
|
-
"time",
|
|
9619
|
-
"datetime"
|
|
9620
|
-
]
|
|
9688
|
+
"path": "timestamp",
|
|
9689
|
+
"valueType": "boolean"
|
|
9621
9690
|
}],
|
|
9622
9691
|
"event-emitter": [
|
|
9623
9692
|
{
|
|
@@ -9690,6 +9759,24 @@ Object.freeze({
|
|
|
9690
9759
|
"path": "detected",
|
|
9691
9760
|
"valueType": "boolean"
|
|
9692
9761
|
}],
|
|
9762
|
+
"group-active": [{
|
|
9763
|
+
"path": "active",
|
|
9764
|
+
"valueType": "boolean"
|
|
9765
|
+
}],
|
|
9766
|
+
"group-status": [
|
|
9767
|
+
{
|
|
9768
|
+
"path": "included",
|
|
9769
|
+
"valueType": "number"
|
|
9770
|
+
},
|
|
9771
|
+
{
|
|
9772
|
+
"path": "excluded",
|
|
9773
|
+
"valueType": "number"
|
|
9774
|
+
},
|
|
9775
|
+
{
|
|
9776
|
+
"path": "total",
|
|
9777
|
+
"valueType": "number"
|
|
9778
|
+
}
|
|
9779
|
+
],
|
|
9693
9780
|
"heating-valve": [{
|
|
9694
9781
|
"path": "position",
|
|
9695
9782
|
"valueType": "number"
|
|
@@ -9724,20 +9811,10 @@ Object.freeze({
|
|
|
9724
9811
|
"valueType": "number"
|
|
9725
9812
|
}
|
|
9726
9813
|
],
|
|
9727
|
-
"humidity-sensor": [
|
|
9728
|
-
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
},
|
|
9732
|
-
{
|
|
9733
|
-
"path": "unit",
|
|
9734
|
-
"valueType": "string"
|
|
9735
|
-
},
|
|
9736
|
-
{
|
|
9737
|
-
"path": "precision",
|
|
9738
|
-
"valueType": "number"
|
|
9739
|
-
}
|
|
9740
|
-
],
|
|
9814
|
+
"humidity-sensor": [{
|
|
9815
|
+
"path": "percent",
|
|
9816
|
+
"valueType": "number"
|
|
9817
|
+
}],
|
|
9741
9818
|
"image": [{
|
|
9742
9819
|
"path": "url",
|
|
9743
9820
|
"valueType": "string"
|
|
@@ -9945,6 +10022,10 @@ Object.freeze({
|
|
|
9945
10022
|
]
|
|
9946
10023
|
}
|
|
9947
10024
|
],
|
|
10025
|
+
"meter": [{
|
|
10026
|
+
"path": "value",
|
|
10027
|
+
"valueType": "number"
|
|
10028
|
+
}],
|
|
9948
10029
|
"motion": [
|
|
9949
10030
|
{
|
|
9950
10031
|
"path": "detected",
|
|
@@ -10076,20 +10157,10 @@ Object.freeze({
|
|
|
10076
10157
|
"valueType": "boolean"
|
|
10077
10158
|
}
|
|
10078
10159
|
],
|
|
10079
|
-
"numeric-sensor": [
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
},
|
|
10084
|
-
{
|
|
10085
|
-
"path": "unit",
|
|
10086
|
-
"valueType": "string"
|
|
10087
|
-
},
|
|
10088
|
-
{
|
|
10089
|
-
"path": "precision",
|
|
10090
|
-
"valueType": "number"
|
|
10091
|
-
}
|
|
10092
|
-
],
|
|
10160
|
+
"numeric-sensor": [{
|
|
10161
|
+
"path": "value",
|
|
10162
|
+
"valueType": "number"
|
|
10163
|
+
}],
|
|
10093
10164
|
"pet-feeder": [
|
|
10094
10165
|
{
|
|
10095
10166
|
"path": "foodLevel",
|
|
@@ -10181,14 +10252,6 @@ Object.freeze({
|
|
|
10181
10252
|
{
|
|
10182
10253
|
"path": "powerFactor",
|
|
10183
10254
|
"valueType": "number"
|
|
10184
|
-
},
|
|
10185
|
-
{
|
|
10186
|
-
"path": "unit",
|
|
10187
|
-
"valueType": "string"
|
|
10188
|
-
},
|
|
10189
|
-
{
|
|
10190
|
-
"path": "precision",
|
|
10191
|
-
"valueType": "number"
|
|
10192
10255
|
}
|
|
10193
10256
|
],
|
|
10194
10257
|
"presence": [
|
|
@@ -10217,20 +10280,10 @@ Object.freeze({
|
|
|
10217
10280
|
"valueType": "number"
|
|
10218
10281
|
}
|
|
10219
10282
|
],
|
|
10220
|
-
"pressure-sensor": [
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
},
|
|
10225
|
-
{
|
|
10226
|
-
"path": "unit",
|
|
10227
|
-
"valueType": "string"
|
|
10228
|
-
},
|
|
10229
|
-
{
|
|
10230
|
-
"path": "precision",
|
|
10231
|
-
"valueType": "number"
|
|
10232
|
-
}
|
|
10233
|
-
],
|
|
10283
|
+
"pressure-sensor": [{
|
|
10284
|
+
"path": "hpa",
|
|
10285
|
+
"valueType": "number"
|
|
10286
|
+
}],
|
|
10234
10287
|
"privacy-mask": [{
|
|
10235
10288
|
"path": "enabled",
|
|
10236
10289
|
"valueType": "boolean"
|
|
@@ -10541,20 +10594,10 @@ Object.freeze({
|
|
|
10541
10594
|
"path": "tampered",
|
|
10542
10595
|
"valueType": "boolean"
|
|
10543
10596
|
}],
|
|
10544
|
-
"temperature-sensor": [
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
},
|
|
10549
|
-
{
|
|
10550
|
-
"path": "unit",
|
|
10551
|
-
"valueType": "string"
|
|
10552
|
-
},
|
|
10553
|
-
{
|
|
10554
|
-
"path": "precision",
|
|
10555
|
-
"valueType": "number"
|
|
10556
|
-
}
|
|
10557
|
-
],
|
|
10597
|
+
"temperature-sensor": [{
|
|
10598
|
+
"path": "celsius",
|
|
10599
|
+
"valueType": "number"
|
|
10600
|
+
}],
|
|
10558
10601
|
"update": [
|
|
10559
10602
|
{
|
|
10560
10603
|
"path": "currentVersion",
|
|
@@ -10665,10 +10708,6 @@ Object.freeze({
|
|
|
10665
10708
|
"path": "temperature",
|
|
10666
10709
|
"valueType": "number"
|
|
10667
10710
|
},
|
|
10668
|
-
{
|
|
10669
|
-
"path": "temperatureUnit",
|
|
10670
|
-
"valueType": "string"
|
|
10671
|
-
},
|
|
10672
10711
|
{
|
|
10673
10712
|
"path": "humidity",
|
|
10674
10713
|
"valueType": "number"
|
|
@@ -10677,18 +10716,10 @@ Object.freeze({
|
|
|
10677
10716
|
"path": "pressure",
|
|
10678
10717
|
"valueType": "number"
|
|
10679
10718
|
},
|
|
10680
|
-
{
|
|
10681
|
-
"path": "pressureUnit",
|
|
10682
|
-
"valueType": "string"
|
|
10683
|
-
},
|
|
10684
10719
|
{
|
|
10685
10720
|
"path": "windSpeed",
|
|
10686
10721
|
"valueType": "number"
|
|
10687
10722
|
},
|
|
10688
|
-
{
|
|
10689
|
-
"path": "windSpeedUnit",
|
|
10690
|
-
"valueType": "string"
|
|
10691
|
-
},
|
|
10692
10723
|
{
|
|
10693
10724
|
"path": "windBearing",
|
|
10694
10725
|
"valueType": "number"
|
|
@@ -10738,7 +10769,7 @@ object({
|
|
|
10738
10769
|
params: record(string(), union([string(), number()])).optional()
|
|
10739
10770
|
});
|
|
10740
10771
|
//#endregion
|
|
10741
|
-
//#region ../types/dist/err-msg-
|
|
10772
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10742
10773
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10743
10774
|
DeviceType["Camera"] = "camera";
|
|
10744
10775
|
DeviceType["Hub"] = "hub";
|
|
@@ -10832,8 +10863,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10832
10863
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10833
10864
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10834
10865
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10835
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10866
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10867
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10836
10868
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10869
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10870
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10871
|
+
DeviceType["Washer"] = "washer";
|
|
10872
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10873
|
+
DeviceType["Dryer"] = "dryer";
|
|
10837
10874
|
return DeviceType;
|
|
10838
10875
|
}({});
|
|
10839
10876
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11091,7 +11128,7 @@ function errMsg(err) {
|
|
|
11091
11128
|
return String(err);
|
|
11092
11129
|
}
|
|
11093
11130
|
//#endregion
|
|
11094
|
-
//#region ../types/dist/composition-
|
|
11131
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11095
11132
|
/**
|
|
11096
11133
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11097
11134
|
*
|
|
@@ -11406,6 +11443,13 @@ var table = {
|
|
|
11406
11443
|
apply: () => {
|
|
11407
11444
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11408
11445
|
}
|
|
11446
|
+
},
|
|
11447
|
+
schmitt: {
|
|
11448
|
+
minArgs: 3,
|
|
11449
|
+
maxArgs: 5,
|
|
11450
|
+
apply: () => {
|
|
11451
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11452
|
+
}
|
|
11409
11453
|
}
|
|
11410
11454
|
};
|
|
11411
11455
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11846,15 +11890,232 @@ function validateExpressionSource(src) {
|
|
|
11846
11890
|
}
|
|
11847
11891
|
return null;
|
|
11848
11892
|
}
|
|
11849
|
-
/**
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11893
|
+
/**
|
|
11894
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11895
|
+
*
|
|
11896
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11897
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11898
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11899
|
+
*
|
|
11900
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11901
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11902
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11903
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11904
|
+
* can move later without moving the others.
|
|
11905
|
+
*/
|
|
11906
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11907
|
+
var APPLIANCE_KINDS = [
|
|
11908
|
+
"washer",
|
|
11909
|
+
"dryer",
|
|
11910
|
+
"dishwasher"
|
|
11911
|
+
];
|
|
11912
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11913
|
+
/**
|
|
11914
|
+
* Statistics and integrals over a history read (D944).
|
|
11915
|
+
*
|
|
11916
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11917
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11918
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11919
|
+
* as zero. A truncated read is not published.
|
|
11920
|
+
*/
|
|
11921
|
+
var STATISTIC_STATS = [
|
|
11922
|
+
"min",
|
|
11923
|
+
"max",
|
|
11924
|
+
"mean",
|
|
11925
|
+
"sum",
|
|
11926
|
+
"count",
|
|
11927
|
+
"change"
|
|
11928
|
+
];
|
|
11929
|
+
/**
|
|
11930
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11931
|
+
*
|
|
11932
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11933
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11934
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11935
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11936
|
+
*/
|
|
11937
|
+
var MINUTE_MS = 6e4;
|
|
11938
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11939
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11940
|
+
var ROLLING_SPANS = [
|
|
11941
|
+
"1h",
|
|
11942
|
+
"24h",
|
|
11943
|
+
"2d",
|
|
11944
|
+
"7d",
|
|
11945
|
+
"30d",
|
|
11946
|
+
"custom"
|
|
11947
|
+
];
|
|
11948
|
+
var CALENDAR_PERIODS = [
|
|
11949
|
+
"today",
|
|
11950
|
+
"yesterday",
|
|
11951
|
+
"this-week",
|
|
11952
|
+
"this-month"
|
|
11953
|
+
];
|
|
11954
|
+
var RESET_PERIODS = [
|
|
11955
|
+
"never",
|
|
11956
|
+
"daily",
|
|
11957
|
+
"weekly",
|
|
11958
|
+
"monthly"
|
|
11959
|
+
];
|
|
11960
|
+
5 * MINUTE_MS;
|
|
11961
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11962
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11963
|
+
var rollingWindowObject = object({
|
|
11964
|
+
kind: literal("rolling"),
|
|
11965
|
+
span: _enum(ROLLING_SPANS),
|
|
11966
|
+
customMinutes: number().int().min(5).optional()
|
|
11967
|
+
}).check((payload) => {
|
|
11968
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11969
|
+
code: "custom",
|
|
11970
|
+
message: "a custom range needs a duration in minutes",
|
|
11971
|
+
path: ["customMinutes"],
|
|
11972
|
+
input: payload.value
|
|
11973
|
+
});
|
|
11974
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11975
|
+
code: "custom",
|
|
11976
|
+
message: "only a custom range carries a duration",
|
|
11977
|
+
path: ["customMinutes"],
|
|
11978
|
+
input: payload.value
|
|
11979
|
+
});
|
|
11980
|
+
});
|
|
11981
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11982
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11983
|
+
kind: literal("calendar"),
|
|
11984
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11985
|
+
})]);
|
|
11986
|
+
/**
|
|
11987
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11988
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11989
|
+
* `composition.ts` (D659).
|
|
11990
|
+
*/
|
|
11853
11991
|
var CompositionSourceRefSchema = object({
|
|
11854
11992
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11855
11993
|
addonId: string().min(1),
|
|
11856
11994
|
stableId: string().min(1)
|
|
11857
11995
|
});
|
|
11996
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11997
|
+
"temperature",
|
|
11998
|
+
"humidity",
|
|
11999
|
+
"pressure",
|
|
12000
|
+
"illuminance",
|
|
12001
|
+
"power",
|
|
12002
|
+
"energy",
|
|
12003
|
+
"battery",
|
|
12004
|
+
"numeric",
|
|
12005
|
+
"motion",
|
|
12006
|
+
"contact",
|
|
12007
|
+
"leak",
|
|
12008
|
+
"smoke",
|
|
12009
|
+
"occupancy",
|
|
12010
|
+
"binary",
|
|
12011
|
+
"switch",
|
|
12012
|
+
"light",
|
|
12013
|
+
"fan",
|
|
12014
|
+
"cover",
|
|
12015
|
+
"valve",
|
|
12016
|
+
"lock",
|
|
12017
|
+
"media-player",
|
|
12018
|
+
"climate"
|
|
12019
|
+
];
|
|
12020
|
+
var NUMERIC_AGGREGATES = [
|
|
12021
|
+
"mean",
|
|
12022
|
+
"median",
|
|
12023
|
+
"min",
|
|
12024
|
+
"max",
|
|
12025
|
+
"sum"
|
|
12026
|
+
];
|
|
12027
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12028
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12029
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12030
|
+
var AGGREGATE_REDUCERS = [
|
|
12031
|
+
"mean",
|
|
12032
|
+
"median",
|
|
12033
|
+
"min",
|
|
12034
|
+
"max",
|
|
12035
|
+
"sum",
|
|
12036
|
+
"any",
|
|
12037
|
+
"all"
|
|
12038
|
+
];
|
|
12039
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12040
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12041
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12042
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12043
|
+
var HelperMemberSchema = object({
|
|
12044
|
+
source: CompositionSourceRefSchema,
|
|
12045
|
+
cap: string().min(1),
|
|
12046
|
+
fieldPath: string().min(1)
|
|
12047
|
+
});
|
|
12048
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12049
|
+
object({
|
|
12050
|
+
kind: literal("group"),
|
|
12051
|
+
templateId: GroupTemplateIdSchema,
|
|
12052
|
+
aggregate: AggregateReducerSchema,
|
|
12053
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12054
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12055
|
+
active: ActiveCriterionSchema.optional()
|
|
12056
|
+
}),
|
|
12057
|
+
object({
|
|
12058
|
+
kind: literal("appliance"),
|
|
12059
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12060
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12061
|
+
thresholdWatts: number().positive(),
|
|
12062
|
+
startDwellMs: number().int().nonnegative(),
|
|
12063
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12064
|
+
member: HelperMemberSchema
|
|
12065
|
+
}),
|
|
12066
|
+
object({
|
|
12067
|
+
kind: literal("statistic"),
|
|
12068
|
+
stat: _enum(STATISTIC_STATS),
|
|
12069
|
+
window: StatisticWindowSchema,
|
|
12070
|
+
source: HelperMemberSchema
|
|
12071
|
+
}),
|
|
12072
|
+
object({
|
|
12073
|
+
kind: literal("integral"),
|
|
12074
|
+
reset: _enum(RESET_PERIODS),
|
|
12075
|
+
output: _enum(["energy", "meter"]),
|
|
12076
|
+
source: HelperMemberSchema
|
|
12077
|
+
}),
|
|
12078
|
+
object({
|
|
12079
|
+
kind: literal("threshold"),
|
|
12080
|
+
source: HelperMemberSchema,
|
|
12081
|
+
high: number(),
|
|
12082
|
+
low: number(),
|
|
12083
|
+
onForMs: number().int().nonnegative(),
|
|
12084
|
+
offForMs: number().int().nonnegative()
|
|
12085
|
+
}),
|
|
12086
|
+
object({
|
|
12087
|
+
kind: literal("arithmetic"),
|
|
12088
|
+
op: _enum([
|
|
12089
|
+
"sum",
|
|
12090
|
+
"difference",
|
|
12091
|
+
"ratio"
|
|
12092
|
+
]),
|
|
12093
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12094
|
+
}),
|
|
12095
|
+
object({
|
|
12096
|
+
kind: literal("expression"),
|
|
12097
|
+
expr: string().min(1),
|
|
12098
|
+
inputs: array(object({
|
|
12099
|
+
name: string().min(1),
|
|
12100
|
+
member: HelperMemberSchema
|
|
12101
|
+
})).min(1).max(64),
|
|
12102
|
+
output: _enum(["number", "boolean"])
|
|
12103
|
+
}),
|
|
12104
|
+
object({
|
|
12105
|
+
kind: literal("derivative"),
|
|
12106
|
+
window: RollingWindowSchema,
|
|
12107
|
+
per: _enum([
|
|
12108
|
+
"second",
|
|
12109
|
+
"minute",
|
|
12110
|
+
"hour"
|
|
12111
|
+
]),
|
|
12112
|
+
source: HelperMemberSchema
|
|
12113
|
+
})
|
|
12114
|
+
]);
|
|
12115
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12116
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12117
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12118
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11858
12119
|
/** One field of one capability of one source device. */
|
|
11859
12120
|
var CompositionFieldReadSchema = object({
|
|
11860
12121
|
source: CompositionSourceRefSchema,
|
|
@@ -11898,7 +12159,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11898
12159
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11899
12160
|
CompositionFromSourceSchema,
|
|
11900
12161
|
CompositionExpressionSourceSchema,
|
|
11901
|
-
CompositionCodeSourceSchema
|
|
12162
|
+
CompositionCodeSourceSchema,
|
|
12163
|
+
object({
|
|
12164
|
+
kind: literal("aggregate"),
|
|
12165
|
+
reducer: _enum([
|
|
12166
|
+
"mean",
|
|
12167
|
+
"median",
|
|
12168
|
+
"min",
|
|
12169
|
+
"max",
|
|
12170
|
+
"sum",
|
|
12171
|
+
"any",
|
|
12172
|
+
"all"
|
|
12173
|
+
]),
|
|
12174
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12175
|
+
/**
|
|
12176
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12177
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12178
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12179
|
+
*/
|
|
12180
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12181
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12182
|
+
publish: _enum([
|
|
12183
|
+
"value",
|
|
12184
|
+
"included",
|
|
12185
|
+
"excluded",
|
|
12186
|
+
"total"
|
|
12187
|
+
]),
|
|
12188
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12189
|
+
empty: _enum([
|
|
12190
|
+
"null",
|
|
12191
|
+
"omit",
|
|
12192
|
+
"offline"
|
|
12193
|
+
])
|
|
12194
|
+
}),
|
|
12195
|
+
object({
|
|
12196
|
+
kind: literal("series"),
|
|
12197
|
+
read: CompositionFieldReadSchema,
|
|
12198
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12199
|
+
publish: _enum([
|
|
12200
|
+
"value",
|
|
12201
|
+
"included",
|
|
12202
|
+
"excluded",
|
|
12203
|
+
"total"
|
|
12204
|
+
]),
|
|
12205
|
+
/**
|
|
12206
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12207
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12208
|
+
*/
|
|
12209
|
+
empty: _enum([
|
|
12210
|
+
"null",
|
|
12211
|
+
"omit",
|
|
12212
|
+
"offline"
|
|
12213
|
+
])
|
|
12214
|
+
})
|
|
11902
12215
|
]);
|
|
11903
12216
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11904
12217
|
kind: literal("forward"),
|
|
@@ -11944,7 +12257,13 @@ var CompositionSchema = object({
|
|
|
11944
12257
|
kind: literal("existing"),
|
|
11945
12258
|
device: CompositionSourceRefSchema
|
|
11946
12259
|
})]),
|
|
11947
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12260
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12261
|
+
/**
|
|
12262
|
+
* Present when the block is a helper template. Absent on a free
|
|
12263
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12264
|
+
* never the compiled features.
|
|
12265
|
+
*/
|
|
12266
|
+
helper: HelperSpecSchema.optional()
|
|
11948
12267
|
}).superRefine((composition, ctx) => {
|
|
11949
12268
|
const seen = /* @__PURE__ */ new Set();
|
|
11950
12269
|
composition.features.forEach((feature, index) => {
|
|
@@ -17427,7 +17746,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17427
17746
|
*/
|
|
17428
17747
|
interactiveConnectPath: string().min(1).optional(),
|
|
17429
17748
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17430
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17749
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17750
|
+
/**
|
|
17751
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17752
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17753
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17754
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17755
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17756
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17757
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17758
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17759
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17760
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17761
|
+
* offers it as the default path; the fields the session fills are
|
|
17762
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17763
|
+
*/
|
|
17764
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17431
17765
|
}))
|
|
17432
17766
|
});
|
|
17433
17767
|
var ListInputSchema = object({
|
|
@@ -18422,7 +18756,12 @@ var CompositionProblemSchema = object({
|
|
|
18422
18756
|
"item-field-reserved",
|
|
18423
18757
|
"target-missing",
|
|
18424
18758
|
"target-unreadable",
|
|
18425
|
-
"not-replaceable"
|
|
18759
|
+
"not-replaceable",
|
|
18760
|
+
"native-capability-replace",
|
|
18761
|
+
"mixed-quantity",
|
|
18762
|
+
"helper-mismatch",
|
|
18763
|
+
"member-constraint",
|
|
18764
|
+
"retention"
|
|
18426
18765
|
]),
|
|
18427
18766
|
path: string(),
|
|
18428
18767
|
message: string()
|
|
@@ -18443,7 +18782,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18443
18782
|
"null",
|
|
18444
18783
|
"offline",
|
|
18445
18784
|
"unknown",
|
|
18446
|
-
"release"
|
|
18785
|
+
"release",
|
|
18786
|
+
"omit"
|
|
18447
18787
|
]);
|
|
18448
18788
|
/**
|
|
18449
18789
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18480,9 +18820,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18480
18820
|
reads: array(CompositionFieldReadSchema)
|
|
18481
18821
|
});
|
|
18482
18822
|
/**
|
|
18483
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18484
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18485
|
-
*
|
|
18823
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18824
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18825
|
+
* Replacing a capability the device already serves is refused
|
|
18826
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18827
|
+
* wire for a claim the hub already holds.
|
|
18486
18828
|
*/
|
|
18487
18829
|
var CompositionFeatureModeSchema = _enum([
|
|
18488
18830
|
"new",
|
|
@@ -18653,8 +18995,392 @@ Object.freeze({
|
|
|
18653
18995
|
latchedAt: {
|
|
18654
18996
|
kind: "fixed",
|
|
18655
18997
|
result: ["number", "null"]
|
|
18998
|
+
},
|
|
18999
|
+
schmitt: {
|
|
19000
|
+
kind: "fixed",
|
|
19001
|
+
result: ["boolean", "null"]
|
|
18656
19002
|
}
|
|
18657
19003
|
});
|
|
19004
|
+
/**
|
|
19005
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19006
|
+
* Data, not a form default written into the block.
|
|
19007
|
+
*/
|
|
19008
|
+
var NOW$2 = {
|
|
19009
|
+
fieldPath: "lastFetchedAt",
|
|
19010
|
+
expr: "now"
|
|
19011
|
+
};
|
|
19012
|
+
var CHANGED = {
|
|
19013
|
+
fieldPath: "lastChangedAt",
|
|
19014
|
+
expr: "now"
|
|
19015
|
+
};
|
|
19016
|
+
function numeric(input) {
|
|
19017
|
+
return {
|
|
19018
|
+
...input,
|
|
19019
|
+
family: "numeric",
|
|
19020
|
+
deviceType: DeviceType.Sensor,
|
|
19021
|
+
memberDeviceType: DeviceType.Sensor,
|
|
19022
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19023
|
+
activeWhen: void 0,
|
|
19024
|
+
commandCaps: [],
|
|
19025
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
19026
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
19027
|
+
accept: [{
|
|
19028
|
+
cap: input.outputCap,
|
|
19029
|
+
fieldPath: input.outputField
|
|
19030
|
+
}]
|
|
19031
|
+
};
|
|
19032
|
+
}
|
|
19033
|
+
function binary(input) {
|
|
19034
|
+
return {
|
|
19035
|
+
...input,
|
|
19036
|
+
family: "binary",
|
|
19037
|
+
deviceType: DeviceType.Sensor,
|
|
19038
|
+
memberDeviceType: DeviceType.Sensor,
|
|
19039
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19040
|
+
activeWhen: void 0,
|
|
19041
|
+
commandCaps: [],
|
|
19042
|
+
quantity: "none",
|
|
19043
|
+
baseUnit: void 0,
|
|
19044
|
+
aggregates: BINARY_AGGREGATES,
|
|
19045
|
+
empty: "offline"
|
|
19046
|
+
};
|
|
19047
|
+
}
|
|
19048
|
+
var GROUP_TEMPLATES = [
|
|
19049
|
+
numeric({
|
|
19050
|
+
id: "temperature",
|
|
19051
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
19052
|
+
role: DeviceRole.TemperatureSensor,
|
|
19053
|
+
outputCap: "temperature-sensor",
|
|
19054
|
+
outputField: "celsius",
|
|
19055
|
+
quantity: "temperature",
|
|
19056
|
+
defaultAggregate: "mean",
|
|
19057
|
+
empty: "null",
|
|
19058
|
+
companions: [NOW$2]
|
|
19059
|
+
}),
|
|
19060
|
+
numeric({
|
|
19061
|
+
id: "humidity",
|
|
19062
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19063
|
+
role: DeviceRole.HumiditySensor,
|
|
19064
|
+
outputCap: "humidity-sensor",
|
|
19065
|
+
outputField: "percent",
|
|
19066
|
+
quantity: "humidity",
|
|
19067
|
+
defaultAggregate: "mean",
|
|
19068
|
+
empty: "null",
|
|
19069
|
+
companions: [NOW$2]
|
|
19070
|
+
}),
|
|
19071
|
+
numeric({
|
|
19072
|
+
id: "pressure",
|
|
19073
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
19074
|
+
role: DeviceRole.PressureSensor,
|
|
19075
|
+
outputCap: "pressure-sensor",
|
|
19076
|
+
outputField: "hpa",
|
|
19077
|
+
quantity: "pressure",
|
|
19078
|
+
defaultAggregate: "mean",
|
|
19079
|
+
empty: "null",
|
|
19080
|
+
companions: [NOW$2]
|
|
19081
|
+
}),
|
|
19082
|
+
numeric({
|
|
19083
|
+
id: "illuminance",
|
|
19084
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
19085
|
+
role: DeviceRole.AmbientLightSensor,
|
|
19086
|
+
outputCap: "ambient-light-sensor",
|
|
19087
|
+
outputField: "lux",
|
|
19088
|
+
quantity: "illuminance",
|
|
19089
|
+
defaultAggregate: "mean",
|
|
19090
|
+
empty: "null",
|
|
19091
|
+
companions: [NOW$2]
|
|
19092
|
+
}),
|
|
19093
|
+
numeric({
|
|
19094
|
+
id: "power",
|
|
19095
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
19096
|
+
role: DeviceRole.PowerSensor,
|
|
19097
|
+
outputCap: "power-meter",
|
|
19098
|
+
outputField: "watts",
|
|
19099
|
+
quantity: "power",
|
|
19100
|
+
defaultAggregate: "sum",
|
|
19101
|
+
empty: "omit",
|
|
19102
|
+
companions: [NOW$2]
|
|
19103
|
+
}),
|
|
19104
|
+
numeric({
|
|
19105
|
+
id: "energy",
|
|
19106
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
19107
|
+
role: DeviceRole.EnergySensor,
|
|
19108
|
+
outputCap: "power-meter",
|
|
19109
|
+
outputField: "kwhTotal",
|
|
19110
|
+
quantity: "energy",
|
|
19111
|
+
defaultAggregate: "sum",
|
|
19112
|
+
empty: "omit",
|
|
19113
|
+
companions: [NOW$2]
|
|
19114
|
+
}),
|
|
19115
|
+
numeric({
|
|
19116
|
+
id: "battery",
|
|
19117
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19118
|
+
role: DeviceRole.BatterySensor,
|
|
19119
|
+
outputCap: "battery",
|
|
19120
|
+
outputField: "percentage",
|
|
19121
|
+
quantity: "percentage",
|
|
19122
|
+
defaultAggregate: "mean",
|
|
19123
|
+
empty: "null",
|
|
19124
|
+
companions: [
|
|
19125
|
+
{
|
|
19126
|
+
fieldPath: "charging",
|
|
19127
|
+
expr: "\"unknown\""
|
|
19128
|
+
},
|
|
19129
|
+
{
|
|
19130
|
+
fieldPath: "sleeping",
|
|
19131
|
+
expr: "false"
|
|
19132
|
+
},
|
|
19133
|
+
{
|
|
19134
|
+
fieldPath: "lastUpdated",
|
|
19135
|
+
expr: "now"
|
|
19136
|
+
}
|
|
19137
|
+
]
|
|
19138
|
+
}),
|
|
19139
|
+
numeric({
|
|
19140
|
+
id: "numeric",
|
|
19141
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
19142
|
+
role: DeviceRole.NumericSensor,
|
|
19143
|
+
outputCap: "numeric-sensor",
|
|
19144
|
+
outputField: "value",
|
|
19145
|
+
quantity: "device",
|
|
19146
|
+
defaultAggregate: "mean",
|
|
19147
|
+
empty: "null",
|
|
19148
|
+
companions: [NOW$2]
|
|
19149
|
+
}),
|
|
19150
|
+
binary({
|
|
19151
|
+
id: "motion",
|
|
19152
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
19153
|
+
role: DeviceRole.MotionSensor,
|
|
19154
|
+
outputCap: "motion",
|
|
19155
|
+
outputField: "detected",
|
|
19156
|
+
defaultAggregate: "any",
|
|
19157
|
+
accept: [{
|
|
19158
|
+
cap: "motion",
|
|
19159
|
+
fieldPath: "detected"
|
|
19160
|
+
}],
|
|
19161
|
+
companions: [{
|
|
19162
|
+
fieldPath: "lastDetectedAt",
|
|
19163
|
+
expr: "null"
|
|
19164
|
+
}, {
|
|
19165
|
+
fieldPath: "autoClearAfterMs",
|
|
19166
|
+
expr: "null"
|
|
19167
|
+
}]
|
|
19168
|
+
}),
|
|
19169
|
+
binary({
|
|
19170
|
+
id: "contact",
|
|
19171
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
19172
|
+
role: DeviceRole.ContactSensor,
|
|
19173
|
+
outputCap: "contact",
|
|
19174
|
+
outputField: "entryOpen",
|
|
19175
|
+
defaultAggregate: "any",
|
|
19176
|
+
accept: [{
|
|
19177
|
+
cap: "contact",
|
|
19178
|
+
fieldPath: "entryOpen"
|
|
19179
|
+
}],
|
|
19180
|
+
companions: [CHANGED]
|
|
19181
|
+
}),
|
|
19182
|
+
binary({
|
|
19183
|
+
id: "leak",
|
|
19184
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
19185
|
+
role: DeviceRole.LeakSensor,
|
|
19186
|
+
outputCap: "flood",
|
|
19187
|
+
outputField: "flooded",
|
|
19188
|
+
defaultAggregate: "any",
|
|
19189
|
+
accept: [{
|
|
19190
|
+
cap: "flood",
|
|
19191
|
+
fieldPath: "flooded"
|
|
19192
|
+
}],
|
|
19193
|
+
companions: [CHANGED]
|
|
19194
|
+
}),
|
|
19195
|
+
binary({
|
|
19196
|
+
id: "smoke",
|
|
19197
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
19198
|
+
role: DeviceRole.SmokeSensor,
|
|
19199
|
+
outputCap: "smoke",
|
|
19200
|
+
outputField: "detected",
|
|
19201
|
+
defaultAggregate: "any",
|
|
19202
|
+
accept: [{
|
|
19203
|
+
cap: "smoke",
|
|
19204
|
+
fieldPath: "detected"
|
|
19205
|
+
}],
|
|
19206
|
+
companions: [CHANGED]
|
|
19207
|
+
}),
|
|
19208
|
+
binary({
|
|
19209
|
+
id: "occupancy",
|
|
19210
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
19211
|
+
role: DeviceRole.BinarySensor,
|
|
19212
|
+
outputCap: "binary",
|
|
19213
|
+
outputField: "on",
|
|
19214
|
+
defaultAggregate: "any",
|
|
19215
|
+
accept: [{
|
|
19216
|
+
cap: "motion",
|
|
19217
|
+
fieldPath: "detected"
|
|
19218
|
+
}, {
|
|
19219
|
+
cap: "binary",
|
|
19220
|
+
fieldPath: "on"
|
|
19221
|
+
}],
|
|
19222
|
+
companions: [CHANGED]
|
|
19223
|
+
}),
|
|
19224
|
+
binary({
|
|
19225
|
+
id: "binary",
|
|
19226
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
19227
|
+
role: DeviceRole.BinarySensor,
|
|
19228
|
+
outputCap: "binary",
|
|
19229
|
+
outputField: "on",
|
|
19230
|
+
defaultAggregate: "any",
|
|
19231
|
+
accept: [{
|
|
19232
|
+
cap: "binary",
|
|
19233
|
+
fieldPath: "on"
|
|
19234
|
+
}],
|
|
19235
|
+
companions: [CHANGED]
|
|
19236
|
+
}),
|
|
19237
|
+
actuator({
|
|
19238
|
+
id: "switch",
|
|
19239
|
+
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.",
|
|
19240
|
+
deviceType: DeviceType.Switch,
|
|
19241
|
+
outputCap: "switch",
|
|
19242
|
+
outputField: "on",
|
|
19243
|
+
member: {
|
|
19244
|
+
cap: "switch",
|
|
19245
|
+
fieldPath: "on"
|
|
19246
|
+
},
|
|
19247
|
+
commandCaps: ["switch"]
|
|
19248
|
+
}),
|
|
19249
|
+
actuator({
|
|
19250
|
+
id: "light",
|
|
19251
|
+
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.",
|
|
19252
|
+
deviceType: DeviceType.Light,
|
|
19253
|
+
outputCap: "switch",
|
|
19254
|
+
outputField: "on",
|
|
19255
|
+
member: {
|
|
19256
|
+
cap: "switch",
|
|
19257
|
+
fieldPath: "on"
|
|
19258
|
+
},
|
|
19259
|
+
commandCaps: [
|
|
19260
|
+
"switch",
|
|
19261
|
+
"brightness",
|
|
19262
|
+
"color"
|
|
19263
|
+
]
|
|
19264
|
+
}),
|
|
19265
|
+
actuator({
|
|
19266
|
+
id: "fan",
|
|
19267
|
+
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.",
|
|
19268
|
+
deviceType: DeviceType.Fan,
|
|
19269
|
+
outputCap: "switch",
|
|
19270
|
+
outputField: "on",
|
|
19271
|
+
member: {
|
|
19272
|
+
cap: "switch",
|
|
19273
|
+
fieldPath: "on"
|
|
19274
|
+
},
|
|
19275
|
+
commandCaps: ["switch", "fan-control"]
|
|
19276
|
+
}),
|
|
19277
|
+
actuator({
|
|
19278
|
+
id: "cover",
|
|
19279
|
+
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.",
|
|
19280
|
+
deviceType: DeviceType.Cover,
|
|
19281
|
+
outputCap: "group-active",
|
|
19282
|
+
outputField: "active",
|
|
19283
|
+
member: {
|
|
19284
|
+
cap: "cover",
|
|
19285
|
+
fieldPath: "state"
|
|
19286
|
+
},
|
|
19287
|
+
activeWhen: [
|
|
19288
|
+
"open",
|
|
19289
|
+
"opening",
|
|
19290
|
+
"stopped"
|
|
19291
|
+
],
|
|
19292
|
+
commandCaps: ["cover"]
|
|
19293
|
+
}),
|
|
19294
|
+
actuator({
|
|
19295
|
+
id: "valve",
|
|
19296
|
+
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.",
|
|
19297
|
+
deviceType: DeviceType.Valve,
|
|
19298
|
+
outputCap: "group-active",
|
|
19299
|
+
outputField: "active",
|
|
19300
|
+
member: {
|
|
19301
|
+
cap: "valve",
|
|
19302
|
+
fieldPath: "state"
|
|
19303
|
+
},
|
|
19304
|
+
activeWhen: [
|
|
19305
|
+
"open",
|
|
19306
|
+
"opening",
|
|
19307
|
+
"stopped"
|
|
19308
|
+
],
|
|
19309
|
+
commandCaps: ["valve"]
|
|
19310
|
+
}),
|
|
19311
|
+
actuator({
|
|
19312
|
+
id: "lock",
|
|
19313
|
+
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.",
|
|
19314
|
+
deviceType: DeviceType.Lock,
|
|
19315
|
+
outputCap: "group-active",
|
|
19316
|
+
outputField: "active",
|
|
19317
|
+
member: {
|
|
19318
|
+
cap: "lock-control",
|
|
19319
|
+
fieldPath: "state"
|
|
19320
|
+
},
|
|
19321
|
+
activeWhen: ["locked"],
|
|
19322
|
+
commandCaps: ["lock-control"]
|
|
19323
|
+
}),
|
|
19324
|
+
actuator({
|
|
19325
|
+
id: "media-player",
|
|
19326
|
+
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.",
|
|
19327
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19328
|
+
outputCap: "group-active",
|
|
19329
|
+
outputField: "active",
|
|
19330
|
+
member: {
|
|
19331
|
+
cap: "media-player",
|
|
19332
|
+
fieldPath: "state"
|
|
19333
|
+
},
|
|
19334
|
+
activeWhen: ["playing", "buffering"],
|
|
19335
|
+
commandCaps: ["media-player"]
|
|
19336
|
+
}),
|
|
19337
|
+
actuator({
|
|
19338
|
+
id: "climate",
|
|
19339
|
+
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.",
|
|
19340
|
+
deviceType: DeviceType.Thermostat,
|
|
19341
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19342
|
+
outputCap: "group-active",
|
|
19343
|
+
outputField: "active",
|
|
19344
|
+
member: {
|
|
19345
|
+
cap: "climate-control",
|
|
19346
|
+
fieldPath: "mode"
|
|
19347
|
+
},
|
|
19348
|
+
activeWhen: [
|
|
19349
|
+
"heat",
|
|
19350
|
+
"cool",
|
|
19351
|
+
"auto",
|
|
19352
|
+
"heat_cool",
|
|
19353
|
+
"fan_only",
|
|
19354
|
+
"dry"
|
|
19355
|
+
],
|
|
19356
|
+
commandCaps: ["climate-control"]
|
|
19357
|
+
})
|
|
19358
|
+
];
|
|
19359
|
+
function actuator(input) {
|
|
19360
|
+
return {
|
|
19361
|
+
id: input.id,
|
|
19362
|
+
summary: input.summary,
|
|
19363
|
+
deviceType: input.deviceType,
|
|
19364
|
+
outputCap: input.outputCap,
|
|
19365
|
+
outputField: input.outputField,
|
|
19366
|
+
commandCaps: input.commandCaps,
|
|
19367
|
+
family: "actuator",
|
|
19368
|
+
role: void 0,
|
|
19369
|
+
memberDeviceType: input.deviceType,
|
|
19370
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19371
|
+
activeWhen: input.activeWhen,
|
|
19372
|
+
quantity: "none",
|
|
19373
|
+
baseUnit: void 0,
|
|
19374
|
+
aggregates: BINARY_AGGREGATES,
|
|
19375
|
+
defaultAggregate: "any",
|
|
19376
|
+
empty: "offline",
|
|
19377
|
+
accept: [input.member],
|
|
19378
|
+
companions: [CHANGED]
|
|
19379
|
+
};
|
|
19380
|
+
}
|
|
19381
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19382
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19383
|
+
DeviceType.Camera;
|
|
18658
19384
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18659
19385
|
/**
|
|
18660
19386
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20368,12 +21094,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
20368
21094
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20369
21095
|
* in-place so dispatch keeps working.
|
|
20370
21096
|
*
|
|
20371
|
-
* **
|
|
20372
|
-
*
|
|
20373
|
-
*
|
|
20374
|
-
*
|
|
20375
|
-
* (`ha-domain-mapping`)
|
|
20376
|
-
* stored after that point.
|
|
21097
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
21098
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
21099
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
21100
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
21101
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
21102
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20377
21103
|
*
|
|
20378
21104
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20379
21105
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20387,6 +21113,14 @@ var SourceInfoSchema = object({
|
|
|
20387
21113
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20388
21114
|
* Used to detect rename when `id` changes. */
|
|
20389
21115
|
uniqueId: string().optional(),
|
|
21116
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
21117
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
21118
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
21119
|
+
dateTimeShape: _enum([
|
|
21120
|
+
"date",
|
|
21121
|
+
"time",
|
|
21122
|
+
"datetime"
|
|
21123
|
+
]).optional(),
|
|
20390
21124
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20391
21125
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20392
21126
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41317,7 +42051,8 @@ method(object({
|
|
|
41317
42051
|
"enum"
|
|
41318
42052
|
]),
|
|
41319
42053
|
enumValues: array(string()).optional(),
|
|
41320
|
-
item: boolean().optional()
|
|
42054
|
+
item: boolean().optional(),
|
|
42055
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41321
42056
|
})).readonly(),
|
|
41322
42057
|
itemArray: object({
|
|
41323
42058
|
path: string(),
|
|
@@ -43686,7 +44421,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43686
44421
|
});
|
|
43687
44422
|
/**
|
|
43688
44423
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43689
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44424
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43690
44425
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43691
44426
|
* the originating provider config (mode + sourcePort) so the
|
|
43692
44427
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -45125,8 +45860,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
45125
45860
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
45126
45861
|
var MaskGridShapeSchema = object({
|
|
45127
45862
|
kind: literal("grid"),
|
|
45128
|
-
gridWidth: number(),
|
|
45129
|
-
gridHeight: number(),
|
|
45863
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45864
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
45130
45865
|
cells: array(boolean())
|
|
45131
45866
|
});
|
|
45132
45867
|
discriminatedUnion("kind", [
|
|
@@ -45238,6 +45973,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45238
45973
|
"detection-blind",
|
|
45239
45974
|
"motion-noisy",
|
|
45240
45975
|
"motion-calm",
|
|
45976
|
+
"package-llm-silent",
|
|
45977
|
+
"package-llm-answered",
|
|
45241
45978
|
"recording-stalled",
|
|
45242
45979
|
"recording-healthy",
|
|
45243
45980
|
"recording-degraded",
|
|
@@ -46327,7 +47064,20 @@ var NcRuleInputSchema = object({
|
|
|
46327
47064
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46328
47065
|
* path does not run Zod defaults.
|
|
46329
47066
|
*/
|
|
46330
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
47067
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
47068
|
+
/**
|
|
47069
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
47070
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
47071
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
47072
|
+
* same mark the Library writes, and records whose notification it was and
|
|
47073
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
47074
|
+
*
|
|
47075
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
47076
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
47077
|
+
* authored before this field meant. An editor turns it off by writing
|
|
47078
|
+
* `false`, so it needs no `clear` key.
|
|
47079
|
+
*/
|
|
47080
|
+
askVerdict: boolean().optional()
|
|
46331
47081
|
});
|
|
46332
47082
|
/**
|
|
46333
47083
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56303,6 +57053,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56303
57053
|
deprecated: string().optional(),
|
|
56304
57054
|
distTags: array(string()).readonly()
|
|
56305
57055
|
});
|
|
57056
|
+
/**
|
|
57057
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
57058
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
57059
|
+
* tarball failure — never an empty string standing in for either.
|
|
57060
|
+
*/
|
|
57061
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
57062
|
+
object({
|
|
57063
|
+
status: literal("ok"),
|
|
57064
|
+
markdown: string()
|
|
57065
|
+
}),
|
|
57066
|
+
object({ status: literal("missing") }),
|
|
57067
|
+
object({
|
|
57068
|
+
status: literal("error"),
|
|
57069
|
+
message: string()
|
|
57070
|
+
})
|
|
57071
|
+
]);
|
|
57072
|
+
var PackageDocsSchema = object({
|
|
57073
|
+
name: string(),
|
|
57074
|
+
version: string(),
|
|
57075
|
+
readme: PackageDocBodySchema,
|
|
57076
|
+
changelog: PackageDocBodySchema
|
|
57077
|
+
});
|
|
56306
57078
|
var SearchResultSchema = object({
|
|
56307
57079
|
name: string(),
|
|
56308
57080
|
version: string(),
|
|
@@ -56521,7 +57293,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56521
57293
|
}), object({ success: literal(true) }), {
|
|
56522
57294
|
kind: "mutation",
|
|
56523
57295
|
auth: "admin"
|
|
56524
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57296
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57297
|
+
name: string().min(1),
|
|
57298
|
+
version: string().min(1).optional()
|
|
57299
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56525
57300
|
kind: "mutation",
|
|
56526
57301
|
auth: "admin"
|
|
56527
57302
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56571,46 +57346,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56571
57346
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56572
57347
|
object({
|
|
56573
57348
|
/** Carbon dioxide concentration in ppm. */
|
|
56574
|
-
co2Ppm: number().min(0).optional(),
|
|
57349
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56575
57350
|
/** Total volatile organic compounds in ppb. */
|
|
56576
|
-
vocPpb: number().min(0).optional(),
|
|
57351
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56577
57352
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56578
|
-
pm25: number().min(0).optional(),
|
|
57353
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56579
57354
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56580
|
-
pm10: number().min(0).optional(),
|
|
57355
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56581
57356
|
/** Composite AQI value (typically 0..500). */
|
|
56582
|
-
aqi: number().optional(),
|
|
57357
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56583
57358
|
/** Ms epoch when the slice was last updated. */
|
|
56584
|
-
lastFetchedAt: number()
|
|
56585
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56586
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56587
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56588
|
-
* per slice is unambiguous. */
|
|
56589
|
-
unit: string().optional(),
|
|
56590
|
-
/** Suggested decimal places for numeric display.
|
|
56591
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56592
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56593
|
-
* auto-formatting when absent. */
|
|
56594
|
-
precision: number().int().min(0).max(10).optional()
|
|
57359
|
+
lastFetchedAt: number()
|
|
56595
57360
|
});
|
|
56596
57361
|
DeviceType.Sensor;
|
|
56597
57362
|
object({
|
|
56598
|
-
/** Current illuminance in lux (lx). */
|
|
56599
|
-
lux: number().min(0).meta({
|
|
56600
|
-
|
|
57363
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57364
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57365
|
+
precision: 0,
|
|
56601
57366
|
label: "Illuminance"
|
|
56602
|
-
}),
|
|
57367
|
+
})),
|
|
56603
57368
|
/** Ms epoch when the slice was last updated. */
|
|
56604
|
-
lastFetchedAt: number()
|
|
56605
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56606
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56607
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56608
|
-
unit: string().optional(),
|
|
56609
|
-
/** Suggested decimal places for numeric display.
|
|
56610
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56611
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56612
|
-
* auto-formatting when absent. */
|
|
56613
|
-
precision: number().int().min(0).max(10).optional()
|
|
57369
|
+
lastFetchedAt: number()
|
|
56614
57370
|
});
|
|
56615
57371
|
DeviceType.Sensor;
|
|
56616
57372
|
/**
|
|
@@ -56755,10 +57511,7 @@ var BatteryStatusSchema = object({
|
|
|
56755
57511
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56756
57512
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56757
57513
|
*/
|
|
56758
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56759
|
-
unit: "%",
|
|
56760
|
-
label: "Charge"
|
|
56761
|
-
}),
|
|
57514
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56762
57515
|
/**
|
|
56763
57516
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56764
57517
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56785,7 +57538,14 @@ var BatteryStatusSchema = object({
|
|
|
56785
57538
|
*/
|
|
56786
57539
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56787
57540
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56788
|
-
lastUpdated: number(),
|
|
57541
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57542
|
+
/**
|
|
57543
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57544
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57545
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57546
|
+
* `numeric-sensor` on the same device.
|
|
57547
|
+
*/
|
|
57548
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56789
57549
|
/**
|
|
56790
57550
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56791
57551
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56825,7 +57585,7 @@ var BatteryStatusSchema = object({
|
|
|
56825
57585
|
*/
|
|
56826
57586
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56827
57587
|
});
|
|
56828
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57588
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56829
57589
|
method(object({
|
|
56830
57590
|
deviceId: number(),
|
|
56831
57591
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56845,7 +57605,7 @@ object({
|
|
|
56845
57605
|
DeviceType.Sensor;
|
|
56846
57606
|
object({
|
|
56847
57607
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56848
|
-
percentage: number().min(0).max(100),
|
|
57608
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56849
57609
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56850
57610
|
lastChangedAt: number()
|
|
56851
57611
|
});
|
|
@@ -57230,21 +57990,21 @@ object({
|
|
|
57230
57990
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57231
57991
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57232
57992
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57233
|
-
target: number().nullable(),
|
|
57993
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57234
57994
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57235
57995
|
* in `heat_cool` mode. */
|
|
57236
|
-
targetHigh: number().nullable(),
|
|
57996
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57237
57997
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57238
57998
|
* in `heat_cool` mode. */
|
|
57239
|
-
targetLow: number().nullable(),
|
|
57999
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57240
58000
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57241
58001
|
* humidity control. */
|
|
57242
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58002
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57243
58003
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57244
58004
|
* the device's internal sensor. */
|
|
57245
|
-
currentTemp: number().nullable(),
|
|
58005
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57246
58006
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57247
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58007
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57248
58008
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57249
58009
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57250
58010
|
swingVertical: boolean().nullable(),
|
|
@@ -57252,11 +58012,11 @@ object({
|
|
|
57252
58012
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57253
58013
|
swingHorizontal: boolean().nullable(),
|
|
57254
58014
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57255
|
-
minTemp: number().nullable().optional(),
|
|
58015
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57256
58016
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57257
|
-
maxTemp: number().nullable().optional(),
|
|
58017
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57258
58018
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57259
|
-
tempStep: number().positive().nullable().optional(),
|
|
58019
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57260
58020
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57261
58021
|
lastFetchedAt: number()
|
|
57262
58022
|
});
|
|
@@ -57335,17 +58095,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
57335
58095
|
* modes to expose in the picker without a slice fetch.
|
|
57336
58096
|
*/
|
|
57337
58097
|
var RgbTripletSchema = object({
|
|
57338
|
-
r: number().int().min(0).max(255),
|
|
57339
|
-
g: number().int().min(0).max(255),
|
|
57340
|
-
b: number().int().min(0).max(255)
|
|
58098
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58099
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58100
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57341
58101
|
});
|
|
57342
58102
|
var HsvTripletSchema = object({
|
|
57343
58103
|
/** Hue in degrees, 0..360. */
|
|
57344
|
-
h: number().min(0).max(360),
|
|
58104
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57345
58105
|
/** Saturation as 0..100 inclusive. */
|
|
57346
|
-
s: number().min(0).max(100),
|
|
58106
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57347
58107
|
/** Value/brightness as 0..100 inclusive. */
|
|
57348
|
-
v: number().min(0).max(100)
|
|
58108
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57349
58109
|
});
|
|
57350
58110
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57351
58111
|
object({
|
|
@@ -57374,7 +58134,7 @@ object({
|
|
|
57374
58134
|
/** Populated when `mode === 'hsv'`. */
|
|
57375
58135
|
hsv: HsvTripletSchema.optional(),
|
|
57376
58136
|
/** Populated when `mode === 'mired'`. */
|
|
57377
|
-
mireds: number().int().optional(),
|
|
58137
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57378
58138
|
/** Ms epoch of the last operator-driven change. */
|
|
57379
58139
|
lastChangedAt: number()
|
|
57380
58140
|
});
|
|
@@ -57498,18 +58258,12 @@ _enum([
|
|
|
57498
58258
|
"empty",
|
|
57499
58259
|
"full"
|
|
57500
58260
|
]);
|
|
57501
|
-
/**
|
|
57502
|
-
|
|
57503
|
-
|
|
57504
|
-
"days",
|
|
57505
|
-
"hours",
|
|
57506
|
-
"cycles"
|
|
57507
|
-
]);
|
|
57508
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57509
|
-
* days). `value` null = unknown (D393). */
|
|
58261
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58262
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58263
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57510
58264
|
var ConsumableRemainingSchema = object({
|
|
57511
|
-
value: number().min(0).nullable(),
|
|
57512
|
-
|
|
58265
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58266
|
+
kind: ConsumableRemainingKindSchema
|
|
57513
58267
|
});
|
|
57514
58268
|
var ConsumablesStatusSchema = object({
|
|
57515
58269
|
items: array(object({
|
|
@@ -57518,7 +58272,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57518
58272
|
/** Display name. */
|
|
57519
58273
|
label: string().min(1),
|
|
57520
58274
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57521
|
-
level: number().min(0).max(100).nullable(),
|
|
58275
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57522
58276
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57523
58277
|
status: ConsumableStatusSchema.nullable(),
|
|
57524
58278
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57535,7 +58289,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57535
58289
|
})),
|
|
57536
58290
|
lastChangedAt: number()
|
|
57537
58291
|
});
|
|
57538
|
-
Object.values(DeviceType), [...
|
|
58292
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57539
58293
|
Object.values(DeviceType), method(object({
|
|
57540
58294
|
deviceId: number().int().nonnegative(),
|
|
57541
58295
|
key: string().min(1)
|
|
@@ -57560,39 +58314,17 @@ object({
|
|
|
57560
58314
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57561
58315
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57562
58316
|
* or time-only — HA accepts all three forms). */
|
|
57563
|
-
value: union([number(), string()]),
|
|
58317
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57564
58318
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57565
58319
|
options: array(string()),
|
|
57566
58320
|
/** Ms epoch when the slice was last updated. */
|
|
57567
58321
|
lastChangedAt: number(),
|
|
57568
|
-
/**
|
|
57569
|
-
|
|
57570
|
-
|
|
57571
|
-
|
|
57572
|
-
/**
|
|
57573
|
-
|
|
57574
|
-
min: number().optional(),
|
|
57575
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57576
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57577
|
-
max: number().optional(),
|
|
57578
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57579
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57580
|
-
step: number().optional(),
|
|
57581
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57582
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57583
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57584
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57585
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57586
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57587
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57588
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57589
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57590
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57591
|
-
format: _enum([
|
|
57592
|
-
"date",
|
|
57593
|
-
"time",
|
|
57594
|
-
"datetime"
|
|
57595
|
-
]).optional()
|
|
58322
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58323
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58324
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58325
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58326
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58327
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57596
58328
|
});
|
|
57597
58329
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57598
58330
|
object({
|
|
@@ -57630,9 +58362,9 @@ object({
|
|
|
57630
58362
|
]),
|
|
57631
58363
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57632
58364
|
* no intermediate position surface. */
|
|
57633
|
-
position: number().min(0).max(100).nullable(),
|
|
58365
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57634
58366
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57635
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58367
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57636
58368
|
/** Ms epoch when the slice was last updated. */
|
|
57637
58369
|
lastChangedAt: number()
|
|
57638
58370
|
});
|
|
@@ -57690,9 +58422,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57690
58422
|
object({
|
|
57691
58423
|
mode: DayNightModeSchema,
|
|
57692
58424
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57693
|
-
sensitivity: number().optional(),
|
|
58425
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57694
58426
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57695
|
-
switchDelaySec: number().optional(),
|
|
58427
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57696
58428
|
lastFetchedAt: number()
|
|
57697
58429
|
});
|
|
57698
58430
|
/**
|
|
@@ -57847,11 +58579,11 @@ object({
|
|
|
57847
58579
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57848
58580
|
availablePrograms: array(string()),
|
|
57849
58581
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57850
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58582
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57851
58583
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57852
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58584
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57853
58585
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57854
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58586
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57855
58587
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57856
58588
|
doorOpen: boolean().nullable(),
|
|
57857
58589
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57875,7 +58607,7 @@ object({
|
|
|
57875
58607
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57876
58608
|
machineCareDue: boolean().nullable(),
|
|
57877
58609
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57878
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58610
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57879
58611
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57880
58612
|
halfLoad: boolean().nullable(),
|
|
57881
58613
|
hygienePlus: boolean().nullable(),
|
|
@@ -57890,7 +58622,7 @@ object({
|
|
|
57890
58622
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57891
58623
|
activeEvents: array(string()),
|
|
57892
58624
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57893
|
-
errorCode: number().nullable(),
|
|
58625
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57894
58626
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57895
58627
|
errorLabel: string().nullable(),
|
|
57896
58628
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58036,24 +58768,14 @@ object({
|
|
|
58036
58768
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58037
58769
|
lastPressedAt: number().nullable(),
|
|
58038
58770
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58039
|
-
pressCountSinceStart: number()
|
|
58771
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58040
58772
|
});
|
|
58041
58773
|
object({
|
|
58042
58774
|
deviceId: number(),
|
|
58043
58775
|
timestamp: number()
|
|
58044
58776
|
});
|
|
58045
58777
|
DeviceType.Button, DeviceType.Camera;
|
|
58046
|
-
|
|
58047
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
58048
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
58049
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
58050
|
-
* The option set is stable across observations; it is persisted in the
|
|
58051
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
58052
|
-
* stored in `sourceInfo`.
|
|
58053
|
-
*/
|
|
58054
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
58055
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
58056
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58778
|
+
_enum([
|
|
58057
58779
|
"date",
|
|
58058
58780
|
"time",
|
|
58059
58781
|
"datetime"
|
|
@@ -58061,12 +58783,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
58061
58783
|
object({
|
|
58062
58784
|
value: string(),
|
|
58063
58785
|
/**
|
|
58064
|
-
* Set
|
|
58065
|
-
* as
|
|
58066
|
-
*
|
|
58067
|
-
* a time-only sensor → `'time'`.
|
|
58786
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58787
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58788
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
58068
58789
|
*/
|
|
58069
|
-
|
|
58790
|
+
timestamp: boolean().optional(),
|
|
58070
58791
|
/** Ms epoch when the slice was last updated. */
|
|
58071
58792
|
lastFetchedAt: number()
|
|
58072
58793
|
});
|
|
@@ -58085,13 +58806,13 @@ var EventFireSchema = object({
|
|
|
58085
58806
|
deviceId: number(),
|
|
58086
58807
|
eventType: string(),
|
|
58087
58808
|
data: record(string(), unknown()).nullable(),
|
|
58088
|
-
timestamp: number(),
|
|
58089
|
-
seq: number()
|
|
58809
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58810
|
+
seq: number().meta(readingMeta("count"))
|
|
58090
58811
|
});
|
|
58091
58812
|
object({
|
|
58092
58813
|
eventTypes: array(string()),
|
|
58093
58814
|
lastEvent: EventFireSchema.nullable(),
|
|
58094
|
-
eventCountSinceStart: number()
|
|
58815
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
58095
58816
|
});
|
|
58096
58817
|
DeviceType.EventEmitter;
|
|
58097
58818
|
var IdentitySchema = object({
|
|
@@ -58480,10 +59201,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58480
59201
|
object({
|
|
58481
59202
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58482
59203
|
* speed surface (single-speed fan). */
|
|
58483
|
-
percentage: number().min(0).max(100).nullable(),
|
|
59204
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58484
59205
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58485
59206
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58486
|
-
percentageStep: number().positive().optional(),
|
|
59207
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
58487
59208
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
58488
59209
|
* — empty string when no preset is active or supported. */
|
|
58489
59210
|
preset: string(),
|
|
@@ -58565,7 +59286,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58565
59286
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58566
59287
|
model: string().nullable(),
|
|
58567
59288
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58568
|
-
channelCount: number().nullable(),
|
|
59289
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58569
59290
|
/**
|
|
58570
59291
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58571
59292
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58597,9 +59318,45 @@ object({
|
|
|
58597
59318
|
lastChangedAt: number()
|
|
58598
59319
|
});
|
|
58599
59320
|
DeviceType.Sensor;
|
|
59321
|
+
object({
|
|
59322
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
59323
|
+
results: array(object({
|
|
59324
|
+
deviceId: number().int().nonnegative(),
|
|
59325
|
+
cap: string().min(1),
|
|
59326
|
+
method: string().min(1),
|
|
59327
|
+
ok: boolean(),
|
|
59328
|
+
error: string().optional(),
|
|
59329
|
+
/** Ms epoch of the attempt. */
|
|
59330
|
+
at: number()
|
|
59331
|
+
})) });
|
|
59332
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
59333
|
+
object({
|
|
59334
|
+
active: boolean().meta({ label: "Active" }),
|
|
59335
|
+
/** Ms epoch when the slice was last updated. */
|
|
59336
|
+
lastChangedAt: number()
|
|
59337
|
+
});
|
|
59338
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
59339
|
+
object({
|
|
59340
|
+
/** Members whose current value entered the aggregate. */
|
|
59341
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
59342
|
+
precision: 0,
|
|
59343
|
+
label: "Reporting"
|
|
59344
|
+
})),
|
|
59345
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
59346
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
59347
|
+
precision: 0,
|
|
59348
|
+
label: "Excluded"
|
|
59349
|
+
})),
|
|
59350
|
+
/** `included` + `excluded`. */
|
|
59351
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
59352
|
+
precision: 0,
|
|
59353
|
+
label: "Members"
|
|
59354
|
+
}))
|
|
59355
|
+
});
|
|
59356
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58600
59357
|
object({
|
|
58601
59358
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58602
|
-
position: number().min(0).max(100).nullable(),
|
|
59359
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58603
59360
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58604
59361
|
lastFetchedAt: number()
|
|
58605
59362
|
});
|
|
@@ -58608,9 +59365,9 @@ object({
|
|
|
58608
59365
|
/** Whether the humidifier is currently on. */
|
|
58609
59366
|
on: boolean(),
|
|
58610
59367
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58611
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59368
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58612
59369
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58613
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59370
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58614
59371
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58615
59372
|
* device has no mode surface. */
|
|
58616
59373
|
mode: string().nullable(),
|
|
@@ -58620,9 +59377,9 @@ object({
|
|
|
58620
59377
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58621
59378
|
action: string().nullable(),
|
|
58622
59379
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58623
|
-
minHumidity: number().nullable(),
|
|
59380
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58624
59381
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58625
|
-
maxHumidity: number().nullable(),
|
|
59382
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58626
59383
|
/** Ms epoch when the slice was last updated. */
|
|
58627
59384
|
lastChangedAt: number()
|
|
58628
59385
|
});
|
|
@@ -58646,22 +59403,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58646
59403
|
auth: "protected"
|
|
58647
59404
|
});
|
|
58648
59405
|
object({
|
|
58649
|
-
/** Current relative humidity, 0..100. */
|
|
58650
|
-
percent: number().min(0).max(100).meta({
|
|
58651
|
-
|
|
59406
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59407
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59408
|
+
precision: 0,
|
|
58652
59409
|
label: "Humidity"
|
|
58653
|
-
}),
|
|
59410
|
+
})),
|
|
58654
59411
|
/** Ms epoch when the slice was last updated. */
|
|
58655
|
-
lastFetchedAt: number()
|
|
58656
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58657
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58658
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58659
|
-
unit: string().optional(),
|
|
58660
|
-
/** Suggested decimal places for numeric display.
|
|
58661
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58662
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58663
|
-
* auto-formatting when absent. */
|
|
58664
|
-
precision: number().int().min(0).max(10).optional()
|
|
59412
|
+
lastFetchedAt: number()
|
|
58665
59413
|
});
|
|
58666
59414
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58667
59415
|
object({
|
|
@@ -58669,7 +59417,7 @@ object({
|
|
|
58669
59417
|
* entity exposes no `entity_picture` (yet). */
|
|
58670
59418
|
url: string().nullable(),
|
|
58671
59419
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58672
|
-
lastUpdated: number().nullable()
|
|
59420
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58673
59421
|
});
|
|
58674
59422
|
DeviceType.Image;
|
|
58675
59423
|
/**
|
|
@@ -58725,19 +59473,19 @@ var NormalizedRangeSchema = object({
|
|
|
58725
59473
|
});
|
|
58726
59474
|
object({
|
|
58727
59475
|
/** Normalized 0–100. */
|
|
58728
|
-
brightness: number().optional(),
|
|
59476
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58729
59477
|
/** Normalized 0–100. */
|
|
58730
|
-
contrast: number().optional(),
|
|
59478
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58731
59479
|
/** Normalized 0–100. */
|
|
58732
|
-
saturation: number().optional(),
|
|
59480
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58733
59481
|
/** Normalized 0–100. */
|
|
58734
|
-
sharpness: number().optional(),
|
|
59482
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58735
59483
|
mirror: boolean().optional(),
|
|
58736
59484
|
flip: boolean().optional(),
|
|
58737
59485
|
rotate: ImageRotateSchema.optional(),
|
|
58738
59486
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58739
59487
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58740
|
-
warmth: number().optional(),
|
|
59488
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58741
59489
|
exposureMode: ExposureModeSchema.optional(),
|
|
58742
59490
|
backlightMode: BacklightModeSchema.optional(),
|
|
58743
59491
|
lastFetchedAt: number()
|
|
@@ -58982,10 +59730,10 @@ var IntercomAbilitySchema = object({
|
|
|
58982
59730
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58983
59731
|
codecs: array(string()),
|
|
58984
59732
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58985
|
-
sampleRate: number(),
|
|
59733
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58986
59734
|
duplex: _enum(["half", "full"]),
|
|
58987
59735
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58988
|
-
maxBacklogMs: number()
|
|
59736
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58989
59737
|
});
|
|
58990
59738
|
var IntercomStatusSchema = object({
|
|
58991
59739
|
/** True while a talk session is open. */
|
|
@@ -59096,13 +59844,13 @@ object({
|
|
|
59096
59844
|
activity: LawnMowerActivitySchema,
|
|
59097
59845
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
59098
59846
|
* reading. */
|
|
59099
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59847
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59100
59848
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
59101
59849
|
* task is active / progress is unavailable. */
|
|
59102
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59850
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59103
59851
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
59104
59852
|
* or null when unknown. */
|
|
59105
|
-
currentCode: number().nullable(),
|
|
59853
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
59106
59854
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
59107
59855
|
currentCodeLabel: string().nullable(),
|
|
59108
59856
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -59512,7 +60260,14 @@ DeviceType.Lock, method(object({
|
|
|
59512
60260
|
auth: "protected"
|
|
59513
60261
|
}), method(object({
|
|
59514
60262
|
deviceId: number().int().nonnegative(),
|
|
59515
|
-
code: string().min(1).optional()
|
|
60263
|
+
code: string().min(1).optional(),
|
|
60264
|
+
/**
|
|
60265
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
60266
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
60267
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
60268
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
60269
|
+
*/
|
|
60270
|
+
confirm: boolean().optional()
|
|
59516
60271
|
}), _void(), {
|
|
59517
60272
|
kind: "mutation",
|
|
59518
60273
|
auth: "protected"
|
|
@@ -59520,6 +60275,11 @@ DeviceType.Lock, method(object({
|
|
|
59520
60275
|
kind: "mutation",
|
|
59521
60276
|
auth: "protected"
|
|
59522
60277
|
});
|
|
60278
|
+
object({
|
|
60279
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
60280
|
+
lastFetchedAt: number()
|
|
60281
|
+
});
|
|
60282
|
+
DeviceType.Sensor;
|
|
59523
60283
|
/**
|
|
59524
60284
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59525
60285
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59564,7 +60324,7 @@ object({
|
|
|
59564
60324
|
state: MediaPlayerStateSchema,
|
|
59565
60325
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59566
60326
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59567
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
60327
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59568
60328
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59569
60329
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59570
60330
|
isMuted: boolean().nullable(),
|
|
@@ -59577,10 +60337,10 @@ object({
|
|
|
59577
60337
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59578
60338
|
/** Current playback position in ms. Null when not seekable or
|
|
59579
60339
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59580
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
60340
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59581
60341
|
/** Total duration of the current media in ms. Null when unknown
|
|
59582
60342
|
* (live stream) or nothing is playing. */
|
|
59583
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
60343
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59584
60344
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59585
60345
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59586
60346
|
shuffle: boolean().nullable(),
|
|
@@ -59880,7 +60640,7 @@ object({
|
|
|
59880
60640
|
* it, every provider seeded it at boot, and every session left it
|
|
59881
60641
|
* `detected: true` after its detach.
|
|
59882
60642
|
*/
|
|
59883
|
-
autoClearAfterMs: number().nullable()
|
|
60643
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59884
60644
|
});
|
|
59885
60645
|
/**
|
|
59886
60646
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59930,7 +60690,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59930
60690
|
});
|
|
59931
60691
|
object({
|
|
59932
60692
|
enabled: boolean(),
|
|
59933
|
-
sensitivity: number(),
|
|
60693
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59934
60694
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59935
60695
|
regions: array(MotionZoneRegionSchema),
|
|
59936
60696
|
lastFetchedAt: number()
|
|
@@ -60234,7 +60994,7 @@ var NavigationStatusSchema = object({
|
|
|
60234
60994
|
following: boolean(),
|
|
60235
60995
|
flash: boolean(),
|
|
60236
60996
|
lightMode: NavigationLightModeSchema,
|
|
60237
|
-
lightLevel: number().min(40).max(100),
|
|
60997
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
60238
60998
|
/** Ms epoch when the slice was last updated. */
|
|
60239
60999
|
lastChangedAt: number()
|
|
60240
61000
|
});
|
|
@@ -60280,13 +61040,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
60280
61040
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
60281
61041
|
* SKIP a null rather than coerce it.
|
|
60282
61042
|
*/
|
|
60283
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
61043
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60284
61044
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
60285
|
-
rssiDbm: number().optional(),
|
|
61045
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
60286
61046
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
60287
61047
|
ssid: string().optional(),
|
|
60288
61048
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
60289
|
-
lastUpdated: number()
|
|
61049
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
60290
61050
|
});
|
|
60291
61051
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
60292
61052
|
deviceId: number(),
|
|
@@ -60605,7 +61365,7 @@ object({
|
|
|
60605
61365
|
lastError: string().nullable(),
|
|
60606
61366
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60607
61367
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60608
|
-
queueDepth: number().int().nonnegative(),
|
|
61368
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60609
61369
|
/** Per-feature capability matrix — authoritative source for the
|
|
60610
61370
|
* compose-form field gating. */
|
|
60611
61371
|
supports: NotifierSupportsSchema
|
|
@@ -60655,15 +61415,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60655
61415
|
acceptedAt: number()
|
|
60656
61416
|
});
|
|
60657
61417
|
object({
|
|
60658
|
-
|
|
60659
|
-
|
|
60660
|
-
* Populated live from the upstream source on each state push.
|
|
60661
|
-
* Absent for unitless sensors. */
|
|
60662
|
-
unit: string().optional(),
|
|
60663
|
-
/** Suggested decimal places for numeric display.
|
|
60664
|
-
* Populated live from the upstream source when provided.
|
|
60665
|
-
* Falls back to auto-formatting when absent. */
|
|
60666
|
-
precision: number().int().min(0).max(10).optional(),
|
|
61418
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
61419
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60667
61420
|
/** Ms epoch when the slice was last updated. */
|
|
60668
61421
|
lastFetchedAt: number()
|
|
60669
61422
|
});
|
|
@@ -60953,23 +61706,26 @@ object({
|
|
|
60953
61706
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60954
61707
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60955
61708
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60956
|
-
foodLevel: number().nullable(),
|
|
61709
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60957
61710
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60958
61711
|
* single-hopper models. */
|
|
60959
|
-
food1: number().nullable(),
|
|
61712
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60960
61713
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60961
61714
|
* single-hopper models. */
|
|
60962
|
-
food2: number().nullable(),
|
|
61715
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60963
61716
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60964
61717
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60965
61718
|
* below the feeder's low threshold. */
|
|
60966
61719
|
lowFood: boolean(),
|
|
60967
61720
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60968
61721
|
* device has no battery reading. */
|
|
60969
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60970
|
-
/**
|
|
60971
|
-
*
|
|
60972
|
-
|
|
61722
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61723
|
+
/**
|
|
61724
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61725
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61726
|
+
* model has no desiccant sensor.
|
|
61727
|
+
*/
|
|
61728
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60973
61729
|
/** True while a feed is in progress. */
|
|
60974
61730
|
feeding: boolean(),
|
|
60975
61731
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60980,7 +61736,7 @@ object({
|
|
|
60980
61736
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60981
61737
|
error: string().nullable(),
|
|
60982
61738
|
/** Raw device error code (0 / null = no error). */
|
|
60983
|
-
errorCode: number().nullable(),
|
|
61739
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60984
61740
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60985
61741
|
isDualHopper: boolean(),
|
|
60986
61742
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60990,7 +61746,7 @@ object({
|
|
|
60990
61746
|
/** Play a chime when dispensing. */
|
|
60991
61747
|
feedSound: boolean(),
|
|
60992
61748
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60993
|
-
volume: number(),
|
|
61749
|
+
volume: number().meta(readingMeta("none")),
|
|
60994
61750
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60995
61751
|
lastFetchedAt: number()
|
|
60996
61752
|
});
|
|
@@ -61427,38 +62183,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61427
62183
|
});
|
|
61428
62184
|
object({
|
|
61429
62185
|
/** Instantaneous power draw in watts. */
|
|
61430
|
-
watts: number().optional().meta({
|
|
61431
|
-
unit: "W",
|
|
61432
|
-
label: "Power"
|
|
61433
|
-
}),
|
|
62186
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61434
62187
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61435
|
-
kwhTotal: number().optional().meta({
|
|
61436
|
-
unit: "kWh",
|
|
61437
|
-
label: "Energy"
|
|
61438
|
-
}),
|
|
62188
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61439
62189
|
/** Voltage in volts. */
|
|
61440
|
-
volts: number().optional(),
|
|
62190
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61441
62191
|
/** Current in amperes. */
|
|
61442
|
-
amps: number().optional(),
|
|
61443
|
-
/** Apparent power in volt-amperes
|
|
61444
|
-
va: number().optional(),
|
|
62192
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
62193
|
+
/** Apparent power in volt-amperes. */
|
|
62194
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61445
62195
|
/** Power factor (0..1) if reported. */
|
|
61446
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
62196
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61447
62197
|
/** Ms epoch when the slice was last updated. */
|
|
61448
|
-
lastFetchedAt: number()
|
|
61449
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
61450
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
61451
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
61452
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
61453
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
61454
|
-
unit: string().optional(),
|
|
61455
|
-
/** Suggested decimal places for numeric display.
|
|
61456
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61457
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61458
|
-
* auto-formatting when absent. */
|
|
61459
|
-
precision: number().int().min(0).max(10).optional()
|
|
62198
|
+
lastFetchedAt: number()
|
|
61460
62199
|
});
|
|
61461
|
-
|
|
62200
|
+
[
|
|
62201
|
+
DeviceType.Sensor,
|
|
62202
|
+
DeviceType.Switch,
|
|
62203
|
+
DeviceType.Light,
|
|
62204
|
+
DeviceType.Fan,
|
|
62205
|
+
DeviceType.Climate,
|
|
62206
|
+
DeviceType.Thermostat,
|
|
62207
|
+
DeviceType.Humidifier,
|
|
62208
|
+
DeviceType.WaterHeater,
|
|
62209
|
+
DeviceType.MediaPlayer,
|
|
62210
|
+
DeviceType.Washer,
|
|
62211
|
+
DeviceType.Dryer,
|
|
62212
|
+
DeviceType.Dishwasher,
|
|
62213
|
+
DeviceType.Vacuum,
|
|
62214
|
+
DeviceType.LawnMower,
|
|
62215
|
+
DeviceType.PetFeeder
|
|
62216
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61462
62217
|
/**
|
|
61463
62218
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61464
62219
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61477,11 +62232,11 @@ DeviceType.Sensor;
|
|
|
61477
62232
|
*/
|
|
61478
62233
|
var GpsLocationSchema = object({
|
|
61479
62234
|
/** Latitude in decimal degrees, -90..90. */
|
|
61480
|
-
latitude: number().min(-90).max(90),
|
|
62235
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
61481
62236
|
/** Longitude in decimal degrees, -180..180. */
|
|
61482
|
-
longitude: number().min(-180).max(180),
|
|
62237
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
61483
62238
|
/** Reported accuracy in meters (lower = better). */
|
|
61484
|
-
accuracyMeters: number().nonnegative()
|
|
62239
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
61485
62240
|
});
|
|
61486
62241
|
object({
|
|
61487
62242
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -61493,25 +62248,16 @@ object({
|
|
|
61493
62248
|
gps: GpsLocationSchema.nullable(),
|
|
61494
62249
|
/** Optional battery level of the tracking device (0..100). Null
|
|
61495
62250
|
* when not reported. */
|
|
61496
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
62251
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61497
62252
|
/** Ms epoch when the slice was last updated. */
|
|
61498
62253
|
lastChangedAt: number()
|
|
61499
62254
|
});
|
|
61500
62255
|
DeviceType.Presence;
|
|
61501
62256
|
object({
|
|
61502
|
-
/** Current pressure in hPa. */
|
|
61503
|
-
hpa: number(),
|
|
62257
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
62258
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61504
62259
|
/** Ms epoch when the slice was last updated. */
|
|
61505
|
-
lastFetchedAt: number()
|
|
61506
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61507
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61508
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61509
|
-
unit: string().optional(),
|
|
61510
|
-
/** Suggested decimal places for numeric display.
|
|
61511
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61512
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61513
|
-
* auto-formatting when absent. */
|
|
61514
|
-
precision: number().int().min(0).max(10).optional()
|
|
62260
|
+
lastFetchedAt: number()
|
|
61515
62261
|
});
|
|
61516
62262
|
DeviceType.Sensor;
|
|
61517
62263
|
/**
|
|
@@ -61844,8 +62590,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61844
62590
|
}), _void(), { kind: "mutation" });
|
|
61845
62591
|
var PtzAutotrackSettingsSchema = object({
|
|
61846
62592
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61847
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61848
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62593
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62594
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61849
62595
|
});
|
|
61850
62596
|
/**
|
|
61851
62597
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61902,7 +62648,7 @@ object({
|
|
|
61902
62648
|
/** null = unknown — never coerced to false (D393). */
|
|
61903
62649
|
running: boolean().nullable(),
|
|
61904
62650
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61905
|
-
since: number().nullable(),
|
|
62651
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61906
62652
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61907
62653
|
phase: string().nullable(),
|
|
61908
62654
|
/** null until a reading has been published (D393). */
|
|
@@ -61914,7 +62660,7 @@ object({
|
|
|
61914
62660
|
phase: string().nullable()
|
|
61915
62661
|
});
|
|
61916
62662
|
Object.values(DeviceType);
|
|
61917
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62663
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61918
62664
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61919
62665
|
kind: "mutation",
|
|
61920
62666
|
auth: "admin"
|
|
@@ -63100,9 +63846,9 @@ var RecordTriggerSchema = _enum([
|
|
|
63100
63846
|
*/
|
|
63101
63847
|
var RecordWindowSchema = object({
|
|
63102
63848
|
trigger: RecordTriggerSchema,
|
|
63103
|
-
day: number().int().min(0).max(6),
|
|
63104
|
-
startMinute: number().int().min(0).max(1439),
|
|
63105
|
-
endMinute: number().int().min(1).max(1440)
|
|
63849
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63850
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63851
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
63106
63852
|
});
|
|
63107
63853
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
63108
63854
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -63171,10 +63917,10 @@ object({
|
|
|
63171
63917
|
/** Master "record to the card at all" switch. */
|
|
63172
63918
|
enabled: boolean().nullable(),
|
|
63173
63919
|
overwriteWhenFull: boolean().nullable(),
|
|
63174
|
-
preRecordSec: number().nullable(),
|
|
63175
|
-
postRecordSec: number().nullable(),
|
|
63920
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63921
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63176
63922
|
/** Length of one recorded file, in minutes. */
|
|
63177
|
-
segmentMinutes: number().nullable(),
|
|
63923
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
63178
63924
|
/** The primary track's weekly windows, flattened. */
|
|
63179
63925
|
windows: array(RecordWindowSchema),
|
|
63180
63926
|
/**
|
|
@@ -63190,7 +63936,7 @@ object({
|
|
|
63190
63936
|
* provider reporting a non-zero count also reports the schedule as not
|
|
63191
63937
|
* writable.
|
|
63192
63938
|
*/
|
|
63193
|
-
unreadableWindows: number(),
|
|
63939
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
63194
63940
|
/**
|
|
63195
63941
|
* The camera is scheduled to record and has NO usable storage.
|
|
63196
63942
|
*
|
|
@@ -63827,7 +64573,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63827
64573
|
url: string().optional(),
|
|
63828
64574
|
codec: string().optional(),
|
|
63829
64575
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63830
|
-
fps: number().positive().optional(),
|
|
64576
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63831
64577
|
label: string().optional(),
|
|
63832
64578
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63833
64579
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63857,18 +64603,18 @@ var StreamProfileSchema = _enum([
|
|
|
63857
64603
|
]);
|
|
63858
64604
|
/** The current encoding config of one stream profile. */
|
|
63859
64605
|
var StreamProfileConfigSchema = object({
|
|
63860
|
-
width: number(),
|
|
63861
|
-
height: number(),
|
|
64606
|
+
width: number().meta(readingMeta("none")),
|
|
64607
|
+
height: number().meta(readingMeta("none")),
|
|
63862
64608
|
codec: _enum(["h264", "h265"]),
|
|
63863
|
-
framerate: number(),
|
|
63864
|
-
bitrate: number(),
|
|
64609
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64610
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63865
64611
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63866
64612
|
encoderProfile: _enum([
|
|
63867
64613
|
"high",
|
|
63868
64614
|
"main",
|
|
63869
64615
|
"baseline"
|
|
63870
64616
|
]).optional(),
|
|
63871
|
-
gop: number().optional(),
|
|
64617
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63872
64618
|
/**
|
|
63873
64619
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63874
64620
|
*
|
|
@@ -63953,7 +64699,7 @@ object({
|
|
|
63953
64699
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63954
64700
|
lastChangedAt: number()
|
|
63955
64701
|
});
|
|
63956
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64702
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63957
64703
|
deviceId: number(),
|
|
63958
64704
|
on: boolean()
|
|
63959
64705
|
}), _void(), {
|
|
@@ -64511,23 +65257,13 @@ object({
|
|
|
64511
65257
|
});
|
|
64512
65258
|
DeviceType.Sensor;
|
|
64513
65259
|
object({
|
|
64514
|
-
/** Current temperature in Celsius. */
|
|
64515
|
-
celsius: number().meta({
|
|
64516
|
-
|
|
65260
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
65261
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
65262
|
+
precision: 1,
|
|
64517
65263
|
label: "Temperature"
|
|
64518
|
-
}),
|
|
65264
|
+
})),
|
|
64519
65265
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64520
|
-
lastFetchedAt: number()
|
|
64521
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64522
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64523
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64524
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64525
|
-
unit: string().optional(),
|
|
64526
|
-
/** Suggested decimal places for numeric display.
|
|
64527
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64528
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64529
|
-
* auto-formatting when absent. */
|
|
64530
|
-
precision: number().int().min(0).max(10).optional()
|
|
65266
|
+
lastFetchedAt: number()
|
|
64531
65267
|
});
|
|
64532
65268
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64533
65269
|
/**
|
|
@@ -64779,16 +65515,16 @@ object({
|
|
|
64779
65515
|
]),
|
|
64780
65516
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64781
65517
|
* reading. */
|
|
64782
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65518
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64783
65519
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64784
65520
|
* the vacuum has no speed control. */
|
|
64785
65521
|
fanSpeed: string().nullable(),
|
|
64786
65522
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64787
65523
|
availableFanSpeeds: array(string()),
|
|
64788
65524
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64789
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65525
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64790
65526
|
/** Current error code (0 / null = no error). */
|
|
64791
|
-
errorCode: number().nullable(),
|
|
65527
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64792
65528
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64793
65529
|
errorLabel: string().nullable(),
|
|
64794
65530
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64827,7 +65563,7 @@ object({
|
|
|
64827
65563
|
]),
|
|
64828
65564
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64829
65565
|
* intermediate position surface. */
|
|
64830
|
-
position: number().min(0).max(100).nullable(),
|
|
65566
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64831
65567
|
/** Ms epoch when the slice was last updated. */
|
|
64832
65568
|
lastChangedAt: number()
|
|
64833
65569
|
});
|
|
@@ -64855,9 +65591,9 @@ object({
|
|
|
64855
65591
|
DeviceType.Sensor;
|
|
64856
65592
|
object({
|
|
64857
65593
|
/** Current measured temperature. Null when not reported. */
|
|
64858
|
-
currentTemp: number().nullable(),
|
|
65594
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64859
65595
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64860
|
-
targetTemp: number().nullable(),
|
|
65596
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64861
65597
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64862
65598
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64863
65599
|
* device reports an unknown state. */
|
|
@@ -64868,9 +65604,9 @@ object({
|
|
|
64868
65604
|
* has no away surface. */
|
|
64869
65605
|
away: boolean().nullable(),
|
|
64870
65606
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64871
|
-
minTemp: number().nullable(),
|
|
65607
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64872
65608
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64873
|
-
maxTemp: number().nullable(),
|
|
65609
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64874
65610
|
/** Ms epoch when the slice was last updated. */
|
|
64875
65611
|
lastChangedAt: number()
|
|
64876
65612
|
});
|
|
@@ -64894,25 +65630,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64894
65630
|
auth: "protected"
|
|
64895
65631
|
});
|
|
64896
65632
|
object({
|
|
64897
|
-
/** Verbatim
|
|
64898
|
-
* when no condition has been reported yet. */
|
|
65633
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64899
65634
|
condition: string().nullable(),
|
|
64900
|
-
/** Current temperature in
|
|
64901
|
-
temperature: number().nullable(),
|
|
64902
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64903
|
-
temperatureUnit: string().nullable(),
|
|
65635
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65636
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64904
65637
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64905
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64906
|
-
/** Barometric pressure in
|
|
64907
|
-
pressure: number().nullable(),
|
|
64908
|
-
/**
|
|
64909
|
-
|
|
64910
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64911
|
-
windSpeed: number().nullable(),
|
|
64912
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64913
|
-
windSpeedUnit: string().nullable(),
|
|
65638
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65639
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65640
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65641
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65642
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64914
65643
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64915
|
-
windBearing: number().nullable(),
|
|
65644
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64916
65645
|
/** Ms epoch when the slice was last updated. */
|
|
64917
65646
|
lastFetchedAt: number()
|
|
64918
65647
|
});
|
|
@@ -65662,8 +66391,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65662
66391
|
kind: "mutation",
|
|
65663
66392
|
auth: "admin"
|
|
65664
66393
|
});
|
|
66394
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65665
66395
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65666
|
-
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;
|
|
66396
|
+
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;
|
|
65667
66397
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65668
66398
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65669
66399
|
new Set(CAP_NAMES);
|
|
@@ -65716,7 +66446,7 @@ var AccessoryKind = {
|
|
|
65716
66446
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65717
66447
|
};
|
|
65718
66448
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65719
|
-
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;
|
|
66449
|
+
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;
|
|
65720
66450
|
new Set(Object.values(DeviceType));
|
|
65721
66451
|
Object.freeze({
|
|
65722
66452
|
"accessories.getStatus": {
|
|
@@ -65824,6 +66554,13 @@ Object.freeze({
|
|
|
65824
66554
|
access: "view",
|
|
65825
66555
|
role: "admin"
|
|
65826
66556
|
},
|
|
66557
|
+
"addons.getPackageDocs": {
|
|
66558
|
+
capName: "addons",
|
|
66559
|
+
capScope: "system",
|
|
66560
|
+
addonId: null,
|
|
66561
|
+
access: "view",
|
|
66562
|
+
role: "admin"
|
|
66563
|
+
},
|
|
65827
66564
|
"addons.getVersions": {
|
|
65828
66565
|
capName: "addons",
|
|
65829
66566
|
capScope: "system",
|
|
@@ -68932,6 +69669,27 @@ Object.freeze({
|
|
|
68932
69669
|
access: "view",
|
|
68933
69670
|
role: "viewer"
|
|
68934
69671
|
},
|
|
69672
|
+
"groupActive.getStatus": {
|
|
69673
|
+
capName: "group-active",
|
|
69674
|
+
capScope: "device",
|
|
69675
|
+
addonId: null,
|
|
69676
|
+
access: "view",
|
|
69677
|
+
role: "viewer"
|
|
69678
|
+
},
|
|
69679
|
+
"groupCommands.getStatus": {
|
|
69680
|
+
capName: "group-commands",
|
|
69681
|
+
capScope: "device",
|
|
69682
|
+
addonId: null,
|
|
69683
|
+
access: "view",
|
|
69684
|
+
role: "viewer"
|
|
69685
|
+
},
|
|
69686
|
+
"groupStatus.getStatus": {
|
|
69687
|
+
capName: "group-status",
|
|
69688
|
+
capScope: "device",
|
|
69689
|
+
addonId: null,
|
|
69690
|
+
access: "view",
|
|
69691
|
+
role: "viewer"
|
|
69692
|
+
},
|
|
68935
69693
|
"heatingValve.getStatus": {
|
|
68936
69694
|
capName: "heating-valve",
|
|
68937
69695
|
capScope: "device",
|
|
@@ -69884,6 +70642,13 @@ Object.freeze({
|
|
|
69884
70642
|
access: "create",
|
|
69885
70643
|
role: "admin"
|
|
69886
70644
|
},
|
|
70645
|
+
"meter.getStatus": {
|
|
70646
|
+
capName: "meter",
|
|
70647
|
+
capScope: "device",
|
|
70648
|
+
addonId: null,
|
|
70649
|
+
access: "view",
|
|
70650
|
+
role: "viewer"
|
|
70651
|
+
},
|
|
69887
70652
|
"metricsProvider.collectSnapshot": {
|
|
69888
70653
|
capName: "metrics-provider",
|
|
69889
70654
|
capScope: "system",
|
|
@@ -77982,7 +78747,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77982
78747
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77983
78748
|
icon: "square"
|
|
77984
78749
|
}
|
|
77985
|
-
}
|
|
78750
|
+
},
|
|
78751
|
+
overrides: { byType: {
|
|
78752
|
+
[DeviceType.Washer]: {
|
|
78753
|
+
state: { running: {
|
|
78754
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78755
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78756
|
+
} },
|
|
78757
|
+
events: {
|
|
78758
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78759
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78760
|
+
}
|
|
78761
|
+
},
|
|
78762
|
+
[DeviceType.Dryer]: {
|
|
78763
|
+
state: { running: {
|
|
78764
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78765
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78766
|
+
} },
|
|
78767
|
+
events: {
|
|
78768
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78769
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78770
|
+
}
|
|
78771
|
+
},
|
|
78772
|
+
[DeviceType.Dishwasher]: {
|
|
78773
|
+
state: { running: {
|
|
78774
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78775
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78776
|
+
} },
|
|
78777
|
+
events: {
|
|
78778
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78779
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78780
|
+
}
|
|
78781
|
+
}
|
|
78782
|
+
} }
|
|
77986
78783
|
},
|
|
77987
78784
|
update: {
|
|
77988
78785
|
scope: "device",
|
|
@@ -78754,6 +79551,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78754
79551
|
icon: "flame"
|
|
78755
79552
|
}]
|
|
78756
79553
|
},
|
|
79554
|
+
"group-active": {
|
|
79555
|
+
scope: "device",
|
|
79556
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79557
|
+
},
|
|
79558
|
+
"group-commands": {
|
|
79559
|
+
scope: "device",
|
|
79560
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79561
|
+
},
|
|
79562
|
+
"group-status": {
|
|
79563
|
+
scope: "device",
|
|
79564
|
+
noun: t("Group", "Gruppo"),
|
|
79565
|
+
state: [
|
|
79566
|
+
{
|
|
79567
|
+
kind: "numeric",
|
|
79568
|
+
field: "included",
|
|
79569
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79570
|
+
label: t("Reporting", "Rispondono"),
|
|
79571
|
+
icon: "users"
|
|
79572
|
+
},
|
|
79573
|
+
{
|
|
79574
|
+
kind: "numeric",
|
|
79575
|
+
field: "excluded",
|
|
79576
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79577
|
+
label: t("Excluded", "Esclusi"),
|
|
79578
|
+
icon: "users"
|
|
79579
|
+
},
|
|
79580
|
+
{
|
|
79581
|
+
kind: "numeric",
|
|
79582
|
+
field: "total",
|
|
79583
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79584
|
+
label: t("Members", "Membri"),
|
|
79585
|
+
icon: "sigma"
|
|
79586
|
+
}
|
|
79587
|
+
]
|
|
79588
|
+
},
|
|
78757
79589
|
"humidity-sensor": {
|
|
78758
79590
|
scope: "device",
|
|
78759
79591
|
noun: t("Humidity", "Umidità"),
|
|
@@ -78779,6 +79611,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78779
79611
|
}],
|
|
78780
79612
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78781
79613
|
},
|
|
79614
|
+
meter: {
|
|
79615
|
+
scope: "device",
|
|
79616
|
+
noun: t("Meter", "Contatore"),
|
|
79617
|
+
state: [{
|
|
79618
|
+
kind: "numeric",
|
|
79619
|
+
field: "value",
|
|
79620
|
+
quantity: t("the total", "il totale"),
|
|
79621
|
+
label: t("Total", "Totale"),
|
|
79622
|
+
icon: "gauge"
|
|
79623
|
+
}]
|
|
79624
|
+
},
|
|
78782
79625
|
"numeric-sensor": {
|
|
78783
79626
|
scope: "device",
|
|
78784
79627
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78787,7 +79630,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78787
79630
|
field: "value",
|
|
78788
79631
|
quantity: t("the reading", "il valore"),
|
|
78789
79632
|
label: t("Reading", "Valore"),
|
|
78790
|
-
unitField: "unit",
|
|
78791
79633
|
icon: "gauge"
|
|
78792
79634
|
}]
|
|
78793
79635
|
},
|
|
@@ -78923,7 +79765,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78923
79765
|
field: "temperature",
|
|
78924
79766
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78925
79767
|
label: t("Temperature", "Temperatura"),
|
|
78926
|
-
|
|
79768
|
+
unit: "°C",
|
|
78927
79769
|
icon: "thermometer"
|
|
78928
79770
|
},
|
|
78929
79771
|
{
|
|
@@ -78939,7 +79781,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78939
79781
|
field: "windSpeed",
|
|
78940
79782
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78941
79783
|
label: t("Wind", "Vento"),
|
|
78942
|
-
|
|
79784
|
+
unit: "m/s",
|
|
78943
79785
|
icon: "wind"
|
|
78944
79786
|
},
|
|
78945
79787
|
{
|
|
@@ -78947,7 +79789,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78947
79789
|
field: "pressure",
|
|
78948
79790
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78949
79791
|
label: t("Pressure", "Pressione"),
|
|
78950
|
-
|
|
79792
|
+
unit: "hPa",
|
|
78951
79793
|
icon: "gauge"
|
|
78952
79794
|
}
|
|
78953
79795
|
]
|
|
@@ -79252,8 +80094,47 @@ function projectAction(cap, action) {
|
|
|
79252
80094
|
};
|
|
79253
80095
|
}
|
|
79254
80096
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
79255
|
-
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;
|
|
80097
|
+
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;
|
|
79256
80098
|
DeviceFeature.BatteryOperated;
|
|
80099
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
80100
|
+
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.";
|
|
80101
|
+
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.";
|
|
80102
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
80103
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
80104
|
+
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.";
|
|
80105
|
+
function withheld(reason) {
|
|
80106
|
+
return {
|
|
80107
|
+
[DeviceType.Washer]: {
|
|
80108
|
+
exported: false,
|
|
80109
|
+
reason
|
|
80110
|
+
},
|
|
80111
|
+
[DeviceType.Dryer]: {
|
|
80112
|
+
exported: false,
|
|
80113
|
+
reason
|
|
80114
|
+
},
|
|
80115
|
+
[DeviceType.Dishwasher]: {
|
|
80116
|
+
exported: false,
|
|
80117
|
+
reason
|
|
80118
|
+
}
|
|
80119
|
+
};
|
|
80120
|
+
}
|
|
80121
|
+
function offered(received) {
|
|
80122
|
+
return {
|
|
80123
|
+
[DeviceType.Washer]: {
|
|
80124
|
+
exported: true,
|
|
80125
|
+
as: received
|
|
80126
|
+
},
|
|
80127
|
+
[DeviceType.Dryer]: {
|
|
80128
|
+
exported: true,
|
|
80129
|
+
as: received
|
|
80130
|
+
},
|
|
80131
|
+
[DeviceType.Dishwasher]: {
|
|
80132
|
+
exported: true,
|
|
80133
|
+
as: received
|
|
80134
|
+
}
|
|
80135
|
+
};
|
|
80136
|
+
}
|
|
80137
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
79257
80138
|
Object.freeze({
|
|
79258
80139
|
"accessories.getStatus": [{
|
|
79259
80140
|
name: "deviceId",
|
|
@@ -80220,6 +81101,21 @@ Object.freeze({
|
|
|
80220
81101
|
form: "single",
|
|
80221
81102
|
optional: false
|
|
80222
81103
|
}],
|
|
81104
|
+
"groupActive.getStatus": [{
|
|
81105
|
+
name: "deviceId",
|
|
81106
|
+
form: "single",
|
|
81107
|
+
optional: false
|
|
81108
|
+
}],
|
|
81109
|
+
"groupCommands.getStatus": [{
|
|
81110
|
+
name: "deviceId",
|
|
81111
|
+
form: "single",
|
|
81112
|
+
optional: false
|
|
81113
|
+
}],
|
|
81114
|
+
"groupStatus.getStatus": [{
|
|
81115
|
+
name: "deviceId",
|
|
81116
|
+
form: "single",
|
|
81117
|
+
optional: false
|
|
81118
|
+
}],
|
|
80223
81119
|
"heatingValve.getStatus": [{
|
|
80224
81120
|
name: "deviceId",
|
|
80225
81121
|
form: "single",
|
|
@@ -80420,6 +81316,11 @@ Object.freeze({
|
|
|
80420
81316
|
form: "single",
|
|
80421
81317
|
optional: false
|
|
80422
81318
|
}],
|
|
81319
|
+
"meter.getStatus": [{
|
|
81320
|
+
name: "deviceId",
|
|
81321
|
+
form: "single",
|
|
81322
|
+
optional: false
|
|
81323
|
+
}],
|
|
80423
81324
|
"motion.getStatus": [{
|
|
80424
81325
|
name: "deviceId",
|
|
80425
81326
|
form: "single",
|
|
@@ -82027,7 +82928,6 @@ Object.freeze({
|
|
|
82027
82928
|
"network-access": "ingress",
|
|
82028
82929
|
"smtp-provider": "email"
|
|
82029
82930
|
});
|
|
82030
|
-
DeviceType.Camera;
|
|
82031
82931
|
/**
|
|
82032
82932
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
82033
82933
|
* `z.infer`, they do not restate the shape.
|
|
@@ -82204,6 +83104,8 @@ new Map(Object.entries({
|
|
|
82204
83104
|
"detection-blind": "device-events",
|
|
82205
83105
|
"motion-noisy": "device-events",
|
|
82206
83106
|
"motion-calm": "device-events",
|
|
83107
|
+
"package-llm-silent": "device-events",
|
|
83108
|
+
"package-llm-answered": "device-events",
|
|
82207
83109
|
"recording-stalled": "device-events",
|
|
82208
83110
|
"recording-healthy": "device-events",
|
|
82209
83111
|
"recording-degraded": "device-events",
|
|
@@ -82287,6 +83189,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
82287
83189
|
label: "Motion without a subject",
|
|
82288
83190
|
kinds: ["motion-noisy", "motion-calm"]
|
|
82289
83191
|
},
|
|
83192
|
+
{
|
|
83193
|
+
id: "package-llm",
|
|
83194
|
+
family: "device-events",
|
|
83195
|
+
label: "Package confirm",
|
|
83196
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
83197
|
+
},
|
|
82290
83198
|
{
|
|
82291
83199
|
id: "recording",
|
|
82292
83200
|
family: "device-events",
|
|
@@ -82468,6 +83376,8 @@ var DEVICE_EVENTS = [
|
|
|
82468
83376
|
"detection-blind",
|
|
82469
83377
|
"motion-noisy",
|
|
82470
83378
|
"motion-calm",
|
|
83379
|
+
"package-llm-silent",
|
|
83380
|
+
"package-llm-answered",
|
|
82471
83381
|
"recording-stalled",
|
|
82472
83382
|
"recording-healthy",
|
|
82473
83383
|
"recording-degraded",
|
|
@@ -82736,6 +83646,15 @@ new Map([
|
|
|
82736
83646
|
snapshotLabel: "Cameras with constant motion now",
|
|
82737
83647
|
snapshotSection: null
|
|
82738
83648
|
},
|
|
83649
|
+
{
|
|
83650
|
+
id: "package-llm-confirm",
|
|
83651
|
+
family: "device-events",
|
|
83652
|
+
label: "Package confirm (not answering / answering again)",
|
|
83653
|
+
bad: ["package-llm-silent"],
|
|
83654
|
+
recovery: ["package-llm-answered"],
|
|
83655
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
83656
|
+
snapshotSection: null
|
|
83657
|
+
},
|
|
82739
83658
|
{
|
|
82740
83659
|
id: "recording-health",
|
|
82741
83660
|
family: "device-events",
|