@camstack/addon-provider-velux 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.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -325,6 +325,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
325
325
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
326
326
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
327
327
|
/**
|
|
328
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
329
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
330
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
331
|
+
*/
|
|
332
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
333
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
334
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
335
|
+
/**
|
|
328
336
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
329
337
|
* (a settings change via `setAgentInferenceDevices` /
|
|
330
338
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5434,7 +5442,7 @@ var ZodIssueCode = {
|
|
|
5434
5442
|
var ZodFirstPartyTypeKind;
|
|
5435
5443
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5436
5444
|
//#endregion
|
|
5437
|
-
//#region ../types/dist/sleep
|
|
5445
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5438
5446
|
/**
|
|
5439
5447
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5440
5448
|
* window to float samples (D455).
|
|
@@ -7988,6 +7996,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
7988
7996
|
}).strict();
|
|
7989
7997
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
7990
7998
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
7999
|
+
var READING_QUANTITIES = [
|
|
8000
|
+
"temperature",
|
|
8001
|
+
"pressure",
|
|
8002
|
+
"speed",
|
|
8003
|
+
"precipitation",
|
|
8004
|
+
"precipitation-rate",
|
|
8005
|
+
"length",
|
|
8006
|
+
"area",
|
|
8007
|
+
"illuminance",
|
|
8008
|
+
"irradiance",
|
|
8009
|
+
"power",
|
|
8010
|
+
"energy",
|
|
8011
|
+
"voltage",
|
|
8012
|
+
"current",
|
|
8013
|
+
"apparent-power",
|
|
8014
|
+
"humidity",
|
|
8015
|
+
"percentage",
|
|
8016
|
+
"concentration-volume",
|
|
8017
|
+
"concentration-mass",
|
|
8018
|
+
"concentration-ppb",
|
|
8019
|
+
"volume",
|
|
8020
|
+
"duration",
|
|
8021
|
+
"duration-ms",
|
|
8022
|
+
"information",
|
|
8023
|
+
"sound-level",
|
|
8024
|
+
"signal-level",
|
|
8025
|
+
"colour-temperature",
|
|
8026
|
+
"angle",
|
|
8027
|
+
"bitrate",
|
|
8028
|
+
"rate",
|
|
8029
|
+
"mass",
|
|
8030
|
+
"index",
|
|
8031
|
+
"ratio",
|
|
8032
|
+
"count",
|
|
8033
|
+
"none",
|
|
8034
|
+
"device"
|
|
8035
|
+
];
|
|
8036
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8037
|
+
new Set(READING_QUANTITIES);
|
|
8038
|
+
/**
|
|
8039
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8040
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8041
|
+
*/
|
|
8042
|
+
var QUANTITY_BASE = {
|
|
8043
|
+
temperature: "°C",
|
|
8044
|
+
pressure: "hPa",
|
|
8045
|
+
speed: "m/s",
|
|
8046
|
+
precipitation: "mm",
|
|
8047
|
+
"precipitation-rate": "mm/h",
|
|
8048
|
+
length: "m",
|
|
8049
|
+
area: "m²",
|
|
8050
|
+
illuminance: "lx",
|
|
8051
|
+
irradiance: "W/m²",
|
|
8052
|
+
power: "W",
|
|
8053
|
+
energy: "kWh",
|
|
8054
|
+
voltage: "V",
|
|
8055
|
+
current: "A",
|
|
8056
|
+
"apparent-power": "VA",
|
|
8057
|
+
humidity: "%",
|
|
8058
|
+
percentage: "%",
|
|
8059
|
+
"concentration-volume": "ppm",
|
|
8060
|
+
"concentration-mass": "µg/m³",
|
|
8061
|
+
"concentration-ppb": "ppb",
|
|
8062
|
+
volume: "L",
|
|
8063
|
+
duration: "s",
|
|
8064
|
+
"duration-ms": "ms",
|
|
8065
|
+
information: "B",
|
|
8066
|
+
"sound-level": "dBFS",
|
|
8067
|
+
"signal-level": "dBm",
|
|
8068
|
+
"colour-temperature": "mired",
|
|
8069
|
+
angle: "°",
|
|
8070
|
+
bitrate: "kbps",
|
|
8071
|
+
rate: "fps",
|
|
8072
|
+
mass: "kg",
|
|
8073
|
+
index: "none",
|
|
8074
|
+
ratio: "none",
|
|
8075
|
+
count: "none",
|
|
8076
|
+
none: "none",
|
|
8077
|
+
device: "device"
|
|
8078
|
+
};
|
|
8079
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8080
|
+
function baseUnitOf(quantity) {
|
|
8081
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8082
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8083
|
+
return symbol;
|
|
8084
|
+
}
|
|
8085
|
+
function readingMeta(quantity, extras) {
|
|
8086
|
+
return {
|
|
8087
|
+
quantity,
|
|
8088
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8089
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8090
|
+
};
|
|
8091
|
+
}
|
|
7991
8092
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
7992
8093
|
var CamProfileSchema = _enum([
|
|
7993
8094
|
"high",
|
|
@@ -8015,8 +8116,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8015
8116
|
"derived"
|
|
8016
8117
|
]);
|
|
8017
8118
|
var CamStreamResolutionSchema = object({
|
|
8018
|
-
width: number().int().positive(),
|
|
8019
|
-
height: number().int().positive()
|
|
8119
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8120
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8020
8121
|
});
|
|
8021
8122
|
var CameraStreamSchema = object({
|
|
8022
8123
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8534,6 +8635,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8534
8635
|
"filesystem-browse",
|
|
8535
8636
|
"flood",
|
|
8536
8637
|
"gas",
|
|
8638
|
+
"group-active",
|
|
8639
|
+
"group-commands",
|
|
8640
|
+
"group-status",
|
|
8537
8641
|
"heating-valve",
|
|
8538
8642
|
"humidifier",
|
|
8539
8643
|
"humidity-sensor",
|
|
@@ -8554,6 +8658,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8554
8658
|
"login-method",
|
|
8555
8659
|
"media-player",
|
|
8556
8660
|
"mesh-network",
|
|
8661
|
+
"meter",
|
|
8557
8662
|
"metrics-provider",
|
|
8558
8663
|
"model-convert",
|
|
8559
8664
|
"model-distributor",
|
|
@@ -8663,14 +8768,6 @@ Object.freeze({
|
|
|
8663
8768
|
{
|
|
8664
8769
|
"path": "aqi",
|
|
8665
8770
|
"valueType": "number"
|
|
8666
|
-
},
|
|
8667
|
-
{
|
|
8668
|
-
"path": "unit",
|
|
8669
|
-
"valueType": "string"
|
|
8670
|
-
},
|
|
8671
|
-
{
|
|
8672
|
-
"path": "precision",
|
|
8673
|
-
"valueType": "number"
|
|
8674
8771
|
}
|
|
8675
8772
|
],
|
|
8676
8773
|
"alarm-panel": [
|
|
@@ -8706,20 +8803,10 @@ Object.freeze({
|
|
|
8706
8803
|
"valueType": "boolean"
|
|
8707
8804
|
}
|
|
8708
8805
|
],
|
|
8709
|
-
"ambient-light-sensor": [
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
},
|
|
8714
|
-
{
|
|
8715
|
-
"path": "unit",
|
|
8716
|
-
"valueType": "string"
|
|
8717
|
-
},
|
|
8718
|
-
{
|
|
8719
|
-
"path": "precision",
|
|
8720
|
-
"valueType": "number"
|
|
8721
|
-
}
|
|
8722
|
-
],
|
|
8806
|
+
"ambient-light-sensor": [{
|
|
8807
|
+
"path": "lux",
|
|
8808
|
+
"valueType": "number"
|
|
8809
|
+
}],
|
|
8723
8810
|
"audio-metrics": [
|
|
8724
8811
|
{
|
|
8725
8812
|
"path": "ts",
|
|
@@ -8799,6 +8886,10 @@ Object.freeze({
|
|
|
8799
8886
|
"path": "lastUpdated",
|
|
8800
8887
|
"valueType": "number"
|
|
8801
8888
|
},
|
|
8889
|
+
{
|
|
8890
|
+
"path": "volts",
|
|
8891
|
+
"valueType": "number"
|
|
8892
|
+
},
|
|
8802
8893
|
{
|
|
8803
8894
|
"path": "lastContactAt",
|
|
8804
8895
|
"valueType": "number"
|
|
@@ -9041,10 +9132,6 @@ Object.freeze({
|
|
|
9041
9132
|
"datetime"
|
|
9042
9133
|
]
|
|
9043
9134
|
},
|
|
9044
|
-
{
|
|
9045
|
-
"path": "unit",
|
|
9046
|
-
"valueType": "string"
|
|
9047
|
-
},
|
|
9048
9135
|
{
|
|
9049
9136
|
"path": "min",
|
|
9050
9137
|
"valueType": "number"
|
|
@@ -9056,19 +9143,6 @@ Object.freeze({
|
|
|
9056
9143
|
{
|
|
9057
9144
|
"path": "step",
|
|
9058
9145
|
"valueType": "number"
|
|
9059
|
-
},
|
|
9060
|
-
{
|
|
9061
|
-
"path": "precision",
|
|
9062
|
-
"valueType": "number"
|
|
9063
|
-
},
|
|
9064
|
-
{
|
|
9065
|
-
"path": "format",
|
|
9066
|
-
"valueType": "enum",
|
|
9067
|
-
"enumValues": [
|
|
9068
|
-
"date",
|
|
9069
|
-
"time",
|
|
9070
|
-
"datetime"
|
|
9071
|
-
]
|
|
9072
9146
|
}
|
|
9073
9147
|
],
|
|
9074
9148
|
"cover": [
|
|
@@ -9309,13 +9383,8 @@ Object.freeze({
|
|
|
9309
9383
|
"path": "value",
|
|
9310
9384
|
"valueType": "string"
|
|
9311
9385
|
}, {
|
|
9312
|
-
"path": "
|
|
9313
|
-
"valueType": "
|
|
9314
|
-
"enumValues": [
|
|
9315
|
-
"date",
|
|
9316
|
-
"time",
|
|
9317
|
-
"datetime"
|
|
9318
|
-
]
|
|
9386
|
+
"path": "timestamp",
|
|
9387
|
+
"valueType": "boolean"
|
|
9319
9388
|
}],
|
|
9320
9389
|
"event-emitter": [
|
|
9321
9390
|
{
|
|
@@ -9388,6 +9457,24 @@ Object.freeze({
|
|
|
9388
9457
|
"path": "detected",
|
|
9389
9458
|
"valueType": "boolean"
|
|
9390
9459
|
}],
|
|
9460
|
+
"group-active": [{
|
|
9461
|
+
"path": "active",
|
|
9462
|
+
"valueType": "boolean"
|
|
9463
|
+
}],
|
|
9464
|
+
"group-status": [
|
|
9465
|
+
{
|
|
9466
|
+
"path": "included",
|
|
9467
|
+
"valueType": "number"
|
|
9468
|
+
},
|
|
9469
|
+
{
|
|
9470
|
+
"path": "excluded",
|
|
9471
|
+
"valueType": "number"
|
|
9472
|
+
},
|
|
9473
|
+
{
|
|
9474
|
+
"path": "total",
|
|
9475
|
+
"valueType": "number"
|
|
9476
|
+
}
|
|
9477
|
+
],
|
|
9391
9478
|
"heating-valve": [{
|
|
9392
9479
|
"path": "position",
|
|
9393
9480
|
"valueType": "number"
|
|
@@ -9422,20 +9509,10 @@ Object.freeze({
|
|
|
9422
9509
|
"valueType": "number"
|
|
9423
9510
|
}
|
|
9424
9511
|
],
|
|
9425
|
-
"humidity-sensor": [
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
},
|
|
9430
|
-
{
|
|
9431
|
-
"path": "unit",
|
|
9432
|
-
"valueType": "string"
|
|
9433
|
-
},
|
|
9434
|
-
{
|
|
9435
|
-
"path": "precision",
|
|
9436
|
-
"valueType": "number"
|
|
9437
|
-
}
|
|
9438
|
-
],
|
|
9512
|
+
"humidity-sensor": [{
|
|
9513
|
+
"path": "percent",
|
|
9514
|
+
"valueType": "number"
|
|
9515
|
+
}],
|
|
9439
9516
|
"image": [{
|
|
9440
9517
|
"path": "url",
|
|
9441
9518
|
"valueType": "string"
|
|
@@ -9643,6 +9720,10 @@ Object.freeze({
|
|
|
9643
9720
|
]
|
|
9644
9721
|
}
|
|
9645
9722
|
],
|
|
9723
|
+
"meter": [{
|
|
9724
|
+
"path": "value",
|
|
9725
|
+
"valueType": "number"
|
|
9726
|
+
}],
|
|
9646
9727
|
"motion": [
|
|
9647
9728
|
{
|
|
9648
9729
|
"path": "detected",
|
|
@@ -9774,20 +9855,10 @@ Object.freeze({
|
|
|
9774
9855
|
"valueType": "boolean"
|
|
9775
9856
|
}
|
|
9776
9857
|
],
|
|
9777
|
-
"numeric-sensor": [
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
},
|
|
9782
|
-
{
|
|
9783
|
-
"path": "unit",
|
|
9784
|
-
"valueType": "string"
|
|
9785
|
-
},
|
|
9786
|
-
{
|
|
9787
|
-
"path": "precision",
|
|
9788
|
-
"valueType": "number"
|
|
9789
|
-
}
|
|
9790
|
-
],
|
|
9858
|
+
"numeric-sensor": [{
|
|
9859
|
+
"path": "value",
|
|
9860
|
+
"valueType": "number"
|
|
9861
|
+
}],
|
|
9791
9862
|
"pet-feeder": [
|
|
9792
9863
|
{
|
|
9793
9864
|
"path": "foodLevel",
|
|
@@ -9879,14 +9950,6 @@ Object.freeze({
|
|
|
9879
9950
|
{
|
|
9880
9951
|
"path": "powerFactor",
|
|
9881
9952
|
"valueType": "number"
|
|
9882
|
-
},
|
|
9883
|
-
{
|
|
9884
|
-
"path": "unit",
|
|
9885
|
-
"valueType": "string"
|
|
9886
|
-
},
|
|
9887
|
-
{
|
|
9888
|
-
"path": "precision",
|
|
9889
|
-
"valueType": "number"
|
|
9890
9953
|
}
|
|
9891
9954
|
],
|
|
9892
9955
|
"presence": [
|
|
@@ -9915,20 +9978,10 @@ Object.freeze({
|
|
|
9915
9978
|
"valueType": "number"
|
|
9916
9979
|
}
|
|
9917
9980
|
],
|
|
9918
|
-
"pressure-sensor": [
|
|
9919
|
-
|
|
9920
|
-
|
|
9921
|
-
|
|
9922
|
-
},
|
|
9923
|
-
{
|
|
9924
|
-
"path": "unit",
|
|
9925
|
-
"valueType": "string"
|
|
9926
|
-
},
|
|
9927
|
-
{
|
|
9928
|
-
"path": "precision",
|
|
9929
|
-
"valueType": "number"
|
|
9930
|
-
}
|
|
9931
|
-
],
|
|
9981
|
+
"pressure-sensor": [{
|
|
9982
|
+
"path": "hpa",
|
|
9983
|
+
"valueType": "number"
|
|
9984
|
+
}],
|
|
9932
9985
|
"privacy-mask": [{
|
|
9933
9986
|
"path": "enabled",
|
|
9934
9987
|
"valueType": "boolean"
|
|
@@ -10239,20 +10292,10 @@ Object.freeze({
|
|
|
10239
10292
|
"path": "tampered",
|
|
10240
10293
|
"valueType": "boolean"
|
|
10241
10294
|
}],
|
|
10242
|
-
"temperature-sensor": [
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
},
|
|
10247
|
-
{
|
|
10248
|
-
"path": "unit",
|
|
10249
|
-
"valueType": "string"
|
|
10250
|
-
},
|
|
10251
|
-
{
|
|
10252
|
-
"path": "precision",
|
|
10253
|
-
"valueType": "number"
|
|
10254
|
-
}
|
|
10255
|
-
],
|
|
10295
|
+
"temperature-sensor": [{
|
|
10296
|
+
"path": "celsius",
|
|
10297
|
+
"valueType": "number"
|
|
10298
|
+
}],
|
|
10256
10299
|
"update": [
|
|
10257
10300
|
{
|
|
10258
10301
|
"path": "currentVersion",
|
|
@@ -10363,10 +10406,6 @@ Object.freeze({
|
|
|
10363
10406
|
"path": "temperature",
|
|
10364
10407
|
"valueType": "number"
|
|
10365
10408
|
},
|
|
10366
|
-
{
|
|
10367
|
-
"path": "temperatureUnit",
|
|
10368
|
-
"valueType": "string"
|
|
10369
|
-
},
|
|
10370
10409
|
{
|
|
10371
10410
|
"path": "humidity",
|
|
10372
10411
|
"valueType": "number"
|
|
@@ -10375,18 +10414,10 @@ Object.freeze({
|
|
|
10375
10414
|
"path": "pressure",
|
|
10376
10415
|
"valueType": "number"
|
|
10377
10416
|
},
|
|
10378
|
-
{
|
|
10379
|
-
"path": "pressureUnit",
|
|
10380
|
-
"valueType": "string"
|
|
10381
|
-
},
|
|
10382
10417
|
{
|
|
10383
10418
|
"path": "windSpeed",
|
|
10384
10419
|
"valueType": "number"
|
|
10385
10420
|
},
|
|
10386
|
-
{
|
|
10387
|
-
"path": "windSpeedUnit",
|
|
10388
|
-
"valueType": "string"
|
|
10389
|
-
},
|
|
10390
10421
|
{
|
|
10391
10422
|
"path": "windBearing",
|
|
10392
10423
|
"valueType": "number"
|
|
@@ -10450,7 +10481,7 @@ function userError(code, params, englishFallback) {
|
|
|
10450
10481
|
return new CamstackError(code, params, englishFallback);
|
|
10451
10482
|
}
|
|
10452
10483
|
//#endregion
|
|
10453
|
-
//#region ../types/dist/err-msg-
|
|
10484
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10454
10485
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10455
10486
|
DeviceType["Camera"] = "camera";
|
|
10456
10487
|
DeviceType["Hub"] = "hub";
|
|
@@ -10544,8 +10575,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10544
10575
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10545
10576
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10546
10577
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10547
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10578
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10579
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10548
10580
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10581
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10582
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10583
|
+
DeviceType["Washer"] = "washer";
|
|
10584
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10585
|
+
DeviceType["Dryer"] = "dryer";
|
|
10549
10586
|
return DeviceType;
|
|
10550
10587
|
}({});
|
|
10551
10588
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10803,7 +10840,7 @@ function errMsg(err) {
|
|
|
10803
10840
|
return String(err);
|
|
10804
10841
|
}
|
|
10805
10842
|
//#endregion
|
|
10806
|
-
//#region ../types/dist/composition-
|
|
10843
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10807
10844
|
/**
|
|
10808
10845
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10809
10846
|
*
|
|
@@ -11118,6 +11155,13 @@ var table = {
|
|
|
11118
11155
|
apply: () => {
|
|
11119
11156
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11120
11157
|
}
|
|
11158
|
+
},
|
|
11159
|
+
schmitt: {
|
|
11160
|
+
minArgs: 3,
|
|
11161
|
+
maxArgs: 5,
|
|
11162
|
+
apply: () => {
|
|
11163
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11164
|
+
}
|
|
11121
11165
|
}
|
|
11122
11166
|
};
|
|
11123
11167
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11558,15 +11602,232 @@ function validateExpressionSource(src) {
|
|
|
11558
11602
|
}
|
|
11559
11603
|
return null;
|
|
11560
11604
|
}
|
|
11561
|
-
/**
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11605
|
+
/**
|
|
11606
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11607
|
+
*
|
|
11608
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11609
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11610
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11611
|
+
*
|
|
11612
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11613
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11614
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11615
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11616
|
+
* can move later without moving the others.
|
|
11617
|
+
*/
|
|
11618
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11619
|
+
var APPLIANCE_KINDS = [
|
|
11620
|
+
"washer",
|
|
11621
|
+
"dryer",
|
|
11622
|
+
"dishwasher"
|
|
11623
|
+
];
|
|
11624
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11625
|
+
/**
|
|
11626
|
+
* Statistics and integrals over a history read (D944).
|
|
11627
|
+
*
|
|
11628
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11629
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11630
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11631
|
+
* as zero. A truncated read is not published.
|
|
11632
|
+
*/
|
|
11633
|
+
var STATISTIC_STATS = [
|
|
11634
|
+
"min",
|
|
11635
|
+
"max",
|
|
11636
|
+
"mean",
|
|
11637
|
+
"sum",
|
|
11638
|
+
"count",
|
|
11639
|
+
"change"
|
|
11640
|
+
];
|
|
11641
|
+
/**
|
|
11642
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11643
|
+
*
|
|
11644
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11645
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11646
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11647
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11648
|
+
*/
|
|
11649
|
+
var MINUTE_MS = 6e4;
|
|
11650
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11651
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11652
|
+
var ROLLING_SPANS = [
|
|
11653
|
+
"1h",
|
|
11654
|
+
"24h",
|
|
11655
|
+
"2d",
|
|
11656
|
+
"7d",
|
|
11657
|
+
"30d",
|
|
11658
|
+
"custom"
|
|
11659
|
+
];
|
|
11660
|
+
var CALENDAR_PERIODS = [
|
|
11661
|
+
"today",
|
|
11662
|
+
"yesterday",
|
|
11663
|
+
"this-week",
|
|
11664
|
+
"this-month"
|
|
11665
|
+
];
|
|
11666
|
+
var RESET_PERIODS = [
|
|
11667
|
+
"never",
|
|
11668
|
+
"daily",
|
|
11669
|
+
"weekly",
|
|
11670
|
+
"monthly"
|
|
11671
|
+
];
|
|
11672
|
+
5 * MINUTE_MS;
|
|
11673
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11674
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11675
|
+
var rollingWindowObject = object({
|
|
11676
|
+
kind: literal("rolling"),
|
|
11677
|
+
span: _enum(ROLLING_SPANS),
|
|
11678
|
+
customMinutes: number().int().min(5).optional()
|
|
11679
|
+
}).check((payload) => {
|
|
11680
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11681
|
+
code: "custom",
|
|
11682
|
+
message: "a custom range needs a duration in minutes",
|
|
11683
|
+
path: ["customMinutes"],
|
|
11684
|
+
input: payload.value
|
|
11685
|
+
});
|
|
11686
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11687
|
+
code: "custom",
|
|
11688
|
+
message: "only a custom range carries a duration",
|
|
11689
|
+
path: ["customMinutes"],
|
|
11690
|
+
input: payload.value
|
|
11691
|
+
});
|
|
11692
|
+
});
|
|
11693
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11694
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11695
|
+
kind: literal("calendar"),
|
|
11696
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11697
|
+
})]);
|
|
11698
|
+
/**
|
|
11699
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11700
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11701
|
+
* `composition.ts` (D659).
|
|
11702
|
+
*/
|
|
11565
11703
|
var CompositionSourceRefSchema = object({
|
|
11566
11704
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11567
11705
|
addonId: string().min(1),
|
|
11568
11706
|
stableId: string().min(1)
|
|
11569
11707
|
});
|
|
11708
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11709
|
+
"temperature",
|
|
11710
|
+
"humidity",
|
|
11711
|
+
"pressure",
|
|
11712
|
+
"illuminance",
|
|
11713
|
+
"power",
|
|
11714
|
+
"energy",
|
|
11715
|
+
"battery",
|
|
11716
|
+
"numeric",
|
|
11717
|
+
"motion",
|
|
11718
|
+
"contact",
|
|
11719
|
+
"leak",
|
|
11720
|
+
"smoke",
|
|
11721
|
+
"occupancy",
|
|
11722
|
+
"binary",
|
|
11723
|
+
"switch",
|
|
11724
|
+
"light",
|
|
11725
|
+
"fan",
|
|
11726
|
+
"cover",
|
|
11727
|
+
"valve",
|
|
11728
|
+
"lock",
|
|
11729
|
+
"media-player",
|
|
11730
|
+
"climate"
|
|
11731
|
+
];
|
|
11732
|
+
var NUMERIC_AGGREGATES = [
|
|
11733
|
+
"mean",
|
|
11734
|
+
"median",
|
|
11735
|
+
"min",
|
|
11736
|
+
"max",
|
|
11737
|
+
"sum"
|
|
11738
|
+
];
|
|
11739
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11740
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11741
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11742
|
+
var AGGREGATE_REDUCERS = [
|
|
11743
|
+
"mean",
|
|
11744
|
+
"median",
|
|
11745
|
+
"min",
|
|
11746
|
+
"max",
|
|
11747
|
+
"sum",
|
|
11748
|
+
"any",
|
|
11749
|
+
"all"
|
|
11750
|
+
];
|
|
11751
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11752
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11753
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11754
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11755
|
+
var HelperMemberSchema = object({
|
|
11756
|
+
source: CompositionSourceRefSchema,
|
|
11757
|
+
cap: string().min(1),
|
|
11758
|
+
fieldPath: string().min(1)
|
|
11759
|
+
});
|
|
11760
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11761
|
+
object({
|
|
11762
|
+
kind: literal("group"),
|
|
11763
|
+
templateId: GroupTemplateIdSchema,
|
|
11764
|
+
aggregate: AggregateReducerSchema,
|
|
11765
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11766
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11767
|
+
active: ActiveCriterionSchema.optional()
|
|
11768
|
+
}),
|
|
11769
|
+
object({
|
|
11770
|
+
kind: literal("appliance"),
|
|
11771
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11772
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11773
|
+
thresholdWatts: number().positive(),
|
|
11774
|
+
startDwellMs: number().int().nonnegative(),
|
|
11775
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11776
|
+
member: HelperMemberSchema
|
|
11777
|
+
}),
|
|
11778
|
+
object({
|
|
11779
|
+
kind: literal("statistic"),
|
|
11780
|
+
stat: _enum(STATISTIC_STATS),
|
|
11781
|
+
window: StatisticWindowSchema,
|
|
11782
|
+
source: HelperMemberSchema
|
|
11783
|
+
}),
|
|
11784
|
+
object({
|
|
11785
|
+
kind: literal("integral"),
|
|
11786
|
+
reset: _enum(RESET_PERIODS),
|
|
11787
|
+
output: _enum(["energy", "meter"]),
|
|
11788
|
+
source: HelperMemberSchema
|
|
11789
|
+
}),
|
|
11790
|
+
object({
|
|
11791
|
+
kind: literal("threshold"),
|
|
11792
|
+
source: HelperMemberSchema,
|
|
11793
|
+
high: number(),
|
|
11794
|
+
low: number(),
|
|
11795
|
+
onForMs: number().int().nonnegative(),
|
|
11796
|
+
offForMs: number().int().nonnegative()
|
|
11797
|
+
}),
|
|
11798
|
+
object({
|
|
11799
|
+
kind: literal("arithmetic"),
|
|
11800
|
+
op: _enum([
|
|
11801
|
+
"sum",
|
|
11802
|
+
"difference",
|
|
11803
|
+
"ratio"
|
|
11804
|
+
]),
|
|
11805
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11806
|
+
}),
|
|
11807
|
+
object({
|
|
11808
|
+
kind: literal("expression"),
|
|
11809
|
+
expr: string().min(1),
|
|
11810
|
+
inputs: array(object({
|
|
11811
|
+
name: string().min(1),
|
|
11812
|
+
member: HelperMemberSchema
|
|
11813
|
+
})).min(1).max(64),
|
|
11814
|
+
output: _enum(["number", "boolean"])
|
|
11815
|
+
}),
|
|
11816
|
+
object({
|
|
11817
|
+
kind: literal("derivative"),
|
|
11818
|
+
window: RollingWindowSchema,
|
|
11819
|
+
per: _enum([
|
|
11820
|
+
"second",
|
|
11821
|
+
"minute",
|
|
11822
|
+
"hour"
|
|
11823
|
+
]),
|
|
11824
|
+
source: HelperMemberSchema
|
|
11825
|
+
})
|
|
11826
|
+
]);
|
|
11827
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11828
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11829
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11830
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11570
11831
|
/** One field of one capability of one source device. */
|
|
11571
11832
|
var CompositionFieldReadSchema = object({
|
|
11572
11833
|
source: CompositionSourceRefSchema,
|
|
@@ -11610,7 +11871,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11610
11871
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11611
11872
|
CompositionFromSourceSchema,
|
|
11612
11873
|
CompositionExpressionSourceSchema,
|
|
11613
|
-
CompositionCodeSourceSchema
|
|
11874
|
+
CompositionCodeSourceSchema,
|
|
11875
|
+
object({
|
|
11876
|
+
kind: literal("aggregate"),
|
|
11877
|
+
reducer: _enum([
|
|
11878
|
+
"mean",
|
|
11879
|
+
"median",
|
|
11880
|
+
"min",
|
|
11881
|
+
"max",
|
|
11882
|
+
"sum",
|
|
11883
|
+
"any",
|
|
11884
|
+
"all"
|
|
11885
|
+
]),
|
|
11886
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11887
|
+
/**
|
|
11888
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11889
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11890
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11891
|
+
*/
|
|
11892
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11893
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11894
|
+
publish: _enum([
|
|
11895
|
+
"value",
|
|
11896
|
+
"included",
|
|
11897
|
+
"excluded",
|
|
11898
|
+
"total"
|
|
11899
|
+
]),
|
|
11900
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11901
|
+
empty: _enum([
|
|
11902
|
+
"null",
|
|
11903
|
+
"omit",
|
|
11904
|
+
"offline"
|
|
11905
|
+
])
|
|
11906
|
+
}),
|
|
11907
|
+
object({
|
|
11908
|
+
kind: literal("series"),
|
|
11909
|
+
read: CompositionFieldReadSchema,
|
|
11910
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11911
|
+
publish: _enum([
|
|
11912
|
+
"value",
|
|
11913
|
+
"included",
|
|
11914
|
+
"excluded",
|
|
11915
|
+
"total"
|
|
11916
|
+
]),
|
|
11917
|
+
/**
|
|
11918
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11919
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11920
|
+
*/
|
|
11921
|
+
empty: _enum([
|
|
11922
|
+
"null",
|
|
11923
|
+
"omit",
|
|
11924
|
+
"offline"
|
|
11925
|
+
])
|
|
11926
|
+
})
|
|
11614
11927
|
]);
|
|
11615
11928
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11616
11929
|
kind: literal("forward"),
|
|
@@ -11656,7 +11969,13 @@ var CompositionSchema = object({
|
|
|
11656
11969
|
kind: literal("existing"),
|
|
11657
11970
|
device: CompositionSourceRefSchema
|
|
11658
11971
|
})]),
|
|
11659
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
11972
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
11973
|
+
/**
|
|
11974
|
+
* Present when the block is a helper template. Absent on a free
|
|
11975
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
11976
|
+
* never the compiled features.
|
|
11977
|
+
*/
|
|
11978
|
+
helper: HelperSpecSchema.optional()
|
|
11660
11979
|
}).superRefine((composition, ctx) => {
|
|
11661
11980
|
const seen = /* @__PURE__ */ new Set();
|
|
11662
11981
|
composition.features.forEach((feature, index) => {
|
|
@@ -16763,7 +17082,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16763
17082
|
*/
|
|
16764
17083
|
interactiveConnectPath: string().min(1).optional(),
|
|
16765
17084
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16766
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17085
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17086
|
+
/**
|
|
17087
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17088
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17089
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17090
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17091
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17092
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17093
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17094
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17095
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17096
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17097
|
+
* offers it as the default path; the fields the session fills are
|
|
17098
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17099
|
+
*/
|
|
17100
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16767
17101
|
}))
|
|
16768
17102
|
});
|
|
16769
17103
|
var ListInputSchema = object({
|
|
@@ -17864,7 +18198,12 @@ var CompositionProblemSchema = object({
|
|
|
17864
18198
|
"item-field-reserved",
|
|
17865
18199
|
"target-missing",
|
|
17866
18200
|
"target-unreadable",
|
|
17867
|
-
"not-replaceable"
|
|
18201
|
+
"not-replaceable",
|
|
18202
|
+
"native-capability-replace",
|
|
18203
|
+
"mixed-quantity",
|
|
18204
|
+
"helper-mismatch",
|
|
18205
|
+
"member-constraint",
|
|
18206
|
+
"retention"
|
|
17868
18207
|
]),
|
|
17869
18208
|
path: string(),
|
|
17870
18209
|
message: string()
|
|
@@ -17885,7 +18224,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17885
18224
|
"null",
|
|
17886
18225
|
"offline",
|
|
17887
18226
|
"unknown",
|
|
17888
|
-
"release"
|
|
18227
|
+
"release",
|
|
18228
|
+
"omit"
|
|
17889
18229
|
]);
|
|
17890
18230
|
/**
|
|
17891
18231
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17922,9 +18262,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17922
18262
|
reads: array(CompositionFieldReadSchema)
|
|
17923
18263
|
});
|
|
17924
18264
|
/**
|
|
17925
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17926
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17927
|
-
*
|
|
18265
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18266
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18267
|
+
* Replacing a capability the device already serves is refused
|
|
18268
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18269
|
+
* wire for a claim the hub already holds.
|
|
17928
18270
|
*/
|
|
17929
18271
|
var CompositionFeatureModeSchema = _enum([
|
|
17930
18272
|
"new",
|
|
@@ -18095,8 +18437,392 @@ Object.freeze({
|
|
|
18095
18437
|
latchedAt: {
|
|
18096
18438
|
kind: "fixed",
|
|
18097
18439
|
result: ["number", "null"]
|
|
18440
|
+
},
|
|
18441
|
+
schmitt: {
|
|
18442
|
+
kind: "fixed",
|
|
18443
|
+
result: ["boolean", "null"]
|
|
18098
18444
|
}
|
|
18099
18445
|
});
|
|
18446
|
+
/**
|
|
18447
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18448
|
+
* Data, not a form default written into the block.
|
|
18449
|
+
*/
|
|
18450
|
+
var NOW$2 = {
|
|
18451
|
+
fieldPath: "lastFetchedAt",
|
|
18452
|
+
expr: "now"
|
|
18453
|
+
};
|
|
18454
|
+
var CHANGED = {
|
|
18455
|
+
fieldPath: "lastChangedAt",
|
|
18456
|
+
expr: "now"
|
|
18457
|
+
};
|
|
18458
|
+
function numeric(input) {
|
|
18459
|
+
return {
|
|
18460
|
+
...input,
|
|
18461
|
+
family: "numeric",
|
|
18462
|
+
deviceType: DeviceType.Sensor,
|
|
18463
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18464
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18465
|
+
activeWhen: void 0,
|
|
18466
|
+
commandCaps: [],
|
|
18467
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18468
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18469
|
+
accept: [{
|
|
18470
|
+
cap: input.outputCap,
|
|
18471
|
+
fieldPath: input.outputField
|
|
18472
|
+
}]
|
|
18473
|
+
};
|
|
18474
|
+
}
|
|
18475
|
+
function binary(input) {
|
|
18476
|
+
return {
|
|
18477
|
+
...input,
|
|
18478
|
+
family: "binary",
|
|
18479
|
+
deviceType: DeviceType.Sensor,
|
|
18480
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18481
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18482
|
+
activeWhen: void 0,
|
|
18483
|
+
commandCaps: [],
|
|
18484
|
+
quantity: "none",
|
|
18485
|
+
baseUnit: void 0,
|
|
18486
|
+
aggregates: BINARY_AGGREGATES,
|
|
18487
|
+
empty: "offline"
|
|
18488
|
+
};
|
|
18489
|
+
}
|
|
18490
|
+
var GROUP_TEMPLATES = [
|
|
18491
|
+
numeric({
|
|
18492
|
+
id: "temperature",
|
|
18493
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18494
|
+
role: DeviceRole.TemperatureSensor,
|
|
18495
|
+
outputCap: "temperature-sensor",
|
|
18496
|
+
outputField: "celsius",
|
|
18497
|
+
quantity: "temperature",
|
|
18498
|
+
defaultAggregate: "mean",
|
|
18499
|
+
empty: "null",
|
|
18500
|
+
companions: [NOW$2]
|
|
18501
|
+
}),
|
|
18502
|
+
numeric({
|
|
18503
|
+
id: "humidity",
|
|
18504
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18505
|
+
role: DeviceRole.HumiditySensor,
|
|
18506
|
+
outputCap: "humidity-sensor",
|
|
18507
|
+
outputField: "percent",
|
|
18508
|
+
quantity: "humidity",
|
|
18509
|
+
defaultAggregate: "mean",
|
|
18510
|
+
empty: "null",
|
|
18511
|
+
companions: [NOW$2]
|
|
18512
|
+
}),
|
|
18513
|
+
numeric({
|
|
18514
|
+
id: "pressure",
|
|
18515
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18516
|
+
role: DeviceRole.PressureSensor,
|
|
18517
|
+
outputCap: "pressure-sensor",
|
|
18518
|
+
outputField: "hpa",
|
|
18519
|
+
quantity: "pressure",
|
|
18520
|
+
defaultAggregate: "mean",
|
|
18521
|
+
empty: "null",
|
|
18522
|
+
companions: [NOW$2]
|
|
18523
|
+
}),
|
|
18524
|
+
numeric({
|
|
18525
|
+
id: "illuminance",
|
|
18526
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18527
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18528
|
+
outputCap: "ambient-light-sensor",
|
|
18529
|
+
outputField: "lux",
|
|
18530
|
+
quantity: "illuminance",
|
|
18531
|
+
defaultAggregate: "mean",
|
|
18532
|
+
empty: "null",
|
|
18533
|
+
companions: [NOW$2]
|
|
18534
|
+
}),
|
|
18535
|
+
numeric({
|
|
18536
|
+
id: "power",
|
|
18537
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18538
|
+
role: DeviceRole.PowerSensor,
|
|
18539
|
+
outputCap: "power-meter",
|
|
18540
|
+
outputField: "watts",
|
|
18541
|
+
quantity: "power",
|
|
18542
|
+
defaultAggregate: "sum",
|
|
18543
|
+
empty: "omit",
|
|
18544
|
+
companions: [NOW$2]
|
|
18545
|
+
}),
|
|
18546
|
+
numeric({
|
|
18547
|
+
id: "energy",
|
|
18548
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18549
|
+
role: DeviceRole.EnergySensor,
|
|
18550
|
+
outputCap: "power-meter",
|
|
18551
|
+
outputField: "kwhTotal",
|
|
18552
|
+
quantity: "energy",
|
|
18553
|
+
defaultAggregate: "sum",
|
|
18554
|
+
empty: "omit",
|
|
18555
|
+
companions: [NOW$2]
|
|
18556
|
+
}),
|
|
18557
|
+
numeric({
|
|
18558
|
+
id: "battery",
|
|
18559
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18560
|
+
role: DeviceRole.BatterySensor,
|
|
18561
|
+
outputCap: "battery",
|
|
18562
|
+
outputField: "percentage",
|
|
18563
|
+
quantity: "percentage",
|
|
18564
|
+
defaultAggregate: "mean",
|
|
18565
|
+
empty: "null",
|
|
18566
|
+
companions: [
|
|
18567
|
+
{
|
|
18568
|
+
fieldPath: "charging",
|
|
18569
|
+
expr: "\"unknown\""
|
|
18570
|
+
},
|
|
18571
|
+
{
|
|
18572
|
+
fieldPath: "sleeping",
|
|
18573
|
+
expr: "false"
|
|
18574
|
+
},
|
|
18575
|
+
{
|
|
18576
|
+
fieldPath: "lastUpdated",
|
|
18577
|
+
expr: "now"
|
|
18578
|
+
}
|
|
18579
|
+
]
|
|
18580
|
+
}),
|
|
18581
|
+
numeric({
|
|
18582
|
+
id: "numeric",
|
|
18583
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18584
|
+
role: DeviceRole.NumericSensor,
|
|
18585
|
+
outputCap: "numeric-sensor",
|
|
18586
|
+
outputField: "value",
|
|
18587
|
+
quantity: "device",
|
|
18588
|
+
defaultAggregate: "mean",
|
|
18589
|
+
empty: "null",
|
|
18590
|
+
companions: [NOW$2]
|
|
18591
|
+
}),
|
|
18592
|
+
binary({
|
|
18593
|
+
id: "motion",
|
|
18594
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18595
|
+
role: DeviceRole.MotionSensor,
|
|
18596
|
+
outputCap: "motion",
|
|
18597
|
+
outputField: "detected",
|
|
18598
|
+
defaultAggregate: "any",
|
|
18599
|
+
accept: [{
|
|
18600
|
+
cap: "motion",
|
|
18601
|
+
fieldPath: "detected"
|
|
18602
|
+
}],
|
|
18603
|
+
companions: [{
|
|
18604
|
+
fieldPath: "lastDetectedAt",
|
|
18605
|
+
expr: "null"
|
|
18606
|
+
}, {
|
|
18607
|
+
fieldPath: "autoClearAfterMs",
|
|
18608
|
+
expr: "null"
|
|
18609
|
+
}]
|
|
18610
|
+
}),
|
|
18611
|
+
binary({
|
|
18612
|
+
id: "contact",
|
|
18613
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18614
|
+
role: DeviceRole.ContactSensor,
|
|
18615
|
+
outputCap: "contact",
|
|
18616
|
+
outputField: "entryOpen",
|
|
18617
|
+
defaultAggregate: "any",
|
|
18618
|
+
accept: [{
|
|
18619
|
+
cap: "contact",
|
|
18620
|
+
fieldPath: "entryOpen"
|
|
18621
|
+
}],
|
|
18622
|
+
companions: [CHANGED]
|
|
18623
|
+
}),
|
|
18624
|
+
binary({
|
|
18625
|
+
id: "leak",
|
|
18626
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18627
|
+
role: DeviceRole.LeakSensor,
|
|
18628
|
+
outputCap: "flood",
|
|
18629
|
+
outputField: "flooded",
|
|
18630
|
+
defaultAggregate: "any",
|
|
18631
|
+
accept: [{
|
|
18632
|
+
cap: "flood",
|
|
18633
|
+
fieldPath: "flooded"
|
|
18634
|
+
}],
|
|
18635
|
+
companions: [CHANGED]
|
|
18636
|
+
}),
|
|
18637
|
+
binary({
|
|
18638
|
+
id: "smoke",
|
|
18639
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18640
|
+
role: DeviceRole.SmokeSensor,
|
|
18641
|
+
outputCap: "smoke",
|
|
18642
|
+
outputField: "detected",
|
|
18643
|
+
defaultAggregate: "any",
|
|
18644
|
+
accept: [{
|
|
18645
|
+
cap: "smoke",
|
|
18646
|
+
fieldPath: "detected"
|
|
18647
|
+
}],
|
|
18648
|
+
companions: [CHANGED]
|
|
18649
|
+
}),
|
|
18650
|
+
binary({
|
|
18651
|
+
id: "occupancy",
|
|
18652
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18653
|
+
role: DeviceRole.BinarySensor,
|
|
18654
|
+
outputCap: "binary",
|
|
18655
|
+
outputField: "on",
|
|
18656
|
+
defaultAggregate: "any",
|
|
18657
|
+
accept: [{
|
|
18658
|
+
cap: "motion",
|
|
18659
|
+
fieldPath: "detected"
|
|
18660
|
+
}, {
|
|
18661
|
+
cap: "binary",
|
|
18662
|
+
fieldPath: "on"
|
|
18663
|
+
}],
|
|
18664
|
+
companions: [CHANGED]
|
|
18665
|
+
}),
|
|
18666
|
+
binary({
|
|
18667
|
+
id: "binary",
|
|
18668
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18669
|
+
role: DeviceRole.BinarySensor,
|
|
18670
|
+
outputCap: "binary",
|
|
18671
|
+
outputField: "on",
|
|
18672
|
+
defaultAggregate: "any",
|
|
18673
|
+
accept: [{
|
|
18674
|
+
cap: "binary",
|
|
18675
|
+
fieldPath: "on"
|
|
18676
|
+
}],
|
|
18677
|
+
companions: [CHANGED]
|
|
18678
|
+
}),
|
|
18679
|
+
actuator({
|
|
18680
|
+
id: "switch",
|
|
18681
|
+
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.",
|
|
18682
|
+
deviceType: DeviceType.Switch,
|
|
18683
|
+
outputCap: "switch",
|
|
18684
|
+
outputField: "on",
|
|
18685
|
+
member: {
|
|
18686
|
+
cap: "switch",
|
|
18687
|
+
fieldPath: "on"
|
|
18688
|
+
},
|
|
18689
|
+
commandCaps: ["switch"]
|
|
18690
|
+
}),
|
|
18691
|
+
actuator({
|
|
18692
|
+
id: "light",
|
|
18693
|
+
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.",
|
|
18694
|
+
deviceType: DeviceType.Light,
|
|
18695
|
+
outputCap: "switch",
|
|
18696
|
+
outputField: "on",
|
|
18697
|
+
member: {
|
|
18698
|
+
cap: "switch",
|
|
18699
|
+
fieldPath: "on"
|
|
18700
|
+
},
|
|
18701
|
+
commandCaps: [
|
|
18702
|
+
"switch",
|
|
18703
|
+
"brightness",
|
|
18704
|
+
"color"
|
|
18705
|
+
]
|
|
18706
|
+
}),
|
|
18707
|
+
actuator({
|
|
18708
|
+
id: "fan",
|
|
18709
|
+
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.",
|
|
18710
|
+
deviceType: DeviceType.Fan,
|
|
18711
|
+
outputCap: "switch",
|
|
18712
|
+
outputField: "on",
|
|
18713
|
+
member: {
|
|
18714
|
+
cap: "switch",
|
|
18715
|
+
fieldPath: "on"
|
|
18716
|
+
},
|
|
18717
|
+
commandCaps: ["switch", "fan-control"]
|
|
18718
|
+
}),
|
|
18719
|
+
actuator({
|
|
18720
|
+
id: "cover",
|
|
18721
|
+
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.",
|
|
18722
|
+
deviceType: DeviceType.Cover,
|
|
18723
|
+
outputCap: "group-active",
|
|
18724
|
+
outputField: "active",
|
|
18725
|
+
member: {
|
|
18726
|
+
cap: "cover",
|
|
18727
|
+
fieldPath: "state"
|
|
18728
|
+
},
|
|
18729
|
+
activeWhen: [
|
|
18730
|
+
"open",
|
|
18731
|
+
"opening",
|
|
18732
|
+
"stopped"
|
|
18733
|
+
],
|
|
18734
|
+
commandCaps: ["cover"]
|
|
18735
|
+
}),
|
|
18736
|
+
actuator({
|
|
18737
|
+
id: "valve",
|
|
18738
|
+
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.",
|
|
18739
|
+
deviceType: DeviceType.Valve,
|
|
18740
|
+
outputCap: "group-active",
|
|
18741
|
+
outputField: "active",
|
|
18742
|
+
member: {
|
|
18743
|
+
cap: "valve",
|
|
18744
|
+
fieldPath: "state"
|
|
18745
|
+
},
|
|
18746
|
+
activeWhen: [
|
|
18747
|
+
"open",
|
|
18748
|
+
"opening",
|
|
18749
|
+
"stopped"
|
|
18750
|
+
],
|
|
18751
|
+
commandCaps: ["valve"]
|
|
18752
|
+
}),
|
|
18753
|
+
actuator({
|
|
18754
|
+
id: "lock",
|
|
18755
|
+
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.",
|
|
18756
|
+
deviceType: DeviceType.Lock,
|
|
18757
|
+
outputCap: "group-active",
|
|
18758
|
+
outputField: "active",
|
|
18759
|
+
member: {
|
|
18760
|
+
cap: "lock-control",
|
|
18761
|
+
fieldPath: "state"
|
|
18762
|
+
},
|
|
18763
|
+
activeWhen: ["locked"],
|
|
18764
|
+
commandCaps: ["lock-control"]
|
|
18765
|
+
}),
|
|
18766
|
+
actuator({
|
|
18767
|
+
id: "media-player",
|
|
18768
|
+
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.",
|
|
18769
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18770
|
+
outputCap: "group-active",
|
|
18771
|
+
outputField: "active",
|
|
18772
|
+
member: {
|
|
18773
|
+
cap: "media-player",
|
|
18774
|
+
fieldPath: "state"
|
|
18775
|
+
},
|
|
18776
|
+
activeWhen: ["playing", "buffering"],
|
|
18777
|
+
commandCaps: ["media-player"]
|
|
18778
|
+
}),
|
|
18779
|
+
actuator({
|
|
18780
|
+
id: "climate",
|
|
18781
|
+
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.",
|
|
18782
|
+
deviceType: DeviceType.Thermostat,
|
|
18783
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18784
|
+
outputCap: "group-active",
|
|
18785
|
+
outputField: "active",
|
|
18786
|
+
member: {
|
|
18787
|
+
cap: "climate-control",
|
|
18788
|
+
fieldPath: "mode"
|
|
18789
|
+
},
|
|
18790
|
+
activeWhen: [
|
|
18791
|
+
"heat",
|
|
18792
|
+
"cool",
|
|
18793
|
+
"auto",
|
|
18794
|
+
"heat_cool",
|
|
18795
|
+
"fan_only",
|
|
18796
|
+
"dry"
|
|
18797
|
+
],
|
|
18798
|
+
commandCaps: ["climate-control"]
|
|
18799
|
+
})
|
|
18800
|
+
];
|
|
18801
|
+
function actuator(input) {
|
|
18802
|
+
return {
|
|
18803
|
+
id: input.id,
|
|
18804
|
+
summary: input.summary,
|
|
18805
|
+
deviceType: input.deviceType,
|
|
18806
|
+
outputCap: input.outputCap,
|
|
18807
|
+
outputField: input.outputField,
|
|
18808
|
+
commandCaps: input.commandCaps,
|
|
18809
|
+
family: "actuator",
|
|
18810
|
+
role: void 0,
|
|
18811
|
+
memberDeviceType: input.deviceType,
|
|
18812
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18813
|
+
activeWhen: input.activeWhen,
|
|
18814
|
+
quantity: "none",
|
|
18815
|
+
baseUnit: void 0,
|
|
18816
|
+
aggregates: BINARY_AGGREGATES,
|
|
18817
|
+
defaultAggregate: "any",
|
|
18818
|
+
empty: "offline",
|
|
18819
|
+
accept: [input.member],
|
|
18820
|
+
companions: [CHANGED]
|
|
18821
|
+
};
|
|
18822
|
+
}
|
|
18823
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18824
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18825
|
+
DeviceType.Camera;
|
|
18100
18826
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18101
18827
|
/**
|
|
18102
18828
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19923,12 +20649,12 @@ function buildDeviceAdminUrl(parts) {
|
|
|
19923
20649
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19924
20650
|
* in-place so dispatch keeps working.
|
|
19925
20651
|
*
|
|
19926
|
-
* **
|
|
19927
|
-
*
|
|
19928
|
-
*
|
|
19929
|
-
*
|
|
19930
|
-
* (`ha-domain-mapping`)
|
|
19931
|
-
* stored after that point.
|
|
20652
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20653
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20654
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20655
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20656
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20657
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19932
20658
|
*
|
|
19933
20659
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19934
20660
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19942,6 +20668,14 @@ var SourceInfoSchema = object({
|
|
|
19942
20668
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19943
20669
|
* Used to detect rename when `id` changes. */
|
|
19944
20670
|
uniqueId: string().optional(),
|
|
20671
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20672
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20673
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20674
|
+
dateTimeShape: _enum([
|
|
20675
|
+
"date",
|
|
20676
|
+
"time",
|
|
20677
|
+
"datetime"
|
|
20678
|
+
]).optional(),
|
|
19945
20679
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19946
20680
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19947
20681
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41046,7 +41780,8 @@ method(object({
|
|
|
41046
41780
|
"enum"
|
|
41047
41781
|
]),
|
|
41048
41782
|
enumValues: array(string()).optional(),
|
|
41049
|
-
item: boolean().optional()
|
|
41783
|
+
item: boolean().optional(),
|
|
41784
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41050
41785
|
})).readonly(),
|
|
41051
41786
|
itemArray: object({
|
|
41052
41787
|
path: string(),
|
|
@@ -43407,7 +44142,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43407
44142
|
});
|
|
43408
44143
|
/**
|
|
43409
44144
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43410
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44145
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43411
44146
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43412
44147
|
* the originating provider config (mode + sourcePort) so the
|
|
43413
44148
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44890,8 +45625,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44890
45625
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44891
45626
|
var MaskGridShapeSchema = object({
|
|
44892
45627
|
kind: literal("grid"),
|
|
44893
|
-
gridWidth: number(),
|
|
44894
|
-
gridHeight: number(),
|
|
45628
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45629
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44895
45630
|
cells: array(boolean())
|
|
44896
45631
|
});
|
|
44897
45632
|
discriminatedUnion("kind", [
|
|
@@ -45003,6 +45738,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45003
45738
|
"detection-blind",
|
|
45004
45739
|
"motion-noisy",
|
|
45005
45740
|
"motion-calm",
|
|
45741
|
+
"package-llm-silent",
|
|
45742
|
+
"package-llm-answered",
|
|
45006
45743
|
"recording-stalled",
|
|
45007
45744
|
"recording-healthy",
|
|
45008
45745
|
"recording-degraded",
|
|
@@ -46092,7 +46829,20 @@ var NcRuleInputSchema = object({
|
|
|
46092
46829
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46093
46830
|
* path does not run Zod defaults.
|
|
46094
46831
|
*/
|
|
46095
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46832
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46833
|
+
/**
|
|
46834
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46835
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46836
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46837
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46838
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46839
|
+
*
|
|
46840
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46841
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46842
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46843
|
+
* `false`, so it needs no `clear` key.
|
|
46844
|
+
*/
|
|
46845
|
+
askVerdict: boolean().optional()
|
|
46096
46846
|
});
|
|
46097
46847
|
/**
|
|
46098
46848
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56094,6 +56844,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56094
56844
|
deprecated: string().optional(),
|
|
56095
56845
|
distTags: array(string()).readonly()
|
|
56096
56846
|
});
|
|
56847
|
+
/**
|
|
56848
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56849
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56850
|
+
* tarball failure — never an empty string standing in for either.
|
|
56851
|
+
*/
|
|
56852
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56853
|
+
object({
|
|
56854
|
+
status: literal("ok"),
|
|
56855
|
+
markdown: string()
|
|
56856
|
+
}),
|
|
56857
|
+
object({ status: literal("missing") }),
|
|
56858
|
+
object({
|
|
56859
|
+
status: literal("error"),
|
|
56860
|
+
message: string()
|
|
56861
|
+
})
|
|
56862
|
+
]);
|
|
56863
|
+
var PackageDocsSchema = object({
|
|
56864
|
+
name: string(),
|
|
56865
|
+
version: string(),
|
|
56866
|
+
readme: PackageDocBodySchema,
|
|
56867
|
+
changelog: PackageDocBodySchema
|
|
56868
|
+
});
|
|
56097
56869
|
var SearchResultSchema = object({
|
|
56098
56870
|
name: string(),
|
|
56099
56871
|
version: string(),
|
|
@@ -56312,7 +57084,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56312
57084
|
}), object({ success: literal(true) }), {
|
|
56313
57085
|
kind: "mutation",
|
|
56314
57086
|
auth: "admin"
|
|
56315
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57087
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57088
|
+
name: string().min(1),
|
|
57089
|
+
version: string().min(1).optional()
|
|
57090
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56316
57091
|
kind: "mutation",
|
|
56317
57092
|
auth: "admin"
|
|
56318
57093
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56371,27 +57146,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56371
57146
|
*/
|
|
56372
57147
|
var AirQualitySensorStatusSchema = object({
|
|
56373
57148
|
/** Carbon dioxide concentration in ppm. */
|
|
56374
|
-
co2Ppm: number().min(0).optional(),
|
|
57149
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56375
57150
|
/** Total volatile organic compounds in ppb. */
|
|
56376
|
-
vocPpb: number().min(0).optional(),
|
|
57151
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56377
57152
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56378
|
-
pm25: number().min(0).optional(),
|
|
57153
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56379
57154
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56380
|
-
pm10: number().min(0).optional(),
|
|
57155
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56381
57156
|
/** Composite AQI value (typically 0..500). */
|
|
56382
|
-
aqi: number().optional(),
|
|
57157
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56383
57158
|
/** Ms epoch when the slice was last updated. */
|
|
56384
|
-
lastFetchedAt: number()
|
|
56385
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56386
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56387
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56388
|
-
* per slice is unambiguous. */
|
|
56389
|
-
unit: string().optional(),
|
|
56390
|
-
/** Suggested decimal places for numeric display.
|
|
56391
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56392
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56393
|
-
* auto-formatting when absent. */
|
|
56394
|
-
precision: number().int().min(0).max(10).optional()
|
|
57159
|
+
lastFetchedAt: number()
|
|
56395
57160
|
});
|
|
56396
57161
|
var airQualitySensorCapability = {
|
|
56397
57162
|
name: "air-quality-sensor",
|
|
@@ -56428,12 +57193,12 @@ var airQualitySensorCapability = {
|
|
|
56428
57193
|
},
|
|
56429
57194
|
pm25: {
|
|
56430
57195
|
kind: "gauge",
|
|
56431
|
-
unit: "
|
|
57196
|
+
unit: "µg/m³",
|
|
56432
57197
|
deadband: 1
|
|
56433
57198
|
},
|
|
56434
57199
|
pm10: {
|
|
56435
57200
|
kind: "gauge",
|
|
56436
|
-
unit: "
|
|
57201
|
+
unit: "µg/m³",
|
|
56437
57202
|
deadband: 1
|
|
56438
57203
|
},
|
|
56439
57204
|
aqi: {
|
|
@@ -56451,22 +57216,13 @@ var airQualitySensorCapability = {
|
|
|
56451
57216
|
* entries with `device_class: illuminance`.
|
|
56452
57217
|
*/
|
|
56453
57218
|
var AmbientLightSensorStatusSchema = object({
|
|
56454
|
-
/** Current illuminance in lux (lx). */
|
|
56455
|
-
lux: number().min(0).meta({
|
|
56456
|
-
|
|
57219
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57220
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57221
|
+
precision: 0,
|
|
56457
57222
|
label: "Illuminance"
|
|
56458
|
-
}),
|
|
57223
|
+
})),
|
|
56459
57224
|
/** Ms epoch when the slice was last updated. */
|
|
56460
|
-
lastFetchedAt: number()
|
|
56461
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56462
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56463
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56464
|
-
unit: string().optional(),
|
|
56465
|
-
/** Suggested decimal places for numeric display.
|
|
56466
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56467
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56468
|
-
* auto-formatting when absent. */
|
|
56469
|
-
precision: number().int().min(0).max(10).optional()
|
|
57225
|
+
lastFetchedAt: number()
|
|
56470
57226
|
});
|
|
56471
57227
|
var ambientLightSensorCapability = {
|
|
56472
57228
|
name: "ambient-light-sensor",
|
|
@@ -56498,12 +57254,7 @@ var ambientLightSensorCapability = {
|
|
|
56498
57254
|
} } },
|
|
56499
57255
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56500
57256
|
* whether persisting is worth a SQLite commit. */
|
|
56501
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56502
|
-
customize: {
|
|
56503
|
-
version: 1,
|
|
56504
|
-
advanced: "derive",
|
|
56505
|
-
targets: []
|
|
56506
|
-
}
|
|
57257
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56507
57258
|
};
|
|
56508
57259
|
/**
|
|
56509
57260
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56730,10 +57481,7 @@ var BatteryStatusSchema = object({
|
|
|
56730
57481
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56731
57482
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56732
57483
|
*/
|
|
56733
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56734
|
-
unit: "%",
|
|
56735
|
-
label: "Charge"
|
|
56736
|
-
}),
|
|
57484
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56737
57485
|
/**
|
|
56738
57486
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56739
57487
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56760,7 +57508,14 @@ var BatteryStatusSchema = object({
|
|
|
56760
57508
|
*/
|
|
56761
57509
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56762
57510
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56763
|
-
lastUpdated: number(),
|
|
57511
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57512
|
+
/**
|
|
57513
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57514
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57515
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57516
|
+
* `numeric-sensor` on the same device.
|
|
57517
|
+
*/
|
|
57518
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56764
57519
|
/**
|
|
56765
57520
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56766
57521
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56807,12 +57562,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56807
57562
|
DeviceType.Switch,
|
|
56808
57563
|
DeviceType.PetFeeder,
|
|
56809
57564
|
DeviceType.Container,
|
|
56810
|
-
DeviceType.Thermostat
|
|
57565
|
+
DeviceType.Thermostat,
|
|
57566
|
+
DeviceType.EventEmitter
|
|
56811
57567
|
];
|
|
56812
57568
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56813
57569
|
var batteryCustomize = {
|
|
56814
57570
|
version: 1,
|
|
56815
|
-
advanced: "derive",
|
|
56816
57571
|
targets: [{
|
|
56817
57572
|
id: "percentage",
|
|
56818
57573
|
cardinality: "scalar",
|
|
@@ -56821,7 +57576,7 @@ var batteryCustomize = {
|
|
|
56821
57576
|
stateField: "percentage"
|
|
56822
57577
|
},
|
|
56823
57578
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56824
|
-
apply: "add
|
|
57579
|
+
apply: "add",
|
|
56825
57580
|
path: "percentage",
|
|
56826
57581
|
sources: [{
|
|
56827
57582
|
kind: "field",
|
|
@@ -56942,10 +57697,16 @@ onStatusChanged: { data: object({
|
|
|
56942
57697
|
/**
|
|
56943
57698
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
56944
57699
|
*/
|
|
56945
|
-
history: { fields: {
|
|
56946
|
-
|
|
56947
|
-
|
|
56948
|
-
|
|
57700
|
+
history: { fields: {
|
|
57701
|
+
percentage: {
|
|
57702
|
+
kind: "gauge",
|
|
57703
|
+
unit: "%"
|
|
57704
|
+
},
|
|
57705
|
+
volts: {
|
|
57706
|
+
kind: "gauge",
|
|
57707
|
+
unit: "V"
|
|
57708
|
+
}
|
|
57709
|
+
} },
|
|
56949
57710
|
customize: batteryCustomize,
|
|
56950
57711
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56951
57712
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -56992,12 +57753,7 @@ var binaryCapability = {
|
|
|
56992
57753
|
history: { fields: { on: { kind: "boolean" } } },
|
|
56993
57754
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56994
57755
|
* whether persisting is worth a SQLite commit. */
|
|
56995
|
-
volatileStateFields: ["lastChangedAt"]
|
|
56996
|
-
customize: {
|
|
56997
|
-
version: 1,
|
|
56998
|
-
advanced: "derive",
|
|
56999
|
-
targets: []
|
|
57000
|
-
}
|
|
57756
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57001
57757
|
};
|
|
57002
57758
|
/**
|
|
57003
57759
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57013,7 +57769,7 @@ var binaryCapability = {
|
|
|
57013
57769
|
*/
|
|
57014
57770
|
var BrightnessStatusSchema = object({
|
|
57015
57771
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57016
|
-
percentage: number().min(0).max(100),
|
|
57772
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57017
57773
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57018
57774
|
lastChangedAt: number()
|
|
57019
57775
|
});
|
|
@@ -57467,21 +58223,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57467
58223
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57468
58224
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57469
58225
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57470
|
-
target: number().nullable(),
|
|
58226
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57471
58227
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57472
58228
|
* in `heat_cool` mode. */
|
|
57473
|
-
targetHigh: number().nullable(),
|
|
58229
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57474
58230
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57475
58231
|
* in `heat_cool` mode. */
|
|
57476
|
-
targetLow: number().nullable(),
|
|
58232
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57477
58233
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57478
58234
|
* humidity control. */
|
|
57479
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58235
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57480
58236
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57481
58237
|
* the device's internal sensor. */
|
|
57482
|
-
currentTemp: number().nullable(),
|
|
58238
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57483
58239
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57484
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58240
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57485
58241
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57486
58242
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57487
58243
|
swingVertical: boolean().nullable(),
|
|
@@ -57489,11 +58245,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57489
58245
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57490
58246
|
swingHorizontal: boolean().nullable(),
|
|
57491
58247
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57492
|
-
minTemp: number().nullable().optional(),
|
|
58248
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57493
58249
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57494
|
-
maxTemp: number().nullable().optional(),
|
|
58250
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57495
58251
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57496
|
-
tempStep: number().positive().nullable().optional(),
|
|
58252
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57497
58253
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57498
58254
|
lastFetchedAt: number()
|
|
57499
58255
|
});
|
|
@@ -57635,17 +58391,17 @@ var climateControlCapability = {
|
|
|
57635
58391
|
* modes to expose in the picker without a slice fetch.
|
|
57636
58392
|
*/
|
|
57637
58393
|
var RgbTripletSchema = object({
|
|
57638
|
-
r: number().int().min(0).max(255),
|
|
57639
|
-
g: number().int().min(0).max(255),
|
|
57640
|
-
b: number().int().min(0).max(255)
|
|
58394
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58395
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58396
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57641
58397
|
});
|
|
57642
58398
|
var HsvTripletSchema = object({
|
|
57643
58399
|
/** Hue in degrees, 0..360. */
|
|
57644
|
-
h: number().min(0).max(360),
|
|
58400
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57645
58401
|
/** Saturation as 0..100 inclusive. */
|
|
57646
|
-
s: number().min(0).max(100),
|
|
58402
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57647
58403
|
/** Value/brightness as 0..100 inclusive. */
|
|
57648
|
-
v: number().min(0).max(100)
|
|
58404
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57649
58405
|
});
|
|
57650
58406
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57651
58407
|
object({
|
|
@@ -57674,7 +58430,7 @@ var ColorStatusSchema = object({
|
|
|
57674
58430
|
/** Populated when `mode === 'hsv'`. */
|
|
57675
58431
|
hsv: HsvTripletSchema.optional(),
|
|
57676
58432
|
/** Populated when `mode === 'mired'`. */
|
|
57677
|
-
mireds: number().int().optional(),
|
|
58433
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57678
58434
|
/** Ms epoch of the last operator-driven change. */
|
|
57679
58435
|
lastChangedAt: number()
|
|
57680
58436
|
});
|
|
@@ -57869,18 +58625,12 @@ _enum([
|
|
|
57869
58625
|
"empty",
|
|
57870
58626
|
"full"
|
|
57871
58627
|
]);
|
|
57872
|
-
/**
|
|
57873
|
-
|
|
57874
|
-
|
|
57875
|
-
"days",
|
|
57876
|
-
"hours",
|
|
57877
|
-
"cycles"
|
|
57878
|
-
]);
|
|
57879
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57880
|
-
* days). `value` null = unknown (D393). */
|
|
58628
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58629
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58630
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57881
58631
|
var ConsumableRemainingSchema = object({
|
|
57882
|
-
value: number().min(0).nullable(),
|
|
57883
|
-
|
|
58632
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58633
|
+
kind: ConsumableRemainingKindSchema
|
|
57884
58634
|
});
|
|
57885
58635
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
57886
58636
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -57893,7 +58643,7 @@ var ConsumableItemSchema = object({
|
|
|
57893
58643
|
/** Display name. */
|
|
57894
58644
|
label: string().min(1),
|
|
57895
58645
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57896
|
-
level: number().min(0).max(100).nullable(),
|
|
58646
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57897
58647
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57898
58648
|
status: ConsumableStatusSchema.nullable(),
|
|
57899
58649
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57975,8 +58725,8 @@ var consumablesCustomize = {
|
|
|
57975
58725
|
transforms: [{ kind: "identity" }]
|
|
57976
58726
|
}],
|
|
57977
58727
|
literals: [{
|
|
57978
|
-
path: "remaining.
|
|
57979
|
-
values: [...
|
|
58728
|
+
path: "remaining.kind",
|
|
58729
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
57980
58730
|
}]
|
|
57981
58731
|
},
|
|
57982
58732
|
{
|
|
@@ -58105,7 +58855,6 @@ reset: method(object({
|
|
|
58105
58855
|
},
|
|
58106
58856
|
"remaining.value": {
|
|
58107
58857
|
kind: "gauge",
|
|
58108
|
-
unitFrom: "remaining.unit",
|
|
58109
58858
|
deadband: 1,
|
|
58110
58859
|
displayName: "Remaining"
|
|
58111
58860
|
}
|
|
@@ -58175,10 +58924,9 @@ var contactCapability = {
|
|
|
58175
58924
|
* (empty array for the other kinds). It lives in the slice because
|
|
58176
58925
|
* HA `select.*` entities may update their options at runtime.
|
|
58177
58926
|
*
|
|
58178
|
-
*
|
|
58179
|
-
*
|
|
58180
|
-
*
|
|
58181
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
58927
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
58928
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
58929
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58182
58930
|
*/
|
|
58183
58931
|
var ControlStatusSchema = object({
|
|
58184
58932
|
kind: _enum([
|
|
@@ -58190,39 +58938,17 @@ var ControlStatusSchema = object({
|
|
|
58190
58938
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58191
58939
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58192
58940
|
* or time-only — HA accepts all three forms). */
|
|
58193
|
-
value: union([number(), string()]),
|
|
58941
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58194
58942
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58195
58943
|
options: array(string()),
|
|
58196
58944
|
/** Ms epoch when the slice was last updated. */
|
|
58197
58945
|
lastChangedAt: number(),
|
|
58198
|
-
/**
|
|
58199
|
-
|
|
58200
|
-
|
|
58201
|
-
|
|
58202
|
-
/**
|
|
58203
|
-
|
|
58204
|
-
min: number().optional(),
|
|
58205
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58206
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58207
|
-
max: number().optional(),
|
|
58208
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58209
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58210
|
-
step: number().optional(),
|
|
58211
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58212
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58213
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58214
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58215
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58216
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58217
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58218
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58219
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58220
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58221
|
-
format: _enum([
|
|
58222
|
-
"date",
|
|
58223
|
-
"time",
|
|
58224
|
-
"datetime"
|
|
58225
|
-
]).optional()
|
|
58946
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58947
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58948
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58949
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58950
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58951
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58226
58952
|
});
|
|
58227
58953
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58228
58954
|
object({
|
|
@@ -58288,9 +59014,9 @@ var CoverStatusSchema = object({
|
|
|
58288
59014
|
]),
|
|
58289
59015
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58290
59016
|
* no intermediate position surface. */
|
|
58291
|
-
position: number().min(0).max(100).nullable(),
|
|
59017
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58292
59018
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58293
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59019
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58294
59020
|
/** Ms epoch when the slice was last updated. */
|
|
58295
59021
|
lastChangedAt: number()
|
|
58296
59022
|
});
|
|
@@ -58393,9 +59119,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58393
59119
|
var DayNightStatusSchema = object({
|
|
58394
59120
|
mode: DayNightModeSchema,
|
|
58395
59121
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58396
|
-
sensitivity: number().optional(),
|
|
59122
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58397
59123
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58398
|
-
switchDelaySec: number().optional(),
|
|
59124
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58399
59125
|
lastFetchedAt: number()
|
|
58400
59126
|
});
|
|
58401
59127
|
/**
|
|
@@ -58613,11 +59339,11 @@ var DishwasherStatusSchema = object({
|
|
|
58613
59339
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58614
59340
|
availablePrograms: array(string()),
|
|
58615
59341
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58616
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59342
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58617
59343
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58618
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59344
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58619
59345
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58620
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59346
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58621
59347
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58622
59348
|
doorOpen: boolean().nullable(),
|
|
58623
59349
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58641,7 +59367,7 @@ var DishwasherStatusSchema = object({
|
|
|
58641
59367
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58642
59368
|
machineCareDue: boolean().nullable(),
|
|
58643
59369
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58644
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59370
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58645
59371
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58646
59372
|
halfLoad: boolean().nullable(),
|
|
58647
59373
|
hygienePlus: boolean().nullable(),
|
|
@@ -58656,7 +59382,7 @@ var DishwasherStatusSchema = object({
|
|
|
58656
59382
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58657
59383
|
activeEvents: array(string()),
|
|
58658
59384
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58659
|
-
errorCode: number().nullable(),
|
|
59385
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58660
59386
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58661
59387
|
errorLabel: string().nullable(),
|
|
58662
59388
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58887,7 +59613,7 @@ var DoorbellStatusSchema = object({
|
|
|
58887
59613
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58888
59614
|
lastPressedAt: number().nullable(),
|
|
58889
59615
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58890
|
-
pressCountSinceStart: number()
|
|
59616
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58891
59617
|
});
|
|
58892
59618
|
var DoorbellPressEventSchema = object({
|
|
58893
59619
|
deviceId: number(),
|
|
@@ -58952,17 +59678,7 @@ onPressed: {
|
|
|
58952
59678
|
history: "none",
|
|
58953
59679
|
customize: doorbellCustomize
|
|
58954
59680
|
};
|
|
58955
|
-
|
|
58956
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
58957
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
58958
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
58959
|
-
* The option set is stable across observations; it is persisted in the
|
|
58960
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
58961
|
-
* stored in `sourceInfo`.
|
|
58962
|
-
*/
|
|
58963
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
58964
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
58965
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
59681
|
+
_enum([
|
|
58966
59682
|
"date",
|
|
58967
59683
|
"time",
|
|
58968
59684
|
"datetime"
|
|
@@ -58970,12 +59686,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
58970
59686
|
var EnumSensorStatusSchema = object({
|
|
58971
59687
|
value: string(),
|
|
58972
59688
|
/**
|
|
58973
|
-
* Set
|
|
58974
|
-
* as
|
|
58975
|
-
*
|
|
58976
|
-
* a time-only sensor → `'time'`.
|
|
59689
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
59690
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
59691
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
58977
59692
|
*/
|
|
58978
|
-
|
|
59693
|
+
timestamp: boolean().optional(),
|
|
58979
59694
|
/** Ms epoch when the slice was last updated. */
|
|
58980
59695
|
lastFetchedAt: number()
|
|
58981
59696
|
});
|
|
@@ -59002,11 +59717,11 @@ var enumSensorCapability = {
|
|
|
59002
59717
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59003
59718
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59004
59719
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59005
|
-
* `
|
|
59720
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59006
59721
|
*/
|
|
59007
59722
|
history: { fields: { value: {
|
|
59008
59723
|
kind: "enum",
|
|
59009
|
-
skipWhenSet: "
|
|
59724
|
+
skipWhenSet: "timestamp"
|
|
59010
59725
|
} } },
|
|
59011
59726
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59012
59727
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59026,13 +59741,13 @@ var EventFireSchema = object({
|
|
|
59026
59741
|
deviceId: number(),
|
|
59027
59742
|
eventType: string(),
|
|
59028
59743
|
data: record(string(), unknown()).nullable(),
|
|
59029
|
-
timestamp: number(),
|
|
59030
|
-
seq: number()
|
|
59744
|
+
timestamp: number().meta(readingMeta("none")),
|
|
59745
|
+
seq: number().meta(readingMeta("count"))
|
|
59031
59746
|
});
|
|
59032
59747
|
var EventEmitterStatusSchema = object({
|
|
59033
59748
|
eventTypes: array(string()),
|
|
59034
59749
|
lastEvent: EventFireSchema.nullable(),
|
|
59035
|
-
eventCountSinceStart: number()
|
|
59750
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59036
59751
|
});
|
|
59037
59752
|
var eventEmitterCapability = {
|
|
59038
59753
|
name: "event-emitter",
|
|
@@ -59445,10 +60160,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59445
60160
|
var FanControlStatusSchema = object({
|
|
59446
60161
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59447
60162
|
* speed surface (single-speed fan). */
|
|
59448
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60163
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59449
60164
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59450
60165
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59451
|
-
percentageStep: number().positive().optional(),
|
|
60166
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59452
60167
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59453
60168
|
* — empty string when no preset is active or supported. */
|
|
59454
60169
|
preset: string(),
|
|
@@ -59569,7 +60284,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59569
60284
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59570
60285
|
model: string().nullable(),
|
|
59571
60286
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59572
|
-
channelCount: number().nullable(),
|
|
60287
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59573
60288
|
/**
|
|
59574
60289
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59575
60290
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59692,9 +60407,151 @@ var gasCapability = {
|
|
|
59692
60407
|
* whether persisting is worth a SQLite commit. */
|
|
59693
60408
|
volatileStateFields: ["lastChangedAt"]
|
|
59694
60409
|
};
|
|
60410
|
+
var GroupCommandsSchema = object({
|
|
60411
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60412
|
+
results: array(object({
|
|
60413
|
+
deviceId: number().int().nonnegative(),
|
|
60414
|
+
cap: string().min(1),
|
|
60415
|
+
method: string().min(1),
|
|
60416
|
+
ok: boolean(),
|
|
60417
|
+
error: string().optional(),
|
|
60418
|
+
/** Ms epoch of the attempt. */
|
|
60419
|
+
at: number()
|
|
60420
|
+
})) });
|
|
60421
|
+
var groupCommandsCapability = {
|
|
60422
|
+
name: "group-commands",
|
|
60423
|
+
scope: "device",
|
|
60424
|
+
deviceNative: true,
|
|
60425
|
+
mode: "singleton",
|
|
60426
|
+
deviceTypes: [
|
|
60427
|
+
DeviceType.Switch,
|
|
60428
|
+
DeviceType.Light,
|
|
60429
|
+
DeviceType.Fan,
|
|
60430
|
+
DeviceType.Cover,
|
|
60431
|
+
DeviceType.Valve,
|
|
60432
|
+
DeviceType.Lock,
|
|
60433
|
+
DeviceType.MediaPlayer,
|
|
60434
|
+
DeviceType.Thermostat,
|
|
60435
|
+
DeviceType.Climate
|
|
60436
|
+
],
|
|
60437
|
+
methods: {},
|
|
60438
|
+
status: {
|
|
60439
|
+
schema: GroupCommandsSchema,
|
|
60440
|
+
kind: "push"
|
|
60441
|
+
},
|
|
60442
|
+
runtimeState: GroupCommandsSchema,
|
|
60443
|
+
/**
|
|
60444
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
60445
|
+
* failure would outlive the command that caused it.
|
|
60446
|
+
*
|
|
60447
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60448
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60449
|
+
*/
|
|
60450
|
+
durability: "session",
|
|
60451
|
+
history: "none"
|
|
60452
|
+
};
|
|
60453
|
+
/**
|
|
60454
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
60455
|
+
* included member is, or every included member is. What "active" means is the
|
|
60456
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
60457
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
60458
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
60459
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
60460
|
+
* empty included set takes the device offline, never `active: false`.
|
|
60461
|
+
*/
|
|
60462
|
+
var GroupActiveSchema = object({
|
|
60463
|
+
active: boolean().meta({ label: "Active" }),
|
|
60464
|
+
/** Ms epoch when the slice was last updated. */
|
|
60465
|
+
lastChangedAt: number()
|
|
60466
|
+
});
|
|
60467
|
+
var groupActiveCapability = {
|
|
60468
|
+
name: "group-active",
|
|
60469
|
+
scope: "device",
|
|
60470
|
+
deviceNative: true,
|
|
60471
|
+
mode: "singleton",
|
|
60472
|
+
deviceTypes: [
|
|
60473
|
+
DeviceType.Cover,
|
|
60474
|
+
DeviceType.Valve,
|
|
60475
|
+
DeviceType.Lock,
|
|
60476
|
+
DeviceType.MediaPlayer,
|
|
60477
|
+
DeviceType.Climate,
|
|
60478
|
+
DeviceType.Thermostat
|
|
60479
|
+
],
|
|
60480
|
+
methods: {},
|
|
60481
|
+
status: {
|
|
60482
|
+
schema: GroupActiveSchema,
|
|
60483
|
+
kind: "push"
|
|
60484
|
+
},
|
|
60485
|
+
runtimeState: GroupActiveSchema,
|
|
60486
|
+
/**
|
|
60487
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
60488
|
+
* next source event; a restored value would outlive the members it named.
|
|
60489
|
+
*
|
|
60490
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60491
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60492
|
+
*/
|
|
60493
|
+
durability: "session",
|
|
60494
|
+
history: "none"
|
|
60495
|
+
};
|
|
60496
|
+
/**
|
|
60497
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60498
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60499
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60500
|
+
* series that later statistics read is the output cap's own history block.
|
|
60501
|
+
*/
|
|
60502
|
+
var GroupStatusSchema = object({
|
|
60503
|
+
/** Members whose current value entered the aggregate. */
|
|
60504
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60505
|
+
precision: 0,
|
|
60506
|
+
label: "Reporting"
|
|
60507
|
+
})),
|
|
60508
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60509
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60510
|
+
precision: 0,
|
|
60511
|
+
label: "Excluded"
|
|
60512
|
+
})),
|
|
60513
|
+
/** `included` + `excluded`. */
|
|
60514
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60515
|
+
precision: 0,
|
|
60516
|
+
label: "Members"
|
|
60517
|
+
}))
|
|
60518
|
+
});
|
|
60519
|
+
var groupStatusCapability = {
|
|
60520
|
+
name: "group-status",
|
|
60521
|
+
scope: "device",
|
|
60522
|
+
deviceNative: true,
|
|
60523
|
+
mode: "singleton",
|
|
60524
|
+
deviceTypes: [
|
|
60525
|
+
DeviceType.Sensor,
|
|
60526
|
+
DeviceType.Switch,
|
|
60527
|
+
DeviceType.Light,
|
|
60528
|
+
DeviceType.Fan,
|
|
60529
|
+
DeviceType.Cover,
|
|
60530
|
+
DeviceType.Valve,
|
|
60531
|
+
DeviceType.Lock,
|
|
60532
|
+
DeviceType.MediaPlayer,
|
|
60533
|
+
DeviceType.Thermostat,
|
|
60534
|
+
DeviceType.Climate
|
|
60535
|
+
],
|
|
60536
|
+
methods: {},
|
|
60537
|
+
status: {
|
|
60538
|
+
schema: GroupStatusSchema,
|
|
60539
|
+
kind: "push"
|
|
60540
|
+
},
|
|
60541
|
+
runtimeState: GroupStatusSchema,
|
|
60542
|
+
/**
|
|
60543
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60544
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60545
|
+
*
|
|
60546
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60547
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60548
|
+
*/
|
|
60549
|
+
durability: "session",
|
|
60550
|
+
history: "none"
|
|
60551
|
+
};
|
|
59695
60552
|
var HeatingValveStatusSchema = object({
|
|
59696
60553
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59697
|
-
position: number().min(0).max(100).nullable(),
|
|
60554
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59698
60555
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59699
60556
|
lastFetchedAt: number()
|
|
59700
60557
|
});
|
|
@@ -59737,9 +60594,9 @@ var HumidifierStatusSchema = object({
|
|
|
59737
60594
|
/** Whether the humidifier is currently on. */
|
|
59738
60595
|
on: boolean(),
|
|
59739
60596
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59740
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60597
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59741
60598
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59742
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60599
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59743
60600
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59744
60601
|
* device has no mode surface. */
|
|
59745
60602
|
mode: string().nullable(),
|
|
@@ -59749,9 +60606,9 @@ var HumidifierStatusSchema = object({
|
|
|
59749
60606
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59750
60607
|
action: string().nullable(),
|
|
59751
60608
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59752
|
-
minHumidity: number().nullable(),
|
|
60609
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59753
60610
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59754
|
-
maxHumidity: number().nullable(),
|
|
60611
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59755
60612
|
/** Ms epoch when the slice was last updated. */
|
|
59756
60613
|
lastChangedAt: number()
|
|
59757
60614
|
});
|
|
@@ -59821,22 +60678,13 @@ var humidifierCapability = {
|
|
|
59821
60678
|
* `sourceInfo`.
|
|
59822
60679
|
*/
|
|
59823
60680
|
var HumiditySensorStatusSchema = object({
|
|
59824
|
-
/** Current relative humidity, 0..100. */
|
|
59825
|
-
percent: number().min(0).max(100).meta({
|
|
59826
|
-
|
|
60681
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60682
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60683
|
+
precision: 0,
|
|
59827
60684
|
label: "Humidity"
|
|
59828
|
-
}),
|
|
60685
|
+
})),
|
|
59829
60686
|
/** Ms epoch when the slice was last updated. */
|
|
59830
|
-
lastFetchedAt: number()
|
|
59831
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59832
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59833
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59834
|
-
unit: string().optional(),
|
|
59835
|
-
/** Suggested decimal places for numeric display.
|
|
59836
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59837
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59838
|
-
* auto-formatting when absent. */
|
|
59839
|
-
precision: number().int().min(0).max(10).optional()
|
|
60687
|
+
lastFetchedAt: number()
|
|
59840
60688
|
});
|
|
59841
60689
|
var humiditySensorCapability = {
|
|
59842
60690
|
name: "humidity-sensor",
|
|
@@ -59867,12 +60715,7 @@ var humiditySensorCapability = {
|
|
|
59867
60715
|
} } },
|
|
59868
60716
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59869
60717
|
* whether persisting is worth a SQLite commit. */
|
|
59870
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
59871
|
-
customize: {
|
|
59872
|
-
version: 1,
|
|
59873
|
-
advanced: "derive",
|
|
59874
|
-
targets: []
|
|
59875
|
-
}
|
|
60718
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
59876
60719
|
};
|
|
59877
60720
|
/**
|
|
59878
60721
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -59893,7 +60736,7 @@ var ImageStatusSchema = object({
|
|
|
59893
60736
|
* entity exposes no `entity_picture` (yet). */
|
|
59894
60737
|
url: string().nullable(),
|
|
59895
60738
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
59896
|
-
lastUpdated: number().nullable()
|
|
60739
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
59897
60740
|
});
|
|
59898
60741
|
var imageCapability = {
|
|
59899
60742
|
name: "image",
|
|
@@ -59981,19 +60824,19 @@ var NormalizedRangeSchema = object({
|
|
|
59981
60824
|
*/
|
|
59982
60825
|
var ImageSettingsStatusSchema = object({
|
|
59983
60826
|
/** Normalized 0–100. */
|
|
59984
|
-
brightness: number().optional(),
|
|
60827
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
59985
60828
|
/** Normalized 0–100. */
|
|
59986
|
-
contrast: number().optional(),
|
|
60829
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
59987
60830
|
/** Normalized 0–100. */
|
|
59988
|
-
saturation: number().optional(),
|
|
60831
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
59989
60832
|
/** Normalized 0–100. */
|
|
59990
|
-
sharpness: number().optional(),
|
|
60833
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
59991
60834
|
mirror: boolean().optional(),
|
|
59992
60835
|
flip: boolean().optional(),
|
|
59993
60836
|
rotate: ImageRotateSchema.optional(),
|
|
59994
60837
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
59995
60838
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
59996
|
-
warmth: number().optional(),
|
|
60839
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
59997
60840
|
exposureMode: ExposureModeSchema.optional(),
|
|
59998
60841
|
backlightMode: BacklightModeSchema.optional(),
|
|
59999
60842
|
lastFetchedAt: number()
|
|
@@ -60272,10 +61115,10 @@ var IntercomAbilitySchema = object({
|
|
|
60272
61115
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60273
61116
|
codecs: array(string()),
|
|
60274
61117
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60275
|
-
sampleRate: number(),
|
|
61118
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60276
61119
|
duplex: _enum(["half", "full"]),
|
|
60277
61120
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60278
|
-
maxBacklogMs: number()
|
|
61121
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60279
61122
|
});
|
|
60280
61123
|
var IntercomStatusSchema = object({
|
|
60281
61124
|
/** True while a talk session is open. */
|
|
@@ -60502,13 +61345,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60502
61345
|
activity: LawnMowerActivitySchema,
|
|
60503
61346
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60504
61347
|
* reading. */
|
|
60505
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61348
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60506
61349
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60507
61350
|
* task is active / progress is unavailable. */
|
|
60508
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61351
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60509
61352
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60510
61353
|
* or null when unknown. */
|
|
60511
|
-
currentCode: number().nullable(),
|
|
61354
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60512
61355
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60513
61356
|
currentCodeLabel: string().nullable(),
|
|
60514
61357
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -60961,7 +61804,14 @@ var lockControlCapability = {
|
|
|
60961
61804
|
}),
|
|
60962
61805
|
unlock: method(object({
|
|
60963
61806
|
deviceId: number().int().nonnegative(),
|
|
60964
|
-
code: string().min(1).optional()
|
|
61807
|
+
code: string().min(1).optional(),
|
|
61808
|
+
/**
|
|
61809
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
61810
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
61811
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
61812
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
61813
|
+
*/
|
|
61814
|
+
confirm: boolean().optional()
|
|
60965
61815
|
}), _void(), {
|
|
60966
61816
|
kind: "mutation",
|
|
60967
61817
|
auth: "protected"
|
|
@@ -60998,6 +61848,44 @@ var lockControlCapability = {
|
|
|
60998
61848
|
volatileStateFields: ["lastChangedAt"]
|
|
60999
61849
|
};
|
|
61000
61850
|
/**
|
|
61851
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
61852
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
61853
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
61854
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
61855
|
+
*/
|
|
61856
|
+
var MeterStatusSchema = object({
|
|
61857
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
61858
|
+
lastFetchedAt: number()
|
|
61859
|
+
});
|
|
61860
|
+
var meterCapability = {
|
|
61861
|
+
name: "meter",
|
|
61862
|
+
scope: "device",
|
|
61863
|
+
deviceNative: true,
|
|
61864
|
+
mode: "singleton",
|
|
61865
|
+
deviceTypes: [DeviceType.Sensor],
|
|
61866
|
+
methods: {},
|
|
61867
|
+
status: {
|
|
61868
|
+
schema: MeterStatusSchema,
|
|
61869
|
+
kind: "push"
|
|
61870
|
+
},
|
|
61871
|
+
runtimeState: MeterStatusSchema,
|
|
61872
|
+
/**
|
|
61873
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
61874
|
+
* history integral. A restart shows it only until the history pass
|
|
61875
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
61876
|
+
*
|
|
61877
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61878
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61879
|
+
*/
|
|
61880
|
+
durability: "restored",
|
|
61881
|
+
history: { fields: { value: {
|
|
61882
|
+
kind: "counter",
|
|
61883
|
+
deadband: .001,
|
|
61884
|
+
minIntervalMs: 6e4
|
|
61885
|
+
} } },
|
|
61886
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
61887
|
+
};
|
|
61888
|
+
/**
|
|
61001
61889
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61002
61890
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61003
61891
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -61041,7 +61929,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61041
61929
|
state: MediaPlayerStateSchema,
|
|
61042
61930
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61043
61931
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61044
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
61932
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61045
61933
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61046
61934
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61047
61935
|
isMuted: boolean().nullable(),
|
|
@@ -61054,10 +61942,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61054
61942
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61055
61943
|
/** Current playback position in ms. Null when not seekable or
|
|
61056
61944
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61057
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
61945
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61058
61946
|
/** Total duration of the current media in ms. Null when unknown
|
|
61059
61947
|
* (live stream) or nothing is playing. */
|
|
61060
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
61948
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61061
61949
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61062
61950
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61063
61951
|
shuffle: boolean().nullable(),
|
|
@@ -61366,7 +62254,7 @@ var motionCustomize = {
|
|
|
61366
62254
|
eventName: "onMotionChanged"
|
|
61367
62255
|
},
|
|
61368
62256
|
deviceTypes: [DeviceType.Camera],
|
|
61369
|
-
apply: "
|
|
62257
|
+
apply: "add",
|
|
61370
62258
|
applyAuthority: {
|
|
61371
62259
|
kind: "camera-sensors",
|
|
61372
62260
|
timeoutField: "motionCooldownMs"
|
|
@@ -61438,7 +62326,7 @@ var MotionStatusSchema = object({
|
|
|
61438
62326
|
* it, every provider seeded it at boot, and every session left it
|
|
61439
62327
|
* `detected: true` after its detach.
|
|
61440
62328
|
*/
|
|
61441
|
-
autoClearAfterMs: number().nullable()
|
|
62329
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61442
62330
|
});
|
|
61443
62331
|
/**
|
|
61444
62332
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61475,12 +62363,18 @@ var motionCapability = {
|
|
|
61475
62363
|
methods: {
|
|
61476
62364
|
/**
|
|
61477
62365
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
61478
|
-
* for consumers that don't need the full status object
|
|
61479
|
-
*
|
|
61480
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
61481
|
-
* consumer.
|
|
62366
|
+
* for consumers that don't need the full status object. A composed
|
|
62367
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
61482
62368
|
*/
|
|
61483
62369
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62370
|
+
/**
|
|
62371
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62372
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62373
|
+
*/
|
|
62374
|
+
composedMethods: { isDetected: {
|
|
62375
|
+
kind: "slice",
|
|
62376
|
+
field: "detected"
|
|
62377
|
+
} },
|
|
61484
62378
|
events: {
|
|
61485
62379
|
/**
|
|
61486
62380
|
* Fires every time the runner transitions a camera between
|
|
@@ -61620,7 +62514,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61620
62514
|
* the grid region(s). */
|
|
61621
62515
|
var MotionZoneStatusSchema = object({
|
|
61622
62516
|
enabled: boolean(),
|
|
61623
|
-
sensitivity: number(),
|
|
62517
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61624
62518
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61625
62519
|
regions: array(MotionZoneRegionSchema),
|
|
61626
62520
|
lastFetchedAt: number()
|
|
@@ -61990,7 +62884,7 @@ var NavigationStatusSchema = object({
|
|
|
61990
62884
|
following: boolean(),
|
|
61991
62885
|
flash: boolean(),
|
|
61992
62886
|
lightMode: NavigationLightModeSchema,
|
|
61993
|
-
lightLevel: number().min(40).max(100),
|
|
62887
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
61994
62888
|
/** Ms epoch when the slice was last updated. */
|
|
61995
62889
|
lastChangedAt: number()
|
|
61996
62890
|
});
|
|
@@ -62124,13 +63018,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62124
63018
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62125
63019
|
* SKIP a null rather than coerce it.
|
|
62126
63020
|
*/
|
|
62127
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63021
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62128
63022
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62129
|
-
rssiDbm: number().optional(),
|
|
63023
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62130
63024
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62131
63025
|
ssid: string().optional(),
|
|
62132
63026
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62133
|
-
lastUpdated: number()
|
|
63027
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62134
63028
|
});
|
|
62135
63029
|
var networkLinkCapability = {
|
|
62136
63030
|
name: "network-link",
|
|
@@ -62515,7 +63409,7 @@ var NotifierStatusSchema = object({
|
|
|
62515
63409
|
lastError: string().nullable(),
|
|
62516
63410
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62517
63411
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62518
|
-
queueDepth: number().int().nonnegative(),
|
|
63412
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62519
63413
|
/** Per-feature capability matrix — authoritative source for the
|
|
62520
63414
|
* compose-form field gating. */
|
|
62521
63415
|
supports: NotifierSupportsSchema
|
|
@@ -62607,11 +63501,9 @@ onSent: { data: object({
|
|
|
62607
63501
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62608
63502
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62609
63503
|
*
|
|
62610
|
-
* The
|
|
62611
|
-
*
|
|
62612
|
-
*
|
|
62613
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62614
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63504
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63505
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63506
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62615
63507
|
*
|
|
62616
63508
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62617
63509
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62620,15 +63512,8 @@ onSent: { data: object({
|
|
|
62620
63512
|
* numeric values land here.
|
|
62621
63513
|
*/
|
|
62622
63514
|
var NumericSensorStatusSchema = object({
|
|
62623
|
-
|
|
62624
|
-
|
|
62625
|
-
* Populated live from the upstream source on each state push.
|
|
62626
|
-
* Absent for unitless sensors. */
|
|
62627
|
-
unit: string().optional(),
|
|
62628
|
-
/** Suggested decimal places for numeric display.
|
|
62629
|
-
* Populated live from the upstream source when provided.
|
|
62630
|
-
* Falls back to auto-formatting when absent. */
|
|
62631
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63515
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63516
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62632
63517
|
/** Ms epoch when the slice was last updated. */
|
|
62633
63518
|
lastFetchedAt: number()
|
|
62634
63519
|
});
|
|
@@ -62652,11 +63537,11 @@ var numericSensorCapability = {
|
|
|
62652
63537
|
*/
|
|
62653
63538
|
durability: "restored",
|
|
62654
63539
|
/**
|
|
62655
|
-
* History (D850): recorded series. The unit is
|
|
63540
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63541
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62656
63542
|
*/
|
|
62657
63543
|
history: { fields: { value: {
|
|
62658
63544
|
kind: "gauge",
|
|
62659
|
-
unitFrom: "unit",
|
|
62660
63545
|
minIntervalMs: 3e4
|
|
62661
63546
|
} } },
|
|
62662
63547
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -62948,23 +63833,26 @@ var PetFeederStatusSchema = object({
|
|
|
62948
63833
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
62949
63834
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
62950
63835
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
62951
|
-
foodLevel: number().nullable(),
|
|
63836
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62952
63837
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
62953
63838
|
* single-hopper models. */
|
|
62954
|
-
food1: number().nullable(),
|
|
63839
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
62955
63840
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
62956
63841
|
* single-hopper models. */
|
|
62957
|
-
food2: number().nullable(),
|
|
63842
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
62958
63843
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
62959
63844
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
62960
63845
|
* below the feeder's low threshold. */
|
|
62961
63846
|
lowFood: boolean(),
|
|
62962
63847
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
62963
63848
|
* device has no battery reading. */
|
|
62964
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
62965
|
-
/**
|
|
62966
|
-
*
|
|
62967
|
-
|
|
63849
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63850
|
+
/**
|
|
63851
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
63852
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
63853
|
+
* model has no desiccant sensor.
|
|
63854
|
+
*/
|
|
63855
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
62968
63856
|
/** True while a feed is in progress. */
|
|
62969
63857
|
feeding: boolean(),
|
|
62970
63858
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -62975,7 +63863,7 @@ var PetFeederStatusSchema = object({
|
|
|
62975
63863
|
* with `errorCode` for consumers that want the raw integer. */
|
|
62976
63864
|
error: string().nullable(),
|
|
62977
63865
|
/** Raw device error code (0 / null = no error). */
|
|
62978
|
-
errorCode: number().nullable(),
|
|
63866
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
62979
63867
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
62980
63868
|
isDualHopper: boolean(),
|
|
62981
63869
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -62985,7 +63873,7 @@ var PetFeederStatusSchema = object({
|
|
|
62985
63873
|
/** Play a chime when dispensing. */
|
|
62986
63874
|
feedSound: boolean(),
|
|
62987
63875
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
62988
|
-
volume: number(),
|
|
63876
|
+
volume: number().meta(readingMeta("none")),
|
|
62989
63877
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
62990
63878
|
lastFetchedAt: number()
|
|
62991
63879
|
});
|
|
@@ -63104,7 +63992,7 @@ var petFeederCapability = {
|
|
|
63104
63992
|
},
|
|
63105
63993
|
desiccantLeftDays: {
|
|
63106
63994
|
kind: "gauge",
|
|
63107
|
-
unit: "
|
|
63995
|
+
unit: "s"
|
|
63108
63996
|
}
|
|
63109
63997
|
} }
|
|
63110
63998
|
};
|
|
@@ -63505,43 +64393,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63505
64393
|
*/
|
|
63506
64394
|
var PowerMeterStatusSchema = object({
|
|
63507
64395
|
/** Instantaneous power draw in watts. */
|
|
63508
|
-
watts: number().optional().meta({
|
|
63509
|
-
unit: "W",
|
|
63510
|
-
label: "Power"
|
|
63511
|
-
}),
|
|
64396
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63512
64397
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63513
|
-
kwhTotal: number().optional().meta({
|
|
63514
|
-
unit: "kWh",
|
|
63515
|
-
label: "Energy"
|
|
63516
|
-
}),
|
|
64398
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63517
64399
|
/** Voltage in volts. */
|
|
63518
|
-
volts: number().optional(),
|
|
64400
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
63519
64401
|
/** Current in amperes. */
|
|
63520
|
-
amps: number().optional(),
|
|
63521
|
-
/** Apparent power in volt-amperes
|
|
63522
|
-
va: number().optional(),
|
|
64402
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
64403
|
+
/** Apparent power in volt-amperes. */
|
|
64404
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63523
64405
|
/** Power factor (0..1) if reported. */
|
|
63524
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
64406
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63525
64407
|
/** Ms epoch when the slice was last updated. */
|
|
63526
|
-
lastFetchedAt: number()
|
|
63527
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63528
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63529
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63530
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63531
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63532
|
-
unit: string().optional(),
|
|
63533
|
-
/** Suggested decimal places for numeric display.
|
|
63534
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63535
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63536
|
-
* auto-formatting when absent. */
|
|
63537
|
-
precision: number().int().min(0).max(10).optional()
|
|
64408
|
+
lastFetchedAt: number()
|
|
63538
64409
|
});
|
|
64410
|
+
/**
|
|
64411
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
64412
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
64413
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
64414
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
64415
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
64416
|
+
*/
|
|
64417
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
64418
|
+
DeviceType.Sensor,
|
|
64419
|
+
DeviceType.Switch,
|
|
64420
|
+
DeviceType.Light,
|
|
64421
|
+
DeviceType.Fan,
|
|
64422
|
+
DeviceType.Climate,
|
|
64423
|
+
DeviceType.Thermostat,
|
|
64424
|
+
DeviceType.Humidifier,
|
|
64425
|
+
DeviceType.WaterHeater,
|
|
64426
|
+
DeviceType.MediaPlayer,
|
|
64427
|
+
DeviceType.Washer,
|
|
64428
|
+
DeviceType.Dryer,
|
|
64429
|
+
DeviceType.Dishwasher,
|
|
64430
|
+
DeviceType.Vacuum,
|
|
64431
|
+
DeviceType.LawnMower,
|
|
64432
|
+
DeviceType.PetFeeder
|
|
64433
|
+
];
|
|
64434
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
64435
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
64436
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
64437
|
+
function powerTarget(id, unit) {
|
|
64438
|
+
return {
|
|
64439
|
+
id,
|
|
64440
|
+
cardinality: "scalar",
|
|
64441
|
+
vocabulary: {
|
|
64442
|
+
cap: "power-meter",
|
|
64443
|
+
stateField: id
|
|
64444
|
+
},
|
|
64445
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
64446
|
+
apply: "add",
|
|
64447
|
+
path: id,
|
|
64448
|
+
sources: [{
|
|
64449
|
+
kind: "numeric",
|
|
64450
|
+
requiredUnit: unit,
|
|
64451
|
+
transforms: [{ kind: "identity" }]
|
|
64452
|
+
}],
|
|
64453
|
+
companions: [{
|
|
64454
|
+
kind: "clock",
|
|
64455
|
+
path: "lastFetchedAt",
|
|
64456
|
+
when: "always"
|
|
64457
|
+
}],
|
|
64458
|
+
sourceReport: { status: "assignment-status" },
|
|
64459
|
+
advancedExpression: true
|
|
64460
|
+
};
|
|
64461
|
+
}
|
|
64462
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
64463
|
+
var powerMeterCustomize = {
|
|
64464
|
+
version: 1,
|
|
64465
|
+
targets: [
|
|
64466
|
+
powerTarget("watts", "W"),
|
|
64467
|
+
powerTarget("kwhTotal", "kWh"),
|
|
64468
|
+
powerTarget("volts", "V"),
|
|
64469
|
+
powerTarget("amps", "A")
|
|
64470
|
+
]
|
|
64471
|
+
};
|
|
63539
64472
|
var powerMeterCapability = {
|
|
63540
64473
|
name: "power-meter",
|
|
63541
64474
|
scope: "device",
|
|
63542
64475
|
deviceNative: true,
|
|
63543
64476
|
mode: "singleton",
|
|
63544
|
-
deviceTypes:
|
|
64477
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
63545
64478
|
methods: {},
|
|
63546
64479
|
status: {
|
|
63547
64480
|
schema: PowerMeterStatusSchema,
|
|
@@ -63599,11 +64532,7 @@ var powerMeterCapability = {
|
|
|
63599
64532
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63600
64533
|
* whether persisting is worth a SQLite commit. */
|
|
63601
64534
|
volatileStateFields: ["lastFetchedAt"],
|
|
63602
|
-
customize:
|
|
63603
|
-
version: 1,
|
|
63604
|
-
advanced: "derive",
|
|
63605
|
-
targets: []
|
|
63606
|
-
}
|
|
64535
|
+
customize: powerMeterCustomize
|
|
63607
64536
|
};
|
|
63608
64537
|
/**
|
|
63609
64538
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63623,11 +64552,11 @@ var powerMeterCapability = {
|
|
|
63623
64552
|
*/
|
|
63624
64553
|
var GpsLocationSchema = object({
|
|
63625
64554
|
/** Latitude in decimal degrees, -90..90. */
|
|
63626
|
-
latitude: number().min(-90).max(90),
|
|
64555
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63627
64556
|
/** Longitude in decimal degrees, -180..180. */
|
|
63628
|
-
longitude: number().min(-180).max(180),
|
|
64557
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63629
64558
|
/** Reported accuracy in meters (lower = better). */
|
|
63630
|
-
accuracyMeters: number().nonnegative()
|
|
64559
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63631
64560
|
});
|
|
63632
64561
|
var PresenceStatusSchema = object({
|
|
63633
64562
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63639,7 +64568,7 @@ var PresenceStatusSchema = object({
|
|
|
63639
64568
|
gps: GpsLocationSchema.nullable(),
|
|
63640
64569
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63641
64570
|
* when not reported. */
|
|
63642
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64571
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63643
64572
|
/** Ms epoch when the slice was last updated. */
|
|
63644
64573
|
lastChangedAt: number()
|
|
63645
64574
|
});
|
|
@@ -63689,19 +64618,10 @@ var presenceCapability = {
|
|
|
63689
64618
|
* `sourceInfo`.
|
|
63690
64619
|
*/
|
|
63691
64620
|
var PressureSensorStatusSchema = object({
|
|
63692
|
-
/** Current pressure in hPa. */
|
|
63693
|
-
hpa: number(),
|
|
64621
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64622
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63694
64623
|
/** Ms epoch when the slice was last updated. */
|
|
63695
|
-
lastFetchedAt: number()
|
|
63696
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63697
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63698
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63699
|
-
unit: string().optional(),
|
|
63700
|
-
/** Suggested decimal places for numeric display.
|
|
63701
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63702
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63703
|
-
* auto-formatting when absent. */
|
|
63704
|
-
precision: number().int().min(0).max(10).optional()
|
|
64624
|
+
lastFetchedAt: number()
|
|
63705
64625
|
});
|
|
63706
64626
|
var pressureSensorCapability = {
|
|
63707
64627
|
name: "pressure-sensor",
|
|
@@ -64115,8 +65035,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64115
65035
|
}), _void(), { kind: "mutation" });
|
|
64116
65036
|
var PtzAutotrackSettingsSchema = object({
|
|
64117
65037
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64118
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64119
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65038
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65039
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64120
65040
|
});
|
|
64121
65041
|
/**
|
|
64122
65042
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64270,7 +65190,7 @@ var RunningStateStatusSchema = object({
|
|
|
64270
65190
|
/** null = unknown — never coerced to false (D393). */
|
|
64271
65191
|
running: boolean().nullable(),
|
|
64272
65192
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64273
|
-
since: number().nullable(),
|
|
65193
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64274
65194
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64275
65195
|
phase: string().nullable(),
|
|
64276
65196
|
/** null until a reading has been published (D393). */
|
|
@@ -64285,7 +65205,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64285
65205
|
/** Generic Customize target for the running boolean (D936). */
|
|
64286
65206
|
var runningCustomize = {
|
|
64287
65207
|
version: 1,
|
|
64288
|
-
advanced: "derive",
|
|
64289
65208
|
targets: [{
|
|
64290
65209
|
id: "running",
|
|
64291
65210
|
cardinality: "scalar",
|
|
@@ -64294,6 +65213,8 @@ var runningCustomize = {
|
|
|
64294
65213
|
stateField: "running"
|
|
64295
65214
|
},
|
|
64296
65215
|
deviceTypes: [
|
|
65216
|
+
DeviceType.Washer,
|
|
65217
|
+
DeviceType.Dryer,
|
|
64297
65218
|
DeviceType.Dishwasher,
|
|
64298
65219
|
DeviceType.Vacuum,
|
|
64299
65220
|
DeviceType.LawnMower,
|
|
@@ -64305,7 +65226,7 @@ var runningCustomize = {
|
|
|
64305
65226
|
DeviceType.Thermostat,
|
|
64306
65227
|
DeviceType.PetFeeder
|
|
64307
65228
|
],
|
|
64308
|
-
apply: "add
|
|
65229
|
+
apply: "add",
|
|
64309
65230
|
path: "running",
|
|
64310
65231
|
sources: [
|
|
64311
65232
|
{
|
|
@@ -65569,9 +66490,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65569
66490
|
*/
|
|
65570
66491
|
var RecordWindowSchema = object({
|
|
65571
66492
|
trigger: RecordTriggerSchema,
|
|
65572
|
-
day: number().int().min(0).max(6),
|
|
65573
|
-
startMinute: number().int().min(0).max(1439),
|
|
65574
|
-
endMinute: number().int().min(1).max(1440)
|
|
66493
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
66494
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
66495
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65575
66496
|
});
|
|
65576
66497
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65577
66498
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65647,10 +66568,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65647
66568
|
/** Master "record to the card at all" switch. */
|
|
65648
66569
|
enabled: boolean().nullable(),
|
|
65649
66570
|
overwriteWhenFull: boolean().nullable(),
|
|
65650
|
-
preRecordSec: number().nullable(),
|
|
65651
|
-
postRecordSec: number().nullable(),
|
|
66571
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66572
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65652
66573
|
/** Length of one recorded file, in minutes. */
|
|
65653
|
-
segmentMinutes: number().nullable(),
|
|
66574
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65654
66575
|
/** The primary track's weekly windows, flattened. */
|
|
65655
66576
|
windows: array(RecordWindowSchema),
|
|
65656
66577
|
/**
|
|
@@ -65666,7 +66587,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65666
66587
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65667
66588
|
* writable.
|
|
65668
66589
|
*/
|
|
65669
|
-
unreadableWindows: number(),
|
|
66590
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65670
66591
|
/**
|
|
65671
66592
|
* The camera is scheduled to record and has NO usable storage.
|
|
65672
66593
|
*
|
|
@@ -66511,7 +67432,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66511
67432
|
url: string().optional(),
|
|
66512
67433
|
codec: string().optional(),
|
|
66513
67434
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66514
|
-
fps: number().positive().optional(),
|
|
67435
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66515
67436
|
label: string().optional(),
|
|
66516
67437
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66517
67438
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66598,18 +67519,18 @@ var StreamProfileSchema = _enum([
|
|
|
66598
67519
|
]);
|
|
66599
67520
|
/** The current encoding config of one stream profile. */
|
|
66600
67521
|
var StreamProfileConfigSchema = object({
|
|
66601
|
-
width: number(),
|
|
66602
|
-
height: number(),
|
|
67522
|
+
width: number().meta(readingMeta("none")),
|
|
67523
|
+
height: number().meta(readingMeta("none")),
|
|
66603
67524
|
codec: _enum(["h264", "h265"]),
|
|
66604
|
-
framerate: number(),
|
|
66605
|
-
bitrate: number(),
|
|
67525
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67526
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66606
67527
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66607
67528
|
encoderProfile: _enum([
|
|
66608
67529
|
"high",
|
|
66609
67530
|
"main",
|
|
66610
67531
|
"baseline"
|
|
66611
67532
|
]).optional(),
|
|
66612
|
-
gop: number().optional(),
|
|
67533
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66613
67534
|
/**
|
|
66614
67535
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66615
67536
|
*
|
|
@@ -66783,7 +67704,8 @@ var switchCapability = {
|
|
|
66783
67704
|
deviceTypes: [
|
|
66784
67705
|
DeviceType.Switch,
|
|
66785
67706
|
DeviceType.Siren,
|
|
66786
|
-
DeviceType.Light
|
|
67707
|
+
DeviceType.Light,
|
|
67708
|
+
DeviceType.Fan
|
|
66787
67709
|
],
|
|
66788
67710
|
methods: { setState: method(object({
|
|
66789
67711
|
deviceId: number(),
|
|
@@ -66830,12 +67752,7 @@ var switchCapability = {
|
|
|
66830
67752
|
label: "On",
|
|
66831
67753
|
kind: "boolean"
|
|
66832
67754
|
}
|
|
66833
|
-
}] }
|
|
66834
|
-
customize: {
|
|
66835
|
-
version: 1,
|
|
66836
|
-
advanced: "derive",
|
|
66837
|
-
targets: []
|
|
66838
|
-
}
|
|
67755
|
+
}] }
|
|
66839
67756
|
};
|
|
66840
67757
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66841
67758
|
function hasControlCharacter(value) {
|
|
@@ -67418,35 +68335,21 @@ var tamperCapability = {
|
|
|
67418
68335
|
* entries with `device_class: temperature` and any future native
|
|
67419
68336
|
* thermometer.
|
|
67420
68337
|
*
|
|
67421
|
-
*
|
|
67422
|
-
*
|
|
67423
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67424
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67425
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67426
|
-
* `sourceInfo`.
|
|
68338
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
68339
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67427
68340
|
*
|
|
67428
68341
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67429
68342
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67430
68343
|
* changed" steady state.
|
|
67431
68344
|
*/
|
|
67432
68345
|
var TemperatureSensorStatusSchema = object({
|
|
67433
|
-
/** Current temperature in Celsius. */
|
|
67434
|
-
celsius: number().meta({
|
|
67435
|
-
|
|
68346
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68347
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
68348
|
+
precision: 1,
|
|
67436
68349
|
label: "Temperature"
|
|
67437
|
-
}),
|
|
68350
|
+
})),
|
|
67438
68351
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67439
|
-
lastFetchedAt: number()
|
|
67440
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67441
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67442
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67443
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67444
|
-
unit: string().optional(),
|
|
67445
|
-
/** Suggested decimal places for numeric display.
|
|
67446
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67447
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67448
|
-
* auto-formatting when absent. */
|
|
67449
|
-
precision: number().int().min(0).max(10).optional()
|
|
68352
|
+
lastFetchedAt: number()
|
|
67450
68353
|
});
|
|
67451
68354
|
var temperatureSensorCapability = {
|
|
67452
68355
|
name: "temperature-sensor",
|
|
@@ -67477,12 +68380,7 @@ var temperatureSensorCapability = {
|
|
|
67477
68380
|
} } },
|
|
67478
68381
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67479
68382
|
* whether persisting is worth a SQLite commit. */
|
|
67480
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67481
|
-
customize: {
|
|
67482
|
-
version: 1,
|
|
67483
|
-
advanced: "derive",
|
|
67484
|
-
targets: []
|
|
67485
|
-
}
|
|
68383
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67486
68384
|
};
|
|
67487
68385
|
/**
|
|
67488
68386
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67765,16 +68663,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67765
68663
|
]),
|
|
67766
68664
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67767
68665
|
* reading. */
|
|
67768
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68666
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67769
68667
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67770
68668
|
* the vacuum has no speed control. */
|
|
67771
68669
|
fanSpeed: string().nullable(),
|
|
67772
68670
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67773
68671
|
availableFanSpeeds: array(string()),
|
|
67774
68672
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67775
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68673
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67776
68674
|
/** Current error code (0 / null = no error). */
|
|
67777
|
-
errorCode: number().nullable(),
|
|
68675
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67778
68676
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67779
68677
|
errorLabel: string().nullable(),
|
|
67780
68678
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67852,7 +68750,7 @@ var ValveStatusSchema = object({
|
|
|
67852
68750
|
]),
|
|
67853
68751
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
67854
68752
|
* intermediate position surface. */
|
|
67855
|
-
position: number().min(0).max(100).nullable(),
|
|
68753
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67856
68754
|
/** Ms epoch when the slice was last updated. */
|
|
67857
68755
|
lastChangedAt: number()
|
|
67858
68756
|
});
|
|
@@ -67960,9 +68858,9 @@ var vibrationCapability = {
|
|
|
67960
68858
|
*/
|
|
67961
68859
|
var WaterHeaterStatusSchema = object({
|
|
67962
68860
|
/** Current measured temperature. Null when not reported. */
|
|
67963
|
-
currentTemp: number().nullable(),
|
|
68861
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67964
68862
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
67965
|
-
targetTemp: number().nullable(),
|
|
68863
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67966
68864
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
67967
68865
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
67968
68866
|
* device reports an unknown state. */
|
|
@@ -67973,9 +68871,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
67973
68871
|
* has no away surface. */
|
|
67974
68872
|
away: boolean().nullable(),
|
|
67975
68873
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
67976
|
-
minTemp: number().nullable(),
|
|
68874
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67977
68875
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
67978
|
-
maxTemp: number().nullable(),
|
|
68876
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67979
68877
|
/** Ms epoch when the slice was last updated. */
|
|
67980
68878
|
lastChangedAt: number()
|
|
67981
68879
|
});
|
|
@@ -68060,25 +68958,18 @@ var waterHeaterCapability = {
|
|
|
68060
68958
|
* Forecast deferred — current conditions only for v1.
|
|
68061
68959
|
*/
|
|
68062
68960
|
var WeatherStatusSchema = object({
|
|
68063
|
-
/** Verbatim
|
|
68064
|
-
* when no condition has been reported yet. */
|
|
68961
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68065
68962
|
condition: string().nullable(),
|
|
68066
|
-
/** Current temperature in
|
|
68067
|
-
temperature: number().nullable(),
|
|
68068
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68069
|
-
temperatureUnit: string().nullable(),
|
|
68963
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
68964
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68070
68965
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68071
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68072
|
-
/** Barometric pressure in
|
|
68073
|
-
pressure: number().nullable(),
|
|
68074
|
-
/**
|
|
68075
|
-
|
|
68076
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68077
|
-
windSpeed: number().nullable(),
|
|
68078
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68079
|
-
windSpeedUnit: string().nullable(),
|
|
68966
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
68967
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
68968
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
68969
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
68970
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68080
68971
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68081
|
-
windBearing: number().nullable(),
|
|
68972
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68082
68973
|
/** Ms epoch when the slice was last updated. */
|
|
68083
68974
|
lastFetchedAt: number()
|
|
68084
68975
|
});
|
|
@@ -68106,12 +68997,12 @@ var weatherCapability = {
|
|
|
68106
68997
|
*/
|
|
68107
68998
|
durability: "session",
|
|
68108
68999
|
/**
|
|
68109
|
-
* History (D850): recorded series.
|
|
69000
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68110
69001
|
*/
|
|
68111
69002
|
history: { fields: {
|
|
68112
69003
|
temperature: {
|
|
68113
69004
|
kind: "gauge",
|
|
68114
|
-
|
|
69005
|
+
unit: "°C",
|
|
68115
69006
|
deadband: .2
|
|
68116
69007
|
},
|
|
68117
69008
|
humidity: {
|
|
@@ -68121,12 +69012,12 @@ var weatherCapability = {
|
|
|
68121
69012
|
},
|
|
68122
69013
|
pressure: {
|
|
68123
69014
|
kind: "gauge",
|
|
68124
|
-
|
|
69015
|
+
unit: "hPa",
|
|
68125
69016
|
deadband: .5
|
|
68126
69017
|
},
|
|
68127
69018
|
windSpeed: {
|
|
68128
69019
|
kind: "gauge",
|
|
68129
|
-
|
|
69020
|
+
unit: "m/s",
|
|
68130
69021
|
deadband: .5
|
|
68131
69022
|
}
|
|
68132
69023
|
} }
|
|
@@ -69027,8 +69918,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
69027
69918
|
kind: "mutation",
|
|
69028
69919
|
auth: "admin"
|
|
69029
69920
|
});
|
|
69921
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
69030
69922
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
69031
|
-
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;
|
|
69923
|
+
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;
|
|
69032
69924
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
69033
69925
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
69034
69926
|
new Set(CAP_NAMES);
|
|
@@ -69357,6 +70249,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69357
70249
|
featureProbe: featureProbeCapability,
|
|
69358
70250
|
flood: floodCapability,
|
|
69359
70251
|
gas: gasCapability,
|
|
70252
|
+
groupActive: groupActiveCapability,
|
|
70253
|
+
groupCommands: groupCommandsCapability,
|
|
70254
|
+
groupStatus: groupStatusCapability,
|
|
69360
70255
|
heatingValve: heatingValveCapability,
|
|
69361
70256
|
humidifier: humidifierCapability,
|
|
69362
70257
|
humiditySensor: humiditySensorCapability,
|
|
@@ -69366,6 +70261,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69366
70261
|
lawnMowerControl: lawnMowerControlCapability,
|
|
69367
70262
|
lockControl: lockControlCapability,
|
|
69368
70263
|
mediaPlayer: mediaPlayerCapability,
|
|
70264
|
+
meter: meterCapability,
|
|
69369
70265
|
motion: motionCapability,
|
|
69370
70266
|
motionTrigger: motionTriggerCapability,
|
|
69371
70267
|
motionZones: motionZonesCapability,
|
|
@@ -70625,7 +71521,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
70625
71521
|
return toDeviceSummary(device, this.addonId);
|
|
70626
71522
|
}
|
|
70627
71523
|
};
|
|
70628
|
-
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;
|
|
71524
|
+
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;
|
|
70629
71525
|
new Set(Object.values(DeviceType));
|
|
70630
71526
|
Object.freeze({
|
|
70631
71527
|
"accessories.getStatus": {
|
|
@@ -70733,6 +71629,13 @@ Object.freeze({
|
|
|
70733
71629
|
access: "view",
|
|
70734
71630
|
role: "admin"
|
|
70735
71631
|
},
|
|
71632
|
+
"addons.getPackageDocs": {
|
|
71633
|
+
capName: "addons",
|
|
71634
|
+
capScope: "system",
|
|
71635
|
+
addonId: null,
|
|
71636
|
+
access: "view",
|
|
71637
|
+
role: "admin"
|
|
71638
|
+
},
|
|
70736
71639
|
"addons.getVersions": {
|
|
70737
71640
|
capName: "addons",
|
|
70738
71641
|
capScope: "system",
|
|
@@ -73841,6 +74744,27 @@ Object.freeze({
|
|
|
73841
74744
|
access: "view",
|
|
73842
74745
|
role: "viewer"
|
|
73843
74746
|
},
|
|
74747
|
+
"groupActive.getStatus": {
|
|
74748
|
+
capName: "group-active",
|
|
74749
|
+
capScope: "device",
|
|
74750
|
+
addonId: null,
|
|
74751
|
+
access: "view",
|
|
74752
|
+
role: "viewer"
|
|
74753
|
+
},
|
|
74754
|
+
"groupCommands.getStatus": {
|
|
74755
|
+
capName: "group-commands",
|
|
74756
|
+
capScope: "device",
|
|
74757
|
+
addonId: null,
|
|
74758
|
+
access: "view",
|
|
74759
|
+
role: "viewer"
|
|
74760
|
+
},
|
|
74761
|
+
"groupStatus.getStatus": {
|
|
74762
|
+
capName: "group-status",
|
|
74763
|
+
capScope: "device",
|
|
74764
|
+
addonId: null,
|
|
74765
|
+
access: "view",
|
|
74766
|
+
role: "viewer"
|
|
74767
|
+
},
|
|
73844
74768
|
"heatingValve.getStatus": {
|
|
73845
74769
|
capName: "heating-valve",
|
|
73846
74770
|
capScope: "device",
|
|
@@ -74793,6 +75717,13 @@ Object.freeze({
|
|
|
74793
75717
|
access: "create",
|
|
74794
75718
|
role: "admin"
|
|
74795
75719
|
},
|
|
75720
|
+
"meter.getStatus": {
|
|
75721
|
+
capName: "meter",
|
|
75722
|
+
capScope: "device",
|
|
75723
|
+
addonId: null,
|
|
75724
|
+
access: "view",
|
|
75725
|
+
role: "viewer"
|
|
75726
|
+
},
|
|
74796
75727
|
"metricsProvider.collectSnapshot": {
|
|
74797
75728
|
capName: "metrics-provider",
|
|
74798
75729
|
capScope: "system",
|
|
@@ -82891,7 +83822,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
82891
83822
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
82892
83823
|
icon: "square"
|
|
82893
83824
|
}
|
|
82894
|
-
}
|
|
83825
|
+
},
|
|
83826
|
+
overrides: { byType: {
|
|
83827
|
+
[DeviceType.Washer]: {
|
|
83828
|
+
state: { running: {
|
|
83829
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
83830
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
83831
|
+
} },
|
|
83832
|
+
events: {
|
|
83833
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
83834
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
83835
|
+
}
|
|
83836
|
+
},
|
|
83837
|
+
[DeviceType.Dryer]: {
|
|
83838
|
+
state: { running: {
|
|
83839
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
83840
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
83841
|
+
} },
|
|
83842
|
+
events: {
|
|
83843
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
83844
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
83845
|
+
}
|
|
83846
|
+
},
|
|
83847
|
+
[DeviceType.Dishwasher]: {
|
|
83848
|
+
state: { running: {
|
|
83849
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
83850
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
83851
|
+
} },
|
|
83852
|
+
events: {
|
|
83853
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
83854
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
83855
|
+
}
|
|
83856
|
+
}
|
|
83857
|
+
} }
|
|
82895
83858
|
},
|
|
82896
83859
|
update: {
|
|
82897
83860
|
scope: "device",
|
|
@@ -83663,6 +84626,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83663
84626
|
icon: "flame"
|
|
83664
84627
|
}]
|
|
83665
84628
|
},
|
|
84629
|
+
"group-active": {
|
|
84630
|
+
scope: "device",
|
|
84631
|
+
noun: t("Group state", "Stato del gruppo")
|
|
84632
|
+
},
|
|
84633
|
+
"group-commands": {
|
|
84634
|
+
scope: "device",
|
|
84635
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84636
|
+
},
|
|
84637
|
+
"group-status": {
|
|
84638
|
+
scope: "device",
|
|
84639
|
+
noun: t("Group", "Gruppo"),
|
|
84640
|
+
state: [
|
|
84641
|
+
{
|
|
84642
|
+
kind: "numeric",
|
|
84643
|
+
field: "included",
|
|
84644
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84645
|
+
label: t("Reporting", "Rispondono"),
|
|
84646
|
+
icon: "users"
|
|
84647
|
+
},
|
|
84648
|
+
{
|
|
84649
|
+
kind: "numeric",
|
|
84650
|
+
field: "excluded",
|
|
84651
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84652
|
+
label: t("Excluded", "Esclusi"),
|
|
84653
|
+
icon: "users"
|
|
84654
|
+
},
|
|
84655
|
+
{
|
|
84656
|
+
kind: "numeric",
|
|
84657
|
+
field: "total",
|
|
84658
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84659
|
+
label: t("Members", "Membri"),
|
|
84660
|
+
icon: "sigma"
|
|
84661
|
+
}
|
|
84662
|
+
]
|
|
84663
|
+
},
|
|
83666
84664
|
"humidity-sensor": {
|
|
83667
84665
|
scope: "device",
|
|
83668
84666
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83688,6 +84686,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83688
84686
|
}],
|
|
83689
84687
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
83690
84688
|
},
|
|
84689
|
+
meter: {
|
|
84690
|
+
scope: "device",
|
|
84691
|
+
noun: t("Meter", "Contatore"),
|
|
84692
|
+
state: [{
|
|
84693
|
+
kind: "numeric",
|
|
84694
|
+
field: "value",
|
|
84695
|
+
quantity: t("the total", "il totale"),
|
|
84696
|
+
label: t("Total", "Totale"),
|
|
84697
|
+
icon: "gauge"
|
|
84698
|
+
}]
|
|
84699
|
+
},
|
|
83691
84700
|
"numeric-sensor": {
|
|
83692
84701
|
scope: "device",
|
|
83693
84702
|
noun: t("Sensor", "Sensore"),
|
|
@@ -83696,7 +84705,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83696
84705
|
field: "value",
|
|
83697
84706
|
quantity: t("the reading", "il valore"),
|
|
83698
84707
|
label: t("Reading", "Valore"),
|
|
83699
|
-
unitField: "unit",
|
|
83700
84708
|
icon: "gauge"
|
|
83701
84709
|
}]
|
|
83702
84710
|
},
|
|
@@ -83832,7 +84840,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83832
84840
|
field: "temperature",
|
|
83833
84841
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
83834
84842
|
label: t("Temperature", "Temperatura"),
|
|
83835
|
-
|
|
84843
|
+
unit: "°C",
|
|
83836
84844
|
icon: "thermometer"
|
|
83837
84845
|
},
|
|
83838
84846
|
{
|
|
@@ -83848,7 +84856,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83848
84856
|
field: "windSpeed",
|
|
83849
84857
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
83850
84858
|
label: t("Wind", "Vento"),
|
|
83851
|
-
|
|
84859
|
+
unit: "m/s",
|
|
83852
84860
|
icon: "wind"
|
|
83853
84861
|
},
|
|
83854
84862
|
{
|
|
@@ -83856,7 +84864,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83856
84864
|
field: "pressure",
|
|
83857
84865
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
83858
84866
|
label: t("Pressure", "Pressione"),
|
|
83859
|
-
|
|
84867
|
+
unit: "hPa",
|
|
83860
84868
|
icon: "gauge"
|
|
83861
84869
|
}
|
|
83862
84870
|
]
|
|
@@ -84161,8 +85169,47 @@ function projectAction(cap, action) {
|
|
|
84161
85169
|
};
|
|
84162
85170
|
}
|
|
84163
85171
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
84164
|
-
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;
|
|
85172
|
+
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;
|
|
84165
85173
|
DeviceFeature.BatteryOperated;
|
|
85174
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
85175
|
+
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.";
|
|
85176
|
+
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.";
|
|
85177
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
85178
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
85179
|
+
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.";
|
|
85180
|
+
function withheld(reason) {
|
|
85181
|
+
return {
|
|
85182
|
+
[DeviceType.Washer]: {
|
|
85183
|
+
exported: false,
|
|
85184
|
+
reason
|
|
85185
|
+
},
|
|
85186
|
+
[DeviceType.Dryer]: {
|
|
85187
|
+
exported: false,
|
|
85188
|
+
reason
|
|
85189
|
+
},
|
|
85190
|
+
[DeviceType.Dishwasher]: {
|
|
85191
|
+
exported: false,
|
|
85192
|
+
reason
|
|
85193
|
+
}
|
|
85194
|
+
};
|
|
85195
|
+
}
|
|
85196
|
+
function offered(received) {
|
|
85197
|
+
return {
|
|
85198
|
+
[DeviceType.Washer]: {
|
|
85199
|
+
exported: true,
|
|
85200
|
+
as: received
|
|
85201
|
+
},
|
|
85202
|
+
[DeviceType.Dryer]: {
|
|
85203
|
+
exported: true,
|
|
85204
|
+
as: received
|
|
85205
|
+
},
|
|
85206
|
+
[DeviceType.Dishwasher]: {
|
|
85207
|
+
exported: true,
|
|
85208
|
+
as: received
|
|
85209
|
+
}
|
|
85210
|
+
};
|
|
85211
|
+
}
|
|
85212
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
84166
85213
|
Object.freeze({
|
|
84167
85214
|
"accessories.getStatus": [{
|
|
84168
85215
|
name: "deviceId",
|
|
@@ -85129,6 +86176,21 @@ Object.freeze({
|
|
|
85129
86176
|
form: "single",
|
|
85130
86177
|
optional: false
|
|
85131
86178
|
}],
|
|
86179
|
+
"groupActive.getStatus": [{
|
|
86180
|
+
name: "deviceId",
|
|
86181
|
+
form: "single",
|
|
86182
|
+
optional: false
|
|
86183
|
+
}],
|
|
86184
|
+
"groupCommands.getStatus": [{
|
|
86185
|
+
name: "deviceId",
|
|
86186
|
+
form: "single",
|
|
86187
|
+
optional: false
|
|
86188
|
+
}],
|
|
86189
|
+
"groupStatus.getStatus": [{
|
|
86190
|
+
name: "deviceId",
|
|
86191
|
+
form: "single",
|
|
86192
|
+
optional: false
|
|
86193
|
+
}],
|
|
85132
86194
|
"heatingValve.getStatus": [{
|
|
85133
86195
|
name: "deviceId",
|
|
85134
86196
|
form: "single",
|
|
@@ -85329,6 +86391,11 @@ Object.freeze({
|
|
|
85329
86391
|
form: "single",
|
|
85330
86392
|
optional: false
|
|
85331
86393
|
}],
|
|
86394
|
+
"meter.getStatus": [{
|
|
86395
|
+
name: "deviceId",
|
|
86396
|
+
form: "single",
|
|
86397
|
+
optional: false
|
|
86398
|
+
}],
|
|
85332
86399
|
"motion.getStatus": [{
|
|
85333
86400
|
name: "deviceId",
|
|
85334
86401
|
form: "single",
|
|
@@ -86936,7 +88003,6 @@ Object.freeze({
|
|
|
86936
88003
|
"network-access": "ingress",
|
|
86937
88004
|
"smtp-provider": "email"
|
|
86938
88005
|
});
|
|
86939
|
-
DeviceType.Camera;
|
|
86940
88006
|
/**
|
|
86941
88007
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
86942
88008
|
* `z.infer`, they do not restate the shape.
|
|
@@ -87113,6 +88179,8 @@ new Map(Object.entries({
|
|
|
87113
88179
|
"detection-blind": "device-events",
|
|
87114
88180
|
"motion-noisy": "device-events",
|
|
87115
88181
|
"motion-calm": "device-events",
|
|
88182
|
+
"package-llm-silent": "device-events",
|
|
88183
|
+
"package-llm-answered": "device-events",
|
|
87116
88184
|
"recording-stalled": "device-events",
|
|
87117
88185
|
"recording-healthy": "device-events",
|
|
87118
88186
|
"recording-degraded": "device-events",
|
|
@@ -87196,6 +88264,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
87196
88264
|
label: "Motion without a subject",
|
|
87197
88265
|
kinds: ["motion-noisy", "motion-calm"]
|
|
87198
88266
|
},
|
|
88267
|
+
{
|
|
88268
|
+
id: "package-llm",
|
|
88269
|
+
family: "device-events",
|
|
88270
|
+
label: "Package confirm",
|
|
88271
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
88272
|
+
},
|
|
87199
88273
|
{
|
|
87200
88274
|
id: "recording",
|
|
87201
88275
|
family: "device-events",
|
|
@@ -87377,6 +88451,8 @@ var DEVICE_EVENTS = [
|
|
|
87377
88451
|
"detection-blind",
|
|
87378
88452
|
"motion-noisy",
|
|
87379
88453
|
"motion-calm",
|
|
88454
|
+
"package-llm-silent",
|
|
88455
|
+
"package-llm-answered",
|
|
87380
88456
|
"recording-stalled",
|
|
87381
88457
|
"recording-healthy",
|
|
87382
88458
|
"recording-degraded",
|
|
@@ -87645,6 +88721,15 @@ new Map([
|
|
|
87645
88721
|
snapshotLabel: "Cameras with constant motion now",
|
|
87646
88722
|
snapshotSection: null
|
|
87647
88723
|
},
|
|
88724
|
+
{
|
|
88725
|
+
id: "package-llm-confirm",
|
|
88726
|
+
family: "device-events",
|
|
88727
|
+
label: "Package confirm (not answering / answering again)",
|
|
88728
|
+
bad: ["package-llm-silent"],
|
|
88729
|
+
recovery: ["package-llm-answered"],
|
|
88730
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88731
|
+
snapshotSection: null
|
|
88732
|
+
},
|
|
87648
88733
|
{
|
|
87649
88734
|
id: "recording-health",
|
|
87650
88735
|
family: "device-events",
|