@camstack/addon-provider-onvif 1.2.148 → 1.2.150
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 +34 -0
- package/dist/addon.js +1366 -447
- package/dist/addon.mjs +1366 -447
- package/package.json +5 -3
package/dist/addon.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
4
4
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
5
5
|
//#endregion
|
|
6
|
-
//#region ../types/dist/event-category-
|
|
6
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
7
7
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
8
8
|
EventCategory["SystemBoot"] = "system.boot";
|
|
9
9
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -329,6 +329,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
329
329
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
330
330
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
331
331
|
/**
|
|
332
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
333
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
334
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
335
|
+
*/
|
|
336
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
337
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
338
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
339
|
+
/**
|
|
332
340
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
333
341
|
* (a settings change via `setAgentInferenceDevices` /
|
|
334
342
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5438,7 +5446,7 @@ var ZodIssueCode = {
|
|
|
5438
5446
|
var ZodFirstPartyTypeKind;
|
|
5439
5447
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5440
5448
|
//#endregion
|
|
5441
|
-
//#region ../types/dist/sleep
|
|
5449
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5442
5450
|
/**
|
|
5443
5451
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5444
5452
|
* window to float samples (D455).
|
|
@@ -7925,6 +7933,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
7925
7933
|
}).strict();
|
|
7926
7934
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
7927
7935
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
7936
|
+
var READING_QUANTITIES = [
|
|
7937
|
+
"temperature",
|
|
7938
|
+
"pressure",
|
|
7939
|
+
"speed",
|
|
7940
|
+
"precipitation",
|
|
7941
|
+
"precipitation-rate",
|
|
7942
|
+
"length",
|
|
7943
|
+
"area",
|
|
7944
|
+
"illuminance",
|
|
7945
|
+
"irradiance",
|
|
7946
|
+
"power",
|
|
7947
|
+
"energy",
|
|
7948
|
+
"voltage",
|
|
7949
|
+
"current",
|
|
7950
|
+
"apparent-power",
|
|
7951
|
+
"humidity",
|
|
7952
|
+
"percentage",
|
|
7953
|
+
"concentration-volume",
|
|
7954
|
+
"concentration-mass",
|
|
7955
|
+
"concentration-ppb",
|
|
7956
|
+
"volume",
|
|
7957
|
+
"duration",
|
|
7958
|
+
"duration-ms",
|
|
7959
|
+
"information",
|
|
7960
|
+
"sound-level",
|
|
7961
|
+
"signal-level",
|
|
7962
|
+
"colour-temperature",
|
|
7963
|
+
"angle",
|
|
7964
|
+
"bitrate",
|
|
7965
|
+
"rate",
|
|
7966
|
+
"mass",
|
|
7967
|
+
"index",
|
|
7968
|
+
"ratio",
|
|
7969
|
+
"count",
|
|
7970
|
+
"none",
|
|
7971
|
+
"device"
|
|
7972
|
+
];
|
|
7973
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
7974
|
+
new Set(READING_QUANTITIES);
|
|
7975
|
+
/**
|
|
7976
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
7977
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
7978
|
+
*/
|
|
7979
|
+
var QUANTITY_BASE = {
|
|
7980
|
+
temperature: "°C",
|
|
7981
|
+
pressure: "hPa",
|
|
7982
|
+
speed: "m/s",
|
|
7983
|
+
precipitation: "mm",
|
|
7984
|
+
"precipitation-rate": "mm/h",
|
|
7985
|
+
length: "m",
|
|
7986
|
+
area: "m²",
|
|
7987
|
+
illuminance: "lx",
|
|
7988
|
+
irradiance: "W/m²",
|
|
7989
|
+
power: "W",
|
|
7990
|
+
energy: "kWh",
|
|
7991
|
+
voltage: "V",
|
|
7992
|
+
current: "A",
|
|
7993
|
+
"apparent-power": "VA",
|
|
7994
|
+
humidity: "%",
|
|
7995
|
+
percentage: "%",
|
|
7996
|
+
"concentration-volume": "ppm",
|
|
7997
|
+
"concentration-mass": "µg/m³",
|
|
7998
|
+
"concentration-ppb": "ppb",
|
|
7999
|
+
volume: "L",
|
|
8000
|
+
duration: "s",
|
|
8001
|
+
"duration-ms": "ms",
|
|
8002
|
+
information: "B",
|
|
8003
|
+
"sound-level": "dBFS",
|
|
8004
|
+
"signal-level": "dBm",
|
|
8005
|
+
"colour-temperature": "mired",
|
|
8006
|
+
angle: "°",
|
|
8007
|
+
bitrate: "kbps",
|
|
8008
|
+
rate: "fps",
|
|
8009
|
+
mass: "kg",
|
|
8010
|
+
index: "none",
|
|
8011
|
+
ratio: "none",
|
|
8012
|
+
count: "none",
|
|
8013
|
+
none: "none",
|
|
8014
|
+
device: "device"
|
|
8015
|
+
};
|
|
8016
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8017
|
+
function baseUnitOf(quantity) {
|
|
8018
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8019
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8020
|
+
return symbol;
|
|
8021
|
+
}
|
|
8022
|
+
function readingMeta(quantity, extras) {
|
|
8023
|
+
return {
|
|
8024
|
+
quantity,
|
|
8025
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8026
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8027
|
+
};
|
|
8028
|
+
}
|
|
7928
8029
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
7929
8030
|
var CamProfileSchema = _enum([
|
|
7930
8031
|
"high",
|
|
@@ -7952,8 +8053,8 @@ var CamStreamKindSchema = _enum([
|
|
|
7952
8053
|
"derived"
|
|
7953
8054
|
]);
|
|
7954
8055
|
var CamStreamResolutionSchema = object({
|
|
7955
|
-
width: number().int().positive(),
|
|
7956
|
-
height: number().int().positive()
|
|
8056
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8057
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
7957
8058
|
});
|
|
7958
8059
|
var CameraStreamSchema = object({
|
|
7959
8060
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8467,6 +8568,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8467
8568
|
"filesystem-browse",
|
|
8468
8569
|
"flood",
|
|
8469
8570
|
"gas",
|
|
8571
|
+
"group-active",
|
|
8572
|
+
"group-commands",
|
|
8573
|
+
"group-status",
|
|
8470
8574
|
"heating-valve",
|
|
8471
8575
|
"humidifier",
|
|
8472
8576
|
"humidity-sensor",
|
|
@@ -8487,6 +8591,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8487
8591
|
"login-method",
|
|
8488
8592
|
"media-player",
|
|
8489
8593
|
"mesh-network",
|
|
8594
|
+
"meter",
|
|
8490
8595
|
"metrics-provider",
|
|
8491
8596
|
"model-convert",
|
|
8492
8597
|
"model-distributor",
|
|
@@ -8596,14 +8701,6 @@ Object.freeze({
|
|
|
8596
8701
|
{
|
|
8597
8702
|
"path": "aqi",
|
|
8598
8703
|
"valueType": "number"
|
|
8599
|
-
},
|
|
8600
|
-
{
|
|
8601
|
-
"path": "unit",
|
|
8602
|
-
"valueType": "string"
|
|
8603
|
-
},
|
|
8604
|
-
{
|
|
8605
|
-
"path": "precision",
|
|
8606
|
-
"valueType": "number"
|
|
8607
8704
|
}
|
|
8608
8705
|
],
|
|
8609
8706
|
"alarm-panel": [
|
|
@@ -8639,20 +8736,10 @@ Object.freeze({
|
|
|
8639
8736
|
"valueType": "boolean"
|
|
8640
8737
|
}
|
|
8641
8738
|
],
|
|
8642
|
-
"ambient-light-sensor": [
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
},
|
|
8647
|
-
{
|
|
8648
|
-
"path": "unit",
|
|
8649
|
-
"valueType": "string"
|
|
8650
|
-
},
|
|
8651
|
-
{
|
|
8652
|
-
"path": "precision",
|
|
8653
|
-
"valueType": "number"
|
|
8654
|
-
}
|
|
8655
|
-
],
|
|
8739
|
+
"ambient-light-sensor": [{
|
|
8740
|
+
"path": "lux",
|
|
8741
|
+
"valueType": "number"
|
|
8742
|
+
}],
|
|
8656
8743
|
"audio-metrics": [
|
|
8657
8744
|
{
|
|
8658
8745
|
"path": "ts",
|
|
@@ -8732,6 +8819,10 @@ Object.freeze({
|
|
|
8732
8819
|
"path": "lastUpdated",
|
|
8733
8820
|
"valueType": "number"
|
|
8734
8821
|
},
|
|
8822
|
+
{
|
|
8823
|
+
"path": "volts",
|
|
8824
|
+
"valueType": "number"
|
|
8825
|
+
},
|
|
8735
8826
|
{
|
|
8736
8827
|
"path": "lastContactAt",
|
|
8737
8828
|
"valueType": "number"
|
|
@@ -8974,10 +9065,6 @@ Object.freeze({
|
|
|
8974
9065
|
"datetime"
|
|
8975
9066
|
]
|
|
8976
9067
|
},
|
|
8977
|
-
{
|
|
8978
|
-
"path": "unit",
|
|
8979
|
-
"valueType": "string"
|
|
8980
|
-
},
|
|
8981
9068
|
{
|
|
8982
9069
|
"path": "min",
|
|
8983
9070
|
"valueType": "number"
|
|
@@ -8989,19 +9076,6 @@ Object.freeze({
|
|
|
8989
9076
|
{
|
|
8990
9077
|
"path": "step",
|
|
8991
9078
|
"valueType": "number"
|
|
8992
|
-
},
|
|
8993
|
-
{
|
|
8994
|
-
"path": "precision",
|
|
8995
|
-
"valueType": "number"
|
|
8996
|
-
},
|
|
8997
|
-
{
|
|
8998
|
-
"path": "format",
|
|
8999
|
-
"valueType": "enum",
|
|
9000
|
-
"enumValues": [
|
|
9001
|
-
"date",
|
|
9002
|
-
"time",
|
|
9003
|
-
"datetime"
|
|
9004
|
-
]
|
|
9005
9079
|
}
|
|
9006
9080
|
],
|
|
9007
9081
|
"cover": [
|
|
@@ -9242,13 +9316,8 @@ Object.freeze({
|
|
|
9242
9316
|
"path": "value",
|
|
9243
9317
|
"valueType": "string"
|
|
9244
9318
|
}, {
|
|
9245
|
-
"path": "
|
|
9246
|
-
"valueType": "
|
|
9247
|
-
"enumValues": [
|
|
9248
|
-
"date",
|
|
9249
|
-
"time",
|
|
9250
|
-
"datetime"
|
|
9251
|
-
]
|
|
9319
|
+
"path": "timestamp",
|
|
9320
|
+
"valueType": "boolean"
|
|
9252
9321
|
}],
|
|
9253
9322
|
"event-emitter": [
|
|
9254
9323
|
{
|
|
@@ -9321,6 +9390,24 @@ Object.freeze({
|
|
|
9321
9390
|
"path": "detected",
|
|
9322
9391
|
"valueType": "boolean"
|
|
9323
9392
|
}],
|
|
9393
|
+
"group-active": [{
|
|
9394
|
+
"path": "active",
|
|
9395
|
+
"valueType": "boolean"
|
|
9396
|
+
}],
|
|
9397
|
+
"group-status": [
|
|
9398
|
+
{
|
|
9399
|
+
"path": "included",
|
|
9400
|
+
"valueType": "number"
|
|
9401
|
+
},
|
|
9402
|
+
{
|
|
9403
|
+
"path": "excluded",
|
|
9404
|
+
"valueType": "number"
|
|
9405
|
+
},
|
|
9406
|
+
{
|
|
9407
|
+
"path": "total",
|
|
9408
|
+
"valueType": "number"
|
|
9409
|
+
}
|
|
9410
|
+
],
|
|
9324
9411
|
"heating-valve": [{
|
|
9325
9412
|
"path": "position",
|
|
9326
9413
|
"valueType": "number"
|
|
@@ -9355,20 +9442,10 @@ Object.freeze({
|
|
|
9355
9442
|
"valueType": "number"
|
|
9356
9443
|
}
|
|
9357
9444
|
],
|
|
9358
|
-
"humidity-sensor": [
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
},
|
|
9363
|
-
{
|
|
9364
|
-
"path": "unit",
|
|
9365
|
-
"valueType": "string"
|
|
9366
|
-
},
|
|
9367
|
-
{
|
|
9368
|
-
"path": "precision",
|
|
9369
|
-
"valueType": "number"
|
|
9370
|
-
}
|
|
9371
|
-
],
|
|
9445
|
+
"humidity-sensor": [{
|
|
9446
|
+
"path": "percent",
|
|
9447
|
+
"valueType": "number"
|
|
9448
|
+
}],
|
|
9372
9449
|
"image": [{
|
|
9373
9450
|
"path": "url",
|
|
9374
9451
|
"valueType": "string"
|
|
@@ -9576,6 +9653,10 @@ Object.freeze({
|
|
|
9576
9653
|
]
|
|
9577
9654
|
}
|
|
9578
9655
|
],
|
|
9656
|
+
"meter": [{
|
|
9657
|
+
"path": "value",
|
|
9658
|
+
"valueType": "number"
|
|
9659
|
+
}],
|
|
9579
9660
|
"motion": [
|
|
9580
9661
|
{
|
|
9581
9662
|
"path": "detected",
|
|
@@ -9707,20 +9788,10 @@ Object.freeze({
|
|
|
9707
9788
|
"valueType": "boolean"
|
|
9708
9789
|
}
|
|
9709
9790
|
],
|
|
9710
|
-
"numeric-sensor": [
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
},
|
|
9715
|
-
{
|
|
9716
|
-
"path": "unit",
|
|
9717
|
-
"valueType": "string"
|
|
9718
|
-
},
|
|
9719
|
-
{
|
|
9720
|
-
"path": "precision",
|
|
9721
|
-
"valueType": "number"
|
|
9722
|
-
}
|
|
9723
|
-
],
|
|
9791
|
+
"numeric-sensor": [{
|
|
9792
|
+
"path": "value",
|
|
9793
|
+
"valueType": "number"
|
|
9794
|
+
}],
|
|
9724
9795
|
"pet-feeder": [
|
|
9725
9796
|
{
|
|
9726
9797
|
"path": "foodLevel",
|
|
@@ -9812,14 +9883,6 @@ Object.freeze({
|
|
|
9812
9883
|
{
|
|
9813
9884
|
"path": "powerFactor",
|
|
9814
9885
|
"valueType": "number"
|
|
9815
|
-
},
|
|
9816
|
-
{
|
|
9817
|
-
"path": "unit",
|
|
9818
|
-
"valueType": "string"
|
|
9819
|
-
},
|
|
9820
|
-
{
|
|
9821
|
-
"path": "precision",
|
|
9822
|
-
"valueType": "number"
|
|
9823
9886
|
}
|
|
9824
9887
|
],
|
|
9825
9888
|
"presence": [
|
|
@@ -9848,20 +9911,10 @@ Object.freeze({
|
|
|
9848
9911
|
"valueType": "number"
|
|
9849
9912
|
}
|
|
9850
9913
|
],
|
|
9851
|
-
"pressure-sensor": [
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
},
|
|
9856
|
-
{
|
|
9857
|
-
"path": "unit",
|
|
9858
|
-
"valueType": "string"
|
|
9859
|
-
},
|
|
9860
|
-
{
|
|
9861
|
-
"path": "precision",
|
|
9862
|
-
"valueType": "number"
|
|
9863
|
-
}
|
|
9864
|
-
],
|
|
9914
|
+
"pressure-sensor": [{
|
|
9915
|
+
"path": "hpa",
|
|
9916
|
+
"valueType": "number"
|
|
9917
|
+
}],
|
|
9865
9918
|
"privacy-mask": [{
|
|
9866
9919
|
"path": "enabled",
|
|
9867
9920
|
"valueType": "boolean"
|
|
@@ -10172,20 +10225,10 @@ Object.freeze({
|
|
|
10172
10225
|
"path": "tampered",
|
|
10173
10226
|
"valueType": "boolean"
|
|
10174
10227
|
}],
|
|
10175
|
-
"temperature-sensor": [
|
|
10176
|
-
|
|
10177
|
-
|
|
10178
|
-
|
|
10179
|
-
},
|
|
10180
|
-
{
|
|
10181
|
-
"path": "unit",
|
|
10182
|
-
"valueType": "string"
|
|
10183
|
-
},
|
|
10184
|
-
{
|
|
10185
|
-
"path": "precision",
|
|
10186
|
-
"valueType": "number"
|
|
10187
|
-
}
|
|
10188
|
-
],
|
|
10228
|
+
"temperature-sensor": [{
|
|
10229
|
+
"path": "celsius",
|
|
10230
|
+
"valueType": "number"
|
|
10231
|
+
}],
|
|
10189
10232
|
"update": [
|
|
10190
10233
|
{
|
|
10191
10234
|
"path": "currentVersion",
|
|
@@ -10296,10 +10339,6 @@ Object.freeze({
|
|
|
10296
10339
|
"path": "temperature",
|
|
10297
10340
|
"valueType": "number"
|
|
10298
10341
|
},
|
|
10299
|
-
{
|
|
10300
|
-
"path": "temperatureUnit",
|
|
10301
|
-
"valueType": "string"
|
|
10302
|
-
},
|
|
10303
10342
|
{
|
|
10304
10343
|
"path": "humidity",
|
|
10305
10344
|
"valueType": "number"
|
|
@@ -10308,18 +10347,10 @@ Object.freeze({
|
|
|
10308
10347
|
"path": "pressure",
|
|
10309
10348
|
"valueType": "number"
|
|
10310
10349
|
},
|
|
10311
|
-
{
|
|
10312
|
-
"path": "pressureUnit",
|
|
10313
|
-
"valueType": "string"
|
|
10314
|
-
},
|
|
10315
10350
|
{
|
|
10316
10351
|
"path": "windSpeed",
|
|
10317
10352
|
"valueType": "number"
|
|
10318
10353
|
},
|
|
10319
|
-
{
|
|
10320
|
-
"path": "windSpeedUnit",
|
|
10321
|
-
"valueType": "string"
|
|
10322
|
-
},
|
|
10323
10354
|
{
|
|
10324
10355
|
"path": "windBearing",
|
|
10325
10356
|
"valueType": "number"
|
|
@@ -10369,7 +10400,7 @@ object({
|
|
|
10369
10400
|
params: record(string(), union([string(), number()])).optional()
|
|
10370
10401
|
});
|
|
10371
10402
|
//#endregion
|
|
10372
|
-
//#region ../types/dist/err-msg-
|
|
10403
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10373
10404
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10374
10405
|
DeviceType["Camera"] = "camera";
|
|
10375
10406
|
DeviceType["Hub"] = "hub";
|
|
@@ -10463,8 +10494,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10463
10494
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10464
10495
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10465
10496
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10466
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10497
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10498
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10467
10499
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10500
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10501
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10502
|
+
DeviceType["Washer"] = "washer";
|
|
10503
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10504
|
+
DeviceType["Dryer"] = "dryer";
|
|
10468
10505
|
return DeviceType;
|
|
10469
10506
|
}({});
|
|
10470
10507
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10722,7 +10759,7 @@ function errMsg(err) {
|
|
|
10722
10759
|
return String(err);
|
|
10723
10760
|
}
|
|
10724
10761
|
//#endregion
|
|
10725
|
-
//#region ../types/dist/composition-
|
|
10762
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10726
10763
|
/**
|
|
10727
10764
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10728
10765
|
*
|
|
@@ -11037,6 +11074,13 @@ var table = {
|
|
|
11037
11074
|
apply: () => {
|
|
11038
11075
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11039
11076
|
}
|
|
11077
|
+
},
|
|
11078
|
+
schmitt: {
|
|
11079
|
+
minArgs: 3,
|
|
11080
|
+
maxArgs: 5,
|
|
11081
|
+
apply: () => {
|
|
11082
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11083
|
+
}
|
|
11040
11084
|
}
|
|
11041
11085
|
};
|
|
11042
11086
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11477,15 +11521,232 @@ function validateExpressionSource(src) {
|
|
|
11477
11521
|
}
|
|
11478
11522
|
return null;
|
|
11479
11523
|
}
|
|
11480
|
-
/**
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11524
|
+
/**
|
|
11525
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11526
|
+
*
|
|
11527
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11528
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11529
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11530
|
+
*
|
|
11531
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11532
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11533
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11534
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11535
|
+
* can move later without moving the others.
|
|
11536
|
+
*/
|
|
11537
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11538
|
+
var APPLIANCE_KINDS = [
|
|
11539
|
+
"washer",
|
|
11540
|
+
"dryer",
|
|
11541
|
+
"dishwasher"
|
|
11542
|
+
];
|
|
11543
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11544
|
+
/**
|
|
11545
|
+
* Statistics and integrals over a history read (D944).
|
|
11546
|
+
*
|
|
11547
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11548
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11549
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11550
|
+
* as zero. A truncated read is not published.
|
|
11551
|
+
*/
|
|
11552
|
+
var STATISTIC_STATS = [
|
|
11553
|
+
"min",
|
|
11554
|
+
"max",
|
|
11555
|
+
"mean",
|
|
11556
|
+
"sum",
|
|
11557
|
+
"count",
|
|
11558
|
+
"change"
|
|
11559
|
+
];
|
|
11560
|
+
/**
|
|
11561
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11562
|
+
*
|
|
11563
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11564
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11565
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11566
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11567
|
+
*/
|
|
11568
|
+
var MINUTE_MS = 6e4;
|
|
11569
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11570
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11571
|
+
var ROLLING_SPANS = [
|
|
11572
|
+
"1h",
|
|
11573
|
+
"24h",
|
|
11574
|
+
"2d",
|
|
11575
|
+
"7d",
|
|
11576
|
+
"30d",
|
|
11577
|
+
"custom"
|
|
11578
|
+
];
|
|
11579
|
+
var CALENDAR_PERIODS = [
|
|
11580
|
+
"today",
|
|
11581
|
+
"yesterday",
|
|
11582
|
+
"this-week",
|
|
11583
|
+
"this-month"
|
|
11584
|
+
];
|
|
11585
|
+
var RESET_PERIODS = [
|
|
11586
|
+
"never",
|
|
11587
|
+
"daily",
|
|
11588
|
+
"weekly",
|
|
11589
|
+
"monthly"
|
|
11590
|
+
];
|
|
11591
|
+
5 * MINUTE_MS;
|
|
11592
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11593
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11594
|
+
var rollingWindowObject = object({
|
|
11595
|
+
kind: literal("rolling"),
|
|
11596
|
+
span: _enum(ROLLING_SPANS),
|
|
11597
|
+
customMinutes: number().int().min(5).optional()
|
|
11598
|
+
}).check((payload) => {
|
|
11599
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11600
|
+
code: "custom",
|
|
11601
|
+
message: "a custom range needs a duration in minutes",
|
|
11602
|
+
path: ["customMinutes"],
|
|
11603
|
+
input: payload.value
|
|
11604
|
+
});
|
|
11605
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11606
|
+
code: "custom",
|
|
11607
|
+
message: "only a custom range carries a duration",
|
|
11608
|
+
path: ["customMinutes"],
|
|
11609
|
+
input: payload.value
|
|
11610
|
+
});
|
|
11611
|
+
});
|
|
11612
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11613
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11614
|
+
kind: literal("calendar"),
|
|
11615
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11616
|
+
})]);
|
|
11617
|
+
/**
|
|
11618
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11619
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11620
|
+
* `composition.ts` (D659).
|
|
11621
|
+
*/
|
|
11484
11622
|
var CompositionSourceRefSchema = object({
|
|
11485
11623
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11486
11624
|
addonId: string().min(1),
|
|
11487
11625
|
stableId: string().min(1)
|
|
11488
11626
|
});
|
|
11627
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11628
|
+
"temperature",
|
|
11629
|
+
"humidity",
|
|
11630
|
+
"pressure",
|
|
11631
|
+
"illuminance",
|
|
11632
|
+
"power",
|
|
11633
|
+
"energy",
|
|
11634
|
+
"battery",
|
|
11635
|
+
"numeric",
|
|
11636
|
+
"motion",
|
|
11637
|
+
"contact",
|
|
11638
|
+
"leak",
|
|
11639
|
+
"smoke",
|
|
11640
|
+
"occupancy",
|
|
11641
|
+
"binary",
|
|
11642
|
+
"switch",
|
|
11643
|
+
"light",
|
|
11644
|
+
"fan",
|
|
11645
|
+
"cover",
|
|
11646
|
+
"valve",
|
|
11647
|
+
"lock",
|
|
11648
|
+
"media-player",
|
|
11649
|
+
"climate"
|
|
11650
|
+
];
|
|
11651
|
+
var NUMERIC_AGGREGATES = [
|
|
11652
|
+
"mean",
|
|
11653
|
+
"median",
|
|
11654
|
+
"min",
|
|
11655
|
+
"max",
|
|
11656
|
+
"sum"
|
|
11657
|
+
];
|
|
11658
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11659
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11660
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11661
|
+
var AGGREGATE_REDUCERS = [
|
|
11662
|
+
"mean",
|
|
11663
|
+
"median",
|
|
11664
|
+
"min",
|
|
11665
|
+
"max",
|
|
11666
|
+
"sum",
|
|
11667
|
+
"any",
|
|
11668
|
+
"all"
|
|
11669
|
+
];
|
|
11670
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11671
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11672
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11673
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11674
|
+
var HelperMemberSchema = object({
|
|
11675
|
+
source: CompositionSourceRefSchema,
|
|
11676
|
+
cap: string().min(1),
|
|
11677
|
+
fieldPath: string().min(1)
|
|
11678
|
+
});
|
|
11679
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11680
|
+
object({
|
|
11681
|
+
kind: literal("group"),
|
|
11682
|
+
templateId: GroupTemplateIdSchema,
|
|
11683
|
+
aggregate: AggregateReducerSchema,
|
|
11684
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11685
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11686
|
+
active: ActiveCriterionSchema.optional()
|
|
11687
|
+
}),
|
|
11688
|
+
object({
|
|
11689
|
+
kind: literal("appliance"),
|
|
11690
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11691
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11692
|
+
thresholdWatts: number().positive(),
|
|
11693
|
+
startDwellMs: number().int().nonnegative(),
|
|
11694
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11695
|
+
member: HelperMemberSchema
|
|
11696
|
+
}),
|
|
11697
|
+
object({
|
|
11698
|
+
kind: literal("statistic"),
|
|
11699
|
+
stat: _enum(STATISTIC_STATS),
|
|
11700
|
+
window: StatisticWindowSchema,
|
|
11701
|
+
source: HelperMemberSchema
|
|
11702
|
+
}),
|
|
11703
|
+
object({
|
|
11704
|
+
kind: literal("integral"),
|
|
11705
|
+
reset: _enum(RESET_PERIODS),
|
|
11706
|
+
output: _enum(["energy", "meter"]),
|
|
11707
|
+
source: HelperMemberSchema
|
|
11708
|
+
}),
|
|
11709
|
+
object({
|
|
11710
|
+
kind: literal("threshold"),
|
|
11711
|
+
source: HelperMemberSchema,
|
|
11712
|
+
high: number(),
|
|
11713
|
+
low: number(),
|
|
11714
|
+
onForMs: number().int().nonnegative(),
|
|
11715
|
+
offForMs: number().int().nonnegative()
|
|
11716
|
+
}),
|
|
11717
|
+
object({
|
|
11718
|
+
kind: literal("arithmetic"),
|
|
11719
|
+
op: _enum([
|
|
11720
|
+
"sum",
|
|
11721
|
+
"difference",
|
|
11722
|
+
"ratio"
|
|
11723
|
+
]),
|
|
11724
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11725
|
+
}),
|
|
11726
|
+
object({
|
|
11727
|
+
kind: literal("expression"),
|
|
11728
|
+
expr: string().min(1),
|
|
11729
|
+
inputs: array(object({
|
|
11730
|
+
name: string().min(1),
|
|
11731
|
+
member: HelperMemberSchema
|
|
11732
|
+
})).min(1).max(64),
|
|
11733
|
+
output: _enum(["number", "boolean"])
|
|
11734
|
+
}),
|
|
11735
|
+
object({
|
|
11736
|
+
kind: literal("derivative"),
|
|
11737
|
+
window: RollingWindowSchema,
|
|
11738
|
+
per: _enum([
|
|
11739
|
+
"second",
|
|
11740
|
+
"minute",
|
|
11741
|
+
"hour"
|
|
11742
|
+
]),
|
|
11743
|
+
source: HelperMemberSchema
|
|
11744
|
+
})
|
|
11745
|
+
]);
|
|
11746
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11747
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11748
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11749
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11489
11750
|
/** One field of one capability of one source device. */
|
|
11490
11751
|
var CompositionFieldReadSchema = object({
|
|
11491
11752
|
source: CompositionSourceRefSchema,
|
|
@@ -11529,7 +11790,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11529
11790
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11530
11791
|
CompositionFromSourceSchema,
|
|
11531
11792
|
CompositionExpressionSourceSchema,
|
|
11532
|
-
CompositionCodeSourceSchema
|
|
11793
|
+
CompositionCodeSourceSchema,
|
|
11794
|
+
object({
|
|
11795
|
+
kind: literal("aggregate"),
|
|
11796
|
+
reducer: _enum([
|
|
11797
|
+
"mean",
|
|
11798
|
+
"median",
|
|
11799
|
+
"min",
|
|
11800
|
+
"max",
|
|
11801
|
+
"sum",
|
|
11802
|
+
"any",
|
|
11803
|
+
"all"
|
|
11804
|
+
]),
|
|
11805
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11806
|
+
/**
|
|
11807
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11808
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11809
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11810
|
+
*/
|
|
11811
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11812
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11813
|
+
publish: _enum([
|
|
11814
|
+
"value",
|
|
11815
|
+
"included",
|
|
11816
|
+
"excluded",
|
|
11817
|
+
"total"
|
|
11818
|
+
]),
|
|
11819
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11820
|
+
empty: _enum([
|
|
11821
|
+
"null",
|
|
11822
|
+
"omit",
|
|
11823
|
+
"offline"
|
|
11824
|
+
])
|
|
11825
|
+
}),
|
|
11826
|
+
object({
|
|
11827
|
+
kind: literal("series"),
|
|
11828
|
+
read: CompositionFieldReadSchema,
|
|
11829
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11830
|
+
publish: _enum([
|
|
11831
|
+
"value",
|
|
11832
|
+
"included",
|
|
11833
|
+
"excluded",
|
|
11834
|
+
"total"
|
|
11835
|
+
]),
|
|
11836
|
+
/**
|
|
11837
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11838
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11839
|
+
*/
|
|
11840
|
+
empty: _enum([
|
|
11841
|
+
"null",
|
|
11842
|
+
"omit",
|
|
11843
|
+
"offline"
|
|
11844
|
+
])
|
|
11845
|
+
})
|
|
11533
11846
|
]);
|
|
11534
11847
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11535
11848
|
kind: literal("forward"),
|
|
@@ -11575,7 +11888,13 @@ var CompositionSchema = object({
|
|
|
11575
11888
|
kind: literal("existing"),
|
|
11576
11889
|
device: CompositionSourceRefSchema
|
|
11577
11890
|
})]),
|
|
11578
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
11891
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
11892
|
+
/**
|
|
11893
|
+
* Present when the block is a helper template. Absent on a free
|
|
11894
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
11895
|
+
* never the compiled features.
|
|
11896
|
+
*/
|
|
11897
|
+
helper: HelperSpecSchema.optional()
|
|
11579
11898
|
}).superRefine((composition, ctx) => {
|
|
11580
11899
|
const seen = /* @__PURE__ */ new Set();
|
|
11581
11900
|
composition.features.forEach((feature, index) => {
|
|
@@ -16682,7 +17001,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16682
17001
|
*/
|
|
16683
17002
|
interactiveConnectPath: string().min(1).optional(),
|
|
16684
17003
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16685
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17004
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17005
|
+
/**
|
|
17006
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17007
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17008
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17009
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17010
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17011
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17012
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17013
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17014
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17015
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17016
|
+
* offers it as the default path; the fields the session fills are
|
|
17017
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17018
|
+
*/
|
|
17019
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16686
17020
|
}))
|
|
16687
17021
|
});
|
|
16688
17022
|
var ListInputSchema = object({
|
|
@@ -17677,7 +18011,12 @@ var CompositionProblemSchema = object({
|
|
|
17677
18011
|
"item-field-reserved",
|
|
17678
18012
|
"target-missing",
|
|
17679
18013
|
"target-unreadable",
|
|
17680
|
-
"not-replaceable"
|
|
18014
|
+
"not-replaceable",
|
|
18015
|
+
"native-capability-replace",
|
|
18016
|
+
"mixed-quantity",
|
|
18017
|
+
"helper-mismatch",
|
|
18018
|
+
"member-constraint",
|
|
18019
|
+
"retention"
|
|
17681
18020
|
]),
|
|
17682
18021
|
path: string(),
|
|
17683
18022
|
message: string()
|
|
@@ -17698,7 +18037,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17698
18037
|
"null",
|
|
17699
18038
|
"offline",
|
|
17700
18039
|
"unknown",
|
|
17701
|
-
"release"
|
|
18040
|
+
"release",
|
|
18041
|
+
"omit"
|
|
17702
18042
|
]);
|
|
17703
18043
|
/**
|
|
17704
18044
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17735,9 +18075,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17735
18075
|
reads: array(CompositionFieldReadSchema)
|
|
17736
18076
|
});
|
|
17737
18077
|
/**
|
|
17738
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17739
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17740
|
-
*
|
|
18078
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18079
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18080
|
+
* Replacing a capability the device already serves is refused
|
|
18081
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18082
|
+
* wire for a claim the hub already holds.
|
|
17741
18083
|
*/
|
|
17742
18084
|
var CompositionFeatureModeSchema = _enum([
|
|
17743
18085
|
"new",
|
|
@@ -17908,8 +18250,392 @@ Object.freeze({
|
|
|
17908
18250
|
latchedAt: {
|
|
17909
18251
|
kind: "fixed",
|
|
17910
18252
|
result: ["number", "null"]
|
|
18253
|
+
},
|
|
18254
|
+
schmitt: {
|
|
18255
|
+
kind: "fixed",
|
|
18256
|
+
result: ["boolean", "null"]
|
|
17911
18257
|
}
|
|
17912
18258
|
});
|
|
18259
|
+
/**
|
|
18260
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18261
|
+
* Data, not a form default written into the block.
|
|
18262
|
+
*/
|
|
18263
|
+
var NOW$2 = {
|
|
18264
|
+
fieldPath: "lastFetchedAt",
|
|
18265
|
+
expr: "now"
|
|
18266
|
+
};
|
|
18267
|
+
var CHANGED = {
|
|
18268
|
+
fieldPath: "lastChangedAt",
|
|
18269
|
+
expr: "now"
|
|
18270
|
+
};
|
|
18271
|
+
function numeric(input) {
|
|
18272
|
+
return {
|
|
18273
|
+
...input,
|
|
18274
|
+
family: "numeric",
|
|
18275
|
+
deviceType: DeviceType.Sensor,
|
|
18276
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18277
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18278
|
+
activeWhen: void 0,
|
|
18279
|
+
commandCaps: [],
|
|
18280
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18281
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18282
|
+
accept: [{
|
|
18283
|
+
cap: input.outputCap,
|
|
18284
|
+
fieldPath: input.outputField
|
|
18285
|
+
}]
|
|
18286
|
+
};
|
|
18287
|
+
}
|
|
18288
|
+
function binary(input) {
|
|
18289
|
+
return {
|
|
18290
|
+
...input,
|
|
18291
|
+
family: "binary",
|
|
18292
|
+
deviceType: DeviceType.Sensor,
|
|
18293
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18294
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18295
|
+
activeWhen: void 0,
|
|
18296
|
+
commandCaps: [],
|
|
18297
|
+
quantity: "none",
|
|
18298
|
+
baseUnit: void 0,
|
|
18299
|
+
aggregates: BINARY_AGGREGATES,
|
|
18300
|
+
empty: "offline"
|
|
18301
|
+
};
|
|
18302
|
+
}
|
|
18303
|
+
var GROUP_TEMPLATES = [
|
|
18304
|
+
numeric({
|
|
18305
|
+
id: "temperature",
|
|
18306
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18307
|
+
role: DeviceRole.TemperatureSensor,
|
|
18308
|
+
outputCap: "temperature-sensor",
|
|
18309
|
+
outputField: "celsius",
|
|
18310
|
+
quantity: "temperature",
|
|
18311
|
+
defaultAggregate: "mean",
|
|
18312
|
+
empty: "null",
|
|
18313
|
+
companions: [NOW$2]
|
|
18314
|
+
}),
|
|
18315
|
+
numeric({
|
|
18316
|
+
id: "humidity",
|
|
18317
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18318
|
+
role: DeviceRole.HumiditySensor,
|
|
18319
|
+
outputCap: "humidity-sensor",
|
|
18320
|
+
outputField: "percent",
|
|
18321
|
+
quantity: "humidity",
|
|
18322
|
+
defaultAggregate: "mean",
|
|
18323
|
+
empty: "null",
|
|
18324
|
+
companions: [NOW$2]
|
|
18325
|
+
}),
|
|
18326
|
+
numeric({
|
|
18327
|
+
id: "pressure",
|
|
18328
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18329
|
+
role: DeviceRole.PressureSensor,
|
|
18330
|
+
outputCap: "pressure-sensor",
|
|
18331
|
+
outputField: "hpa",
|
|
18332
|
+
quantity: "pressure",
|
|
18333
|
+
defaultAggregate: "mean",
|
|
18334
|
+
empty: "null",
|
|
18335
|
+
companions: [NOW$2]
|
|
18336
|
+
}),
|
|
18337
|
+
numeric({
|
|
18338
|
+
id: "illuminance",
|
|
18339
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18340
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18341
|
+
outputCap: "ambient-light-sensor",
|
|
18342
|
+
outputField: "lux",
|
|
18343
|
+
quantity: "illuminance",
|
|
18344
|
+
defaultAggregate: "mean",
|
|
18345
|
+
empty: "null",
|
|
18346
|
+
companions: [NOW$2]
|
|
18347
|
+
}),
|
|
18348
|
+
numeric({
|
|
18349
|
+
id: "power",
|
|
18350
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18351
|
+
role: DeviceRole.PowerSensor,
|
|
18352
|
+
outputCap: "power-meter",
|
|
18353
|
+
outputField: "watts",
|
|
18354
|
+
quantity: "power",
|
|
18355
|
+
defaultAggregate: "sum",
|
|
18356
|
+
empty: "omit",
|
|
18357
|
+
companions: [NOW$2]
|
|
18358
|
+
}),
|
|
18359
|
+
numeric({
|
|
18360
|
+
id: "energy",
|
|
18361
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18362
|
+
role: DeviceRole.EnergySensor,
|
|
18363
|
+
outputCap: "power-meter",
|
|
18364
|
+
outputField: "kwhTotal",
|
|
18365
|
+
quantity: "energy",
|
|
18366
|
+
defaultAggregate: "sum",
|
|
18367
|
+
empty: "omit",
|
|
18368
|
+
companions: [NOW$2]
|
|
18369
|
+
}),
|
|
18370
|
+
numeric({
|
|
18371
|
+
id: "battery",
|
|
18372
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18373
|
+
role: DeviceRole.BatterySensor,
|
|
18374
|
+
outputCap: "battery",
|
|
18375
|
+
outputField: "percentage",
|
|
18376
|
+
quantity: "percentage",
|
|
18377
|
+
defaultAggregate: "mean",
|
|
18378
|
+
empty: "null",
|
|
18379
|
+
companions: [
|
|
18380
|
+
{
|
|
18381
|
+
fieldPath: "charging",
|
|
18382
|
+
expr: "\"unknown\""
|
|
18383
|
+
},
|
|
18384
|
+
{
|
|
18385
|
+
fieldPath: "sleeping",
|
|
18386
|
+
expr: "false"
|
|
18387
|
+
},
|
|
18388
|
+
{
|
|
18389
|
+
fieldPath: "lastUpdated",
|
|
18390
|
+
expr: "now"
|
|
18391
|
+
}
|
|
18392
|
+
]
|
|
18393
|
+
}),
|
|
18394
|
+
numeric({
|
|
18395
|
+
id: "numeric",
|
|
18396
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18397
|
+
role: DeviceRole.NumericSensor,
|
|
18398
|
+
outputCap: "numeric-sensor",
|
|
18399
|
+
outputField: "value",
|
|
18400
|
+
quantity: "device",
|
|
18401
|
+
defaultAggregate: "mean",
|
|
18402
|
+
empty: "null",
|
|
18403
|
+
companions: [NOW$2]
|
|
18404
|
+
}),
|
|
18405
|
+
binary({
|
|
18406
|
+
id: "motion",
|
|
18407
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18408
|
+
role: DeviceRole.MotionSensor,
|
|
18409
|
+
outputCap: "motion",
|
|
18410
|
+
outputField: "detected",
|
|
18411
|
+
defaultAggregate: "any",
|
|
18412
|
+
accept: [{
|
|
18413
|
+
cap: "motion",
|
|
18414
|
+
fieldPath: "detected"
|
|
18415
|
+
}],
|
|
18416
|
+
companions: [{
|
|
18417
|
+
fieldPath: "lastDetectedAt",
|
|
18418
|
+
expr: "null"
|
|
18419
|
+
}, {
|
|
18420
|
+
fieldPath: "autoClearAfterMs",
|
|
18421
|
+
expr: "null"
|
|
18422
|
+
}]
|
|
18423
|
+
}),
|
|
18424
|
+
binary({
|
|
18425
|
+
id: "contact",
|
|
18426
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18427
|
+
role: DeviceRole.ContactSensor,
|
|
18428
|
+
outputCap: "contact",
|
|
18429
|
+
outputField: "entryOpen",
|
|
18430
|
+
defaultAggregate: "any",
|
|
18431
|
+
accept: [{
|
|
18432
|
+
cap: "contact",
|
|
18433
|
+
fieldPath: "entryOpen"
|
|
18434
|
+
}],
|
|
18435
|
+
companions: [CHANGED]
|
|
18436
|
+
}),
|
|
18437
|
+
binary({
|
|
18438
|
+
id: "leak",
|
|
18439
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18440
|
+
role: DeviceRole.LeakSensor,
|
|
18441
|
+
outputCap: "flood",
|
|
18442
|
+
outputField: "flooded",
|
|
18443
|
+
defaultAggregate: "any",
|
|
18444
|
+
accept: [{
|
|
18445
|
+
cap: "flood",
|
|
18446
|
+
fieldPath: "flooded"
|
|
18447
|
+
}],
|
|
18448
|
+
companions: [CHANGED]
|
|
18449
|
+
}),
|
|
18450
|
+
binary({
|
|
18451
|
+
id: "smoke",
|
|
18452
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18453
|
+
role: DeviceRole.SmokeSensor,
|
|
18454
|
+
outputCap: "smoke",
|
|
18455
|
+
outputField: "detected",
|
|
18456
|
+
defaultAggregate: "any",
|
|
18457
|
+
accept: [{
|
|
18458
|
+
cap: "smoke",
|
|
18459
|
+
fieldPath: "detected"
|
|
18460
|
+
}],
|
|
18461
|
+
companions: [CHANGED]
|
|
18462
|
+
}),
|
|
18463
|
+
binary({
|
|
18464
|
+
id: "occupancy",
|
|
18465
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18466
|
+
role: DeviceRole.BinarySensor,
|
|
18467
|
+
outputCap: "binary",
|
|
18468
|
+
outputField: "on",
|
|
18469
|
+
defaultAggregate: "any",
|
|
18470
|
+
accept: [{
|
|
18471
|
+
cap: "motion",
|
|
18472
|
+
fieldPath: "detected"
|
|
18473
|
+
}, {
|
|
18474
|
+
cap: "binary",
|
|
18475
|
+
fieldPath: "on"
|
|
18476
|
+
}],
|
|
18477
|
+
companions: [CHANGED]
|
|
18478
|
+
}),
|
|
18479
|
+
binary({
|
|
18480
|
+
id: "binary",
|
|
18481
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18482
|
+
role: DeviceRole.BinarySensor,
|
|
18483
|
+
outputCap: "binary",
|
|
18484
|
+
outputField: "on",
|
|
18485
|
+
defaultAggregate: "any",
|
|
18486
|
+
accept: [{
|
|
18487
|
+
cap: "binary",
|
|
18488
|
+
fieldPath: "on"
|
|
18489
|
+
}],
|
|
18490
|
+
companions: [CHANGED]
|
|
18491
|
+
}),
|
|
18492
|
+
actuator({
|
|
18493
|
+
id: "switch",
|
|
18494
|
+
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.",
|
|
18495
|
+
deviceType: DeviceType.Switch,
|
|
18496
|
+
outputCap: "switch",
|
|
18497
|
+
outputField: "on",
|
|
18498
|
+
member: {
|
|
18499
|
+
cap: "switch",
|
|
18500
|
+
fieldPath: "on"
|
|
18501
|
+
},
|
|
18502
|
+
commandCaps: ["switch"]
|
|
18503
|
+
}),
|
|
18504
|
+
actuator({
|
|
18505
|
+
id: "light",
|
|
18506
|
+
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.",
|
|
18507
|
+
deviceType: DeviceType.Light,
|
|
18508
|
+
outputCap: "switch",
|
|
18509
|
+
outputField: "on",
|
|
18510
|
+
member: {
|
|
18511
|
+
cap: "switch",
|
|
18512
|
+
fieldPath: "on"
|
|
18513
|
+
},
|
|
18514
|
+
commandCaps: [
|
|
18515
|
+
"switch",
|
|
18516
|
+
"brightness",
|
|
18517
|
+
"color"
|
|
18518
|
+
]
|
|
18519
|
+
}),
|
|
18520
|
+
actuator({
|
|
18521
|
+
id: "fan",
|
|
18522
|
+
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.",
|
|
18523
|
+
deviceType: DeviceType.Fan,
|
|
18524
|
+
outputCap: "switch",
|
|
18525
|
+
outputField: "on",
|
|
18526
|
+
member: {
|
|
18527
|
+
cap: "switch",
|
|
18528
|
+
fieldPath: "on"
|
|
18529
|
+
},
|
|
18530
|
+
commandCaps: ["switch", "fan-control"]
|
|
18531
|
+
}),
|
|
18532
|
+
actuator({
|
|
18533
|
+
id: "cover",
|
|
18534
|
+
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.",
|
|
18535
|
+
deviceType: DeviceType.Cover,
|
|
18536
|
+
outputCap: "group-active",
|
|
18537
|
+
outputField: "active",
|
|
18538
|
+
member: {
|
|
18539
|
+
cap: "cover",
|
|
18540
|
+
fieldPath: "state"
|
|
18541
|
+
},
|
|
18542
|
+
activeWhen: [
|
|
18543
|
+
"open",
|
|
18544
|
+
"opening",
|
|
18545
|
+
"stopped"
|
|
18546
|
+
],
|
|
18547
|
+
commandCaps: ["cover"]
|
|
18548
|
+
}),
|
|
18549
|
+
actuator({
|
|
18550
|
+
id: "valve",
|
|
18551
|
+
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.",
|
|
18552
|
+
deviceType: DeviceType.Valve,
|
|
18553
|
+
outputCap: "group-active",
|
|
18554
|
+
outputField: "active",
|
|
18555
|
+
member: {
|
|
18556
|
+
cap: "valve",
|
|
18557
|
+
fieldPath: "state"
|
|
18558
|
+
},
|
|
18559
|
+
activeWhen: [
|
|
18560
|
+
"open",
|
|
18561
|
+
"opening",
|
|
18562
|
+
"stopped"
|
|
18563
|
+
],
|
|
18564
|
+
commandCaps: ["valve"]
|
|
18565
|
+
}),
|
|
18566
|
+
actuator({
|
|
18567
|
+
id: "lock",
|
|
18568
|
+
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.",
|
|
18569
|
+
deviceType: DeviceType.Lock,
|
|
18570
|
+
outputCap: "group-active",
|
|
18571
|
+
outputField: "active",
|
|
18572
|
+
member: {
|
|
18573
|
+
cap: "lock-control",
|
|
18574
|
+
fieldPath: "state"
|
|
18575
|
+
},
|
|
18576
|
+
activeWhen: ["locked"],
|
|
18577
|
+
commandCaps: ["lock-control"]
|
|
18578
|
+
}),
|
|
18579
|
+
actuator({
|
|
18580
|
+
id: "media-player",
|
|
18581
|
+
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.",
|
|
18582
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18583
|
+
outputCap: "group-active",
|
|
18584
|
+
outputField: "active",
|
|
18585
|
+
member: {
|
|
18586
|
+
cap: "media-player",
|
|
18587
|
+
fieldPath: "state"
|
|
18588
|
+
},
|
|
18589
|
+
activeWhen: ["playing", "buffering"],
|
|
18590
|
+
commandCaps: ["media-player"]
|
|
18591
|
+
}),
|
|
18592
|
+
actuator({
|
|
18593
|
+
id: "climate",
|
|
18594
|
+
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.",
|
|
18595
|
+
deviceType: DeviceType.Thermostat,
|
|
18596
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18597
|
+
outputCap: "group-active",
|
|
18598
|
+
outputField: "active",
|
|
18599
|
+
member: {
|
|
18600
|
+
cap: "climate-control",
|
|
18601
|
+
fieldPath: "mode"
|
|
18602
|
+
},
|
|
18603
|
+
activeWhen: [
|
|
18604
|
+
"heat",
|
|
18605
|
+
"cool",
|
|
18606
|
+
"auto",
|
|
18607
|
+
"heat_cool",
|
|
18608
|
+
"fan_only",
|
|
18609
|
+
"dry"
|
|
18610
|
+
],
|
|
18611
|
+
commandCaps: ["climate-control"]
|
|
18612
|
+
})
|
|
18613
|
+
];
|
|
18614
|
+
function actuator(input) {
|
|
18615
|
+
return {
|
|
18616
|
+
id: input.id,
|
|
18617
|
+
summary: input.summary,
|
|
18618
|
+
deviceType: input.deviceType,
|
|
18619
|
+
outputCap: input.outputCap,
|
|
18620
|
+
outputField: input.outputField,
|
|
18621
|
+
commandCaps: input.commandCaps,
|
|
18622
|
+
family: "actuator",
|
|
18623
|
+
role: void 0,
|
|
18624
|
+
memberDeviceType: input.deviceType,
|
|
18625
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18626
|
+
activeWhen: input.activeWhen,
|
|
18627
|
+
quantity: "none",
|
|
18628
|
+
baseUnit: void 0,
|
|
18629
|
+
aggregates: BINARY_AGGREGATES,
|
|
18630
|
+
defaultAggregate: "any",
|
|
18631
|
+
empty: "offline",
|
|
18632
|
+
accept: [input.member],
|
|
18633
|
+
companions: [CHANGED]
|
|
18634
|
+
};
|
|
18635
|
+
}
|
|
18636
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18637
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18638
|
+
DeviceType.Camera;
|
|
17913
18639
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
17914
18640
|
/**
|
|
17915
18641
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19736,12 +20462,12 @@ function buildDeviceAdminUrl(parts) {
|
|
|
19736
20462
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19737
20463
|
* in-place so dispatch keeps working.
|
|
19738
20464
|
*
|
|
19739
|
-
* **
|
|
19740
|
-
*
|
|
19741
|
-
*
|
|
19742
|
-
*
|
|
19743
|
-
* (`ha-domain-mapping`)
|
|
19744
|
-
* stored after that point.
|
|
20465
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20466
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20467
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20468
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20469
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20470
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19745
20471
|
*
|
|
19746
20472
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19747
20473
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19755,6 +20481,14 @@ var SourceInfoSchema = object({
|
|
|
19755
20481
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19756
20482
|
* Used to detect rename when `id` changes. */
|
|
19757
20483
|
uniqueId: string().optional(),
|
|
20484
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20485
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20486
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20487
|
+
dateTimeShape: _enum([
|
|
20488
|
+
"date",
|
|
20489
|
+
"time",
|
|
20490
|
+
"datetime"
|
|
20491
|
+
]).optional(),
|
|
19758
20492
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19759
20493
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19760
20494
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -40748,7 +41482,8 @@ method(object({
|
|
|
40748
41482
|
"enum"
|
|
40749
41483
|
]),
|
|
40750
41484
|
enumValues: array(string()).optional(),
|
|
40751
|
-
item: boolean().optional()
|
|
41485
|
+
item: boolean().optional(),
|
|
41486
|
+
quantity: ReadingQuantitySchema.optional()
|
|
40752
41487
|
})).readonly(),
|
|
40753
41488
|
itemArray: object({
|
|
40754
41489
|
path: string(),
|
|
@@ -43109,7 +43844,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43109
43844
|
});
|
|
43110
43845
|
/**
|
|
43111
43846
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43112
|
-
* MORE than one ingress concurrently (Tailscale
|
|
43847
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43113
43848
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43114
43849
|
* the originating provider config (mode + sourcePort) so the
|
|
43115
43850
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44548,8 +45283,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44548
45283
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44549
45284
|
var MaskGridShapeSchema = object({
|
|
44550
45285
|
kind: literal("grid"),
|
|
44551
|
-
gridWidth: number(),
|
|
44552
|
-
gridHeight: number(),
|
|
45286
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45287
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44553
45288
|
cells: array(boolean())
|
|
44554
45289
|
});
|
|
44555
45290
|
discriminatedUnion("kind", [
|
|
@@ -44661,6 +45396,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44661
45396
|
"detection-blind",
|
|
44662
45397
|
"motion-noisy",
|
|
44663
45398
|
"motion-calm",
|
|
45399
|
+
"package-llm-silent",
|
|
45400
|
+
"package-llm-answered",
|
|
44664
45401
|
"recording-stalled",
|
|
44665
45402
|
"recording-healthy",
|
|
44666
45403
|
"recording-degraded",
|
|
@@ -45750,7 +46487,20 @@ var NcRuleInputSchema = object({
|
|
|
45750
46487
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
45751
46488
|
* path does not run Zod defaults.
|
|
45752
46489
|
*/
|
|
45753
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46490
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46491
|
+
/**
|
|
46492
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46493
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46494
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46495
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46496
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46497
|
+
*
|
|
46498
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46499
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46500
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46501
|
+
* `false`, so it needs no `clear` key.
|
|
46502
|
+
*/
|
|
46503
|
+
askVerdict: boolean().optional()
|
|
45754
46504
|
});
|
|
45755
46505
|
/**
|
|
45756
46506
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -55779,6 +56529,28 @@ var PackageVersionInfoSchema = object({
|
|
|
55779
56529
|
deprecated: string().optional(),
|
|
55780
56530
|
distTags: array(string()).readonly()
|
|
55781
56531
|
});
|
|
56532
|
+
/**
|
|
56533
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56534
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56535
|
+
* tarball failure — never an empty string standing in for either.
|
|
56536
|
+
*/
|
|
56537
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56538
|
+
object({
|
|
56539
|
+
status: literal("ok"),
|
|
56540
|
+
markdown: string()
|
|
56541
|
+
}),
|
|
56542
|
+
object({ status: literal("missing") }),
|
|
56543
|
+
object({
|
|
56544
|
+
status: literal("error"),
|
|
56545
|
+
message: string()
|
|
56546
|
+
})
|
|
56547
|
+
]);
|
|
56548
|
+
var PackageDocsSchema = object({
|
|
56549
|
+
name: string(),
|
|
56550
|
+
version: string(),
|
|
56551
|
+
readme: PackageDocBodySchema,
|
|
56552
|
+
changelog: PackageDocBodySchema
|
|
56553
|
+
});
|
|
55782
56554
|
var SearchResultSchema = object({
|
|
55783
56555
|
name: string(),
|
|
55784
56556
|
version: string(),
|
|
@@ -55997,7 +56769,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
55997
56769
|
}), object({ success: literal(true) }), {
|
|
55998
56770
|
kind: "mutation",
|
|
55999
56771
|
auth: "admin"
|
|
56000
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56772
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56773
|
+
name: string().min(1),
|
|
56774
|
+
version: string().min(1).optional()
|
|
56775
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56001
56776
|
kind: "mutation",
|
|
56002
56777
|
auth: "admin"
|
|
56003
56778
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56047,46 +56822,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56047
56822
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56048
56823
|
object({
|
|
56049
56824
|
/** Carbon dioxide concentration in ppm. */
|
|
56050
|
-
co2Ppm: number().min(0).optional(),
|
|
56825
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56051
56826
|
/** Total volatile organic compounds in ppb. */
|
|
56052
|
-
vocPpb: number().min(0).optional(),
|
|
56827
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56053
56828
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56054
|
-
pm25: number().min(0).optional(),
|
|
56829
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56055
56830
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56056
|
-
pm10: number().min(0).optional(),
|
|
56831
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56057
56832
|
/** Composite AQI value (typically 0..500). */
|
|
56058
|
-
aqi: number().optional(),
|
|
56833
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56059
56834
|
/** Ms epoch when the slice was last updated. */
|
|
56060
|
-
lastFetchedAt: number()
|
|
56061
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56062
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56063
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56064
|
-
* per slice is unambiguous. */
|
|
56065
|
-
unit: string().optional(),
|
|
56066
|
-
/** Suggested decimal places for numeric display.
|
|
56067
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56068
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56069
|
-
* auto-formatting when absent. */
|
|
56070
|
-
precision: number().int().min(0).max(10).optional()
|
|
56835
|
+
lastFetchedAt: number()
|
|
56071
56836
|
});
|
|
56072
56837
|
DeviceType.Sensor;
|
|
56073
56838
|
object({
|
|
56074
|
-
/** Current illuminance in lux (lx). */
|
|
56075
|
-
lux: number().min(0).meta({
|
|
56076
|
-
|
|
56839
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
56840
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
56841
|
+
precision: 0,
|
|
56077
56842
|
label: "Illuminance"
|
|
56078
|
-
}),
|
|
56843
|
+
})),
|
|
56079
56844
|
/** Ms epoch when the slice was last updated. */
|
|
56080
|
-
lastFetchedAt: number()
|
|
56081
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56082
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56083
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56084
|
-
unit: string().optional(),
|
|
56085
|
-
/** Suggested decimal places for numeric display.
|
|
56086
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56087
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56088
|
-
* auto-formatting when absent. */
|
|
56089
|
-
precision: number().int().min(0).max(10).optional()
|
|
56845
|
+
lastFetchedAt: number()
|
|
56090
56846
|
});
|
|
56091
56847
|
DeviceType.Sensor;
|
|
56092
56848
|
/**
|
|
@@ -56231,10 +56987,7 @@ var BatteryStatusSchema = object({
|
|
|
56231
56987
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56232
56988
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56233
56989
|
*/
|
|
56234
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56235
|
-
unit: "%",
|
|
56236
|
-
label: "Charge"
|
|
56237
|
-
}),
|
|
56990
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56238
56991
|
/**
|
|
56239
56992
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56240
56993
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56261,7 +57014,14 @@ var BatteryStatusSchema = object({
|
|
|
56261
57014
|
*/
|
|
56262
57015
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56263
57016
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56264
|
-
lastUpdated: number(),
|
|
57017
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57018
|
+
/**
|
|
57019
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57020
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57021
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57022
|
+
* `numeric-sensor` on the same device.
|
|
57023
|
+
*/
|
|
57024
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56265
57025
|
/**
|
|
56266
57026
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56267
57027
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56301,7 +57061,7 @@ var BatteryStatusSchema = object({
|
|
|
56301
57061
|
*/
|
|
56302
57062
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56303
57063
|
});
|
|
56304
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57064
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56305
57065
|
method(object({
|
|
56306
57066
|
deviceId: number(),
|
|
56307
57067
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56321,7 +57081,7 @@ object({
|
|
|
56321
57081
|
DeviceType.Sensor;
|
|
56322
57082
|
object({
|
|
56323
57083
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56324
|
-
percentage: number().min(0).max(100),
|
|
57084
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56325
57085
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56326
57086
|
lastChangedAt: number()
|
|
56327
57087
|
});
|
|
@@ -56706,21 +57466,21 @@ object({
|
|
|
56706
57466
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
56707
57467
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
56708
57468
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
56709
|
-
target: number().nullable(),
|
|
57469
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
56710
57470
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
56711
57471
|
* in `heat_cool` mode. */
|
|
56712
|
-
targetHigh: number().nullable(),
|
|
57472
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
56713
57473
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
56714
57474
|
* in `heat_cool` mode. */
|
|
56715
|
-
targetLow: number().nullable(),
|
|
57475
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
56716
57476
|
/** Target relative humidity (0..100). Null when the device has no
|
|
56717
57477
|
* humidity control. */
|
|
56718
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57478
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56719
57479
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
56720
57480
|
* the device's internal sensor. */
|
|
56721
|
-
currentTemp: number().nullable(),
|
|
57481
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
56722
57482
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
56723
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57483
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56724
57484
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
56725
57485
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
56726
57486
|
swingVertical: boolean().nullable(),
|
|
@@ -56728,11 +57488,11 @@ object({
|
|
|
56728
57488
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
56729
57489
|
swingHorizontal: boolean().nullable(),
|
|
56730
57490
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56731
|
-
minTemp: number().nullable().optional(),
|
|
57491
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56732
57492
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56733
|
-
maxTemp: number().nullable().optional(),
|
|
57493
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56734
57494
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
56735
|
-
tempStep: number().positive().nullable().optional(),
|
|
57495
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
56736
57496
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
56737
57497
|
lastFetchedAt: number()
|
|
56738
57498
|
});
|
|
@@ -56811,17 +57571,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
56811
57571
|
* modes to expose in the picker without a slice fetch.
|
|
56812
57572
|
*/
|
|
56813
57573
|
var RgbTripletSchema = object({
|
|
56814
|
-
r: number().int().min(0).max(255),
|
|
56815
|
-
g: number().int().min(0).max(255),
|
|
56816
|
-
b: number().int().min(0).max(255)
|
|
57574
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57575
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57576
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
56817
57577
|
});
|
|
56818
57578
|
var HsvTripletSchema = object({
|
|
56819
57579
|
/** Hue in degrees, 0..360. */
|
|
56820
|
-
h: number().min(0).max(360),
|
|
57580
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
56821
57581
|
/** Saturation as 0..100 inclusive. */
|
|
56822
|
-
s: number().min(0).max(100),
|
|
57582
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
56823
57583
|
/** Value/brightness as 0..100 inclusive. */
|
|
56824
|
-
v: number().min(0).max(100)
|
|
57584
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
56825
57585
|
});
|
|
56826
57586
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
56827
57587
|
object({
|
|
@@ -56850,7 +57610,7 @@ object({
|
|
|
56850
57610
|
/** Populated when `mode === 'hsv'`. */
|
|
56851
57611
|
hsv: HsvTripletSchema.optional(),
|
|
56852
57612
|
/** Populated when `mode === 'mired'`. */
|
|
56853
|
-
mireds: number().int().optional(),
|
|
57613
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
56854
57614
|
/** Ms epoch of the last operator-driven change. */
|
|
56855
57615
|
lastChangedAt: number()
|
|
56856
57616
|
});
|
|
@@ -56974,18 +57734,12 @@ _enum([
|
|
|
56974
57734
|
"empty",
|
|
56975
57735
|
"full"
|
|
56976
57736
|
]);
|
|
56977
|
-
/**
|
|
56978
|
-
|
|
56979
|
-
|
|
56980
|
-
"days",
|
|
56981
|
-
"hours",
|
|
56982
|
-
"cycles"
|
|
56983
|
-
]);
|
|
56984
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
56985
|
-
* days). `value` null = unknown (D393). */
|
|
57737
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
57738
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
57739
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
56986
57740
|
var ConsumableRemainingSchema = object({
|
|
56987
|
-
value: number().min(0).nullable(),
|
|
56988
|
-
|
|
57741
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
57742
|
+
kind: ConsumableRemainingKindSchema
|
|
56989
57743
|
});
|
|
56990
57744
|
var ConsumablesStatusSchema = object({
|
|
56991
57745
|
items: array(object({
|
|
@@ -56994,7 +57748,7 @@ var ConsumablesStatusSchema = object({
|
|
|
56994
57748
|
/** Display name. */
|
|
56995
57749
|
label: string().min(1),
|
|
56996
57750
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
56997
|
-
level: number().min(0).max(100).nullable(),
|
|
57751
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
56998
57752
|
/** The provider's discrete verdict when known (binary mode). */
|
|
56999
57753
|
status: ConsumableStatusSchema.nullable(),
|
|
57000
57754
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57011,7 +57765,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57011
57765
|
})),
|
|
57012
57766
|
lastChangedAt: number()
|
|
57013
57767
|
});
|
|
57014
|
-
Object.values(DeviceType), [...
|
|
57768
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57015
57769
|
Object.values(DeviceType), method(object({
|
|
57016
57770
|
deviceId: number().int().nonnegative(),
|
|
57017
57771
|
key: string().min(1)
|
|
@@ -57036,39 +57790,17 @@ object({
|
|
|
57036
57790
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57037
57791
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57038
57792
|
* or time-only — HA accepts all three forms). */
|
|
57039
|
-
value: union([number(), string()]),
|
|
57793
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57040
57794
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57041
57795
|
options: array(string()),
|
|
57042
57796
|
/** Ms epoch when the slice was last updated. */
|
|
57043
57797
|
lastChangedAt: number(),
|
|
57044
|
-
/**
|
|
57045
|
-
|
|
57046
|
-
|
|
57047
|
-
|
|
57048
|
-
/**
|
|
57049
|
-
|
|
57050
|
-
min: number().optional(),
|
|
57051
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57052
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57053
|
-
max: number().optional(),
|
|
57054
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57055
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57056
|
-
step: number().optional(),
|
|
57057
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57058
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57059
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57060
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57061
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57062
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57063
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57064
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57065
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57066
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57067
|
-
format: _enum([
|
|
57068
|
-
"date",
|
|
57069
|
-
"time",
|
|
57070
|
-
"datetime"
|
|
57071
|
-
]).optional()
|
|
57798
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
57799
|
+
min: number().optional().meta(readingMeta("device")),
|
|
57800
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
57801
|
+
max: number().optional().meta(readingMeta("device")),
|
|
57802
|
+
/** Step increment, in the device quantity's base unit. */
|
|
57803
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57072
57804
|
});
|
|
57073
57805
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57074
57806
|
object({
|
|
@@ -57106,9 +57838,9 @@ object({
|
|
|
57106
57838
|
]),
|
|
57107
57839
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57108
57840
|
* no intermediate position surface. */
|
|
57109
|
-
position: number().min(0).max(100).nullable(),
|
|
57841
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57110
57842
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57111
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
57843
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57112
57844
|
/** Ms epoch when the slice was last updated. */
|
|
57113
57845
|
lastChangedAt: number()
|
|
57114
57846
|
});
|
|
@@ -57166,9 +57898,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57166
57898
|
object({
|
|
57167
57899
|
mode: DayNightModeSchema,
|
|
57168
57900
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57169
|
-
sensitivity: number().optional(),
|
|
57901
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57170
57902
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57171
|
-
switchDelaySec: number().optional(),
|
|
57903
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57172
57904
|
lastFetchedAt: number()
|
|
57173
57905
|
});
|
|
57174
57906
|
/**
|
|
@@ -57323,11 +58055,11 @@ object({
|
|
|
57323
58055
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57324
58056
|
availablePrograms: array(string()),
|
|
57325
58057
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57326
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58058
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57327
58059
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57328
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58060
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57329
58061
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57330
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58062
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57331
58063
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57332
58064
|
doorOpen: boolean().nullable(),
|
|
57333
58065
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57351,7 +58083,7 @@ object({
|
|
|
57351
58083
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57352
58084
|
machineCareDue: boolean().nullable(),
|
|
57353
58085
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57354
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58086
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57355
58087
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57356
58088
|
halfLoad: boolean().nullable(),
|
|
57357
58089
|
hygienePlus: boolean().nullable(),
|
|
@@ -57366,7 +58098,7 @@ object({
|
|
|
57366
58098
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57367
58099
|
activeEvents: array(string()),
|
|
57368
58100
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57369
|
-
errorCode: number().nullable(),
|
|
58101
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57370
58102
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57371
58103
|
errorLabel: string().nullable(),
|
|
57372
58104
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -57512,24 +58244,14 @@ object({
|
|
|
57512
58244
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
57513
58245
|
lastPressedAt: number().nullable(),
|
|
57514
58246
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
57515
|
-
pressCountSinceStart: number()
|
|
58247
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
57516
58248
|
});
|
|
57517
58249
|
object({
|
|
57518
58250
|
deviceId: number(),
|
|
57519
58251
|
timestamp: number()
|
|
57520
58252
|
});
|
|
57521
58253
|
DeviceType.Button, DeviceType.Camera;
|
|
57522
|
-
|
|
57523
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
57524
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
57525
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
57526
|
-
* The option set is stable across observations; it is persisted in the
|
|
57527
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
57528
|
-
* stored in `sourceInfo`.
|
|
57529
|
-
*/
|
|
57530
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
57531
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
57532
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58254
|
+
_enum([
|
|
57533
58255
|
"date",
|
|
57534
58256
|
"time",
|
|
57535
58257
|
"datetime"
|
|
@@ -57537,12 +58259,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
57537
58259
|
object({
|
|
57538
58260
|
value: string(),
|
|
57539
58261
|
/**
|
|
57540
|
-
* Set
|
|
57541
|
-
* as
|
|
57542
|
-
*
|
|
57543
|
-
* a time-only sensor → `'time'`.
|
|
58262
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58263
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58264
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
57544
58265
|
*/
|
|
57545
|
-
|
|
58266
|
+
timestamp: boolean().optional(),
|
|
57546
58267
|
/** Ms epoch when the slice was last updated. */
|
|
57547
58268
|
lastFetchedAt: number()
|
|
57548
58269
|
});
|
|
@@ -57561,13 +58282,13 @@ var EventFireSchema = object({
|
|
|
57561
58282
|
deviceId: number(),
|
|
57562
58283
|
eventType: string(),
|
|
57563
58284
|
data: record(string(), unknown()).nullable(),
|
|
57564
|
-
timestamp: number(),
|
|
57565
|
-
seq: number()
|
|
58285
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58286
|
+
seq: number().meta(readingMeta("count"))
|
|
57566
58287
|
});
|
|
57567
58288
|
object({
|
|
57568
58289
|
eventTypes: array(string()),
|
|
57569
58290
|
lastEvent: EventFireSchema.nullable(),
|
|
57570
|
-
eventCountSinceStart: number()
|
|
58291
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
57571
58292
|
});
|
|
57572
58293
|
DeviceType.EventEmitter;
|
|
57573
58294
|
var IdentitySchema = object({
|
|
@@ -57956,10 +58677,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
57956
58677
|
object({
|
|
57957
58678
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
57958
58679
|
* speed surface (single-speed fan). */
|
|
57959
|
-
percentage: number().min(0).max(100).nullable(),
|
|
58680
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57960
58681
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
57961
58682
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
57962
|
-
percentageStep: number().positive().optional(),
|
|
58683
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
57963
58684
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
57964
58685
|
* — empty string when no preset is active or supported. */
|
|
57965
58686
|
preset: string(),
|
|
@@ -58041,7 +58762,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58041
58762
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58042
58763
|
model: string().nullable(),
|
|
58043
58764
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58044
|
-
channelCount: number().nullable(),
|
|
58765
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58045
58766
|
/**
|
|
58046
58767
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58047
58768
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58073,9 +58794,45 @@ object({
|
|
|
58073
58794
|
lastChangedAt: number()
|
|
58074
58795
|
});
|
|
58075
58796
|
DeviceType.Sensor;
|
|
58797
|
+
object({
|
|
58798
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
58799
|
+
results: array(object({
|
|
58800
|
+
deviceId: number().int().nonnegative(),
|
|
58801
|
+
cap: string().min(1),
|
|
58802
|
+
method: string().min(1),
|
|
58803
|
+
ok: boolean(),
|
|
58804
|
+
error: string().optional(),
|
|
58805
|
+
/** Ms epoch of the attempt. */
|
|
58806
|
+
at: number()
|
|
58807
|
+
})) });
|
|
58808
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58809
|
+
object({
|
|
58810
|
+
active: boolean().meta({ label: "Active" }),
|
|
58811
|
+
/** Ms epoch when the slice was last updated. */
|
|
58812
|
+
lastChangedAt: number()
|
|
58813
|
+
});
|
|
58814
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
58815
|
+
object({
|
|
58816
|
+
/** Members whose current value entered the aggregate. */
|
|
58817
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
58818
|
+
precision: 0,
|
|
58819
|
+
label: "Reporting"
|
|
58820
|
+
})),
|
|
58821
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
58822
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
58823
|
+
precision: 0,
|
|
58824
|
+
label: "Excluded"
|
|
58825
|
+
})),
|
|
58826
|
+
/** `included` + `excluded`. */
|
|
58827
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
58828
|
+
precision: 0,
|
|
58829
|
+
label: "Members"
|
|
58830
|
+
}))
|
|
58831
|
+
});
|
|
58832
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58076
58833
|
object({
|
|
58077
58834
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58078
|
-
position: number().min(0).max(100).nullable(),
|
|
58835
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58079
58836
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58080
58837
|
lastFetchedAt: number()
|
|
58081
58838
|
});
|
|
@@ -58084,9 +58841,9 @@ object({
|
|
|
58084
58841
|
/** Whether the humidifier is currently on. */
|
|
58085
58842
|
on: boolean(),
|
|
58086
58843
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58087
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58844
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58088
58845
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58089
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58846
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58090
58847
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58091
58848
|
* device has no mode surface. */
|
|
58092
58849
|
mode: string().nullable(),
|
|
@@ -58096,9 +58853,9 @@ object({
|
|
|
58096
58853
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58097
58854
|
action: string().nullable(),
|
|
58098
58855
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58099
|
-
minHumidity: number().nullable(),
|
|
58856
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58100
58857
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58101
|
-
maxHumidity: number().nullable(),
|
|
58858
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58102
58859
|
/** Ms epoch when the slice was last updated. */
|
|
58103
58860
|
lastChangedAt: number()
|
|
58104
58861
|
});
|
|
@@ -58122,22 +58879,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58122
58879
|
auth: "protected"
|
|
58123
58880
|
});
|
|
58124
58881
|
object({
|
|
58125
|
-
/** Current relative humidity, 0..100. */
|
|
58126
|
-
percent: number().min(0).max(100).meta({
|
|
58127
|
-
|
|
58882
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
58883
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
58884
|
+
precision: 0,
|
|
58128
58885
|
label: "Humidity"
|
|
58129
|
-
}),
|
|
58886
|
+
})),
|
|
58130
58887
|
/** Ms epoch when the slice was last updated. */
|
|
58131
|
-
lastFetchedAt: number()
|
|
58132
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58133
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58134
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58135
|
-
unit: string().optional(),
|
|
58136
|
-
/** Suggested decimal places for numeric display.
|
|
58137
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58138
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58139
|
-
* auto-formatting when absent. */
|
|
58140
|
-
precision: number().int().min(0).max(10).optional()
|
|
58888
|
+
lastFetchedAt: number()
|
|
58141
58889
|
});
|
|
58142
58890
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58143
58891
|
object({
|
|
@@ -58145,7 +58893,7 @@ object({
|
|
|
58145
58893
|
* entity exposes no `entity_picture` (yet). */
|
|
58146
58894
|
url: string().nullable(),
|
|
58147
58895
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58148
|
-
lastUpdated: number().nullable()
|
|
58896
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58149
58897
|
});
|
|
58150
58898
|
DeviceType.Image;
|
|
58151
58899
|
/**
|
|
@@ -58201,19 +58949,19 @@ var NormalizedRangeSchema = object({
|
|
|
58201
58949
|
});
|
|
58202
58950
|
object({
|
|
58203
58951
|
/** Normalized 0–100. */
|
|
58204
|
-
brightness: number().optional(),
|
|
58952
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58205
58953
|
/** Normalized 0–100. */
|
|
58206
|
-
contrast: number().optional(),
|
|
58954
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58207
58955
|
/** Normalized 0–100. */
|
|
58208
|
-
saturation: number().optional(),
|
|
58956
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58209
58957
|
/** Normalized 0–100. */
|
|
58210
|
-
sharpness: number().optional(),
|
|
58958
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58211
58959
|
mirror: boolean().optional(),
|
|
58212
58960
|
flip: boolean().optional(),
|
|
58213
58961
|
rotate: ImageRotateSchema.optional(),
|
|
58214
58962
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58215
58963
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58216
|
-
warmth: number().optional(),
|
|
58964
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58217
58965
|
exposureMode: ExposureModeSchema.optional(),
|
|
58218
58966
|
backlightMode: BacklightModeSchema.optional(),
|
|
58219
58967
|
lastFetchedAt: number()
|
|
@@ -58458,10 +59206,10 @@ var IntercomAbilitySchema = object({
|
|
|
58458
59206
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58459
59207
|
codecs: array(string()),
|
|
58460
59208
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58461
|
-
sampleRate: number(),
|
|
59209
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58462
59210
|
duplex: _enum(["half", "full"]),
|
|
58463
59211
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58464
|
-
maxBacklogMs: number()
|
|
59212
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58465
59213
|
});
|
|
58466
59214
|
var IntercomStatusSchema = object({
|
|
58467
59215
|
/** True while a talk session is open. */
|
|
@@ -58572,13 +59320,13 @@ object({
|
|
|
58572
59320
|
activity: LawnMowerActivitySchema,
|
|
58573
59321
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
58574
59322
|
* reading. */
|
|
58575
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59323
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58576
59324
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
58577
59325
|
* task is active / progress is unavailable. */
|
|
58578
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59326
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58579
59327
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
58580
59328
|
* or null when unknown. */
|
|
58581
|
-
currentCode: number().nullable(),
|
|
59329
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
58582
59330
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
58583
59331
|
currentCodeLabel: string().nullable(),
|
|
58584
59332
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -58988,7 +59736,14 @@ DeviceType.Lock, method(object({
|
|
|
58988
59736
|
auth: "protected"
|
|
58989
59737
|
}), method(object({
|
|
58990
59738
|
deviceId: number().int().nonnegative(),
|
|
58991
|
-
code: string().min(1).optional()
|
|
59739
|
+
code: string().min(1).optional(),
|
|
59740
|
+
/**
|
|
59741
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
59742
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
59743
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
59744
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
59745
|
+
*/
|
|
59746
|
+
confirm: boolean().optional()
|
|
58992
59747
|
}), _void(), {
|
|
58993
59748
|
kind: "mutation",
|
|
58994
59749
|
auth: "protected"
|
|
@@ -58996,6 +59751,11 @@ DeviceType.Lock, method(object({
|
|
|
58996
59751
|
kind: "mutation",
|
|
58997
59752
|
auth: "protected"
|
|
58998
59753
|
});
|
|
59754
|
+
object({
|
|
59755
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
59756
|
+
lastFetchedAt: number()
|
|
59757
|
+
});
|
|
59758
|
+
DeviceType.Sensor;
|
|
58999
59759
|
/**
|
|
59000
59760
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59001
59761
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59040,7 +59800,7 @@ object({
|
|
|
59040
59800
|
state: MediaPlayerStateSchema,
|
|
59041
59801
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59042
59802
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59043
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
59803
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59044
59804
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59045
59805
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59046
59806
|
isMuted: boolean().nullable(),
|
|
@@ -59053,10 +59813,10 @@ object({
|
|
|
59053
59813
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59054
59814
|
/** Current playback position in ms. Null when not seekable or
|
|
59055
59815
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59056
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
59816
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59057
59817
|
/** Total duration of the current media in ms. Null when unknown
|
|
59058
59818
|
* (live stream) or nothing is playing. */
|
|
59059
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
59819
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59060
59820
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59061
59821
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59062
59822
|
shuffle: boolean().nullable(),
|
|
@@ -59356,7 +60116,7 @@ object({
|
|
|
59356
60116
|
* it, every provider seeded it at boot, and every session left it
|
|
59357
60117
|
* `detected: true` after its detach.
|
|
59358
60118
|
*/
|
|
59359
|
-
autoClearAfterMs: number().nullable()
|
|
60119
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59360
60120
|
});
|
|
59361
60121
|
/**
|
|
59362
60122
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59406,7 +60166,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59406
60166
|
});
|
|
59407
60167
|
object({
|
|
59408
60168
|
enabled: boolean(),
|
|
59409
|
-
sensitivity: number(),
|
|
60169
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59410
60170
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59411
60171
|
regions: array(MotionZoneRegionSchema),
|
|
59412
60172
|
lastFetchedAt: number()
|
|
@@ -59710,7 +60470,7 @@ var NavigationStatusSchema = object({
|
|
|
59710
60470
|
following: boolean(),
|
|
59711
60471
|
flash: boolean(),
|
|
59712
60472
|
lightMode: NavigationLightModeSchema,
|
|
59713
|
-
lightLevel: number().min(40).max(100),
|
|
60473
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
59714
60474
|
/** Ms epoch when the slice was last updated. */
|
|
59715
60475
|
lastChangedAt: number()
|
|
59716
60476
|
});
|
|
@@ -59756,13 +60516,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
59756
60516
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
59757
60517
|
* SKIP a null rather than coerce it.
|
|
59758
60518
|
*/
|
|
59759
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
60519
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59760
60520
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
59761
|
-
rssiDbm: number().optional(),
|
|
60521
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
59762
60522
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
59763
60523
|
ssid: string().optional(),
|
|
59764
60524
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
59765
|
-
lastUpdated: number()
|
|
60525
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
59766
60526
|
});
|
|
59767
60527
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
59768
60528
|
deviceId: number(),
|
|
@@ -60081,7 +60841,7 @@ object({
|
|
|
60081
60841
|
lastError: string().nullable(),
|
|
60082
60842
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60083
60843
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60084
|
-
queueDepth: number().int().nonnegative(),
|
|
60844
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60085
60845
|
/** Per-feature capability matrix — authoritative source for the
|
|
60086
60846
|
* compose-form field gating. */
|
|
60087
60847
|
supports: NotifierSupportsSchema
|
|
@@ -60131,15 +60891,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60131
60891
|
acceptedAt: number()
|
|
60132
60892
|
});
|
|
60133
60893
|
object({
|
|
60134
|
-
|
|
60135
|
-
|
|
60136
|
-
* Populated live from the upstream source on each state push.
|
|
60137
|
-
* Absent for unitless sensors. */
|
|
60138
|
-
unit: string().optional(),
|
|
60139
|
-
/** Suggested decimal places for numeric display.
|
|
60140
|
-
* Populated live from the upstream source when provided.
|
|
60141
|
-
* Falls back to auto-formatting when absent. */
|
|
60142
|
-
precision: number().int().min(0).max(10).optional(),
|
|
60894
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
60895
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60143
60896
|
/** Ms epoch when the slice was last updated. */
|
|
60144
60897
|
lastFetchedAt: number()
|
|
60145
60898
|
});
|
|
@@ -60429,23 +61182,26 @@ object({
|
|
|
60429
61182
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60430
61183
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60431
61184
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60432
|
-
foodLevel: number().nullable(),
|
|
61185
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60433
61186
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60434
61187
|
* single-hopper models. */
|
|
60435
|
-
food1: number().nullable(),
|
|
61188
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60436
61189
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60437
61190
|
* single-hopper models. */
|
|
60438
|
-
food2: number().nullable(),
|
|
61191
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60439
61192
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60440
61193
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60441
61194
|
* below the feeder's low threshold. */
|
|
60442
61195
|
lowFood: boolean(),
|
|
60443
61196
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60444
61197
|
* device has no battery reading. */
|
|
60445
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60446
|
-
/**
|
|
60447
|
-
*
|
|
60448
|
-
|
|
61198
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61199
|
+
/**
|
|
61200
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61201
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61202
|
+
* model has no desiccant sensor.
|
|
61203
|
+
*/
|
|
61204
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60449
61205
|
/** True while a feed is in progress. */
|
|
60450
61206
|
feeding: boolean(),
|
|
60451
61207
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60456,7 +61212,7 @@ object({
|
|
|
60456
61212
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60457
61213
|
error: string().nullable(),
|
|
60458
61214
|
/** Raw device error code (0 / null = no error). */
|
|
60459
|
-
errorCode: number().nullable(),
|
|
61215
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60460
61216
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60461
61217
|
isDualHopper: boolean(),
|
|
60462
61218
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60466,7 +61222,7 @@ object({
|
|
|
60466
61222
|
/** Play a chime when dispensing. */
|
|
60467
61223
|
feedSound: boolean(),
|
|
60468
61224
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60469
|
-
volume: number(),
|
|
61225
|
+
volume: number().meta(readingMeta("none")),
|
|
60470
61226
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60471
61227
|
lastFetchedAt: number()
|
|
60472
61228
|
});
|
|
@@ -60903,38 +61659,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
60903
61659
|
});
|
|
60904
61660
|
object({
|
|
60905
61661
|
/** Instantaneous power draw in watts. */
|
|
60906
|
-
watts: number().optional().meta({
|
|
60907
|
-
unit: "W",
|
|
60908
|
-
label: "Power"
|
|
60909
|
-
}),
|
|
61662
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
60910
61663
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
60911
|
-
kwhTotal: number().optional().meta({
|
|
60912
|
-
unit: "kWh",
|
|
60913
|
-
label: "Energy"
|
|
60914
|
-
}),
|
|
61664
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
60915
61665
|
/** Voltage in volts. */
|
|
60916
|
-
volts: number().optional(),
|
|
61666
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
60917
61667
|
/** Current in amperes. */
|
|
60918
|
-
amps: number().optional(),
|
|
60919
|
-
/** Apparent power in volt-amperes
|
|
60920
|
-
va: number().optional(),
|
|
61668
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61669
|
+
/** Apparent power in volt-amperes. */
|
|
61670
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
60921
61671
|
/** Power factor (0..1) if reported. */
|
|
60922
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
61672
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
60923
61673
|
/** Ms epoch when the slice was last updated. */
|
|
60924
|
-
lastFetchedAt: number()
|
|
60925
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
60926
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
60927
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
60928
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
60929
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
60930
|
-
unit: string().optional(),
|
|
60931
|
-
/** Suggested decimal places for numeric display.
|
|
60932
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
60933
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
60934
|
-
* auto-formatting when absent. */
|
|
60935
|
-
precision: number().int().min(0).max(10).optional()
|
|
61674
|
+
lastFetchedAt: number()
|
|
60936
61675
|
});
|
|
60937
|
-
|
|
61676
|
+
[
|
|
61677
|
+
DeviceType.Sensor,
|
|
61678
|
+
DeviceType.Switch,
|
|
61679
|
+
DeviceType.Light,
|
|
61680
|
+
DeviceType.Fan,
|
|
61681
|
+
DeviceType.Climate,
|
|
61682
|
+
DeviceType.Thermostat,
|
|
61683
|
+
DeviceType.Humidifier,
|
|
61684
|
+
DeviceType.WaterHeater,
|
|
61685
|
+
DeviceType.MediaPlayer,
|
|
61686
|
+
DeviceType.Washer,
|
|
61687
|
+
DeviceType.Dryer,
|
|
61688
|
+
DeviceType.Dishwasher,
|
|
61689
|
+
DeviceType.Vacuum,
|
|
61690
|
+
DeviceType.LawnMower,
|
|
61691
|
+
DeviceType.PetFeeder
|
|
61692
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
60938
61693
|
/**
|
|
60939
61694
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
60940
61695
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -60953,11 +61708,11 @@ DeviceType.Sensor;
|
|
|
60953
61708
|
*/
|
|
60954
61709
|
var GpsLocationSchema = object({
|
|
60955
61710
|
/** Latitude in decimal degrees, -90..90. */
|
|
60956
|
-
latitude: number().min(-90).max(90),
|
|
61711
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
60957
61712
|
/** Longitude in decimal degrees, -180..180. */
|
|
60958
|
-
longitude: number().min(-180).max(180),
|
|
61713
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
60959
61714
|
/** Reported accuracy in meters (lower = better). */
|
|
60960
|
-
accuracyMeters: number().nonnegative()
|
|
61715
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
60961
61716
|
});
|
|
60962
61717
|
object({
|
|
60963
61718
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -60969,25 +61724,16 @@ object({
|
|
|
60969
61724
|
gps: GpsLocationSchema.nullable(),
|
|
60970
61725
|
/** Optional battery level of the tracking device (0..100). Null
|
|
60971
61726
|
* when not reported. */
|
|
60972
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
61727
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60973
61728
|
/** Ms epoch when the slice was last updated. */
|
|
60974
61729
|
lastChangedAt: number()
|
|
60975
61730
|
});
|
|
60976
61731
|
DeviceType.Presence;
|
|
60977
61732
|
object({
|
|
60978
|
-
/** Current pressure in hPa. */
|
|
60979
|
-
hpa: number(),
|
|
61733
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
61734
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
60980
61735
|
/** Ms epoch when the slice was last updated. */
|
|
60981
|
-
lastFetchedAt: number()
|
|
60982
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
60983
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
60984
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
60985
|
-
unit: string().optional(),
|
|
60986
|
-
/** Suggested decimal places for numeric display.
|
|
60987
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
60988
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
60989
|
-
* auto-formatting when absent. */
|
|
60990
|
-
precision: number().int().min(0).max(10).optional()
|
|
61736
|
+
lastFetchedAt: number()
|
|
60991
61737
|
});
|
|
60992
61738
|
DeviceType.Sensor;
|
|
60993
61739
|
/**
|
|
@@ -61412,8 +62158,8 @@ var ptzCapability = {
|
|
|
61412
62158
|
};
|
|
61413
62159
|
var PtzAutotrackSettingsSchema = object({
|
|
61414
62160
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61415
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61416
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62161
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62162
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61417
62163
|
});
|
|
61418
62164
|
/**
|
|
61419
62165
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61470,7 +62216,7 @@ object({
|
|
|
61470
62216
|
/** null = unknown — never coerced to false (D393). */
|
|
61471
62217
|
running: boolean().nullable(),
|
|
61472
62218
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61473
|
-
since: number().nullable(),
|
|
62219
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61474
62220
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61475
62221
|
phase: string().nullable(),
|
|
61476
62222
|
/** null until a reading has been published (D393). */
|
|
@@ -61482,7 +62228,7 @@ object({
|
|
|
61482
62228
|
phase: string().nullable()
|
|
61483
62229
|
});
|
|
61484
62230
|
Object.values(DeviceType);
|
|
61485
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62231
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61486
62232
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61487
62233
|
kind: "mutation",
|
|
61488
62234
|
auth: "admin"
|
|
@@ -62668,9 +63414,9 @@ var RecordTriggerSchema = _enum([
|
|
|
62668
63414
|
*/
|
|
62669
63415
|
var RecordWindowSchema = object({
|
|
62670
63416
|
trigger: RecordTriggerSchema,
|
|
62671
|
-
day: number().int().min(0).max(6),
|
|
62672
|
-
startMinute: number().int().min(0).max(1439),
|
|
62673
|
-
endMinute: number().int().min(1).max(1440)
|
|
63417
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63418
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63419
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
62674
63420
|
});
|
|
62675
63421
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
62676
63422
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -62739,10 +63485,10 @@ object({
|
|
|
62739
63485
|
/** Master "record to the card at all" switch. */
|
|
62740
63486
|
enabled: boolean().nullable(),
|
|
62741
63487
|
overwriteWhenFull: boolean().nullable(),
|
|
62742
|
-
preRecordSec: number().nullable(),
|
|
62743
|
-
postRecordSec: number().nullable(),
|
|
63488
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63489
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
62744
63490
|
/** Length of one recorded file, in minutes. */
|
|
62745
|
-
segmentMinutes: number().nullable(),
|
|
63491
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
62746
63492
|
/** The primary track's weekly windows, flattened. */
|
|
62747
63493
|
windows: array(RecordWindowSchema),
|
|
62748
63494
|
/**
|
|
@@ -62758,7 +63504,7 @@ object({
|
|
|
62758
63504
|
* provider reporting a non-zero count also reports the schedule as not
|
|
62759
63505
|
* writable.
|
|
62760
63506
|
*/
|
|
62761
|
-
unreadableWindows: number(),
|
|
63507
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
62762
63508
|
/**
|
|
62763
63509
|
* The camera is scheduled to record and has NO usable storage.
|
|
62764
63510
|
*
|
|
@@ -63395,7 +64141,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63395
64141
|
url: string().optional(),
|
|
63396
64142
|
codec: string().optional(),
|
|
63397
64143
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63398
|
-
fps: number().positive().optional(),
|
|
64144
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63399
64145
|
label: string().optional(),
|
|
63400
64146
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63401
64147
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63425,18 +64171,18 @@ var StreamProfileSchema = _enum([
|
|
|
63425
64171
|
]);
|
|
63426
64172
|
/** The current encoding config of one stream profile. */
|
|
63427
64173
|
var StreamProfileConfigSchema = object({
|
|
63428
|
-
width: number(),
|
|
63429
|
-
height: number(),
|
|
64174
|
+
width: number().meta(readingMeta("none")),
|
|
64175
|
+
height: number().meta(readingMeta("none")),
|
|
63430
64176
|
codec: _enum(["h264", "h265"]),
|
|
63431
|
-
framerate: number(),
|
|
63432
|
-
bitrate: number(),
|
|
64177
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64178
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63433
64179
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63434
64180
|
encoderProfile: _enum([
|
|
63435
64181
|
"high",
|
|
63436
64182
|
"main",
|
|
63437
64183
|
"baseline"
|
|
63438
64184
|
]).optional(),
|
|
63439
|
-
gop: number().optional(),
|
|
64185
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63440
64186
|
/**
|
|
63441
64187
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63442
64188
|
*
|
|
@@ -63521,7 +64267,7 @@ object({
|
|
|
63521
64267
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63522
64268
|
lastChangedAt: number()
|
|
63523
64269
|
});
|
|
63524
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64270
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63525
64271
|
deviceId: number(),
|
|
63526
64272
|
on: boolean()
|
|
63527
64273
|
}), _void(), {
|
|
@@ -64079,23 +64825,13 @@ object({
|
|
|
64079
64825
|
});
|
|
64080
64826
|
DeviceType.Sensor;
|
|
64081
64827
|
object({
|
|
64082
|
-
/** Current temperature in Celsius. */
|
|
64083
|
-
celsius: number().meta({
|
|
64084
|
-
|
|
64828
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
64829
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
64830
|
+
precision: 1,
|
|
64085
64831
|
label: "Temperature"
|
|
64086
|
-
}),
|
|
64832
|
+
})),
|
|
64087
64833
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64088
|
-
lastFetchedAt: number()
|
|
64089
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64090
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64091
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64092
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64093
|
-
unit: string().optional(),
|
|
64094
|
-
/** Suggested decimal places for numeric display.
|
|
64095
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64096
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64097
|
-
* auto-formatting when absent. */
|
|
64098
|
-
precision: number().int().min(0).max(10).optional()
|
|
64834
|
+
lastFetchedAt: number()
|
|
64099
64835
|
});
|
|
64100
64836
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64101
64837
|
/**
|
|
@@ -64347,16 +65083,16 @@ object({
|
|
|
64347
65083
|
]),
|
|
64348
65084
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64349
65085
|
* reading. */
|
|
64350
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65086
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64351
65087
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64352
65088
|
* the vacuum has no speed control. */
|
|
64353
65089
|
fanSpeed: string().nullable(),
|
|
64354
65090
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64355
65091
|
availableFanSpeeds: array(string()),
|
|
64356
65092
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64357
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65093
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64358
65094
|
/** Current error code (0 / null = no error). */
|
|
64359
|
-
errorCode: number().nullable(),
|
|
65095
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64360
65096
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64361
65097
|
errorLabel: string().nullable(),
|
|
64362
65098
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64395,7 +65131,7 @@ object({
|
|
|
64395
65131
|
]),
|
|
64396
65132
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64397
65133
|
* intermediate position surface. */
|
|
64398
|
-
position: number().min(0).max(100).nullable(),
|
|
65134
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64399
65135
|
/** Ms epoch when the slice was last updated. */
|
|
64400
65136
|
lastChangedAt: number()
|
|
64401
65137
|
});
|
|
@@ -64423,9 +65159,9 @@ object({
|
|
|
64423
65159
|
DeviceType.Sensor;
|
|
64424
65160
|
object({
|
|
64425
65161
|
/** Current measured temperature. Null when not reported. */
|
|
64426
|
-
currentTemp: number().nullable(),
|
|
65162
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64427
65163
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64428
|
-
targetTemp: number().nullable(),
|
|
65164
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64429
65165
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64430
65166
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64431
65167
|
* device reports an unknown state. */
|
|
@@ -64436,9 +65172,9 @@ object({
|
|
|
64436
65172
|
* has no away surface. */
|
|
64437
65173
|
away: boolean().nullable(),
|
|
64438
65174
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64439
|
-
minTemp: number().nullable(),
|
|
65175
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64440
65176
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64441
|
-
maxTemp: number().nullable(),
|
|
65177
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64442
65178
|
/** Ms epoch when the slice was last updated. */
|
|
64443
65179
|
lastChangedAt: number()
|
|
64444
65180
|
});
|
|
@@ -64462,25 +65198,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64462
65198
|
auth: "protected"
|
|
64463
65199
|
});
|
|
64464
65200
|
object({
|
|
64465
|
-
/** Verbatim
|
|
64466
|
-
* when no condition has been reported yet. */
|
|
65201
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64467
65202
|
condition: string().nullable(),
|
|
64468
|
-
/** Current temperature in
|
|
64469
|
-
temperature: number().nullable(),
|
|
64470
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64471
|
-
temperatureUnit: string().nullable(),
|
|
65203
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65204
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64472
65205
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64473
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64474
|
-
/** Barometric pressure in
|
|
64475
|
-
pressure: number().nullable(),
|
|
64476
|
-
/**
|
|
64477
|
-
|
|
64478
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64479
|
-
windSpeed: number().nullable(),
|
|
64480
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64481
|
-
windSpeedUnit: string().nullable(),
|
|
65206
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65207
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65208
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65209
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65210
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64482
65211
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64483
|
-
windBearing: number().nullable(),
|
|
65212
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64484
65213
|
/** Ms epoch when the slice was last updated. */
|
|
64485
65214
|
lastFetchedAt: number()
|
|
64486
65215
|
});
|
|
@@ -65230,8 +65959,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65230
65959
|
kind: "mutation",
|
|
65231
65960
|
auth: "admin"
|
|
65232
65961
|
});
|
|
65962
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65233
65963
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65234
|
-
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;
|
|
65964
|
+
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;
|
|
65235
65965
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65236
65966
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65237
65967
|
new Set(CAP_NAMES);
|
|
@@ -66109,7 +66839,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
66109
66839
|
return toDeviceSummary(device, this.addonId);
|
|
66110
66840
|
}
|
|
66111
66841
|
};
|
|
66112
|
-
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;
|
|
66842
|
+
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;
|
|
66113
66843
|
new Set(Object.values(DeviceType));
|
|
66114
66844
|
Object.freeze({
|
|
66115
66845
|
"accessories.getStatus": {
|
|
@@ -66217,6 +66947,13 @@ Object.freeze({
|
|
|
66217
66947
|
access: "view",
|
|
66218
66948
|
role: "admin"
|
|
66219
66949
|
},
|
|
66950
|
+
"addons.getPackageDocs": {
|
|
66951
|
+
capName: "addons",
|
|
66952
|
+
capScope: "system",
|
|
66953
|
+
addonId: null,
|
|
66954
|
+
access: "view",
|
|
66955
|
+
role: "admin"
|
|
66956
|
+
},
|
|
66220
66957
|
"addons.getVersions": {
|
|
66221
66958
|
capName: "addons",
|
|
66222
66959
|
capScope: "system",
|
|
@@ -69325,6 +70062,27 @@ Object.freeze({
|
|
|
69325
70062
|
access: "view",
|
|
69326
70063
|
role: "viewer"
|
|
69327
70064
|
},
|
|
70065
|
+
"groupActive.getStatus": {
|
|
70066
|
+
capName: "group-active",
|
|
70067
|
+
capScope: "device",
|
|
70068
|
+
addonId: null,
|
|
70069
|
+
access: "view",
|
|
70070
|
+
role: "viewer"
|
|
70071
|
+
},
|
|
70072
|
+
"groupCommands.getStatus": {
|
|
70073
|
+
capName: "group-commands",
|
|
70074
|
+
capScope: "device",
|
|
70075
|
+
addonId: null,
|
|
70076
|
+
access: "view",
|
|
70077
|
+
role: "viewer"
|
|
70078
|
+
},
|
|
70079
|
+
"groupStatus.getStatus": {
|
|
70080
|
+
capName: "group-status",
|
|
70081
|
+
capScope: "device",
|
|
70082
|
+
addonId: null,
|
|
70083
|
+
access: "view",
|
|
70084
|
+
role: "viewer"
|
|
70085
|
+
},
|
|
69328
70086
|
"heatingValve.getStatus": {
|
|
69329
70087
|
capName: "heating-valve",
|
|
69330
70088
|
capScope: "device",
|
|
@@ -70277,6 +71035,13 @@ Object.freeze({
|
|
|
70277
71035
|
access: "create",
|
|
70278
71036
|
role: "admin"
|
|
70279
71037
|
},
|
|
71038
|
+
"meter.getStatus": {
|
|
71039
|
+
capName: "meter",
|
|
71040
|
+
capScope: "device",
|
|
71041
|
+
addonId: null,
|
|
71042
|
+
access: "view",
|
|
71043
|
+
role: "viewer"
|
|
71044
|
+
},
|
|
70280
71045
|
"metricsProvider.collectSnapshot": {
|
|
70281
71046
|
capName: "metrics-provider",
|
|
70282
71047
|
capScope: "system",
|
|
@@ -78375,7 +79140,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
78375
79140
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
78376
79141
|
icon: "square"
|
|
78377
79142
|
}
|
|
78378
|
-
}
|
|
79143
|
+
},
|
|
79144
|
+
overrides: { byType: {
|
|
79145
|
+
[DeviceType.Washer]: {
|
|
79146
|
+
state: { running: {
|
|
79147
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
79148
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
79149
|
+
} },
|
|
79150
|
+
events: {
|
|
79151
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
79152
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
79153
|
+
}
|
|
79154
|
+
},
|
|
79155
|
+
[DeviceType.Dryer]: {
|
|
79156
|
+
state: { running: {
|
|
79157
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
79158
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
79159
|
+
} },
|
|
79160
|
+
events: {
|
|
79161
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
79162
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
79163
|
+
}
|
|
79164
|
+
},
|
|
79165
|
+
[DeviceType.Dishwasher]: {
|
|
79166
|
+
state: { running: {
|
|
79167
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
79168
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
79169
|
+
} },
|
|
79170
|
+
events: {
|
|
79171
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
79172
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
79173
|
+
}
|
|
79174
|
+
}
|
|
79175
|
+
} }
|
|
78379
79176
|
},
|
|
78380
79177
|
update: {
|
|
78381
79178
|
scope: "device",
|
|
@@ -79147,6 +79944,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79147
79944
|
icon: "flame"
|
|
79148
79945
|
}]
|
|
79149
79946
|
},
|
|
79947
|
+
"group-active": {
|
|
79948
|
+
scope: "device",
|
|
79949
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79950
|
+
},
|
|
79951
|
+
"group-commands": {
|
|
79952
|
+
scope: "device",
|
|
79953
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79954
|
+
},
|
|
79955
|
+
"group-status": {
|
|
79956
|
+
scope: "device",
|
|
79957
|
+
noun: t("Group", "Gruppo"),
|
|
79958
|
+
state: [
|
|
79959
|
+
{
|
|
79960
|
+
kind: "numeric",
|
|
79961
|
+
field: "included",
|
|
79962
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79963
|
+
label: t("Reporting", "Rispondono"),
|
|
79964
|
+
icon: "users"
|
|
79965
|
+
},
|
|
79966
|
+
{
|
|
79967
|
+
kind: "numeric",
|
|
79968
|
+
field: "excluded",
|
|
79969
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79970
|
+
label: t("Excluded", "Esclusi"),
|
|
79971
|
+
icon: "users"
|
|
79972
|
+
},
|
|
79973
|
+
{
|
|
79974
|
+
kind: "numeric",
|
|
79975
|
+
field: "total",
|
|
79976
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79977
|
+
label: t("Members", "Membri"),
|
|
79978
|
+
icon: "sigma"
|
|
79979
|
+
}
|
|
79980
|
+
]
|
|
79981
|
+
},
|
|
79150
79982
|
"humidity-sensor": {
|
|
79151
79983
|
scope: "device",
|
|
79152
79984
|
noun: t("Humidity", "Umidità"),
|
|
@@ -79172,6 +80004,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79172
80004
|
}],
|
|
79173
80005
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
79174
80006
|
},
|
|
80007
|
+
meter: {
|
|
80008
|
+
scope: "device",
|
|
80009
|
+
noun: t("Meter", "Contatore"),
|
|
80010
|
+
state: [{
|
|
80011
|
+
kind: "numeric",
|
|
80012
|
+
field: "value",
|
|
80013
|
+
quantity: t("the total", "il totale"),
|
|
80014
|
+
label: t("Total", "Totale"),
|
|
80015
|
+
icon: "gauge"
|
|
80016
|
+
}]
|
|
80017
|
+
},
|
|
79175
80018
|
"numeric-sensor": {
|
|
79176
80019
|
scope: "device",
|
|
79177
80020
|
noun: t("Sensor", "Sensore"),
|
|
@@ -79180,7 +80023,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79180
80023
|
field: "value",
|
|
79181
80024
|
quantity: t("the reading", "il valore"),
|
|
79182
80025
|
label: t("Reading", "Valore"),
|
|
79183
|
-
unitField: "unit",
|
|
79184
80026
|
icon: "gauge"
|
|
79185
80027
|
}]
|
|
79186
80028
|
},
|
|
@@ -79316,7 +80158,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79316
80158
|
field: "temperature",
|
|
79317
80159
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
79318
80160
|
label: t("Temperature", "Temperatura"),
|
|
79319
|
-
|
|
80161
|
+
unit: "°C",
|
|
79320
80162
|
icon: "thermometer"
|
|
79321
80163
|
},
|
|
79322
80164
|
{
|
|
@@ -79332,7 +80174,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79332
80174
|
field: "windSpeed",
|
|
79333
80175
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
79334
80176
|
label: t("Wind", "Vento"),
|
|
79335
|
-
|
|
80177
|
+
unit: "m/s",
|
|
79336
80178
|
icon: "wind"
|
|
79337
80179
|
},
|
|
79338
80180
|
{
|
|
@@ -79340,7 +80182,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
79340
80182
|
field: "pressure",
|
|
79341
80183
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
79342
80184
|
label: t("Pressure", "Pressione"),
|
|
79343
|
-
|
|
80185
|
+
unit: "hPa",
|
|
79344
80186
|
icon: "gauge"
|
|
79345
80187
|
}
|
|
79346
80188
|
]
|
|
@@ -79645,8 +80487,47 @@ function projectAction(cap, action) {
|
|
|
79645
80487
|
};
|
|
79646
80488
|
}
|
|
79647
80489
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
79648
|
-
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;
|
|
80490
|
+
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;
|
|
79649
80491
|
DeviceFeature.BatteryOperated;
|
|
80492
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
80493
|
+
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.";
|
|
80494
|
+
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.";
|
|
80495
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
80496
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
80497
|
+
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.";
|
|
80498
|
+
function withheld(reason) {
|
|
80499
|
+
return {
|
|
80500
|
+
[DeviceType.Washer]: {
|
|
80501
|
+
exported: false,
|
|
80502
|
+
reason
|
|
80503
|
+
},
|
|
80504
|
+
[DeviceType.Dryer]: {
|
|
80505
|
+
exported: false,
|
|
80506
|
+
reason
|
|
80507
|
+
},
|
|
80508
|
+
[DeviceType.Dishwasher]: {
|
|
80509
|
+
exported: false,
|
|
80510
|
+
reason
|
|
80511
|
+
}
|
|
80512
|
+
};
|
|
80513
|
+
}
|
|
80514
|
+
function offered(received) {
|
|
80515
|
+
return {
|
|
80516
|
+
[DeviceType.Washer]: {
|
|
80517
|
+
exported: true,
|
|
80518
|
+
as: received
|
|
80519
|
+
},
|
|
80520
|
+
[DeviceType.Dryer]: {
|
|
80521
|
+
exported: true,
|
|
80522
|
+
as: received
|
|
80523
|
+
},
|
|
80524
|
+
[DeviceType.Dishwasher]: {
|
|
80525
|
+
exported: true,
|
|
80526
|
+
as: received
|
|
80527
|
+
}
|
|
80528
|
+
};
|
|
80529
|
+
}
|
|
80530
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
79650
80531
|
/** Reject after `ms`; always clears its own timer. */
|
|
79651
80532
|
async function withTimeout$1(promise, ms, label) {
|
|
79652
80533
|
let timer;
|
|
@@ -80679,6 +81560,21 @@ Object.freeze({
|
|
|
80679
81560
|
form: "single",
|
|
80680
81561
|
optional: false
|
|
80681
81562
|
}],
|
|
81563
|
+
"groupActive.getStatus": [{
|
|
81564
|
+
name: "deviceId",
|
|
81565
|
+
form: "single",
|
|
81566
|
+
optional: false
|
|
81567
|
+
}],
|
|
81568
|
+
"groupCommands.getStatus": [{
|
|
81569
|
+
name: "deviceId",
|
|
81570
|
+
form: "single",
|
|
81571
|
+
optional: false
|
|
81572
|
+
}],
|
|
81573
|
+
"groupStatus.getStatus": [{
|
|
81574
|
+
name: "deviceId",
|
|
81575
|
+
form: "single",
|
|
81576
|
+
optional: false
|
|
81577
|
+
}],
|
|
80682
81578
|
"heatingValve.getStatus": [{
|
|
80683
81579
|
name: "deviceId",
|
|
80684
81580
|
form: "single",
|
|
@@ -80879,6 +81775,11 @@ Object.freeze({
|
|
|
80879
81775
|
form: "single",
|
|
80880
81776
|
optional: false
|
|
80881
81777
|
}],
|
|
81778
|
+
"meter.getStatus": [{
|
|
81779
|
+
name: "deviceId",
|
|
81780
|
+
form: "single",
|
|
81781
|
+
optional: false
|
|
81782
|
+
}],
|
|
80882
81783
|
"motion.getStatus": [{
|
|
80883
81784
|
name: "deviceId",
|
|
80884
81785
|
form: "single",
|
|
@@ -82486,7 +83387,6 @@ Object.freeze({
|
|
|
82486
83387
|
"network-access": "ingress",
|
|
82487
83388
|
"smtp-provider": "email"
|
|
82488
83389
|
});
|
|
82489
|
-
DeviceType.Camera;
|
|
82490
83390
|
/**
|
|
82491
83391
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
82492
83392
|
* `z.infer`, they do not restate the shape.
|
|
@@ -82663,6 +83563,8 @@ new Map(Object.entries({
|
|
|
82663
83563
|
"detection-blind": "device-events",
|
|
82664
83564
|
"motion-noisy": "device-events",
|
|
82665
83565
|
"motion-calm": "device-events",
|
|
83566
|
+
"package-llm-silent": "device-events",
|
|
83567
|
+
"package-llm-answered": "device-events",
|
|
82666
83568
|
"recording-stalled": "device-events",
|
|
82667
83569
|
"recording-healthy": "device-events",
|
|
82668
83570
|
"recording-degraded": "device-events",
|
|
@@ -82746,6 +83648,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
82746
83648
|
label: "Motion without a subject",
|
|
82747
83649
|
kinds: ["motion-noisy", "motion-calm"]
|
|
82748
83650
|
},
|
|
83651
|
+
{
|
|
83652
|
+
id: "package-llm",
|
|
83653
|
+
family: "device-events",
|
|
83654
|
+
label: "Package confirm",
|
|
83655
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
83656
|
+
},
|
|
82749
83657
|
{
|
|
82750
83658
|
id: "recording",
|
|
82751
83659
|
family: "device-events",
|
|
@@ -82927,6 +83835,8 @@ var DEVICE_EVENTS = [
|
|
|
82927
83835
|
"detection-blind",
|
|
82928
83836
|
"motion-noisy",
|
|
82929
83837
|
"motion-calm",
|
|
83838
|
+
"package-llm-silent",
|
|
83839
|
+
"package-llm-answered",
|
|
82930
83840
|
"recording-stalled",
|
|
82931
83841
|
"recording-healthy",
|
|
82932
83842
|
"recording-degraded",
|
|
@@ -83195,6 +84105,15 @@ new Map([
|
|
|
83195
84105
|
snapshotLabel: "Cameras with constant motion now",
|
|
83196
84106
|
snapshotSection: null
|
|
83197
84107
|
},
|
|
84108
|
+
{
|
|
84109
|
+
id: "package-llm-confirm",
|
|
84110
|
+
family: "device-events",
|
|
84111
|
+
label: "Package confirm (not answering / answering again)",
|
|
84112
|
+
bad: ["package-llm-silent"],
|
|
84113
|
+
recovery: ["package-llm-answered"],
|
|
84114
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
84115
|
+
snapshotSection: null
|
|
84116
|
+
},
|
|
83198
84117
|
{
|
|
83199
84118
|
id: "recording-health",
|
|
83200
84119
|
family: "device-events",
|