@camstack/addon-provider-rademacher 0.2.146 → 0.2.148
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 +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.mjs
CHANGED
|
@@ -983,7 +983,7 @@ var Rademacher = class {
|
|
|
983
983
|
}
|
|
984
984
|
};
|
|
985
985
|
//#endregion
|
|
986
|
-
//#region ../types/dist/event-category-
|
|
986
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
987
987
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
988
988
|
EventCategory["SystemBoot"] = "system.boot";
|
|
989
989
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -1309,6 +1309,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
1309
1309
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
1310
1310
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
1311
1311
|
/**
|
|
1312
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
1313
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
1314
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
1315
|
+
*/
|
|
1316
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
1317
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
1318
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
1319
|
+
/**
|
|
1312
1320
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
1313
1321
|
* (a settings change via `setAgentInferenceDevices` /
|
|
1314
1322
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -6418,7 +6426,7 @@ var ZodIssueCode = {
|
|
|
6418
6426
|
var ZodFirstPartyTypeKind;
|
|
6419
6427
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6420
6428
|
//#endregion
|
|
6421
|
-
//#region ../types/dist/sleep
|
|
6429
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
6422
6430
|
/**
|
|
6423
6431
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6424
6432
|
* window to float samples (D455).
|
|
@@ -8972,6 +8980,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
8972
8980
|
}).strict();
|
|
8973
8981
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8974
8982
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8983
|
+
var READING_QUANTITIES = [
|
|
8984
|
+
"temperature",
|
|
8985
|
+
"pressure",
|
|
8986
|
+
"speed",
|
|
8987
|
+
"precipitation",
|
|
8988
|
+
"precipitation-rate",
|
|
8989
|
+
"length",
|
|
8990
|
+
"area",
|
|
8991
|
+
"illuminance",
|
|
8992
|
+
"irradiance",
|
|
8993
|
+
"power",
|
|
8994
|
+
"energy",
|
|
8995
|
+
"voltage",
|
|
8996
|
+
"current",
|
|
8997
|
+
"apparent-power",
|
|
8998
|
+
"humidity",
|
|
8999
|
+
"percentage",
|
|
9000
|
+
"concentration-volume",
|
|
9001
|
+
"concentration-mass",
|
|
9002
|
+
"concentration-ppb",
|
|
9003
|
+
"volume",
|
|
9004
|
+
"duration",
|
|
9005
|
+
"duration-ms",
|
|
9006
|
+
"information",
|
|
9007
|
+
"sound-level",
|
|
9008
|
+
"signal-level",
|
|
9009
|
+
"colour-temperature",
|
|
9010
|
+
"angle",
|
|
9011
|
+
"bitrate",
|
|
9012
|
+
"rate",
|
|
9013
|
+
"mass",
|
|
9014
|
+
"index",
|
|
9015
|
+
"ratio",
|
|
9016
|
+
"count",
|
|
9017
|
+
"none",
|
|
9018
|
+
"device"
|
|
9019
|
+
];
|
|
9020
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
9021
|
+
new Set(READING_QUANTITIES);
|
|
9022
|
+
/**
|
|
9023
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
9024
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
9025
|
+
*/
|
|
9026
|
+
var QUANTITY_BASE = {
|
|
9027
|
+
temperature: "°C",
|
|
9028
|
+
pressure: "hPa",
|
|
9029
|
+
speed: "m/s",
|
|
9030
|
+
precipitation: "mm",
|
|
9031
|
+
"precipitation-rate": "mm/h",
|
|
9032
|
+
length: "m",
|
|
9033
|
+
area: "m²",
|
|
9034
|
+
illuminance: "lx",
|
|
9035
|
+
irradiance: "W/m²",
|
|
9036
|
+
power: "W",
|
|
9037
|
+
energy: "kWh",
|
|
9038
|
+
voltage: "V",
|
|
9039
|
+
current: "A",
|
|
9040
|
+
"apparent-power": "VA",
|
|
9041
|
+
humidity: "%",
|
|
9042
|
+
percentage: "%",
|
|
9043
|
+
"concentration-volume": "ppm",
|
|
9044
|
+
"concentration-mass": "µg/m³",
|
|
9045
|
+
"concentration-ppb": "ppb",
|
|
9046
|
+
volume: "L",
|
|
9047
|
+
duration: "s",
|
|
9048
|
+
"duration-ms": "ms",
|
|
9049
|
+
information: "B",
|
|
9050
|
+
"sound-level": "dBFS",
|
|
9051
|
+
"signal-level": "dBm",
|
|
9052
|
+
"colour-temperature": "mired",
|
|
9053
|
+
angle: "°",
|
|
9054
|
+
bitrate: "kbps",
|
|
9055
|
+
rate: "fps",
|
|
9056
|
+
mass: "kg",
|
|
9057
|
+
index: "none",
|
|
9058
|
+
ratio: "none",
|
|
9059
|
+
count: "none",
|
|
9060
|
+
none: "none",
|
|
9061
|
+
device: "device"
|
|
9062
|
+
};
|
|
9063
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
9064
|
+
function baseUnitOf(quantity) {
|
|
9065
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
9066
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
9067
|
+
return symbol;
|
|
9068
|
+
}
|
|
9069
|
+
function readingMeta(quantity, extras) {
|
|
9070
|
+
return {
|
|
9071
|
+
quantity,
|
|
9072
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
9073
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
9074
|
+
};
|
|
9075
|
+
}
|
|
8975
9076
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8976
9077
|
var CamProfileSchema = _enum([
|
|
8977
9078
|
"high",
|
|
@@ -8999,8 +9100,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8999
9100
|
"derived"
|
|
9000
9101
|
]);
|
|
9001
9102
|
var CamStreamResolutionSchema = object({
|
|
9002
|
-
width: number().int().positive(),
|
|
9003
|
-
height: number().int().positive()
|
|
9103
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
9104
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
9004
9105
|
});
|
|
9005
9106
|
var CameraStreamSchema = object({
|
|
9006
9107
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -9518,6 +9619,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
9518
9619
|
"filesystem-browse",
|
|
9519
9620
|
"flood",
|
|
9520
9621
|
"gas",
|
|
9622
|
+
"group-active",
|
|
9623
|
+
"group-commands",
|
|
9624
|
+
"group-status",
|
|
9521
9625
|
"heating-valve",
|
|
9522
9626
|
"humidifier",
|
|
9523
9627
|
"humidity-sensor",
|
|
@@ -9538,6 +9642,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9538
9642
|
"login-method",
|
|
9539
9643
|
"media-player",
|
|
9540
9644
|
"mesh-network",
|
|
9645
|
+
"meter",
|
|
9541
9646
|
"metrics-provider",
|
|
9542
9647
|
"model-convert",
|
|
9543
9648
|
"model-distributor",
|
|
@@ -9647,14 +9752,6 @@ Object.freeze({
|
|
|
9647
9752
|
{
|
|
9648
9753
|
"path": "aqi",
|
|
9649
9754
|
"valueType": "number"
|
|
9650
|
-
},
|
|
9651
|
-
{
|
|
9652
|
-
"path": "unit",
|
|
9653
|
-
"valueType": "string"
|
|
9654
|
-
},
|
|
9655
|
-
{
|
|
9656
|
-
"path": "precision",
|
|
9657
|
-
"valueType": "number"
|
|
9658
9755
|
}
|
|
9659
9756
|
],
|
|
9660
9757
|
"alarm-panel": [
|
|
@@ -9690,20 +9787,10 @@ Object.freeze({
|
|
|
9690
9787
|
"valueType": "boolean"
|
|
9691
9788
|
}
|
|
9692
9789
|
],
|
|
9693
|
-
"ambient-light-sensor": [
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
},
|
|
9698
|
-
{
|
|
9699
|
-
"path": "unit",
|
|
9700
|
-
"valueType": "string"
|
|
9701
|
-
},
|
|
9702
|
-
{
|
|
9703
|
-
"path": "precision",
|
|
9704
|
-
"valueType": "number"
|
|
9705
|
-
}
|
|
9706
|
-
],
|
|
9790
|
+
"ambient-light-sensor": [{
|
|
9791
|
+
"path": "lux",
|
|
9792
|
+
"valueType": "number"
|
|
9793
|
+
}],
|
|
9707
9794
|
"audio-metrics": [
|
|
9708
9795
|
{
|
|
9709
9796
|
"path": "ts",
|
|
@@ -9783,6 +9870,10 @@ Object.freeze({
|
|
|
9783
9870
|
"path": "lastUpdated",
|
|
9784
9871
|
"valueType": "number"
|
|
9785
9872
|
},
|
|
9873
|
+
{
|
|
9874
|
+
"path": "volts",
|
|
9875
|
+
"valueType": "number"
|
|
9876
|
+
},
|
|
9786
9877
|
{
|
|
9787
9878
|
"path": "lastContactAt",
|
|
9788
9879
|
"valueType": "number"
|
|
@@ -10025,10 +10116,6 @@ Object.freeze({
|
|
|
10025
10116
|
"datetime"
|
|
10026
10117
|
]
|
|
10027
10118
|
},
|
|
10028
|
-
{
|
|
10029
|
-
"path": "unit",
|
|
10030
|
-
"valueType": "string"
|
|
10031
|
-
},
|
|
10032
10119
|
{
|
|
10033
10120
|
"path": "min",
|
|
10034
10121
|
"valueType": "number"
|
|
@@ -10040,19 +10127,6 @@ Object.freeze({
|
|
|
10040
10127
|
{
|
|
10041
10128
|
"path": "step",
|
|
10042
10129
|
"valueType": "number"
|
|
10043
|
-
},
|
|
10044
|
-
{
|
|
10045
|
-
"path": "precision",
|
|
10046
|
-
"valueType": "number"
|
|
10047
|
-
},
|
|
10048
|
-
{
|
|
10049
|
-
"path": "format",
|
|
10050
|
-
"valueType": "enum",
|
|
10051
|
-
"enumValues": [
|
|
10052
|
-
"date",
|
|
10053
|
-
"time",
|
|
10054
|
-
"datetime"
|
|
10055
|
-
]
|
|
10056
10130
|
}
|
|
10057
10131
|
],
|
|
10058
10132
|
"cover": [
|
|
@@ -10293,13 +10367,8 @@ Object.freeze({
|
|
|
10293
10367
|
"path": "value",
|
|
10294
10368
|
"valueType": "string"
|
|
10295
10369
|
}, {
|
|
10296
|
-
"path": "
|
|
10297
|
-
"valueType": "
|
|
10298
|
-
"enumValues": [
|
|
10299
|
-
"date",
|
|
10300
|
-
"time",
|
|
10301
|
-
"datetime"
|
|
10302
|
-
]
|
|
10370
|
+
"path": "timestamp",
|
|
10371
|
+
"valueType": "boolean"
|
|
10303
10372
|
}],
|
|
10304
10373
|
"event-emitter": [
|
|
10305
10374
|
{
|
|
@@ -10372,6 +10441,24 @@ Object.freeze({
|
|
|
10372
10441
|
"path": "detected",
|
|
10373
10442
|
"valueType": "boolean"
|
|
10374
10443
|
}],
|
|
10444
|
+
"group-active": [{
|
|
10445
|
+
"path": "active",
|
|
10446
|
+
"valueType": "boolean"
|
|
10447
|
+
}],
|
|
10448
|
+
"group-status": [
|
|
10449
|
+
{
|
|
10450
|
+
"path": "included",
|
|
10451
|
+
"valueType": "number"
|
|
10452
|
+
},
|
|
10453
|
+
{
|
|
10454
|
+
"path": "excluded",
|
|
10455
|
+
"valueType": "number"
|
|
10456
|
+
},
|
|
10457
|
+
{
|
|
10458
|
+
"path": "total",
|
|
10459
|
+
"valueType": "number"
|
|
10460
|
+
}
|
|
10461
|
+
],
|
|
10375
10462
|
"heating-valve": [{
|
|
10376
10463
|
"path": "position",
|
|
10377
10464
|
"valueType": "number"
|
|
@@ -10406,20 +10493,10 @@ Object.freeze({
|
|
|
10406
10493
|
"valueType": "number"
|
|
10407
10494
|
}
|
|
10408
10495
|
],
|
|
10409
|
-
"humidity-sensor": [
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10413
|
-
},
|
|
10414
|
-
{
|
|
10415
|
-
"path": "unit",
|
|
10416
|
-
"valueType": "string"
|
|
10417
|
-
},
|
|
10418
|
-
{
|
|
10419
|
-
"path": "precision",
|
|
10420
|
-
"valueType": "number"
|
|
10421
|
-
}
|
|
10422
|
-
],
|
|
10496
|
+
"humidity-sensor": [{
|
|
10497
|
+
"path": "percent",
|
|
10498
|
+
"valueType": "number"
|
|
10499
|
+
}],
|
|
10423
10500
|
"image": [{
|
|
10424
10501
|
"path": "url",
|
|
10425
10502
|
"valueType": "string"
|
|
@@ -10627,6 +10704,10 @@ Object.freeze({
|
|
|
10627
10704
|
]
|
|
10628
10705
|
}
|
|
10629
10706
|
],
|
|
10707
|
+
"meter": [{
|
|
10708
|
+
"path": "value",
|
|
10709
|
+
"valueType": "number"
|
|
10710
|
+
}],
|
|
10630
10711
|
"motion": [
|
|
10631
10712
|
{
|
|
10632
10713
|
"path": "detected",
|
|
@@ -10758,20 +10839,10 @@ Object.freeze({
|
|
|
10758
10839
|
"valueType": "boolean"
|
|
10759
10840
|
}
|
|
10760
10841
|
],
|
|
10761
|
-
"numeric-sensor": [
|
|
10762
|
-
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
},
|
|
10766
|
-
{
|
|
10767
|
-
"path": "unit",
|
|
10768
|
-
"valueType": "string"
|
|
10769
|
-
},
|
|
10770
|
-
{
|
|
10771
|
-
"path": "precision",
|
|
10772
|
-
"valueType": "number"
|
|
10773
|
-
}
|
|
10774
|
-
],
|
|
10842
|
+
"numeric-sensor": [{
|
|
10843
|
+
"path": "value",
|
|
10844
|
+
"valueType": "number"
|
|
10845
|
+
}],
|
|
10775
10846
|
"pet-feeder": [
|
|
10776
10847
|
{
|
|
10777
10848
|
"path": "foodLevel",
|
|
@@ -10863,14 +10934,6 @@ Object.freeze({
|
|
|
10863
10934
|
{
|
|
10864
10935
|
"path": "powerFactor",
|
|
10865
10936
|
"valueType": "number"
|
|
10866
|
-
},
|
|
10867
|
-
{
|
|
10868
|
-
"path": "unit",
|
|
10869
|
-
"valueType": "string"
|
|
10870
|
-
},
|
|
10871
|
-
{
|
|
10872
|
-
"path": "precision",
|
|
10873
|
-
"valueType": "number"
|
|
10874
10937
|
}
|
|
10875
10938
|
],
|
|
10876
10939
|
"presence": [
|
|
@@ -10899,20 +10962,10 @@ Object.freeze({
|
|
|
10899
10962
|
"valueType": "number"
|
|
10900
10963
|
}
|
|
10901
10964
|
],
|
|
10902
|
-
"pressure-sensor": [
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
},
|
|
10907
|
-
{
|
|
10908
|
-
"path": "unit",
|
|
10909
|
-
"valueType": "string"
|
|
10910
|
-
},
|
|
10911
|
-
{
|
|
10912
|
-
"path": "precision",
|
|
10913
|
-
"valueType": "number"
|
|
10914
|
-
}
|
|
10915
|
-
],
|
|
10965
|
+
"pressure-sensor": [{
|
|
10966
|
+
"path": "hpa",
|
|
10967
|
+
"valueType": "number"
|
|
10968
|
+
}],
|
|
10916
10969
|
"privacy-mask": [{
|
|
10917
10970
|
"path": "enabled",
|
|
10918
10971
|
"valueType": "boolean"
|
|
@@ -11223,20 +11276,10 @@ Object.freeze({
|
|
|
11223
11276
|
"path": "tampered",
|
|
11224
11277
|
"valueType": "boolean"
|
|
11225
11278
|
}],
|
|
11226
|
-
"temperature-sensor": [
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
},
|
|
11231
|
-
{
|
|
11232
|
-
"path": "unit",
|
|
11233
|
-
"valueType": "string"
|
|
11234
|
-
},
|
|
11235
|
-
{
|
|
11236
|
-
"path": "precision",
|
|
11237
|
-
"valueType": "number"
|
|
11238
|
-
}
|
|
11239
|
-
],
|
|
11279
|
+
"temperature-sensor": [{
|
|
11280
|
+
"path": "celsius",
|
|
11281
|
+
"valueType": "number"
|
|
11282
|
+
}],
|
|
11240
11283
|
"update": [
|
|
11241
11284
|
{
|
|
11242
11285
|
"path": "currentVersion",
|
|
@@ -11347,10 +11390,6 @@ Object.freeze({
|
|
|
11347
11390
|
"path": "temperature",
|
|
11348
11391
|
"valueType": "number"
|
|
11349
11392
|
},
|
|
11350
|
-
{
|
|
11351
|
-
"path": "temperatureUnit",
|
|
11352
|
-
"valueType": "string"
|
|
11353
|
-
},
|
|
11354
11393
|
{
|
|
11355
11394
|
"path": "humidity",
|
|
11356
11395
|
"valueType": "number"
|
|
@@ -11359,18 +11398,10 @@ Object.freeze({
|
|
|
11359
11398
|
"path": "pressure",
|
|
11360
11399
|
"valueType": "number"
|
|
11361
11400
|
},
|
|
11362
|
-
{
|
|
11363
|
-
"path": "pressureUnit",
|
|
11364
|
-
"valueType": "string"
|
|
11365
|
-
},
|
|
11366
11401
|
{
|
|
11367
11402
|
"path": "windSpeed",
|
|
11368
11403
|
"valueType": "number"
|
|
11369
11404
|
},
|
|
11370
|
-
{
|
|
11371
|
-
"path": "windSpeedUnit",
|
|
11372
|
-
"valueType": "string"
|
|
11373
|
-
},
|
|
11374
11405
|
{
|
|
11375
11406
|
"path": "windBearing",
|
|
11376
11407
|
"valueType": "number"
|
|
@@ -11420,7 +11451,7 @@ object({
|
|
|
11420
11451
|
params: record(string(), union([string(), number()])).optional()
|
|
11421
11452
|
});
|
|
11422
11453
|
//#endregion
|
|
11423
|
-
//#region ../types/dist/err-msg-
|
|
11454
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
11424
11455
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
11425
11456
|
DeviceType["Camera"] = "camera";
|
|
11426
11457
|
DeviceType["Hub"] = "hub";
|
|
@@ -11514,8 +11545,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
11514
11545
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11515
11546
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
11516
11547
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
11517
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
11548
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
11549
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
11518
11550
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
11551
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
11552
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
11553
|
+
DeviceType["Washer"] = "washer";
|
|
11554
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
11555
|
+
DeviceType["Dryer"] = "dryer";
|
|
11519
11556
|
return DeviceType;
|
|
11520
11557
|
}({});
|
|
11521
11558
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11773,7 +11810,7 @@ function errMsg(err) {
|
|
|
11773
11810
|
return String(err);
|
|
11774
11811
|
}
|
|
11775
11812
|
//#endregion
|
|
11776
|
-
//#region ../types/dist/composition-
|
|
11813
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11777
11814
|
/**
|
|
11778
11815
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11779
11816
|
*
|
|
@@ -12088,6 +12125,13 @@ var table = {
|
|
|
12088
12125
|
apply: () => {
|
|
12089
12126
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
12090
12127
|
}
|
|
12128
|
+
},
|
|
12129
|
+
schmitt: {
|
|
12130
|
+
minArgs: 3,
|
|
12131
|
+
maxArgs: 5,
|
|
12132
|
+
apply: () => {
|
|
12133
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
12134
|
+
}
|
|
12091
12135
|
}
|
|
12092
12136
|
};
|
|
12093
12137
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -12528,15 +12572,232 @@ function validateExpressionSource(src) {
|
|
|
12528
12572
|
}
|
|
12529
12573
|
return null;
|
|
12530
12574
|
}
|
|
12531
|
-
/**
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
|
|
12575
|
+
/**
|
|
12576
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
12577
|
+
*
|
|
12578
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
12579
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
12580
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
12581
|
+
*
|
|
12582
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
12583
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
12584
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
12585
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
12586
|
+
* can move later without moving the others.
|
|
12587
|
+
*/
|
|
12588
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
12589
|
+
var APPLIANCE_KINDS = [
|
|
12590
|
+
"washer",
|
|
12591
|
+
"dryer",
|
|
12592
|
+
"dishwasher"
|
|
12593
|
+
];
|
|
12594
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
12595
|
+
/**
|
|
12596
|
+
* Statistics and integrals over a history read (D944).
|
|
12597
|
+
*
|
|
12598
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
12599
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
12600
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
12601
|
+
* as zero. A truncated read is not published.
|
|
12602
|
+
*/
|
|
12603
|
+
var STATISTIC_STATS = [
|
|
12604
|
+
"min",
|
|
12605
|
+
"max",
|
|
12606
|
+
"mean",
|
|
12607
|
+
"sum",
|
|
12608
|
+
"count",
|
|
12609
|
+
"change"
|
|
12610
|
+
];
|
|
12611
|
+
/**
|
|
12612
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
12613
|
+
*
|
|
12614
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
12615
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
12616
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
12617
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
12618
|
+
*/
|
|
12619
|
+
var MINUTE_MS = 6e4;
|
|
12620
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
12621
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
12622
|
+
var ROLLING_SPANS = [
|
|
12623
|
+
"1h",
|
|
12624
|
+
"24h",
|
|
12625
|
+
"2d",
|
|
12626
|
+
"7d",
|
|
12627
|
+
"30d",
|
|
12628
|
+
"custom"
|
|
12629
|
+
];
|
|
12630
|
+
var CALENDAR_PERIODS = [
|
|
12631
|
+
"today",
|
|
12632
|
+
"yesterday",
|
|
12633
|
+
"this-week",
|
|
12634
|
+
"this-month"
|
|
12635
|
+
];
|
|
12636
|
+
var RESET_PERIODS = [
|
|
12637
|
+
"never",
|
|
12638
|
+
"daily",
|
|
12639
|
+
"weekly",
|
|
12640
|
+
"monthly"
|
|
12641
|
+
];
|
|
12642
|
+
5 * MINUTE_MS;
|
|
12643
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
12644
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
12645
|
+
var rollingWindowObject = object({
|
|
12646
|
+
kind: literal("rolling"),
|
|
12647
|
+
span: _enum(ROLLING_SPANS),
|
|
12648
|
+
customMinutes: number().int().min(5).optional()
|
|
12649
|
+
}).check((payload) => {
|
|
12650
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
12651
|
+
code: "custom",
|
|
12652
|
+
message: "a custom range needs a duration in minutes",
|
|
12653
|
+
path: ["customMinutes"],
|
|
12654
|
+
input: payload.value
|
|
12655
|
+
});
|
|
12656
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
12657
|
+
code: "custom",
|
|
12658
|
+
message: "only a custom range carries a duration",
|
|
12659
|
+
path: ["customMinutes"],
|
|
12660
|
+
input: payload.value
|
|
12661
|
+
});
|
|
12662
|
+
});
|
|
12663
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12664
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12665
|
+
kind: literal("calendar"),
|
|
12666
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12667
|
+
})]);
|
|
12668
|
+
/**
|
|
12669
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
12670
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
12671
|
+
* `composition.ts` (D659).
|
|
12672
|
+
*/
|
|
12535
12673
|
var CompositionSourceRefSchema = object({
|
|
12536
12674
|
/** The owning addon; `stableId` is unique only within it. */
|
|
12537
12675
|
addonId: string().min(1),
|
|
12538
12676
|
stableId: string().min(1)
|
|
12539
12677
|
});
|
|
12678
|
+
var GROUP_TEMPLATE_IDS = [
|
|
12679
|
+
"temperature",
|
|
12680
|
+
"humidity",
|
|
12681
|
+
"pressure",
|
|
12682
|
+
"illuminance",
|
|
12683
|
+
"power",
|
|
12684
|
+
"energy",
|
|
12685
|
+
"battery",
|
|
12686
|
+
"numeric",
|
|
12687
|
+
"motion",
|
|
12688
|
+
"contact",
|
|
12689
|
+
"leak",
|
|
12690
|
+
"smoke",
|
|
12691
|
+
"occupancy",
|
|
12692
|
+
"binary",
|
|
12693
|
+
"switch",
|
|
12694
|
+
"light",
|
|
12695
|
+
"fan",
|
|
12696
|
+
"cover",
|
|
12697
|
+
"valve",
|
|
12698
|
+
"lock",
|
|
12699
|
+
"media-player",
|
|
12700
|
+
"climate"
|
|
12701
|
+
];
|
|
12702
|
+
var NUMERIC_AGGREGATES = [
|
|
12703
|
+
"mean",
|
|
12704
|
+
"median",
|
|
12705
|
+
"min",
|
|
12706
|
+
"max",
|
|
12707
|
+
"sum"
|
|
12708
|
+
];
|
|
12709
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12710
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12711
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12712
|
+
var AGGREGATE_REDUCERS = [
|
|
12713
|
+
"mean",
|
|
12714
|
+
"median",
|
|
12715
|
+
"min",
|
|
12716
|
+
"max",
|
|
12717
|
+
"sum",
|
|
12718
|
+
"any",
|
|
12719
|
+
"all"
|
|
12720
|
+
];
|
|
12721
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12722
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12723
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12724
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12725
|
+
var HelperMemberSchema = object({
|
|
12726
|
+
source: CompositionSourceRefSchema,
|
|
12727
|
+
cap: string().min(1),
|
|
12728
|
+
fieldPath: string().min(1)
|
|
12729
|
+
});
|
|
12730
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12731
|
+
object({
|
|
12732
|
+
kind: literal("group"),
|
|
12733
|
+
templateId: GroupTemplateIdSchema,
|
|
12734
|
+
aggregate: AggregateReducerSchema,
|
|
12735
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12736
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12737
|
+
active: ActiveCriterionSchema.optional()
|
|
12738
|
+
}),
|
|
12739
|
+
object({
|
|
12740
|
+
kind: literal("appliance"),
|
|
12741
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12742
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12743
|
+
thresholdWatts: number().positive(),
|
|
12744
|
+
startDwellMs: number().int().nonnegative(),
|
|
12745
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12746
|
+
member: HelperMemberSchema
|
|
12747
|
+
}),
|
|
12748
|
+
object({
|
|
12749
|
+
kind: literal("statistic"),
|
|
12750
|
+
stat: _enum(STATISTIC_STATS),
|
|
12751
|
+
window: StatisticWindowSchema,
|
|
12752
|
+
source: HelperMemberSchema
|
|
12753
|
+
}),
|
|
12754
|
+
object({
|
|
12755
|
+
kind: literal("integral"),
|
|
12756
|
+
reset: _enum(RESET_PERIODS),
|
|
12757
|
+
output: _enum(["energy", "meter"]),
|
|
12758
|
+
source: HelperMemberSchema
|
|
12759
|
+
}),
|
|
12760
|
+
object({
|
|
12761
|
+
kind: literal("threshold"),
|
|
12762
|
+
source: HelperMemberSchema,
|
|
12763
|
+
high: number(),
|
|
12764
|
+
low: number(),
|
|
12765
|
+
onForMs: number().int().nonnegative(),
|
|
12766
|
+
offForMs: number().int().nonnegative()
|
|
12767
|
+
}),
|
|
12768
|
+
object({
|
|
12769
|
+
kind: literal("arithmetic"),
|
|
12770
|
+
op: _enum([
|
|
12771
|
+
"sum",
|
|
12772
|
+
"difference",
|
|
12773
|
+
"ratio"
|
|
12774
|
+
]),
|
|
12775
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12776
|
+
}),
|
|
12777
|
+
object({
|
|
12778
|
+
kind: literal("expression"),
|
|
12779
|
+
expr: string().min(1),
|
|
12780
|
+
inputs: array(object({
|
|
12781
|
+
name: string().min(1),
|
|
12782
|
+
member: HelperMemberSchema
|
|
12783
|
+
})).min(1).max(64),
|
|
12784
|
+
output: _enum(["number", "boolean"])
|
|
12785
|
+
}),
|
|
12786
|
+
object({
|
|
12787
|
+
kind: literal("derivative"),
|
|
12788
|
+
window: RollingWindowSchema,
|
|
12789
|
+
per: _enum([
|
|
12790
|
+
"second",
|
|
12791
|
+
"minute",
|
|
12792
|
+
"hour"
|
|
12793
|
+
]),
|
|
12794
|
+
source: HelperMemberSchema
|
|
12795
|
+
})
|
|
12796
|
+
]);
|
|
12797
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12798
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12799
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12800
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
12540
12801
|
/** One field of one capability of one source device. */
|
|
12541
12802
|
var CompositionFieldReadSchema = object({
|
|
12542
12803
|
source: CompositionSourceRefSchema,
|
|
@@ -12580,7 +12841,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
12580
12841
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
12581
12842
|
CompositionFromSourceSchema,
|
|
12582
12843
|
CompositionExpressionSourceSchema,
|
|
12583
|
-
CompositionCodeSourceSchema
|
|
12844
|
+
CompositionCodeSourceSchema,
|
|
12845
|
+
object({
|
|
12846
|
+
kind: literal("aggregate"),
|
|
12847
|
+
reducer: _enum([
|
|
12848
|
+
"mean",
|
|
12849
|
+
"median",
|
|
12850
|
+
"min",
|
|
12851
|
+
"max",
|
|
12852
|
+
"sum",
|
|
12853
|
+
"any",
|
|
12854
|
+
"all"
|
|
12855
|
+
]),
|
|
12856
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12857
|
+
/**
|
|
12858
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12859
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12860
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12861
|
+
*/
|
|
12862
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12863
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12864
|
+
publish: _enum([
|
|
12865
|
+
"value",
|
|
12866
|
+
"included",
|
|
12867
|
+
"excluded",
|
|
12868
|
+
"total"
|
|
12869
|
+
]),
|
|
12870
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12871
|
+
empty: _enum([
|
|
12872
|
+
"null",
|
|
12873
|
+
"omit",
|
|
12874
|
+
"offline"
|
|
12875
|
+
])
|
|
12876
|
+
}),
|
|
12877
|
+
object({
|
|
12878
|
+
kind: literal("series"),
|
|
12879
|
+
read: CompositionFieldReadSchema,
|
|
12880
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12881
|
+
publish: _enum([
|
|
12882
|
+
"value",
|
|
12883
|
+
"included",
|
|
12884
|
+
"excluded",
|
|
12885
|
+
"total"
|
|
12886
|
+
]),
|
|
12887
|
+
/**
|
|
12888
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12889
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12890
|
+
*/
|
|
12891
|
+
empty: _enum([
|
|
12892
|
+
"null",
|
|
12893
|
+
"omit",
|
|
12894
|
+
"offline"
|
|
12895
|
+
])
|
|
12896
|
+
})
|
|
12584
12897
|
]);
|
|
12585
12898
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
12586
12899
|
kind: literal("forward"),
|
|
@@ -12626,7 +12939,13 @@ var CompositionSchema = object({
|
|
|
12626
12939
|
kind: literal("existing"),
|
|
12627
12940
|
device: CompositionSourceRefSchema
|
|
12628
12941
|
})]),
|
|
12629
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12942
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12943
|
+
/**
|
|
12944
|
+
* Present when the block is a helper template. Absent on a free
|
|
12945
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12946
|
+
* never the compiled features.
|
|
12947
|
+
*/
|
|
12948
|
+
helper: HelperSpecSchema.optional()
|
|
12630
12949
|
}).superRefine((composition, ctx) => {
|
|
12631
12950
|
const seen = /* @__PURE__ */ new Set();
|
|
12632
12951
|
composition.features.forEach((feature, index) => {
|
|
@@ -17733,7 +18052,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17733
18052
|
*/
|
|
17734
18053
|
interactiveConnectPath: string().min(1).optional(),
|
|
17735
18054
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17736
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
18055
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
18056
|
+
/**
|
|
18057
|
+
* The kind signs in through a server-held interactive session instead of
|
|
18058
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
18059
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
18060
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
18061
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
18062
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
18063
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
18064
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
18065
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
18066
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
18067
|
+
* offers it as the default path; the fields the session fills are
|
|
18068
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
18069
|
+
*/
|
|
18070
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17737
18071
|
}))
|
|
17738
18072
|
});
|
|
17739
18073
|
var ListInputSchema = object({
|
|
@@ -18834,7 +19168,12 @@ var CompositionProblemSchema = object({
|
|
|
18834
19168
|
"item-field-reserved",
|
|
18835
19169
|
"target-missing",
|
|
18836
19170
|
"target-unreadable",
|
|
18837
|
-
"not-replaceable"
|
|
19171
|
+
"not-replaceable",
|
|
19172
|
+
"native-capability-replace",
|
|
19173
|
+
"mixed-quantity",
|
|
19174
|
+
"helper-mismatch",
|
|
19175
|
+
"member-constraint",
|
|
19176
|
+
"retention"
|
|
18838
19177
|
]),
|
|
18839
19178
|
path: string(),
|
|
18840
19179
|
message: string()
|
|
@@ -18855,7 +19194,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18855
19194
|
"null",
|
|
18856
19195
|
"offline",
|
|
18857
19196
|
"unknown",
|
|
18858
|
-
"release"
|
|
19197
|
+
"release",
|
|
19198
|
+
"omit"
|
|
18859
19199
|
]);
|
|
18860
19200
|
/**
|
|
18861
19201
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18892,9 +19232,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18892
19232
|
reads: array(CompositionFieldReadSchema)
|
|
18893
19233
|
});
|
|
18894
19234
|
/**
|
|
18895
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18896
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18897
|
-
*
|
|
19235
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
19236
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
19237
|
+
* Replacing a capability the device already serves is refused
|
|
19238
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
19239
|
+
* wire for a claim the hub already holds.
|
|
18898
19240
|
*/
|
|
18899
19241
|
var CompositionFeatureModeSchema = _enum([
|
|
18900
19242
|
"new",
|
|
@@ -19065,8 +19407,392 @@ Object.freeze({
|
|
|
19065
19407
|
latchedAt: {
|
|
19066
19408
|
kind: "fixed",
|
|
19067
19409
|
result: ["number", "null"]
|
|
19410
|
+
},
|
|
19411
|
+
schmitt: {
|
|
19412
|
+
kind: "fixed",
|
|
19413
|
+
result: ["boolean", "null"]
|
|
19068
19414
|
}
|
|
19069
19415
|
});
|
|
19416
|
+
/**
|
|
19417
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19418
|
+
* Data, not a form default written into the block.
|
|
19419
|
+
*/
|
|
19420
|
+
var NOW$2 = {
|
|
19421
|
+
fieldPath: "lastFetchedAt",
|
|
19422
|
+
expr: "now"
|
|
19423
|
+
};
|
|
19424
|
+
var CHANGED = {
|
|
19425
|
+
fieldPath: "lastChangedAt",
|
|
19426
|
+
expr: "now"
|
|
19427
|
+
};
|
|
19428
|
+
function numeric(input) {
|
|
19429
|
+
return {
|
|
19430
|
+
...input,
|
|
19431
|
+
family: "numeric",
|
|
19432
|
+
deviceType: DeviceType.Sensor,
|
|
19433
|
+
memberDeviceType: DeviceType.Sensor,
|
|
19434
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19435
|
+
activeWhen: void 0,
|
|
19436
|
+
commandCaps: [],
|
|
19437
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
19438
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
19439
|
+
accept: [{
|
|
19440
|
+
cap: input.outputCap,
|
|
19441
|
+
fieldPath: input.outputField
|
|
19442
|
+
}]
|
|
19443
|
+
};
|
|
19444
|
+
}
|
|
19445
|
+
function binary(input) {
|
|
19446
|
+
return {
|
|
19447
|
+
...input,
|
|
19448
|
+
family: "binary",
|
|
19449
|
+
deviceType: DeviceType.Sensor,
|
|
19450
|
+
memberDeviceType: DeviceType.Sensor,
|
|
19451
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19452
|
+
activeWhen: void 0,
|
|
19453
|
+
commandCaps: [],
|
|
19454
|
+
quantity: "none",
|
|
19455
|
+
baseUnit: void 0,
|
|
19456
|
+
aggregates: BINARY_AGGREGATES,
|
|
19457
|
+
empty: "offline"
|
|
19458
|
+
};
|
|
19459
|
+
}
|
|
19460
|
+
var GROUP_TEMPLATES = [
|
|
19461
|
+
numeric({
|
|
19462
|
+
id: "temperature",
|
|
19463
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
19464
|
+
role: DeviceRole.TemperatureSensor,
|
|
19465
|
+
outputCap: "temperature-sensor",
|
|
19466
|
+
outputField: "celsius",
|
|
19467
|
+
quantity: "temperature",
|
|
19468
|
+
defaultAggregate: "mean",
|
|
19469
|
+
empty: "null",
|
|
19470
|
+
companions: [NOW$2]
|
|
19471
|
+
}),
|
|
19472
|
+
numeric({
|
|
19473
|
+
id: "humidity",
|
|
19474
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19475
|
+
role: DeviceRole.HumiditySensor,
|
|
19476
|
+
outputCap: "humidity-sensor",
|
|
19477
|
+
outputField: "percent",
|
|
19478
|
+
quantity: "humidity",
|
|
19479
|
+
defaultAggregate: "mean",
|
|
19480
|
+
empty: "null",
|
|
19481
|
+
companions: [NOW$2]
|
|
19482
|
+
}),
|
|
19483
|
+
numeric({
|
|
19484
|
+
id: "pressure",
|
|
19485
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
19486
|
+
role: DeviceRole.PressureSensor,
|
|
19487
|
+
outputCap: "pressure-sensor",
|
|
19488
|
+
outputField: "hpa",
|
|
19489
|
+
quantity: "pressure",
|
|
19490
|
+
defaultAggregate: "mean",
|
|
19491
|
+
empty: "null",
|
|
19492
|
+
companions: [NOW$2]
|
|
19493
|
+
}),
|
|
19494
|
+
numeric({
|
|
19495
|
+
id: "illuminance",
|
|
19496
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
19497
|
+
role: DeviceRole.AmbientLightSensor,
|
|
19498
|
+
outputCap: "ambient-light-sensor",
|
|
19499
|
+
outputField: "lux",
|
|
19500
|
+
quantity: "illuminance",
|
|
19501
|
+
defaultAggregate: "mean",
|
|
19502
|
+
empty: "null",
|
|
19503
|
+
companions: [NOW$2]
|
|
19504
|
+
}),
|
|
19505
|
+
numeric({
|
|
19506
|
+
id: "power",
|
|
19507
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
19508
|
+
role: DeviceRole.PowerSensor,
|
|
19509
|
+
outputCap: "power-meter",
|
|
19510
|
+
outputField: "watts",
|
|
19511
|
+
quantity: "power",
|
|
19512
|
+
defaultAggregate: "sum",
|
|
19513
|
+
empty: "omit",
|
|
19514
|
+
companions: [NOW$2]
|
|
19515
|
+
}),
|
|
19516
|
+
numeric({
|
|
19517
|
+
id: "energy",
|
|
19518
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
19519
|
+
role: DeviceRole.EnergySensor,
|
|
19520
|
+
outputCap: "power-meter",
|
|
19521
|
+
outputField: "kwhTotal",
|
|
19522
|
+
quantity: "energy",
|
|
19523
|
+
defaultAggregate: "sum",
|
|
19524
|
+
empty: "omit",
|
|
19525
|
+
companions: [NOW$2]
|
|
19526
|
+
}),
|
|
19527
|
+
numeric({
|
|
19528
|
+
id: "battery",
|
|
19529
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19530
|
+
role: DeviceRole.BatterySensor,
|
|
19531
|
+
outputCap: "battery",
|
|
19532
|
+
outputField: "percentage",
|
|
19533
|
+
quantity: "percentage",
|
|
19534
|
+
defaultAggregate: "mean",
|
|
19535
|
+
empty: "null",
|
|
19536
|
+
companions: [
|
|
19537
|
+
{
|
|
19538
|
+
fieldPath: "charging",
|
|
19539
|
+
expr: "\"unknown\""
|
|
19540
|
+
},
|
|
19541
|
+
{
|
|
19542
|
+
fieldPath: "sleeping",
|
|
19543
|
+
expr: "false"
|
|
19544
|
+
},
|
|
19545
|
+
{
|
|
19546
|
+
fieldPath: "lastUpdated",
|
|
19547
|
+
expr: "now"
|
|
19548
|
+
}
|
|
19549
|
+
]
|
|
19550
|
+
}),
|
|
19551
|
+
numeric({
|
|
19552
|
+
id: "numeric",
|
|
19553
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
19554
|
+
role: DeviceRole.NumericSensor,
|
|
19555
|
+
outputCap: "numeric-sensor",
|
|
19556
|
+
outputField: "value",
|
|
19557
|
+
quantity: "device",
|
|
19558
|
+
defaultAggregate: "mean",
|
|
19559
|
+
empty: "null",
|
|
19560
|
+
companions: [NOW$2]
|
|
19561
|
+
}),
|
|
19562
|
+
binary({
|
|
19563
|
+
id: "motion",
|
|
19564
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
19565
|
+
role: DeviceRole.MotionSensor,
|
|
19566
|
+
outputCap: "motion",
|
|
19567
|
+
outputField: "detected",
|
|
19568
|
+
defaultAggregate: "any",
|
|
19569
|
+
accept: [{
|
|
19570
|
+
cap: "motion",
|
|
19571
|
+
fieldPath: "detected"
|
|
19572
|
+
}],
|
|
19573
|
+
companions: [{
|
|
19574
|
+
fieldPath: "lastDetectedAt",
|
|
19575
|
+
expr: "null"
|
|
19576
|
+
}, {
|
|
19577
|
+
fieldPath: "autoClearAfterMs",
|
|
19578
|
+
expr: "null"
|
|
19579
|
+
}]
|
|
19580
|
+
}),
|
|
19581
|
+
binary({
|
|
19582
|
+
id: "contact",
|
|
19583
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
19584
|
+
role: DeviceRole.ContactSensor,
|
|
19585
|
+
outputCap: "contact",
|
|
19586
|
+
outputField: "entryOpen",
|
|
19587
|
+
defaultAggregate: "any",
|
|
19588
|
+
accept: [{
|
|
19589
|
+
cap: "contact",
|
|
19590
|
+
fieldPath: "entryOpen"
|
|
19591
|
+
}],
|
|
19592
|
+
companions: [CHANGED]
|
|
19593
|
+
}),
|
|
19594
|
+
binary({
|
|
19595
|
+
id: "leak",
|
|
19596
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
19597
|
+
role: DeviceRole.LeakSensor,
|
|
19598
|
+
outputCap: "flood",
|
|
19599
|
+
outputField: "flooded",
|
|
19600
|
+
defaultAggregate: "any",
|
|
19601
|
+
accept: [{
|
|
19602
|
+
cap: "flood",
|
|
19603
|
+
fieldPath: "flooded"
|
|
19604
|
+
}],
|
|
19605
|
+
companions: [CHANGED]
|
|
19606
|
+
}),
|
|
19607
|
+
binary({
|
|
19608
|
+
id: "smoke",
|
|
19609
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
19610
|
+
role: DeviceRole.SmokeSensor,
|
|
19611
|
+
outputCap: "smoke",
|
|
19612
|
+
outputField: "detected",
|
|
19613
|
+
defaultAggregate: "any",
|
|
19614
|
+
accept: [{
|
|
19615
|
+
cap: "smoke",
|
|
19616
|
+
fieldPath: "detected"
|
|
19617
|
+
}],
|
|
19618
|
+
companions: [CHANGED]
|
|
19619
|
+
}),
|
|
19620
|
+
binary({
|
|
19621
|
+
id: "occupancy",
|
|
19622
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
19623
|
+
role: DeviceRole.BinarySensor,
|
|
19624
|
+
outputCap: "binary",
|
|
19625
|
+
outputField: "on",
|
|
19626
|
+
defaultAggregate: "any",
|
|
19627
|
+
accept: [{
|
|
19628
|
+
cap: "motion",
|
|
19629
|
+
fieldPath: "detected"
|
|
19630
|
+
}, {
|
|
19631
|
+
cap: "binary",
|
|
19632
|
+
fieldPath: "on"
|
|
19633
|
+
}],
|
|
19634
|
+
companions: [CHANGED]
|
|
19635
|
+
}),
|
|
19636
|
+
binary({
|
|
19637
|
+
id: "binary",
|
|
19638
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
19639
|
+
role: DeviceRole.BinarySensor,
|
|
19640
|
+
outputCap: "binary",
|
|
19641
|
+
outputField: "on",
|
|
19642
|
+
defaultAggregate: "any",
|
|
19643
|
+
accept: [{
|
|
19644
|
+
cap: "binary",
|
|
19645
|
+
fieldPath: "on"
|
|
19646
|
+
}],
|
|
19647
|
+
companions: [CHANGED]
|
|
19648
|
+
}),
|
|
19649
|
+
actuator({
|
|
19650
|
+
id: "switch",
|
|
19651
|
+
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.",
|
|
19652
|
+
deviceType: DeviceType.Switch,
|
|
19653
|
+
outputCap: "switch",
|
|
19654
|
+
outputField: "on",
|
|
19655
|
+
member: {
|
|
19656
|
+
cap: "switch",
|
|
19657
|
+
fieldPath: "on"
|
|
19658
|
+
},
|
|
19659
|
+
commandCaps: ["switch"]
|
|
19660
|
+
}),
|
|
19661
|
+
actuator({
|
|
19662
|
+
id: "light",
|
|
19663
|
+
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.",
|
|
19664
|
+
deviceType: DeviceType.Light,
|
|
19665
|
+
outputCap: "switch",
|
|
19666
|
+
outputField: "on",
|
|
19667
|
+
member: {
|
|
19668
|
+
cap: "switch",
|
|
19669
|
+
fieldPath: "on"
|
|
19670
|
+
},
|
|
19671
|
+
commandCaps: [
|
|
19672
|
+
"switch",
|
|
19673
|
+
"brightness",
|
|
19674
|
+
"color"
|
|
19675
|
+
]
|
|
19676
|
+
}),
|
|
19677
|
+
actuator({
|
|
19678
|
+
id: "fan",
|
|
19679
|
+
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.",
|
|
19680
|
+
deviceType: DeviceType.Fan,
|
|
19681
|
+
outputCap: "switch",
|
|
19682
|
+
outputField: "on",
|
|
19683
|
+
member: {
|
|
19684
|
+
cap: "switch",
|
|
19685
|
+
fieldPath: "on"
|
|
19686
|
+
},
|
|
19687
|
+
commandCaps: ["switch", "fan-control"]
|
|
19688
|
+
}),
|
|
19689
|
+
actuator({
|
|
19690
|
+
id: "cover",
|
|
19691
|
+
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.",
|
|
19692
|
+
deviceType: DeviceType.Cover,
|
|
19693
|
+
outputCap: "group-active",
|
|
19694
|
+
outputField: "active",
|
|
19695
|
+
member: {
|
|
19696
|
+
cap: "cover",
|
|
19697
|
+
fieldPath: "state"
|
|
19698
|
+
},
|
|
19699
|
+
activeWhen: [
|
|
19700
|
+
"open",
|
|
19701
|
+
"opening",
|
|
19702
|
+
"stopped"
|
|
19703
|
+
],
|
|
19704
|
+
commandCaps: ["cover"]
|
|
19705
|
+
}),
|
|
19706
|
+
actuator({
|
|
19707
|
+
id: "valve",
|
|
19708
|
+
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.",
|
|
19709
|
+
deviceType: DeviceType.Valve,
|
|
19710
|
+
outputCap: "group-active",
|
|
19711
|
+
outputField: "active",
|
|
19712
|
+
member: {
|
|
19713
|
+
cap: "valve",
|
|
19714
|
+
fieldPath: "state"
|
|
19715
|
+
},
|
|
19716
|
+
activeWhen: [
|
|
19717
|
+
"open",
|
|
19718
|
+
"opening",
|
|
19719
|
+
"stopped"
|
|
19720
|
+
],
|
|
19721
|
+
commandCaps: ["valve"]
|
|
19722
|
+
}),
|
|
19723
|
+
actuator({
|
|
19724
|
+
id: "lock",
|
|
19725
|
+
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.",
|
|
19726
|
+
deviceType: DeviceType.Lock,
|
|
19727
|
+
outputCap: "group-active",
|
|
19728
|
+
outputField: "active",
|
|
19729
|
+
member: {
|
|
19730
|
+
cap: "lock-control",
|
|
19731
|
+
fieldPath: "state"
|
|
19732
|
+
},
|
|
19733
|
+
activeWhen: ["locked"],
|
|
19734
|
+
commandCaps: ["lock-control"]
|
|
19735
|
+
}),
|
|
19736
|
+
actuator({
|
|
19737
|
+
id: "media-player",
|
|
19738
|
+
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.",
|
|
19739
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19740
|
+
outputCap: "group-active",
|
|
19741
|
+
outputField: "active",
|
|
19742
|
+
member: {
|
|
19743
|
+
cap: "media-player",
|
|
19744
|
+
fieldPath: "state"
|
|
19745
|
+
},
|
|
19746
|
+
activeWhen: ["playing", "buffering"],
|
|
19747
|
+
commandCaps: ["media-player"]
|
|
19748
|
+
}),
|
|
19749
|
+
actuator({
|
|
19750
|
+
id: "climate",
|
|
19751
|
+
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.",
|
|
19752
|
+
deviceType: DeviceType.Thermostat,
|
|
19753
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19754
|
+
outputCap: "group-active",
|
|
19755
|
+
outputField: "active",
|
|
19756
|
+
member: {
|
|
19757
|
+
cap: "climate-control",
|
|
19758
|
+
fieldPath: "mode"
|
|
19759
|
+
},
|
|
19760
|
+
activeWhen: [
|
|
19761
|
+
"heat",
|
|
19762
|
+
"cool",
|
|
19763
|
+
"auto",
|
|
19764
|
+
"heat_cool",
|
|
19765
|
+
"fan_only",
|
|
19766
|
+
"dry"
|
|
19767
|
+
],
|
|
19768
|
+
commandCaps: ["climate-control"]
|
|
19769
|
+
})
|
|
19770
|
+
];
|
|
19771
|
+
function actuator(input) {
|
|
19772
|
+
return {
|
|
19773
|
+
id: input.id,
|
|
19774
|
+
summary: input.summary,
|
|
19775
|
+
deviceType: input.deviceType,
|
|
19776
|
+
outputCap: input.outputCap,
|
|
19777
|
+
outputField: input.outputField,
|
|
19778
|
+
commandCaps: input.commandCaps,
|
|
19779
|
+
family: "actuator",
|
|
19780
|
+
role: void 0,
|
|
19781
|
+
memberDeviceType: input.deviceType,
|
|
19782
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19783
|
+
activeWhen: input.activeWhen,
|
|
19784
|
+
quantity: "none",
|
|
19785
|
+
baseUnit: void 0,
|
|
19786
|
+
aggregates: BINARY_AGGREGATES,
|
|
19787
|
+
defaultAggregate: "any",
|
|
19788
|
+
empty: "offline",
|
|
19789
|
+
accept: [input.member],
|
|
19790
|
+
companions: [CHANGED]
|
|
19791
|
+
};
|
|
19792
|
+
}
|
|
19793
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19794
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19795
|
+
DeviceType.Camera;
|
|
19070
19796
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
19071
19797
|
/**
|
|
19072
19798
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20893,12 +21619,12 @@ function buildDeviceAdminUrl(parts) {
|
|
|
20893
21619
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20894
21620
|
* in-place so dispatch keeps working.
|
|
20895
21621
|
*
|
|
20896
|
-
* **
|
|
20897
|
-
*
|
|
20898
|
-
*
|
|
20899
|
-
*
|
|
20900
|
-
* (`ha-domain-mapping`)
|
|
20901
|
-
* stored after that point.
|
|
21622
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
21623
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
21624
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
21625
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
21626
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
21627
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20902
21628
|
*
|
|
20903
21629
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20904
21630
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20912,6 +21638,14 @@ var SourceInfoSchema = object({
|
|
|
20912
21638
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20913
21639
|
* Used to detect rename when `id` changes. */
|
|
20914
21640
|
uniqueId: string().optional(),
|
|
21641
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
21642
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
21643
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
21644
|
+
dateTimeShape: _enum([
|
|
21645
|
+
"date",
|
|
21646
|
+
"time",
|
|
21647
|
+
"datetime"
|
|
21648
|
+
]).optional(),
|
|
20915
21649
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20916
21650
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20917
21651
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -42016,7 +42750,8 @@ method(object({
|
|
|
42016
42750
|
"enum"
|
|
42017
42751
|
]),
|
|
42018
42752
|
enumValues: array(string()).optional(),
|
|
42019
|
-
item: boolean().optional()
|
|
42753
|
+
item: boolean().optional(),
|
|
42754
|
+
quantity: ReadingQuantitySchema.optional()
|
|
42020
42755
|
})).readonly(),
|
|
42021
42756
|
itemArray: object({
|
|
42022
42757
|
path: string(),
|
|
@@ -44377,7 +45112,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
44377
45112
|
});
|
|
44378
45113
|
/**
|
|
44379
45114
|
* Optional, richer endpoint shape returned by providers that expose
|
|
44380
|
-
* MORE than one ingress concurrently (Tailscale
|
|
45115
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
44381
45116
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
44382
45117
|
* the originating provider config (mode + sourcePort) so the
|
|
44383
45118
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -45860,8 +46595,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
45860
46595
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
45861
46596
|
var MaskGridShapeSchema = object({
|
|
45862
46597
|
kind: literal("grid"),
|
|
45863
|
-
gridWidth: number(),
|
|
45864
|
-
gridHeight: number(),
|
|
46598
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
46599
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
45865
46600
|
cells: array(boolean())
|
|
45866
46601
|
});
|
|
45867
46602
|
discriminatedUnion("kind", [
|
|
@@ -45973,6 +46708,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45973
46708
|
"detection-blind",
|
|
45974
46709
|
"motion-noisy",
|
|
45975
46710
|
"motion-calm",
|
|
46711
|
+
"package-llm-silent",
|
|
46712
|
+
"package-llm-answered",
|
|
45976
46713
|
"recording-stalled",
|
|
45977
46714
|
"recording-healthy",
|
|
45978
46715
|
"recording-degraded",
|
|
@@ -47062,7 +47799,20 @@ var NcRuleInputSchema = object({
|
|
|
47062
47799
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
47063
47800
|
* path does not run Zod defaults.
|
|
47064
47801
|
*/
|
|
47065
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
47802
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
47803
|
+
/**
|
|
47804
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
47805
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
47806
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
47807
|
+
* same mark the Library writes, and records whose notification it was and
|
|
47808
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
47809
|
+
*
|
|
47810
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
47811
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
47812
|
+
* authored before this field meant. An editor turns it off by writing
|
|
47813
|
+
* `false`, so it needs no `clear` key.
|
|
47814
|
+
*/
|
|
47815
|
+
askVerdict: boolean().optional()
|
|
47066
47816
|
});
|
|
47067
47817
|
/**
|
|
47068
47818
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -57064,6 +57814,28 @@ var PackageVersionInfoSchema = object({
|
|
|
57064
57814
|
deprecated: string().optional(),
|
|
57065
57815
|
distTags: array(string()).readonly()
|
|
57066
57816
|
});
|
|
57817
|
+
/**
|
|
57818
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
57819
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
57820
|
+
* tarball failure — never an empty string standing in for either.
|
|
57821
|
+
*/
|
|
57822
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
57823
|
+
object({
|
|
57824
|
+
status: literal("ok"),
|
|
57825
|
+
markdown: string()
|
|
57826
|
+
}),
|
|
57827
|
+
object({ status: literal("missing") }),
|
|
57828
|
+
object({
|
|
57829
|
+
status: literal("error"),
|
|
57830
|
+
message: string()
|
|
57831
|
+
})
|
|
57832
|
+
]);
|
|
57833
|
+
var PackageDocsSchema = object({
|
|
57834
|
+
name: string(),
|
|
57835
|
+
version: string(),
|
|
57836
|
+
readme: PackageDocBodySchema,
|
|
57837
|
+
changelog: PackageDocBodySchema
|
|
57838
|
+
});
|
|
57067
57839
|
var SearchResultSchema = object({
|
|
57068
57840
|
name: string(),
|
|
57069
57841
|
version: string(),
|
|
@@ -57282,7 +58054,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
57282
58054
|
}), object({ success: literal(true) }), {
|
|
57283
58055
|
kind: "mutation",
|
|
57284
58056
|
auth: "admin"
|
|
57285
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
58057
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
58058
|
+
name: string().min(1),
|
|
58059
|
+
version: string().min(1).optional()
|
|
58060
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
57286
58061
|
kind: "mutation",
|
|
57287
58062
|
auth: "admin"
|
|
57288
58063
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -57341,27 +58116,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
57341
58116
|
*/
|
|
57342
58117
|
var AirQualitySensorStatusSchema = object({
|
|
57343
58118
|
/** Carbon dioxide concentration in ppm. */
|
|
57344
|
-
co2Ppm: number().min(0).optional(),
|
|
58119
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
57345
58120
|
/** Total volatile organic compounds in ppb. */
|
|
57346
|
-
vocPpb: number().min(0).optional(),
|
|
58121
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
57347
58122
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
57348
|
-
pm25: number().min(0).optional(),
|
|
58123
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
57349
58124
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
57350
|
-
pm10: number().min(0).optional(),
|
|
58125
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
57351
58126
|
/** Composite AQI value (typically 0..500). */
|
|
57352
|
-
aqi: number().optional(),
|
|
58127
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
57353
58128
|
/** Ms epoch when the slice was last updated. */
|
|
57354
|
-
lastFetchedAt: number()
|
|
57355
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
57356
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
57357
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
57358
|
-
* per slice is unambiguous. */
|
|
57359
|
-
unit: string().optional(),
|
|
57360
|
-
/** Suggested decimal places for numeric display.
|
|
57361
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57362
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57363
|
-
* auto-formatting when absent. */
|
|
57364
|
-
precision: number().int().min(0).max(10).optional()
|
|
58129
|
+
lastFetchedAt: number()
|
|
57365
58130
|
});
|
|
57366
58131
|
var airQualitySensorCapability = {
|
|
57367
58132
|
name: "air-quality-sensor",
|
|
@@ -57398,12 +58163,12 @@ var airQualitySensorCapability = {
|
|
|
57398
58163
|
},
|
|
57399
58164
|
pm25: {
|
|
57400
58165
|
kind: "gauge",
|
|
57401
|
-
unit: "
|
|
58166
|
+
unit: "µg/m³",
|
|
57402
58167
|
deadband: 1
|
|
57403
58168
|
},
|
|
57404
58169
|
pm10: {
|
|
57405
58170
|
kind: "gauge",
|
|
57406
|
-
unit: "
|
|
58171
|
+
unit: "µg/m³",
|
|
57407
58172
|
deadband: 1
|
|
57408
58173
|
},
|
|
57409
58174
|
aqi: {
|
|
@@ -57421,22 +58186,13 @@ var airQualitySensorCapability = {
|
|
|
57421
58186
|
* entries with `device_class: illuminance`.
|
|
57422
58187
|
*/
|
|
57423
58188
|
var AmbientLightSensorStatusSchema = object({
|
|
57424
|
-
/** Current illuminance in lux (lx). */
|
|
57425
|
-
lux: number().min(0).meta({
|
|
57426
|
-
|
|
58189
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
58190
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
58191
|
+
precision: 0,
|
|
57427
58192
|
label: "Illuminance"
|
|
57428
|
-
}),
|
|
58193
|
+
})),
|
|
57429
58194
|
/** Ms epoch when the slice was last updated. */
|
|
57430
|
-
lastFetchedAt: number()
|
|
57431
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
57432
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
57433
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
57434
|
-
unit: string().optional(),
|
|
57435
|
-
/** Suggested decimal places for numeric display.
|
|
57436
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57437
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57438
|
-
* auto-formatting when absent. */
|
|
57439
|
-
precision: number().int().min(0).max(10).optional()
|
|
58195
|
+
lastFetchedAt: number()
|
|
57440
58196
|
});
|
|
57441
58197
|
var ambientLightSensorCapability = {
|
|
57442
58198
|
name: "ambient-light-sensor",
|
|
@@ -57468,12 +58224,7 @@ var ambientLightSensorCapability = {
|
|
|
57468
58224
|
} } },
|
|
57469
58225
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57470
58226
|
* whether persisting is worth a SQLite commit. */
|
|
57471
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
57472
|
-
customize: {
|
|
57473
|
-
version: 1,
|
|
57474
|
-
advanced: "derive",
|
|
57475
|
-
targets: []
|
|
57476
|
-
}
|
|
58227
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
57477
58228
|
};
|
|
57478
58229
|
/**
|
|
57479
58230
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -57700,10 +58451,7 @@ var BatteryStatusSchema = object({
|
|
|
57700
58451
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
57701
58452
|
* declines to band a non-finite reading, which is the correct shape.
|
|
57702
58453
|
*/
|
|
57703
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
57704
|
-
unit: "%",
|
|
57705
|
-
label: "Charge"
|
|
57706
|
-
}),
|
|
58454
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
57707
58455
|
/**
|
|
57708
58456
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
57709
58457
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -57730,7 +58478,14 @@ var BatteryStatusSchema = object({
|
|
|
57730
58478
|
*/
|
|
57731
58479
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
57732
58480
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
57733
|
-
lastUpdated: number(),
|
|
58481
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
58482
|
+
/**
|
|
58483
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
58484
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
58485
|
+
* that only report charge. A second reading on this cap, not a second
|
|
58486
|
+
* `numeric-sensor` on the same device.
|
|
58487
|
+
*/
|
|
58488
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
57734
58489
|
/**
|
|
57735
58490
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
57736
58491
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -57777,12 +58532,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
57777
58532
|
DeviceType.Switch,
|
|
57778
58533
|
DeviceType.PetFeeder,
|
|
57779
58534
|
DeviceType.Container,
|
|
57780
|
-
DeviceType.Thermostat
|
|
58535
|
+
DeviceType.Thermostat,
|
|
58536
|
+
DeviceType.EventEmitter
|
|
57781
58537
|
];
|
|
57782
58538
|
/** Generic Customize target for the percentage reading (D936). */
|
|
57783
58539
|
var batteryCustomize = {
|
|
57784
58540
|
version: 1,
|
|
57785
|
-
advanced: "derive",
|
|
57786
58541
|
targets: [{
|
|
57787
58542
|
id: "percentage",
|
|
57788
58543
|
cardinality: "scalar",
|
|
@@ -57791,7 +58546,7 @@ var batteryCustomize = {
|
|
|
57791
58546
|
stateField: "percentage"
|
|
57792
58547
|
},
|
|
57793
58548
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
57794
|
-
apply: "add
|
|
58549
|
+
apply: "add",
|
|
57795
58550
|
path: "percentage",
|
|
57796
58551
|
sources: [{
|
|
57797
58552
|
kind: "field",
|
|
@@ -57912,10 +58667,16 @@ onStatusChanged: { data: object({
|
|
|
57912
58667
|
/**
|
|
57913
58668
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
57914
58669
|
*/
|
|
57915
|
-
history: { fields: {
|
|
57916
|
-
|
|
57917
|
-
|
|
57918
|
-
|
|
58670
|
+
history: { fields: {
|
|
58671
|
+
percentage: {
|
|
58672
|
+
kind: "gauge",
|
|
58673
|
+
unit: "%"
|
|
58674
|
+
},
|
|
58675
|
+
volts: {
|
|
58676
|
+
kind: "gauge",
|
|
58677
|
+
unit: "V"
|
|
58678
|
+
}
|
|
58679
|
+
} },
|
|
57919
58680
|
customize: batteryCustomize,
|
|
57920
58681
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57921
58682
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57962,12 +58723,7 @@ var binaryCapability = {
|
|
|
57962
58723
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57963
58724
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57964
58725
|
* whether persisting is worth a SQLite commit. */
|
|
57965
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57966
|
-
customize: {
|
|
57967
|
-
version: 1,
|
|
57968
|
-
advanced: "derive",
|
|
57969
|
-
targets: []
|
|
57970
|
-
}
|
|
58726
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57971
58727
|
};
|
|
57972
58728
|
/**
|
|
57973
58729
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57983,7 +58739,7 @@ var binaryCapability = {
|
|
|
57983
58739
|
*/
|
|
57984
58740
|
var BrightnessStatusSchema = object({
|
|
57985
58741
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57986
|
-
percentage: number().min(0).max(100),
|
|
58742
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57987
58743
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57988
58744
|
lastChangedAt: number()
|
|
57989
58745
|
});
|
|
@@ -58437,21 +59193,21 @@ var ClimateControlStatusSchema = object({
|
|
|
58437
59193
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
58438
59194
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
58439
59195
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
58440
|
-
target: number().nullable(),
|
|
59196
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
58441
59197
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
58442
59198
|
* in `heat_cool` mode. */
|
|
58443
|
-
targetHigh: number().nullable(),
|
|
59199
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
58444
59200
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
58445
59201
|
* in `heat_cool` mode. */
|
|
58446
|
-
targetLow: number().nullable(),
|
|
59202
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
58447
59203
|
/** Target relative humidity (0..100). Null when the device has no
|
|
58448
59204
|
* humidity control. */
|
|
58449
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59205
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58450
59206
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
58451
59207
|
* the device's internal sensor. */
|
|
58452
|
-
currentTemp: number().nullable(),
|
|
59208
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
58453
59209
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
58454
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59210
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58455
59211
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
58456
59212
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
58457
59213
|
swingVertical: boolean().nullable(),
|
|
@@ -58459,11 +59215,11 @@ var ClimateControlStatusSchema = object({
|
|
|
58459
59215
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
58460
59216
|
swingHorizontal: boolean().nullable(),
|
|
58461
59217
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58462
|
-
minTemp: number().nullable().optional(),
|
|
59218
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58463
59219
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58464
|
-
maxTemp: number().nullable().optional(),
|
|
59220
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58465
59221
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
58466
|
-
tempStep: number().positive().nullable().optional(),
|
|
59222
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
58467
59223
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
58468
59224
|
lastFetchedAt: number()
|
|
58469
59225
|
});
|
|
@@ -58605,17 +59361,17 @@ var climateControlCapability = {
|
|
|
58605
59361
|
* modes to expose in the picker without a slice fetch.
|
|
58606
59362
|
*/
|
|
58607
59363
|
var RgbTripletSchema = object({
|
|
58608
|
-
r: number().int().min(0).max(255),
|
|
58609
|
-
g: number().int().min(0).max(255),
|
|
58610
|
-
b: number().int().min(0).max(255)
|
|
59364
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
59365
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
59366
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
58611
59367
|
});
|
|
58612
59368
|
var HsvTripletSchema = object({
|
|
58613
59369
|
/** Hue in degrees, 0..360. */
|
|
58614
|
-
h: number().min(0).max(360),
|
|
59370
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
58615
59371
|
/** Saturation as 0..100 inclusive. */
|
|
58616
|
-
s: number().min(0).max(100),
|
|
59372
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
58617
59373
|
/** Value/brightness as 0..100 inclusive. */
|
|
58618
|
-
v: number().min(0).max(100)
|
|
59374
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
58619
59375
|
});
|
|
58620
59376
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
58621
59377
|
object({
|
|
@@ -58644,7 +59400,7 @@ var ColorStatusSchema = object({
|
|
|
58644
59400
|
/** Populated when `mode === 'hsv'`. */
|
|
58645
59401
|
hsv: HsvTripletSchema.optional(),
|
|
58646
59402
|
/** Populated when `mode === 'mired'`. */
|
|
58647
|
-
mireds: number().int().optional(),
|
|
59403
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
58648
59404
|
/** Ms epoch of the last operator-driven change. */
|
|
58649
59405
|
lastChangedAt: number()
|
|
58650
59406
|
});
|
|
@@ -58839,18 +59595,12 @@ _enum([
|
|
|
58839
59595
|
"empty",
|
|
58840
59596
|
"full"
|
|
58841
59597
|
]);
|
|
58842
|
-
/**
|
|
58843
|
-
|
|
58844
|
-
|
|
58845
|
-
"days",
|
|
58846
|
-
"hours",
|
|
58847
|
-
"cycles"
|
|
58848
|
-
]);
|
|
58849
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
58850
|
-
* days). `value` null = unknown (D393). */
|
|
59598
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
59599
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
59600
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
58851
59601
|
var ConsumableRemainingSchema = object({
|
|
58852
|
-
value: number().min(0).nullable(),
|
|
58853
|
-
|
|
59602
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
59603
|
+
kind: ConsumableRemainingKindSchema
|
|
58854
59604
|
});
|
|
58855
59605
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
58856
59606
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -58863,7 +59613,7 @@ var ConsumableItemSchema = object({
|
|
|
58863
59613
|
/** Display name. */
|
|
58864
59614
|
label: string().min(1),
|
|
58865
59615
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
58866
|
-
level: number().min(0).max(100).nullable(),
|
|
59616
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58867
59617
|
/** The provider's discrete verdict when known (binary mode). */
|
|
58868
59618
|
status: ConsumableStatusSchema.nullable(),
|
|
58869
59619
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58945,8 +59695,8 @@ var consumablesCustomize = {
|
|
|
58945
59695
|
transforms: [{ kind: "identity" }]
|
|
58946
59696
|
}],
|
|
58947
59697
|
literals: [{
|
|
58948
|
-
path: "remaining.
|
|
58949
|
-
values: [...
|
|
59698
|
+
path: "remaining.kind",
|
|
59699
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58950
59700
|
}]
|
|
58951
59701
|
},
|
|
58952
59702
|
{
|
|
@@ -59075,7 +59825,6 @@ reset: method(object({
|
|
|
59075
59825
|
},
|
|
59076
59826
|
"remaining.value": {
|
|
59077
59827
|
kind: "gauge",
|
|
59078
|
-
unitFrom: "remaining.unit",
|
|
59079
59828
|
deadband: 1,
|
|
59080
59829
|
displayName: "Remaining"
|
|
59081
59830
|
}
|
|
@@ -59145,10 +59894,9 @@ var contactCapability = {
|
|
|
59145
59894
|
* (empty array for the other kinds). It lives in the slice because
|
|
59146
59895
|
* HA `select.*` entities may update their options at runtime.
|
|
59147
59896
|
*
|
|
59148
|
-
*
|
|
59149
|
-
*
|
|
59150
|
-
*
|
|
59151
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
59897
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
59898
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
59899
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
59152
59900
|
*/
|
|
59153
59901
|
var ControlStatusSchema = object({
|
|
59154
59902
|
kind: _enum([
|
|
@@ -59160,39 +59908,17 @@ var ControlStatusSchema = object({
|
|
|
59160
59908
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
59161
59909
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
59162
59910
|
* or time-only — HA accepts all three forms). */
|
|
59163
|
-
value: union([number(), string()]),
|
|
59911
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
59164
59912
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
59165
59913
|
options: array(string()),
|
|
59166
59914
|
/** Ms epoch when the slice was last updated. */
|
|
59167
59915
|
lastChangedAt: number(),
|
|
59168
|
-
/**
|
|
59169
|
-
|
|
59170
|
-
|
|
59171
|
-
|
|
59172
|
-
/**
|
|
59173
|
-
|
|
59174
|
-
min: number().optional(),
|
|
59175
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
59176
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
59177
|
-
max: number().optional(),
|
|
59178
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
59179
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
59180
|
-
step: number().optional(),
|
|
59181
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
59182
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
59183
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
59184
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
59185
|
-
precision: number().int().min(0).max(10).optional(),
|
|
59186
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
59187
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
59188
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
59189
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
59190
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
59191
|
-
format: _enum([
|
|
59192
|
-
"date",
|
|
59193
|
-
"time",
|
|
59194
|
-
"datetime"
|
|
59195
|
-
]).optional()
|
|
59916
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
59917
|
+
min: number().optional().meta(readingMeta("device")),
|
|
59918
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
59919
|
+
max: number().optional().meta(readingMeta("device")),
|
|
59920
|
+
/** Step increment, in the device quantity's base unit. */
|
|
59921
|
+
step: number().optional().meta(readingMeta("device"))
|
|
59196
59922
|
});
|
|
59197
59923
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
59198
59924
|
object({
|
|
@@ -59258,9 +59984,9 @@ var CoverStatusSchema = object({
|
|
|
59258
59984
|
]),
|
|
59259
59985
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
59260
59986
|
* no intermediate position surface. */
|
|
59261
|
-
position: number().min(0).max(100).nullable(),
|
|
59987
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59262
59988
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
59263
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59989
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59264
59990
|
/** Ms epoch when the slice was last updated. */
|
|
59265
59991
|
lastChangedAt: number()
|
|
59266
59992
|
});
|
|
@@ -59363,9 +60089,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
59363
60089
|
var DayNightStatusSchema = object({
|
|
59364
60090
|
mode: DayNightModeSchema,
|
|
59365
60091
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
59366
|
-
sensitivity: number().optional(),
|
|
60092
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
59367
60093
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
59368
|
-
switchDelaySec: number().optional(),
|
|
60094
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
59369
60095
|
lastFetchedAt: number()
|
|
59370
60096
|
});
|
|
59371
60097
|
/**
|
|
@@ -59583,11 +60309,11 @@ var DishwasherStatusSchema = object({
|
|
|
59583
60309
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
59584
60310
|
availablePrograms: array(string()),
|
|
59585
60311
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
59586
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
60312
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59587
60313
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
59588
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
60314
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59589
60315
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
59590
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
60316
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59591
60317
|
/** True when the door is reported open; null when the door state is not known. */
|
|
59592
60318
|
doorOpen: boolean().nullable(),
|
|
59593
60319
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -59611,7 +60337,7 @@ var DishwasherStatusSchema = object({
|
|
|
59611
60337
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
59612
60338
|
machineCareDue: boolean().nullable(),
|
|
59613
60339
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
59614
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
60340
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
59615
60341
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
59616
60342
|
halfLoad: boolean().nullable(),
|
|
59617
60343
|
hygienePlus: boolean().nullable(),
|
|
@@ -59626,7 +60352,7 @@ var DishwasherStatusSchema = object({
|
|
|
59626
60352
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
59627
60353
|
activeEvents: array(string()),
|
|
59628
60354
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
59629
|
-
errorCode: number().nullable(),
|
|
60355
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
59630
60356
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
59631
60357
|
errorLabel: string().nullable(),
|
|
59632
60358
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -59857,7 +60583,7 @@ var DoorbellStatusSchema = object({
|
|
|
59857
60583
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
59858
60584
|
lastPressedAt: number().nullable(),
|
|
59859
60585
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
59860
|
-
pressCountSinceStart: number()
|
|
60586
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
59861
60587
|
});
|
|
59862
60588
|
var DoorbellPressEventSchema = object({
|
|
59863
60589
|
deviceId: number(),
|
|
@@ -59922,17 +60648,7 @@ onPressed: {
|
|
|
59922
60648
|
history: "none",
|
|
59923
60649
|
customize: doorbellCustomize
|
|
59924
60650
|
};
|
|
59925
|
-
|
|
59926
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
59927
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
59928
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
59929
|
-
* The option set is stable across observations; it is persisted in the
|
|
59930
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
59931
|
-
* stored in `sourceInfo`.
|
|
59932
|
-
*/
|
|
59933
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
59934
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
59935
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
60651
|
+
_enum([
|
|
59936
60652
|
"date",
|
|
59937
60653
|
"time",
|
|
59938
60654
|
"datetime"
|
|
@@ -59940,12 +60656,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59940
60656
|
var EnumSensorStatusSchema = object({
|
|
59941
60657
|
value: string(),
|
|
59942
60658
|
/**
|
|
59943
|
-
* Set
|
|
59944
|
-
* as
|
|
59945
|
-
*
|
|
59946
|
-
* a time-only sensor → `'time'`.
|
|
60659
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
60660
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
60661
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59947
60662
|
*/
|
|
59948
|
-
|
|
60663
|
+
timestamp: boolean().optional(),
|
|
59949
60664
|
/** Ms epoch when the slice was last updated. */
|
|
59950
60665
|
lastFetchedAt: number()
|
|
59951
60666
|
});
|
|
@@ -59972,11 +60687,11 @@ var enumSensorCapability = {
|
|
|
59972
60687
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59973
60688
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59974
60689
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59975
|
-
* `
|
|
60690
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59976
60691
|
*/
|
|
59977
60692
|
history: { fields: { value: {
|
|
59978
60693
|
kind: "enum",
|
|
59979
|
-
skipWhenSet: "
|
|
60694
|
+
skipWhenSet: "timestamp"
|
|
59980
60695
|
} } },
|
|
59981
60696
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59982
60697
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59996,13 +60711,13 @@ var EventFireSchema = object({
|
|
|
59996
60711
|
deviceId: number(),
|
|
59997
60712
|
eventType: string(),
|
|
59998
60713
|
data: record(string(), unknown()).nullable(),
|
|
59999
|
-
timestamp: number(),
|
|
60000
|
-
seq: number()
|
|
60714
|
+
timestamp: number().meta(readingMeta("none")),
|
|
60715
|
+
seq: number().meta(readingMeta("count"))
|
|
60001
60716
|
});
|
|
60002
60717
|
var EventEmitterStatusSchema = object({
|
|
60003
60718
|
eventTypes: array(string()),
|
|
60004
60719
|
lastEvent: EventFireSchema.nullable(),
|
|
60005
|
-
eventCountSinceStart: number()
|
|
60720
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
60006
60721
|
});
|
|
60007
60722
|
var eventEmitterCapability = {
|
|
60008
60723
|
name: "event-emitter",
|
|
@@ -60415,10 +61130,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
60415
61130
|
var FanControlStatusSchema = object({
|
|
60416
61131
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
60417
61132
|
* speed surface (single-speed fan). */
|
|
60418
|
-
percentage: number().min(0).max(100).nullable(),
|
|
61133
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60419
61134
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
60420
61135
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
60421
|
-
percentageStep: number().positive().optional(),
|
|
61136
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
60422
61137
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
60423
61138
|
* — empty string when no preset is active or supported. */
|
|
60424
61139
|
preset: string(),
|
|
@@ -60539,7 +61254,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
60539
61254
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
60540
61255
|
model: string().nullable(),
|
|
60541
61256
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
60542
|
-
channelCount: number().nullable(),
|
|
61257
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
60543
61258
|
/**
|
|
60544
61259
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
60545
61260
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -60662,9 +61377,151 @@ var gasCapability = {
|
|
|
60662
61377
|
* whether persisting is worth a SQLite commit. */
|
|
60663
61378
|
volatileStateFields: ["lastChangedAt"]
|
|
60664
61379
|
};
|
|
61380
|
+
var GroupCommandsSchema = object({
|
|
61381
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
61382
|
+
results: array(object({
|
|
61383
|
+
deviceId: number().int().nonnegative(),
|
|
61384
|
+
cap: string().min(1),
|
|
61385
|
+
method: string().min(1),
|
|
61386
|
+
ok: boolean(),
|
|
61387
|
+
error: string().optional(),
|
|
61388
|
+
/** Ms epoch of the attempt. */
|
|
61389
|
+
at: number()
|
|
61390
|
+
})) });
|
|
61391
|
+
var groupCommandsCapability = {
|
|
61392
|
+
name: "group-commands",
|
|
61393
|
+
scope: "device",
|
|
61394
|
+
deviceNative: true,
|
|
61395
|
+
mode: "singleton",
|
|
61396
|
+
deviceTypes: [
|
|
61397
|
+
DeviceType.Switch,
|
|
61398
|
+
DeviceType.Light,
|
|
61399
|
+
DeviceType.Fan,
|
|
61400
|
+
DeviceType.Cover,
|
|
61401
|
+
DeviceType.Valve,
|
|
61402
|
+
DeviceType.Lock,
|
|
61403
|
+
DeviceType.MediaPlayer,
|
|
61404
|
+
DeviceType.Thermostat,
|
|
61405
|
+
DeviceType.Climate
|
|
61406
|
+
],
|
|
61407
|
+
methods: {},
|
|
61408
|
+
status: {
|
|
61409
|
+
schema: GroupCommandsSchema,
|
|
61410
|
+
kind: "push"
|
|
61411
|
+
},
|
|
61412
|
+
runtimeState: GroupCommandsSchema,
|
|
61413
|
+
/**
|
|
61414
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
61415
|
+
* failure would outlive the command that caused it.
|
|
61416
|
+
*
|
|
61417
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61418
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61419
|
+
*/
|
|
61420
|
+
durability: "session",
|
|
61421
|
+
history: "none"
|
|
61422
|
+
};
|
|
61423
|
+
/**
|
|
61424
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
61425
|
+
* included member is, or every included member is. What "active" means is the
|
|
61426
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
61427
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
61428
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
61429
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
61430
|
+
* empty included set takes the device offline, never `active: false`.
|
|
61431
|
+
*/
|
|
61432
|
+
var GroupActiveSchema = object({
|
|
61433
|
+
active: boolean().meta({ label: "Active" }),
|
|
61434
|
+
/** Ms epoch when the slice was last updated. */
|
|
61435
|
+
lastChangedAt: number()
|
|
61436
|
+
});
|
|
61437
|
+
var groupActiveCapability = {
|
|
61438
|
+
name: "group-active",
|
|
61439
|
+
scope: "device",
|
|
61440
|
+
deviceNative: true,
|
|
61441
|
+
mode: "singleton",
|
|
61442
|
+
deviceTypes: [
|
|
61443
|
+
DeviceType.Cover,
|
|
61444
|
+
DeviceType.Valve,
|
|
61445
|
+
DeviceType.Lock,
|
|
61446
|
+
DeviceType.MediaPlayer,
|
|
61447
|
+
DeviceType.Climate,
|
|
61448
|
+
DeviceType.Thermostat
|
|
61449
|
+
],
|
|
61450
|
+
methods: {},
|
|
61451
|
+
status: {
|
|
61452
|
+
schema: GroupActiveSchema,
|
|
61453
|
+
kind: "push"
|
|
61454
|
+
},
|
|
61455
|
+
runtimeState: GroupActiveSchema,
|
|
61456
|
+
/**
|
|
61457
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
61458
|
+
* next source event; a restored value would outlive the members it named.
|
|
61459
|
+
*
|
|
61460
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61461
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61462
|
+
*/
|
|
61463
|
+
durability: "session",
|
|
61464
|
+
history: "none"
|
|
61465
|
+
};
|
|
61466
|
+
/**
|
|
61467
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
61468
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
61469
|
+
* The reading itself stays on the output capability. History is none — the
|
|
61470
|
+
* series that later statistics read is the output cap's own history block.
|
|
61471
|
+
*/
|
|
61472
|
+
var GroupStatusSchema = object({
|
|
61473
|
+
/** Members whose current value entered the aggregate. */
|
|
61474
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
61475
|
+
precision: 0,
|
|
61476
|
+
label: "Reporting"
|
|
61477
|
+
})),
|
|
61478
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
61479
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
61480
|
+
precision: 0,
|
|
61481
|
+
label: "Excluded"
|
|
61482
|
+
})),
|
|
61483
|
+
/** `included` + `excluded`. */
|
|
61484
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
61485
|
+
precision: 0,
|
|
61486
|
+
label: "Members"
|
|
61487
|
+
}))
|
|
61488
|
+
});
|
|
61489
|
+
var groupStatusCapability = {
|
|
61490
|
+
name: "group-status",
|
|
61491
|
+
scope: "device",
|
|
61492
|
+
deviceNative: true,
|
|
61493
|
+
mode: "singleton",
|
|
61494
|
+
deviceTypes: [
|
|
61495
|
+
DeviceType.Sensor,
|
|
61496
|
+
DeviceType.Switch,
|
|
61497
|
+
DeviceType.Light,
|
|
61498
|
+
DeviceType.Fan,
|
|
61499
|
+
DeviceType.Cover,
|
|
61500
|
+
DeviceType.Valve,
|
|
61501
|
+
DeviceType.Lock,
|
|
61502
|
+
DeviceType.MediaPlayer,
|
|
61503
|
+
DeviceType.Thermostat,
|
|
61504
|
+
DeviceType.Climate
|
|
61505
|
+
],
|
|
61506
|
+
methods: {},
|
|
61507
|
+
status: {
|
|
61508
|
+
schema: GroupStatusSchema,
|
|
61509
|
+
kind: "push"
|
|
61510
|
+
},
|
|
61511
|
+
runtimeState: GroupStatusSchema,
|
|
61512
|
+
/**
|
|
61513
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
61514
|
+
* next source event; a restored count would outlive the readings it named.
|
|
61515
|
+
*
|
|
61516
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61517
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61518
|
+
*/
|
|
61519
|
+
durability: "session",
|
|
61520
|
+
history: "none"
|
|
61521
|
+
};
|
|
60665
61522
|
var HeatingValveStatusSchema = object({
|
|
60666
61523
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
60667
|
-
position: number().min(0).max(100).nullable(),
|
|
61524
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60668
61525
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
60669
61526
|
lastFetchedAt: number()
|
|
60670
61527
|
});
|
|
@@ -60707,9 +61564,9 @@ var HumidifierStatusSchema = object({
|
|
|
60707
61564
|
/** Whether the humidifier is currently on. */
|
|
60708
61565
|
on: boolean(),
|
|
60709
61566
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
60710
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
61567
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60711
61568
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
60712
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
61569
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60713
61570
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
60714
61571
|
* device has no mode surface. */
|
|
60715
61572
|
mode: string().nullable(),
|
|
@@ -60719,9 +61576,9 @@ var HumidifierStatusSchema = object({
|
|
|
60719
61576
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
60720
61577
|
action: string().nullable(),
|
|
60721
61578
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
60722
|
-
minHumidity: number().nullable(),
|
|
61579
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60723
61580
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
60724
|
-
maxHumidity: number().nullable(),
|
|
61581
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60725
61582
|
/** Ms epoch when the slice was last updated. */
|
|
60726
61583
|
lastChangedAt: number()
|
|
60727
61584
|
});
|
|
@@ -60791,22 +61648,13 @@ var humidifierCapability = {
|
|
|
60791
61648
|
* `sourceInfo`.
|
|
60792
61649
|
*/
|
|
60793
61650
|
var HumiditySensorStatusSchema = object({
|
|
60794
|
-
/** Current relative humidity, 0..100. */
|
|
60795
|
-
percent: number().min(0).max(100).meta({
|
|
60796
|
-
|
|
61651
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
61652
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
61653
|
+
precision: 0,
|
|
60797
61654
|
label: "Humidity"
|
|
60798
|
-
}),
|
|
61655
|
+
})),
|
|
60799
61656
|
/** Ms epoch when the slice was last updated. */
|
|
60800
|
-
lastFetchedAt: number()
|
|
60801
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
60802
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
60803
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
60804
|
-
unit: string().optional(),
|
|
60805
|
-
/** Suggested decimal places for numeric display.
|
|
60806
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
60807
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
60808
|
-
* auto-formatting when absent. */
|
|
60809
|
-
precision: number().int().min(0).max(10).optional()
|
|
61657
|
+
lastFetchedAt: number()
|
|
60810
61658
|
});
|
|
60811
61659
|
var humiditySensorCapability = {
|
|
60812
61660
|
name: "humidity-sensor",
|
|
@@ -60837,12 +61685,7 @@ var humiditySensorCapability = {
|
|
|
60837
61685
|
} } },
|
|
60838
61686
|
/** Clock fields: written, but excluded from the compare that decides
|
|
60839
61687
|
* whether persisting is worth a SQLite commit. */
|
|
60840
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
60841
|
-
customize: {
|
|
60842
|
-
version: 1,
|
|
60843
|
-
advanced: "derive",
|
|
60844
|
-
targets: []
|
|
60845
|
-
}
|
|
61688
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
60846
61689
|
};
|
|
60847
61690
|
/**
|
|
60848
61691
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -60863,7 +61706,7 @@ var ImageStatusSchema = object({
|
|
|
60863
61706
|
* entity exposes no `entity_picture` (yet). */
|
|
60864
61707
|
url: string().nullable(),
|
|
60865
61708
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
60866
|
-
lastUpdated: number().nullable()
|
|
61709
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
60867
61710
|
});
|
|
60868
61711
|
var imageCapability = {
|
|
60869
61712
|
name: "image",
|
|
@@ -60951,19 +61794,19 @@ var NormalizedRangeSchema = object({
|
|
|
60951
61794
|
*/
|
|
60952
61795
|
var ImageSettingsStatusSchema = object({
|
|
60953
61796
|
/** Normalized 0–100. */
|
|
60954
|
-
brightness: number().optional(),
|
|
61797
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60955
61798
|
/** Normalized 0–100. */
|
|
60956
|
-
contrast: number().optional(),
|
|
61799
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60957
61800
|
/** Normalized 0–100. */
|
|
60958
|
-
saturation: number().optional(),
|
|
61801
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60959
61802
|
/** Normalized 0–100. */
|
|
60960
|
-
sharpness: number().optional(),
|
|
61803
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60961
61804
|
mirror: boolean().optional(),
|
|
60962
61805
|
flip: boolean().optional(),
|
|
60963
61806
|
rotate: ImageRotateSchema.optional(),
|
|
60964
61807
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60965
61808
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60966
|
-
warmth: number().optional(),
|
|
61809
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60967
61810
|
exposureMode: ExposureModeSchema.optional(),
|
|
60968
61811
|
backlightMode: BacklightModeSchema.optional(),
|
|
60969
61812
|
lastFetchedAt: number()
|
|
@@ -61242,10 +62085,10 @@ var IntercomAbilitySchema = object({
|
|
|
61242
62085
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
61243
62086
|
codecs: array(string()),
|
|
61244
62087
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
61245
|
-
sampleRate: number(),
|
|
62088
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
61246
62089
|
duplex: _enum(["half", "full"]),
|
|
61247
62090
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
61248
|
-
maxBacklogMs: number()
|
|
62091
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
61249
62092
|
});
|
|
61250
62093
|
var IntercomStatusSchema = object({
|
|
61251
62094
|
/** True while a talk session is open. */
|
|
@@ -61472,13 +62315,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
61472
62315
|
activity: LawnMowerActivitySchema,
|
|
61473
62316
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
61474
62317
|
* reading. */
|
|
61475
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
62318
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61476
62319
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
61477
62320
|
* task is active / progress is unavailable. */
|
|
61478
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
62321
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61479
62322
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
61480
62323
|
* or null when unknown. */
|
|
61481
|
-
currentCode: number().nullable(),
|
|
62324
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
61482
62325
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
61483
62326
|
currentCodeLabel: string().nullable(),
|
|
61484
62327
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61931,7 +62774,14 @@ var lockControlCapability = {
|
|
|
61931
62774
|
}),
|
|
61932
62775
|
unlock: method(object({
|
|
61933
62776
|
deviceId: number().int().nonnegative(),
|
|
61934
|
-
code: string().min(1).optional()
|
|
62777
|
+
code: string().min(1).optional(),
|
|
62778
|
+
/**
|
|
62779
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
62780
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
62781
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
62782
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
62783
|
+
*/
|
|
62784
|
+
confirm: boolean().optional()
|
|
61935
62785
|
}), _void(), {
|
|
61936
62786
|
kind: "mutation",
|
|
61937
62787
|
auth: "protected"
|
|
@@ -61968,6 +62818,44 @@ var lockControlCapability = {
|
|
|
61968
62818
|
volatileStateFields: ["lastChangedAt"]
|
|
61969
62819
|
};
|
|
61970
62820
|
/**
|
|
62821
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
62822
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
62823
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
62824
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
62825
|
+
*/
|
|
62826
|
+
var MeterStatusSchema = object({
|
|
62827
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
62828
|
+
lastFetchedAt: number()
|
|
62829
|
+
});
|
|
62830
|
+
var meterCapability = {
|
|
62831
|
+
name: "meter",
|
|
62832
|
+
scope: "device",
|
|
62833
|
+
deviceNative: true,
|
|
62834
|
+
mode: "singleton",
|
|
62835
|
+
deviceTypes: [DeviceType.Sensor],
|
|
62836
|
+
methods: {},
|
|
62837
|
+
status: {
|
|
62838
|
+
schema: MeterStatusSchema,
|
|
62839
|
+
kind: "push"
|
|
62840
|
+
},
|
|
62841
|
+
runtimeState: MeterStatusSchema,
|
|
62842
|
+
/**
|
|
62843
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
62844
|
+
* history integral. A restart shows it only until the history pass
|
|
62845
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
62846
|
+
*
|
|
62847
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
62848
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
62849
|
+
*/
|
|
62850
|
+
durability: "restored",
|
|
62851
|
+
history: { fields: { value: {
|
|
62852
|
+
kind: "counter",
|
|
62853
|
+
deadband: .001,
|
|
62854
|
+
minIntervalMs: 6e4
|
|
62855
|
+
} } },
|
|
62856
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
62857
|
+
};
|
|
62858
|
+
/**
|
|
61971
62859
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61972
62860
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61973
62861
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -62011,7 +62899,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
62011
62899
|
state: MediaPlayerStateSchema,
|
|
62012
62900
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
62013
62901
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
62014
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
62902
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62015
62903
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
62016
62904
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
62017
62905
|
isMuted: boolean().nullable(),
|
|
@@ -62024,10 +62912,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
62024
62912
|
currentMedia: MediaInfoSchema.nullable(),
|
|
62025
62913
|
/** Current playback position in ms. Null when not seekable or
|
|
62026
62914
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
62027
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
62915
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
62028
62916
|
/** Total duration of the current media in ms. Null when unknown
|
|
62029
62917
|
* (live stream) or nothing is playing. */
|
|
62030
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
62918
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
62031
62919
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
62032
62920
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
62033
62921
|
shuffle: boolean().nullable(),
|
|
@@ -62336,7 +63224,7 @@ var motionCustomize = {
|
|
|
62336
63224
|
eventName: "onMotionChanged"
|
|
62337
63225
|
},
|
|
62338
63226
|
deviceTypes: [DeviceType.Camera],
|
|
62339
|
-
apply: "
|
|
63227
|
+
apply: "add",
|
|
62340
63228
|
applyAuthority: {
|
|
62341
63229
|
kind: "camera-sensors",
|
|
62342
63230
|
timeoutField: "motionCooldownMs"
|
|
@@ -62408,7 +63296,7 @@ var MotionStatusSchema = object({
|
|
|
62408
63296
|
* it, every provider seeded it at boot, and every session left it
|
|
62409
63297
|
* `detected: true` after its detach.
|
|
62410
63298
|
*/
|
|
62411
|
-
autoClearAfterMs: number().nullable()
|
|
63299
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
62412
63300
|
});
|
|
62413
63301
|
/**
|
|
62414
63302
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -62445,12 +63333,18 @@ var motionCapability = {
|
|
|
62445
63333
|
methods: {
|
|
62446
63334
|
/**
|
|
62447
63335
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
62448
|
-
* for consumers that don't need the full status object
|
|
62449
|
-
*
|
|
62450
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
62451
|
-
* consumer.
|
|
63336
|
+
* for consumers that don't need the full status object. A composed
|
|
63337
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
62452
63338
|
*/
|
|
62453
63339
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
63340
|
+
/**
|
|
63341
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
63342
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
63343
|
+
*/
|
|
63344
|
+
composedMethods: { isDetected: {
|
|
63345
|
+
kind: "slice",
|
|
63346
|
+
field: "detected"
|
|
63347
|
+
} },
|
|
62454
63348
|
events: {
|
|
62455
63349
|
/**
|
|
62456
63350
|
* Fires every time the runner transitions a camera between
|
|
@@ -62590,7 +63484,7 @@ var MotionZoneRegionSchema = object({
|
|
|
62590
63484
|
* the grid region(s). */
|
|
62591
63485
|
var MotionZoneStatusSchema = object({
|
|
62592
63486
|
enabled: boolean(),
|
|
62593
|
-
sensitivity: number(),
|
|
63487
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
62594
63488
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
62595
63489
|
regions: array(MotionZoneRegionSchema),
|
|
62596
63490
|
lastFetchedAt: number()
|
|
@@ -62960,7 +63854,7 @@ var NavigationStatusSchema = object({
|
|
|
62960
63854
|
following: boolean(),
|
|
62961
63855
|
flash: boolean(),
|
|
62962
63856
|
lightMode: NavigationLightModeSchema,
|
|
62963
|
-
lightLevel: number().min(40).max(100),
|
|
63857
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62964
63858
|
/** Ms epoch when the slice was last updated. */
|
|
62965
63859
|
lastChangedAt: number()
|
|
62966
63860
|
});
|
|
@@ -63094,13 +63988,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
63094
63988
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
63095
63989
|
* SKIP a null rather than coerce it.
|
|
63096
63990
|
*/
|
|
63097
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63991
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63098
63992
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
63099
|
-
rssiDbm: number().optional(),
|
|
63993
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
63100
63994
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
63101
63995
|
ssid: string().optional(),
|
|
63102
63996
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
63103
|
-
lastUpdated: number()
|
|
63997
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
63104
63998
|
});
|
|
63105
63999
|
var networkLinkCapability = {
|
|
63106
64000
|
name: "network-link",
|
|
@@ -63485,7 +64379,7 @@ var NotifierStatusSchema = object({
|
|
|
63485
64379
|
lastError: string().nullable(),
|
|
63486
64380
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
63487
64381
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
63488
|
-
queueDepth: number().int().nonnegative(),
|
|
64382
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
63489
64383
|
/** Per-feature capability matrix — authoritative source for the
|
|
63490
64384
|
* compose-form field gating. */
|
|
63491
64385
|
supports: NotifierSupportsSchema
|
|
@@ -63577,11 +64471,9 @@ onSent: { data: object({
|
|
|
63577
64471
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
63578
64472
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
63579
64473
|
*
|
|
63580
|
-
* The
|
|
63581
|
-
*
|
|
63582
|
-
*
|
|
63583
|
-
* The UI reads them directly from the slice — they are the single source
|
|
63584
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
64474
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
64475
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
64476
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
63585
64477
|
*
|
|
63586
64478
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
63587
64479
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -63590,15 +64482,8 @@ onSent: { data: object({
|
|
|
63590
64482
|
* numeric values land here.
|
|
63591
64483
|
*/
|
|
63592
64484
|
var NumericSensorStatusSchema = object({
|
|
63593
|
-
|
|
63594
|
-
|
|
63595
|
-
* Populated live from the upstream source on each state push.
|
|
63596
|
-
* Absent for unitless sensors. */
|
|
63597
|
-
unit: string().optional(),
|
|
63598
|
-
/** Suggested decimal places for numeric display.
|
|
63599
|
-
* Populated live from the upstream source when provided.
|
|
63600
|
-
* Falls back to auto-formatting when absent. */
|
|
63601
|
-
precision: number().int().min(0).max(10).optional(),
|
|
64485
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
64486
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
63602
64487
|
/** Ms epoch when the slice was last updated. */
|
|
63603
64488
|
lastFetchedAt: number()
|
|
63604
64489
|
});
|
|
@@ -63622,11 +64507,11 @@ var numericSensorCapability = {
|
|
|
63622
64507
|
*/
|
|
63623
64508
|
durability: "restored",
|
|
63624
64509
|
/**
|
|
63625
|
-
* History (D850): recorded series. The unit is
|
|
64510
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
64511
|
+
* resolved when the series is read — the cap has no single unit.
|
|
63626
64512
|
*/
|
|
63627
64513
|
history: { fields: { value: {
|
|
63628
64514
|
kind: "gauge",
|
|
63629
|
-
unitFrom: "unit",
|
|
63630
64515
|
minIntervalMs: 3e4
|
|
63631
64516
|
} } },
|
|
63632
64517
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -63918,23 +64803,26 @@ var PetFeederStatusSchema = object({
|
|
|
63918
64803
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
63919
64804
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
63920
64805
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
63921
|
-
foodLevel: number().nullable(),
|
|
64806
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
63922
64807
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63923
64808
|
* single-hopper models. */
|
|
63924
|
-
food1: number().nullable(),
|
|
64809
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63925
64810
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63926
64811
|
* single-hopper models. */
|
|
63927
|
-
food2: number().nullable(),
|
|
64812
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63928
64813
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63929
64814
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63930
64815
|
* below the feeder's low threshold. */
|
|
63931
64816
|
lowFood: boolean(),
|
|
63932
64817
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63933
64818
|
* device has no battery reading. */
|
|
63934
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63935
|
-
/**
|
|
63936
|
-
*
|
|
63937
|
-
|
|
64819
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64820
|
+
/**
|
|
64821
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
64822
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
64823
|
+
* model has no desiccant sensor.
|
|
64824
|
+
*/
|
|
64825
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63938
64826
|
/** True while a feed is in progress. */
|
|
63939
64827
|
feeding: boolean(),
|
|
63940
64828
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63945,7 +64833,7 @@ var PetFeederStatusSchema = object({
|
|
|
63945
64833
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63946
64834
|
error: string().nullable(),
|
|
63947
64835
|
/** Raw device error code (0 / null = no error). */
|
|
63948
|
-
errorCode: number().nullable(),
|
|
64836
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63949
64837
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63950
64838
|
isDualHopper: boolean(),
|
|
63951
64839
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63955,7 +64843,7 @@ var PetFeederStatusSchema = object({
|
|
|
63955
64843
|
/** Play a chime when dispensing. */
|
|
63956
64844
|
feedSound: boolean(),
|
|
63957
64845
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63958
|
-
volume: number(),
|
|
64846
|
+
volume: number().meta(readingMeta("none")),
|
|
63959
64847
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63960
64848
|
lastFetchedAt: number()
|
|
63961
64849
|
});
|
|
@@ -64074,7 +64962,7 @@ var petFeederCapability = {
|
|
|
64074
64962
|
},
|
|
64075
64963
|
desiccantLeftDays: {
|
|
64076
64964
|
kind: "gauge",
|
|
64077
|
-
unit: "
|
|
64965
|
+
unit: "s"
|
|
64078
64966
|
}
|
|
64079
64967
|
} }
|
|
64080
64968
|
};
|
|
@@ -64475,43 +65363,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
64475
65363
|
*/
|
|
64476
65364
|
var PowerMeterStatusSchema = object({
|
|
64477
65365
|
/** Instantaneous power draw in watts. */
|
|
64478
|
-
watts: number().optional().meta({
|
|
64479
|
-
unit: "W",
|
|
64480
|
-
label: "Power"
|
|
64481
|
-
}),
|
|
65366
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
64482
65367
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
64483
|
-
kwhTotal: number().optional().meta({
|
|
64484
|
-
unit: "kWh",
|
|
64485
|
-
label: "Energy"
|
|
64486
|
-
}),
|
|
65368
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
64487
65369
|
/** Voltage in volts. */
|
|
64488
|
-
volts: number().optional(),
|
|
65370
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
64489
65371
|
/** Current in amperes. */
|
|
64490
|
-
amps: number().optional(),
|
|
64491
|
-
/** Apparent power in volt-amperes
|
|
64492
|
-
va: number().optional(),
|
|
65372
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
65373
|
+
/** Apparent power in volt-amperes. */
|
|
65374
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
64493
65375
|
/** Power factor (0..1) if reported. */
|
|
64494
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
65376
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
64495
65377
|
/** Ms epoch when the slice was last updated. */
|
|
64496
|
-
lastFetchedAt: number()
|
|
64497
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
64498
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
64499
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
64500
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
64501
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
64502
|
-
unit: string().optional(),
|
|
64503
|
-
/** Suggested decimal places for numeric display.
|
|
64504
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64505
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64506
|
-
* auto-formatting when absent. */
|
|
64507
|
-
precision: number().int().min(0).max(10).optional()
|
|
65378
|
+
lastFetchedAt: number()
|
|
64508
65379
|
});
|
|
65380
|
+
/**
|
|
65381
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
65382
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
65383
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
65384
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
65385
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
65386
|
+
*/
|
|
65387
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
65388
|
+
DeviceType.Sensor,
|
|
65389
|
+
DeviceType.Switch,
|
|
65390
|
+
DeviceType.Light,
|
|
65391
|
+
DeviceType.Fan,
|
|
65392
|
+
DeviceType.Climate,
|
|
65393
|
+
DeviceType.Thermostat,
|
|
65394
|
+
DeviceType.Humidifier,
|
|
65395
|
+
DeviceType.WaterHeater,
|
|
65396
|
+
DeviceType.MediaPlayer,
|
|
65397
|
+
DeviceType.Washer,
|
|
65398
|
+
DeviceType.Dryer,
|
|
65399
|
+
DeviceType.Dishwasher,
|
|
65400
|
+
DeviceType.Vacuum,
|
|
65401
|
+
DeviceType.LawnMower,
|
|
65402
|
+
DeviceType.PetFeeder
|
|
65403
|
+
];
|
|
65404
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
65405
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
65406
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
65407
|
+
function powerTarget(id, unit) {
|
|
65408
|
+
return {
|
|
65409
|
+
id,
|
|
65410
|
+
cardinality: "scalar",
|
|
65411
|
+
vocabulary: {
|
|
65412
|
+
cap: "power-meter",
|
|
65413
|
+
stateField: id
|
|
65414
|
+
},
|
|
65415
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
65416
|
+
apply: "add",
|
|
65417
|
+
path: id,
|
|
65418
|
+
sources: [{
|
|
65419
|
+
kind: "numeric",
|
|
65420
|
+
requiredUnit: unit,
|
|
65421
|
+
transforms: [{ kind: "identity" }]
|
|
65422
|
+
}],
|
|
65423
|
+
companions: [{
|
|
65424
|
+
kind: "clock",
|
|
65425
|
+
path: "lastFetchedAt",
|
|
65426
|
+
when: "always"
|
|
65427
|
+
}],
|
|
65428
|
+
sourceReport: { status: "assignment-status" },
|
|
65429
|
+
advancedExpression: true
|
|
65430
|
+
};
|
|
65431
|
+
}
|
|
65432
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
65433
|
+
var powerMeterCustomize = {
|
|
65434
|
+
version: 1,
|
|
65435
|
+
targets: [
|
|
65436
|
+
powerTarget("watts", "W"),
|
|
65437
|
+
powerTarget("kwhTotal", "kWh"),
|
|
65438
|
+
powerTarget("volts", "V"),
|
|
65439
|
+
powerTarget("amps", "A")
|
|
65440
|
+
]
|
|
65441
|
+
};
|
|
64509
65442
|
var powerMeterCapability = {
|
|
64510
65443
|
name: "power-meter",
|
|
64511
65444
|
scope: "device",
|
|
64512
65445
|
deviceNative: true,
|
|
64513
65446
|
mode: "singleton",
|
|
64514
|
-
deviceTypes:
|
|
65447
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
64515
65448
|
methods: {},
|
|
64516
65449
|
status: {
|
|
64517
65450
|
schema: PowerMeterStatusSchema,
|
|
@@ -64569,11 +65502,7 @@ var powerMeterCapability = {
|
|
|
64569
65502
|
/** Clock fields: written, but excluded from the compare that decides
|
|
64570
65503
|
* whether persisting is worth a SQLite commit. */
|
|
64571
65504
|
volatileStateFields: ["lastFetchedAt"],
|
|
64572
|
-
customize:
|
|
64573
|
-
version: 1,
|
|
64574
|
-
advanced: "derive",
|
|
64575
|
-
targets: []
|
|
64576
|
-
}
|
|
65505
|
+
customize: powerMeterCustomize
|
|
64577
65506
|
};
|
|
64578
65507
|
/**
|
|
64579
65508
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -64593,11 +65522,11 @@ var powerMeterCapability = {
|
|
|
64593
65522
|
*/
|
|
64594
65523
|
var GpsLocationSchema = object({
|
|
64595
65524
|
/** Latitude in decimal degrees, -90..90. */
|
|
64596
|
-
latitude: number().min(-90).max(90),
|
|
65525
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
64597
65526
|
/** Longitude in decimal degrees, -180..180. */
|
|
64598
|
-
longitude: number().min(-180).max(180),
|
|
65527
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
64599
65528
|
/** Reported accuracy in meters (lower = better). */
|
|
64600
|
-
accuracyMeters: number().nonnegative()
|
|
65529
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
64601
65530
|
});
|
|
64602
65531
|
var PresenceStatusSchema = object({
|
|
64603
65532
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -64609,7 +65538,7 @@ var PresenceStatusSchema = object({
|
|
|
64609
65538
|
gps: GpsLocationSchema.nullable(),
|
|
64610
65539
|
/** Optional battery level of the tracking device (0..100). Null
|
|
64611
65540
|
* when not reported. */
|
|
64612
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
65541
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64613
65542
|
/** Ms epoch when the slice was last updated. */
|
|
64614
65543
|
lastChangedAt: number()
|
|
64615
65544
|
});
|
|
@@ -64659,19 +65588,10 @@ var presenceCapability = {
|
|
|
64659
65588
|
* `sourceInfo`.
|
|
64660
65589
|
*/
|
|
64661
65590
|
var PressureSensorStatusSchema = object({
|
|
64662
|
-
/** Current pressure in hPa. */
|
|
64663
|
-
hpa: number(),
|
|
65591
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
65592
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
64664
65593
|
/** Ms epoch when the slice was last updated. */
|
|
64665
|
-
lastFetchedAt: number()
|
|
64666
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64667
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64668
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
64669
|
-
unit: string().optional(),
|
|
64670
|
-
/** Suggested decimal places for numeric display.
|
|
64671
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64672
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64673
|
-
* auto-formatting when absent. */
|
|
64674
|
-
precision: number().int().min(0).max(10).optional()
|
|
65594
|
+
lastFetchedAt: number()
|
|
64675
65595
|
});
|
|
64676
65596
|
var pressureSensorCapability = {
|
|
64677
65597
|
name: "pressure-sensor",
|
|
@@ -65085,8 +66005,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
65085
66005
|
}), _void(), { kind: "mutation" });
|
|
65086
66006
|
var PtzAutotrackSettingsSchema = object({
|
|
65087
66007
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
65088
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
65089
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
66008
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
66009
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
65090
66010
|
});
|
|
65091
66011
|
/**
|
|
65092
66012
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -65240,7 +66160,7 @@ var RunningStateStatusSchema = object({
|
|
|
65240
66160
|
/** null = unknown — never coerced to false (D393). */
|
|
65241
66161
|
running: boolean().nullable(),
|
|
65242
66162
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
65243
|
-
since: number().nullable(),
|
|
66163
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
65244
66164
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
65245
66165
|
phase: string().nullable(),
|
|
65246
66166
|
/** null until a reading has been published (D393). */
|
|
@@ -65255,7 +66175,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
65255
66175
|
/** Generic Customize target for the running boolean (D936). */
|
|
65256
66176
|
var runningCustomize = {
|
|
65257
66177
|
version: 1,
|
|
65258
|
-
advanced: "derive",
|
|
65259
66178
|
targets: [{
|
|
65260
66179
|
id: "running",
|
|
65261
66180
|
cardinality: "scalar",
|
|
@@ -65264,6 +66183,8 @@ var runningCustomize = {
|
|
|
65264
66183
|
stateField: "running"
|
|
65265
66184
|
},
|
|
65266
66185
|
deviceTypes: [
|
|
66186
|
+
DeviceType.Washer,
|
|
66187
|
+
DeviceType.Dryer,
|
|
65267
66188
|
DeviceType.Dishwasher,
|
|
65268
66189
|
DeviceType.Vacuum,
|
|
65269
66190
|
DeviceType.LawnMower,
|
|
@@ -65275,7 +66196,7 @@ var runningCustomize = {
|
|
|
65275
66196
|
DeviceType.Thermostat,
|
|
65276
66197
|
DeviceType.PetFeeder
|
|
65277
66198
|
],
|
|
65278
|
-
apply: "add
|
|
66199
|
+
apply: "add",
|
|
65279
66200
|
path: "running",
|
|
65280
66201
|
sources: [
|
|
65281
66202
|
{
|
|
@@ -66539,9 +67460,9 @@ var RecordTriggerSchema = _enum([
|
|
|
66539
67460
|
*/
|
|
66540
67461
|
var RecordWindowSchema = object({
|
|
66541
67462
|
trigger: RecordTriggerSchema,
|
|
66542
|
-
day: number().int().min(0).max(6),
|
|
66543
|
-
startMinute: number().int().min(0).max(1439),
|
|
66544
|
-
endMinute: number().int().min(1).max(1440)
|
|
67463
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
67464
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
67465
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
66545
67466
|
});
|
|
66546
67467
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
66547
67468
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -66617,10 +67538,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
66617
67538
|
/** Master "record to the card at all" switch. */
|
|
66618
67539
|
enabled: boolean().nullable(),
|
|
66619
67540
|
overwriteWhenFull: boolean().nullable(),
|
|
66620
|
-
preRecordSec: number().nullable(),
|
|
66621
|
-
postRecordSec: number().nullable(),
|
|
67541
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
67542
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66622
67543
|
/** Length of one recorded file, in minutes. */
|
|
66623
|
-
segmentMinutes: number().nullable(),
|
|
67544
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
66624
67545
|
/** The primary track's weekly windows, flattened. */
|
|
66625
67546
|
windows: array(RecordWindowSchema),
|
|
66626
67547
|
/**
|
|
@@ -66636,7 +67557,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
66636
67557
|
* provider reporting a non-zero count also reports the schedule as not
|
|
66637
67558
|
* writable.
|
|
66638
67559
|
*/
|
|
66639
|
-
unreadableWindows: number(),
|
|
67560
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
66640
67561
|
/**
|
|
66641
67562
|
* The camera is scheduled to record and has NO usable storage.
|
|
66642
67563
|
*
|
|
@@ -67481,7 +68402,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
67481
68402
|
url: string().optional(),
|
|
67482
68403
|
codec: string().optional(),
|
|
67483
68404
|
resolution: CamStreamResolutionSchema.optional(),
|
|
67484
|
-
fps: number().positive().optional(),
|
|
68405
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
67485
68406
|
label: string().optional(),
|
|
67486
68407
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
67487
68408
|
deviceFeatures: array(string()).optional(),
|
|
@@ -67568,18 +68489,18 @@ var StreamProfileSchema = _enum([
|
|
|
67568
68489
|
]);
|
|
67569
68490
|
/** The current encoding config of one stream profile. */
|
|
67570
68491
|
var StreamProfileConfigSchema = object({
|
|
67571
|
-
width: number(),
|
|
67572
|
-
height: number(),
|
|
68492
|
+
width: number().meta(readingMeta("none")),
|
|
68493
|
+
height: number().meta(readingMeta("none")),
|
|
67573
68494
|
codec: _enum(["h264", "h265"]),
|
|
67574
|
-
framerate: number(),
|
|
67575
|
-
bitrate: number(),
|
|
68495
|
+
framerate: number().meta(readingMeta("rate")),
|
|
68496
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
67576
68497
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
67577
68498
|
encoderProfile: _enum([
|
|
67578
68499
|
"high",
|
|
67579
68500
|
"main",
|
|
67580
68501
|
"baseline"
|
|
67581
68502
|
]).optional(),
|
|
67582
|
-
gop: number().optional(),
|
|
68503
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
67583
68504
|
/**
|
|
67584
68505
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
67585
68506
|
*
|
|
@@ -67753,7 +68674,8 @@ var switchCapability = {
|
|
|
67753
68674
|
deviceTypes: [
|
|
67754
68675
|
DeviceType.Switch,
|
|
67755
68676
|
DeviceType.Siren,
|
|
67756
|
-
DeviceType.Light
|
|
68677
|
+
DeviceType.Light,
|
|
68678
|
+
DeviceType.Fan
|
|
67757
68679
|
],
|
|
67758
68680
|
methods: { setState: method(object({
|
|
67759
68681
|
deviceId: number(),
|
|
@@ -67800,12 +68722,7 @@ var switchCapability = {
|
|
|
67800
68722
|
label: "On",
|
|
67801
68723
|
kind: "boolean"
|
|
67802
68724
|
}
|
|
67803
|
-
}] }
|
|
67804
|
-
customize: {
|
|
67805
|
-
version: 1,
|
|
67806
|
-
advanced: "derive",
|
|
67807
|
-
targets: []
|
|
67808
|
-
}
|
|
68725
|
+
}] }
|
|
67809
68726
|
};
|
|
67810
68727
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
67811
68728
|
function hasControlCharacter(value) {
|
|
@@ -68388,35 +69305,21 @@ var tamperCapability = {
|
|
|
68388
69305
|
* entries with `device_class: temperature` and any future native
|
|
68389
69306
|
* thermometer.
|
|
68390
69307
|
*
|
|
68391
|
-
*
|
|
68392
|
-
*
|
|
68393
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
68394
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
68395
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
68396
|
-
* `sourceInfo`.
|
|
69308
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
69309
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
68397
69310
|
*
|
|
68398
69311
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
68399
69312
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
68400
69313
|
* changed" steady state.
|
|
68401
69314
|
*/
|
|
68402
69315
|
var TemperatureSensorStatusSchema = object({
|
|
68403
|
-
/** Current temperature in Celsius. */
|
|
68404
|
-
celsius: number().meta({
|
|
68405
|
-
|
|
69316
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
69317
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
69318
|
+
precision: 1,
|
|
68406
69319
|
label: "Temperature"
|
|
68407
|
-
}),
|
|
69320
|
+
})),
|
|
68408
69321
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
68409
|
-
lastFetchedAt: number()
|
|
68410
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
68411
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
68412
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
68413
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
68414
|
-
unit: string().optional(),
|
|
68415
|
-
/** Suggested decimal places for numeric display.
|
|
68416
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
68417
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
68418
|
-
* auto-formatting when absent. */
|
|
68419
|
-
precision: number().int().min(0).max(10).optional()
|
|
69322
|
+
lastFetchedAt: number()
|
|
68420
69323
|
});
|
|
68421
69324
|
var temperatureSensorCapability = {
|
|
68422
69325
|
name: "temperature-sensor",
|
|
@@ -68447,12 +69350,7 @@ var temperatureSensorCapability = {
|
|
|
68447
69350
|
} } },
|
|
68448
69351
|
/** Clock fields: written, but excluded from the compare that decides
|
|
68449
69352
|
* whether persisting is worth a SQLite commit. */
|
|
68450
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
68451
|
-
customize: {
|
|
68452
|
-
version: 1,
|
|
68453
|
-
advanced: "derive",
|
|
68454
|
-
targets: []
|
|
68455
|
-
}
|
|
69353
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
68456
69354
|
};
|
|
68457
69355
|
/**
|
|
68458
69356
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -68735,16 +69633,16 @@ var VacuumControlStatusSchema = object({
|
|
|
68735
69633
|
]),
|
|
68736
69634
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
68737
69635
|
* reading. */
|
|
68738
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
69636
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68739
69637
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
68740
69638
|
* the vacuum has no speed control. */
|
|
68741
69639
|
fanSpeed: string().nullable(),
|
|
68742
69640
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
68743
69641
|
availableFanSpeeds: array(string()),
|
|
68744
69642
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
68745
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
69643
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68746
69644
|
/** Current error code (0 / null = no error). */
|
|
68747
|
-
errorCode: number().nullable(),
|
|
69645
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
68748
69646
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
68749
69647
|
errorLabel: string().nullable(),
|
|
68750
69648
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -68822,7 +69720,7 @@ var ValveStatusSchema = object({
|
|
|
68822
69720
|
]),
|
|
68823
69721
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
68824
69722
|
* intermediate position surface. */
|
|
68825
|
-
position: number().min(0).max(100).nullable(),
|
|
69723
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68826
69724
|
/** Ms epoch when the slice was last updated. */
|
|
68827
69725
|
lastChangedAt: number()
|
|
68828
69726
|
});
|
|
@@ -68930,9 +69828,9 @@ var vibrationCapability = {
|
|
|
68930
69828
|
*/
|
|
68931
69829
|
var WaterHeaterStatusSchema = object({
|
|
68932
69830
|
/** Current measured temperature. Null when not reported. */
|
|
68933
|
-
currentTemp: number().nullable(),
|
|
69831
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68934
69832
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68935
|
-
targetTemp: number().nullable(),
|
|
69833
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68936
69834
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68937
69835
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68938
69836
|
* device reports an unknown state. */
|
|
@@ -68943,9 +69841,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68943
69841
|
* has no away surface. */
|
|
68944
69842
|
away: boolean().nullable(),
|
|
68945
69843
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68946
|
-
minTemp: number().nullable(),
|
|
69844
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68947
69845
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68948
|
-
maxTemp: number().nullable(),
|
|
69846
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68949
69847
|
/** Ms epoch when the slice was last updated. */
|
|
68950
69848
|
lastChangedAt: number()
|
|
68951
69849
|
});
|
|
@@ -69030,25 +69928,18 @@ var waterHeaterCapability = {
|
|
|
69030
69928
|
* Forecast deferred — current conditions only for v1.
|
|
69031
69929
|
*/
|
|
69032
69930
|
var WeatherStatusSchema = object({
|
|
69033
|
-
/** Verbatim
|
|
69034
|
-
* when no condition has been reported yet. */
|
|
69931
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
69035
69932
|
condition: string().nullable(),
|
|
69036
|
-
/** Current temperature in
|
|
69037
|
-
temperature: number().nullable(),
|
|
69038
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
69039
|
-
temperatureUnit: string().nullable(),
|
|
69933
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
69934
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
69040
69935
|
/** Relative humidity (0..100). Null when not provided. */
|
|
69041
|
-
humidity: number().min(0).max(100).nullable(),
|
|
69042
|
-
/** Barometric pressure in
|
|
69043
|
-
pressure: number().nullable(),
|
|
69044
|
-
/**
|
|
69045
|
-
|
|
69046
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
69047
|
-
windSpeed: number().nullable(),
|
|
69048
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
69049
|
-
windSpeedUnit: string().nullable(),
|
|
69936
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
69937
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
69938
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
69939
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
69940
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
69050
69941
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
69051
|
-
windBearing: number().nullable(),
|
|
69942
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
69052
69943
|
/** Ms epoch when the slice was last updated. */
|
|
69053
69944
|
lastFetchedAt: number()
|
|
69054
69945
|
});
|
|
@@ -69076,12 +69967,12 @@ var weatherCapability = {
|
|
|
69076
69967
|
*/
|
|
69077
69968
|
durability: "session",
|
|
69078
69969
|
/**
|
|
69079
|
-
* History (D850): recorded series.
|
|
69970
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
69080
69971
|
*/
|
|
69081
69972
|
history: { fields: {
|
|
69082
69973
|
temperature: {
|
|
69083
69974
|
kind: "gauge",
|
|
69084
|
-
|
|
69975
|
+
unit: "°C",
|
|
69085
69976
|
deadband: .2
|
|
69086
69977
|
},
|
|
69087
69978
|
humidity: {
|
|
@@ -69091,12 +69982,12 @@ var weatherCapability = {
|
|
|
69091
69982
|
},
|
|
69092
69983
|
pressure: {
|
|
69093
69984
|
kind: "gauge",
|
|
69094
|
-
|
|
69985
|
+
unit: "hPa",
|
|
69095
69986
|
deadband: .5
|
|
69096
69987
|
},
|
|
69097
69988
|
windSpeed: {
|
|
69098
69989
|
kind: "gauge",
|
|
69099
|
-
|
|
69990
|
+
unit: "m/s",
|
|
69100
69991
|
deadband: .5
|
|
69101
69992
|
}
|
|
69102
69993
|
} }
|
|
@@ -69997,8 +70888,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
69997
70888
|
kind: "mutation",
|
|
69998
70889
|
auth: "admin"
|
|
69999
70890
|
});
|
|
70891
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
70000
70892
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
70001
|
-
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;
|
|
70893
|
+
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;
|
|
70002
70894
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
70003
70895
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
70004
70896
|
new Set(CAP_NAMES);
|
|
@@ -70327,6 +71219,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70327
71219
|
featureProbe: featureProbeCapability,
|
|
70328
71220
|
flood: floodCapability,
|
|
70329
71221
|
gas: gasCapability,
|
|
71222
|
+
groupActive: groupActiveCapability,
|
|
71223
|
+
groupCommands: groupCommandsCapability,
|
|
71224
|
+
groupStatus: groupStatusCapability,
|
|
70330
71225
|
heatingValve: heatingValveCapability,
|
|
70331
71226
|
humidifier: humidifierCapability,
|
|
70332
71227
|
humiditySensor: humiditySensorCapability,
|
|
@@ -70336,6 +71231,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70336
71231
|
lawnMowerControl: lawnMowerControlCapability,
|
|
70337
71232
|
lockControl: lockControlCapability,
|
|
70338
71233
|
mediaPlayer: mediaPlayerCapability,
|
|
71234
|
+
meter: meterCapability,
|
|
70339
71235
|
motion: motionCapability,
|
|
70340
71236
|
motionTrigger: motionTriggerCapability,
|
|
70341
71237
|
motionZones: motionZonesCapability,
|
|
@@ -71595,7 +72491,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
71595
72491
|
return toDeviceSummary(device, this.addonId);
|
|
71596
72492
|
}
|
|
71597
72493
|
};
|
|
71598
|
-
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;
|
|
72494
|
+
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;
|
|
71599
72495
|
new Set(Object.values(DeviceType));
|
|
71600
72496
|
Object.freeze({
|
|
71601
72497
|
"accessories.getStatus": {
|
|
@@ -71703,6 +72599,13 @@ Object.freeze({
|
|
|
71703
72599
|
access: "view",
|
|
71704
72600
|
role: "admin"
|
|
71705
72601
|
},
|
|
72602
|
+
"addons.getPackageDocs": {
|
|
72603
|
+
capName: "addons",
|
|
72604
|
+
capScope: "system",
|
|
72605
|
+
addonId: null,
|
|
72606
|
+
access: "view",
|
|
72607
|
+
role: "admin"
|
|
72608
|
+
},
|
|
71706
72609
|
"addons.getVersions": {
|
|
71707
72610
|
capName: "addons",
|
|
71708
72611
|
capScope: "system",
|
|
@@ -74811,6 +75714,27 @@ Object.freeze({
|
|
|
74811
75714
|
access: "view",
|
|
74812
75715
|
role: "viewer"
|
|
74813
75716
|
},
|
|
75717
|
+
"groupActive.getStatus": {
|
|
75718
|
+
capName: "group-active",
|
|
75719
|
+
capScope: "device",
|
|
75720
|
+
addonId: null,
|
|
75721
|
+
access: "view",
|
|
75722
|
+
role: "viewer"
|
|
75723
|
+
},
|
|
75724
|
+
"groupCommands.getStatus": {
|
|
75725
|
+
capName: "group-commands",
|
|
75726
|
+
capScope: "device",
|
|
75727
|
+
addonId: null,
|
|
75728
|
+
access: "view",
|
|
75729
|
+
role: "viewer"
|
|
75730
|
+
},
|
|
75731
|
+
"groupStatus.getStatus": {
|
|
75732
|
+
capName: "group-status",
|
|
75733
|
+
capScope: "device",
|
|
75734
|
+
addonId: null,
|
|
75735
|
+
access: "view",
|
|
75736
|
+
role: "viewer"
|
|
75737
|
+
},
|
|
74814
75738
|
"heatingValve.getStatus": {
|
|
74815
75739
|
capName: "heating-valve",
|
|
74816
75740
|
capScope: "device",
|
|
@@ -75763,6 +76687,13 @@ Object.freeze({
|
|
|
75763
76687
|
access: "create",
|
|
75764
76688
|
role: "admin"
|
|
75765
76689
|
},
|
|
76690
|
+
"meter.getStatus": {
|
|
76691
|
+
capName: "meter",
|
|
76692
|
+
capScope: "device",
|
|
76693
|
+
addonId: null,
|
|
76694
|
+
access: "view",
|
|
76695
|
+
role: "viewer"
|
|
76696
|
+
},
|
|
75766
76697
|
"metricsProvider.collectSnapshot": {
|
|
75767
76698
|
capName: "metrics-provider",
|
|
75768
76699
|
capScope: "system",
|
|
@@ -83861,7 +84792,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
83861
84792
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
83862
84793
|
icon: "square"
|
|
83863
84794
|
}
|
|
83864
|
-
}
|
|
84795
|
+
},
|
|
84796
|
+
overrides: { byType: {
|
|
84797
|
+
[DeviceType.Washer]: {
|
|
84798
|
+
state: { running: {
|
|
84799
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
84800
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
84801
|
+
} },
|
|
84802
|
+
events: {
|
|
84803
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
84804
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
84805
|
+
}
|
|
84806
|
+
},
|
|
84807
|
+
[DeviceType.Dryer]: {
|
|
84808
|
+
state: { running: {
|
|
84809
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
84810
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
84811
|
+
} },
|
|
84812
|
+
events: {
|
|
84813
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
84814
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
84815
|
+
}
|
|
84816
|
+
},
|
|
84817
|
+
[DeviceType.Dishwasher]: {
|
|
84818
|
+
state: { running: {
|
|
84819
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
84820
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
84821
|
+
} },
|
|
84822
|
+
events: {
|
|
84823
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
84824
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
84825
|
+
}
|
|
84826
|
+
}
|
|
84827
|
+
} }
|
|
83865
84828
|
},
|
|
83866
84829
|
update: {
|
|
83867
84830
|
scope: "device",
|
|
@@ -84633,6 +85596,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84633
85596
|
icon: "flame"
|
|
84634
85597
|
}]
|
|
84635
85598
|
},
|
|
85599
|
+
"group-active": {
|
|
85600
|
+
scope: "device",
|
|
85601
|
+
noun: t("Group state", "Stato del gruppo")
|
|
85602
|
+
},
|
|
85603
|
+
"group-commands": {
|
|
85604
|
+
scope: "device",
|
|
85605
|
+
noun: t("Group command", "Comando di gruppo")
|
|
85606
|
+
},
|
|
85607
|
+
"group-status": {
|
|
85608
|
+
scope: "device",
|
|
85609
|
+
noun: t("Group", "Gruppo"),
|
|
85610
|
+
state: [
|
|
85611
|
+
{
|
|
85612
|
+
kind: "numeric",
|
|
85613
|
+
field: "included",
|
|
85614
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
85615
|
+
label: t("Reporting", "Rispondono"),
|
|
85616
|
+
icon: "users"
|
|
85617
|
+
},
|
|
85618
|
+
{
|
|
85619
|
+
kind: "numeric",
|
|
85620
|
+
field: "excluded",
|
|
85621
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
85622
|
+
label: t("Excluded", "Esclusi"),
|
|
85623
|
+
icon: "users"
|
|
85624
|
+
},
|
|
85625
|
+
{
|
|
85626
|
+
kind: "numeric",
|
|
85627
|
+
field: "total",
|
|
85628
|
+
quantity: t("the member count", "il numero di membri"),
|
|
85629
|
+
label: t("Members", "Membri"),
|
|
85630
|
+
icon: "sigma"
|
|
85631
|
+
}
|
|
85632
|
+
]
|
|
85633
|
+
},
|
|
84636
85634
|
"humidity-sensor": {
|
|
84637
85635
|
scope: "device",
|
|
84638
85636
|
noun: t("Humidity", "Umidità"),
|
|
@@ -84658,6 +85656,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84658
85656
|
}],
|
|
84659
85657
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
84660
85658
|
},
|
|
85659
|
+
meter: {
|
|
85660
|
+
scope: "device",
|
|
85661
|
+
noun: t("Meter", "Contatore"),
|
|
85662
|
+
state: [{
|
|
85663
|
+
kind: "numeric",
|
|
85664
|
+
field: "value",
|
|
85665
|
+
quantity: t("the total", "il totale"),
|
|
85666
|
+
label: t("Total", "Totale"),
|
|
85667
|
+
icon: "gauge"
|
|
85668
|
+
}]
|
|
85669
|
+
},
|
|
84661
85670
|
"numeric-sensor": {
|
|
84662
85671
|
scope: "device",
|
|
84663
85672
|
noun: t("Sensor", "Sensore"),
|
|
@@ -84666,7 +85675,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84666
85675
|
field: "value",
|
|
84667
85676
|
quantity: t("the reading", "il valore"),
|
|
84668
85677
|
label: t("Reading", "Valore"),
|
|
84669
|
-
unitField: "unit",
|
|
84670
85678
|
icon: "gauge"
|
|
84671
85679
|
}]
|
|
84672
85680
|
},
|
|
@@ -84802,7 +85810,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84802
85810
|
field: "temperature",
|
|
84803
85811
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
84804
85812
|
label: t("Temperature", "Temperatura"),
|
|
84805
|
-
|
|
85813
|
+
unit: "°C",
|
|
84806
85814
|
icon: "thermometer"
|
|
84807
85815
|
},
|
|
84808
85816
|
{
|
|
@@ -84818,7 +85826,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84818
85826
|
field: "windSpeed",
|
|
84819
85827
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
84820
85828
|
label: t("Wind", "Vento"),
|
|
84821
|
-
|
|
85829
|
+
unit: "m/s",
|
|
84822
85830
|
icon: "wind"
|
|
84823
85831
|
},
|
|
84824
85832
|
{
|
|
@@ -84826,7 +85834,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84826
85834
|
field: "pressure",
|
|
84827
85835
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
84828
85836
|
label: t("Pressure", "Pressione"),
|
|
84829
|
-
|
|
85837
|
+
unit: "hPa",
|
|
84830
85838
|
icon: "gauge"
|
|
84831
85839
|
}
|
|
84832
85840
|
]
|
|
@@ -85131,8 +86139,47 @@ function projectAction(cap, action) {
|
|
|
85131
86139
|
};
|
|
85132
86140
|
}
|
|
85133
86141
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
85134
|
-
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;
|
|
86142
|
+
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;
|
|
85135
86143
|
DeviceFeature.BatteryOperated;
|
|
86144
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
86145
|
+
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.";
|
|
86146
|
+
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.";
|
|
86147
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
86148
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
86149
|
+
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.";
|
|
86150
|
+
function withheld(reason) {
|
|
86151
|
+
return {
|
|
86152
|
+
[DeviceType.Washer]: {
|
|
86153
|
+
exported: false,
|
|
86154
|
+
reason
|
|
86155
|
+
},
|
|
86156
|
+
[DeviceType.Dryer]: {
|
|
86157
|
+
exported: false,
|
|
86158
|
+
reason
|
|
86159
|
+
},
|
|
86160
|
+
[DeviceType.Dishwasher]: {
|
|
86161
|
+
exported: false,
|
|
86162
|
+
reason
|
|
86163
|
+
}
|
|
86164
|
+
};
|
|
86165
|
+
}
|
|
86166
|
+
function offered(received) {
|
|
86167
|
+
return {
|
|
86168
|
+
[DeviceType.Washer]: {
|
|
86169
|
+
exported: true,
|
|
86170
|
+
as: received
|
|
86171
|
+
},
|
|
86172
|
+
[DeviceType.Dryer]: {
|
|
86173
|
+
exported: true,
|
|
86174
|
+
as: received
|
|
86175
|
+
},
|
|
86176
|
+
[DeviceType.Dishwasher]: {
|
|
86177
|
+
exported: true,
|
|
86178
|
+
as: received
|
|
86179
|
+
}
|
|
86180
|
+
};
|
|
86181
|
+
}
|
|
86182
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
85136
86183
|
Object.freeze({
|
|
85137
86184
|
"accessories.getStatus": [{
|
|
85138
86185
|
name: "deviceId",
|
|
@@ -86099,6 +87146,21 @@ Object.freeze({
|
|
|
86099
87146
|
form: "single",
|
|
86100
87147
|
optional: false
|
|
86101
87148
|
}],
|
|
87149
|
+
"groupActive.getStatus": [{
|
|
87150
|
+
name: "deviceId",
|
|
87151
|
+
form: "single",
|
|
87152
|
+
optional: false
|
|
87153
|
+
}],
|
|
87154
|
+
"groupCommands.getStatus": [{
|
|
87155
|
+
name: "deviceId",
|
|
87156
|
+
form: "single",
|
|
87157
|
+
optional: false
|
|
87158
|
+
}],
|
|
87159
|
+
"groupStatus.getStatus": [{
|
|
87160
|
+
name: "deviceId",
|
|
87161
|
+
form: "single",
|
|
87162
|
+
optional: false
|
|
87163
|
+
}],
|
|
86102
87164
|
"heatingValve.getStatus": [{
|
|
86103
87165
|
name: "deviceId",
|
|
86104
87166
|
form: "single",
|
|
@@ -86299,6 +87361,11 @@ Object.freeze({
|
|
|
86299
87361
|
form: "single",
|
|
86300
87362
|
optional: false
|
|
86301
87363
|
}],
|
|
87364
|
+
"meter.getStatus": [{
|
|
87365
|
+
name: "deviceId",
|
|
87366
|
+
form: "single",
|
|
87367
|
+
optional: false
|
|
87368
|
+
}],
|
|
86302
87369
|
"motion.getStatus": [{
|
|
86303
87370
|
name: "deviceId",
|
|
86304
87371
|
form: "single",
|
|
@@ -87906,7 +88973,6 @@ Object.freeze({
|
|
|
87906
88973
|
"network-access": "ingress",
|
|
87907
88974
|
"smtp-provider": "email"
|
|
87908
88975
|
});
|
|
87909
|
-
DeviceType.Camera;
|
|
87910
88976
|
/**
|
|
87911
88977
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
87912
88978
|
* `z.infer`, they do not restate the shape.
|
|
@@ -88083,6 +89149,8 @@ new Map(Object.entries({
|
|
|
88083
89149
|
"detection-blind": "device-events",
|
|
88084
89150
|
"motion-noisy": "device-events",
|
|
88085
89151
|
"motion-calm": "device-events",
|
|
89152
|
+
"package-llm-silent": "device-events",
|
|
89153
|
+
"package-llm-answered": "device-events",
|
|
88086
89154
|
"recording-stalled": "device-events",
|
|
88087
89155
|
"recording-healthy": "device-events",
|
|
88088
89156
|
"recording-degraded": "device-events",
|
|
@@ -88166,6 +89234,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
88166
89234
|
label: "Motion without a subject",
|
|
88167
89235
|
kinds: ["motion-noisy", "motion-calm"]
|
|
88168
89236
|
},
|
|
89237
|
+
{
|
|
89238
|
+
id: "package-llm",
|
|
89239
|
+
family: "device-events",
|
|
89240
|
+
label: "Package confirm",
|
|
89241
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
89242
|
+
},
|
|
88169
89243
|
{
|
|
88170
89244
|
id: "recording",
|
|
88171
89245
|
family: "device-events",
|
|
@@ -88347,6 +89421,8 @@ var DEVICE_EVENTS = [
|
|
|
88347
89421
|
"detection-blind",
|
|
88348
89422
|
"motion-noisy",
|
|
88349
89423
|
"motion-calm",
|
|
89424
|
+
"package-llm-silent",
|
|
89425
|
+
"package-llm-answered",
|
|
88350
89426
|
"recording-stalled",
|
|
88351
89427
|
"recording-healthy",
|
|
88352
89428
|
"recording-degraded",
|
|
@@ -88615,6 +89691,15 @@ new Map([
|
|
|
88615
89691
|
snapshotLabel: "Cameras with constant motion now",
|
|
88616
89692
|
snapshotSection: null
|
|
88617
89693
|
},
|
|
89694
|
+
{
|
|
89695
|
+
id: "package-llm-confirm",
|
|
89696
|
+
family: "device-events",
|
|
89697
|
+
label: "Package confirm (not answering / answering again)",
|
|
89698
|
+
bad: ["package-llm-silent"],
|
|
89699
|
+
recovery: ["package-llm-answered"],
|
|
89700
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
89701
|
+
snapshotSection: null
|
|
89702
|
+
},
|
|
88618
89703
|
{
|
|
88619
89704
|
id: "recording-health",
|
|
88620
89705
|
family: "device-events",
|