@camstack/addon-provider-wyze 0.2.158 → 0.2.160
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 +39 -0
- package/dist/addon.js +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { getCACertificates, setDefaultCACertificates } from "node:tls";
|
|
|
10
10
|
//#region \0rolldown/runtime.js
|
|
11
11
|
var __require$1 = /* @__PURE__ */ createRequire(import.meta.url);
|
|
12
12
|
//#endregion
|
|
13
|
-
//#region ../types/dist/event-category-
|
|
13
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
14
14
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
15
15
|
EventCategory["SystemBoot"] = "system.boot";
|
|
16
16
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -336,6 +336,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
336
336
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
337
337
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
338
338
|
/**
|
|
339
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
340
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
341
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
342
|
+
*/
|
|
343
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
344
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
345
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
346
|
+
/**
|
|
339
347
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
340
348
|
* (a settings change via `setAgentInferenceDevices` /
|
|
341
349
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5445,7 +5453,7 @@ var ZodIssueCode = {
|
|
|
5445
5453
|
var ZodFirstPartyTypeKind;
|
|
5446
5454
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5447
5455
|
//#endregion
|
|
5448
|
-
//#region ../types/dist/sleep
|
|
5456
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5449
5457
|
/**
|
|
5450
5458
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5451
5459
|
* window to float samples (D455).
|
|
@@ -7999,6 +8007,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
7999
8007
|
}).strict();
|
|
8000
8008
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8001
8009
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8010
|
+
var READING_QUANTITIES = [
|
|
8011
|
+
"temperature",
|
|
8012
|
+
"pressure",
|
|
8013
|
+
"speed",
|
|
8014
|
+
"precipitation",
|
|
8015
|
+
"precipitation-rate",
|
|
8016
|
+
"length",
|
|
8017
|
+
"area",
|
|
8018
|
+
"illuminance",
|
|
8019
|
+
"irradiance",
|
|
8020
|
+
"power",
|
|
8021
|
+
"energy",
|
|
8022
|
+
"voltage",
|
|
8023
|
+
"current",
|
|
8024
|
+
"apparent-power",
|
|
8025
|
+
"humidity",
|
|
8026
|
+
"percentage",
|
|
8027
|
+
"concentration-volume",
|
|
8028
|
+
"concentration-mass",
|
|
8029
|
+
"concentration-ppb",
|
|
8030
|
+
"volume",
|
|
8031
|
+
"duration",
|
|
8032
|
+
"duration-ms",
|
|
8033
|
+
"information",
|
|
8034
|
+
"sound-level",
|
|
8035
|
+
"signal-level",
|
|
8036
|
+
"colour-temperature",
|
|
8037
|
+
"angle",
|
|
8038
|
+
"bitrate",
|
|
8039
|
+
"rate",
|
|
8040
|
+
"mass",
|
|
8041
|
+
"index",
|
|
8042
|
+
"ratio",
|
|
8043
|
+
"count",
|
|
8044
|
+
"none",
|
|
8045
|
+
"device"
|
|
8046
|
+
];
|
|
8047
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8048
|
+
new Set(READING_QUANTITIES);
|
|
8049
|
+
/**
|
|
8050
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8051
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8052
|
+
*/
|
|
8053
|
+
var QUANTITY_BASE = {
|
|
8054
|
+
temperature: "°C",
|
|
8055
|
+
pressure: "hPa",
|
|
8056
|
+
speed: "m/s",
|
|
8057
|
+
precipitation: "mm",
|
|
8058
|
+
"precipitation-rate": "mm/h",
|
|
8059
|
+
length: "m",
|
|
8060
|
+
area: "m²",
|
|
8061
|
+
illuminance: "lx",
|
|
8062
|
+
irradiance: "W/m²",
|
|
8063
|
+
power: "W",
|
|
8064
|
+
energy: "kWh",
|
|
8065
|
+
voltage: "V",
|
|
8066
|
+
current: "A",
|
|
8067
|
+
"apparent-power": "VA",
|
|
8068
|
+
humidity: "%",
|
|
8069
|
+
percentage: "%",
|
|
8070
|
+
"concentration-volume": "ppm",
|
|
8071
|
+
"concentration-mass": "µg/m³",
|
|
8072
|
+
"concentration-ppb": "ppb",
|
|
8073
|
+
volume: "L",
|
|
8074
|
+
duration: "s",
|
|
8075
|
+
"duration-ms": "ms",
|
|
8076
|
+
information: "B",
|
|
8077
|
+
"sound-level": "dBFS",
|
|
8078
|
+
"signal-level": "dBm",
|
|
8079
|
+
"colour-temperature": "mired",
|
|
8080
|
+
angle: "°",
|
|
8081
|
+
bitrate: "kbps",
|
|
8082
|
+
rate: "fps",
|
|
8083
|
+
mass: "kg",
|
|
8084
|
+
index: "none",
|
|
8085
|
+
ratio: "none",
|
|
8086
|
+
count: "none",
|
|
8087
|
+
none: "none",
|
|
8088
|
+
device: "device"
|
|
8089
|
+
};
|
|
8090
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8091
|
+
function baseUnitOf(quantity) {
|
|
8092
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8093
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8094
|
+
return symbol;
|
|
8095
|
+
}
|
|
8096
|
+
function readingMeta(quantity, extras) {
|
|
8097
|
+
return {
|
|
8098
|
+
quantity,
|
|
8099
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8100
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8101
|
+
};
|
|
8102
|
+
}
|
|
8002
8103
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8003
8104
|
var CamProfileSchema = _enum([
|
|
8004
8105
|
"high",
|
|
@@ -8026,8 +8127,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8026
8127
|
"derived"
|
|
8027
8128
|
]);
|
|
8028
8129
|
var CamStreamResolutionSchema = object({
|
|
8029
|
-
width: number().int().positive(),
|
|
8030
|
-
height: number().int().positive()
|
|
8130
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8131
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8031
8132
|
});
|
|
8032
8133
|
var CameraStreamSchema = object({
|
|
8033
8134
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8545,6 +8646,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8545
8646
|
"filesystem-browse",
|
|
8546
8647
|
"flood",
|
|
8547
8648
|
"gas",
|
|
8649
|
+
"group-active",
|
|
8650
|
+
"group-commands",
|
|
8651
|
+
"group-status",
|
|
8548
8652
|
"heating-valve",
|
|
8549
8653
|
"humidifier",
|
|
8550
8654
|
"humidity-sensor",
|
|
@@ -8565,6 +8669,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8565
8669
|
"login-method",
|
|
8566
8670
|
"media-player",
|
|
8567
8671
|
"mesh-network",
|
|
8672
|
+
"meter",
|
|
8568
8673
|
"metrics-provider",
|
|
8569
8674
|
"model-convert",
|
|
8570
8675
|
"model-distributor",
|
|
@@ -8674,14 +8779,6 @@ Object.freeze({
|
|
|
8674
8779
|
{
|
|
8675
8780
|
"path": "aqi",
|
|
8676
8781
|
"valueType": "number"
|
|
8677
|
-
},
|
|
8678
|
-
{
|
|
8679
|
-
"path": "unit",
|
|
8680
|
-
"valueType": "string"
|
|
8681
|
-
},
|
|
8682
|
-
{
|
|
8683
|
-
"path": "precision",
|
|
8684
|
-
"valueType": "number"
|
|
8685
8782
|
}
|
|
8686
8783
|
],
|
|
8687
8784
|
"alarm-panel": [
|
|
@@ -8717,20 +8814,10 @@ Object.freeze({
|
|
|
8717
8814
|
"valueType": "boolean"
|
|
8718
8815
|
}
|
|
8719
8816
|
],
|
|
8720
|
-
"ambient-light-sensor": [
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
},
|
|
8725
|
-
{
|
|
8726
|
-
"path": "unit",
|
|
8727
|
-
"valueType": "string"
|
|
8728
|
-
},
|
|
8729
|
-
{
|
|
8730
|
-
"path": "precision",
|
|
8731
|
-
"valueType": "number"
|
|
8732
|
-
}
|
|
8733
|
-
],
|
|
8817
|
+
"ambient-light-sensor": [{
|
|
8818
|
+
"path": "lux",
|
|
8819
|
+
"valueType": "number"
|
|
8820
|
+
}],
|
|
8734
8821
|
"audio-metrics": [
|
|
8735
8822
|
{
|
|
8736
8823
|
"path": "ts",
|
|
@@ -8810,6 +8897,10 @@ Object.freeze({
|
|
|
8810
8897
|
"path": "lastUpdated",
|
|
8811
8898
|
"valueType": "number"
|
|
8812
8899
|
},
|
|
8900
|
+
{
|
|
8901
|
+
"path": "volts",
|
|
8902
|
+
"valueType": "number"
|
|
8903
|
+
},
|
|
8813
8904
|
{
|
|
8814
8905
|
"path": "lastContactAt",
|
|
8815
8906
|
"valueType": "number"
|
|
@@ -9052,10 +9143,6 @@ Object.freeze({
|
|
|
9052
9143
|
"datetime"
|
|
9053
9144
|
]
|
|
9054
9145
|
},
|
|
9055
|
-
{
|
|
9056
|
-
"path": "unit",
|
|
9057
|
-
"valueType": "string"
|
|
9058
|
-
},
|
|
9059
9146
|
{
|
|
9060
9147
|
"path": "min",
|
|
9061
9148
|
"valueType": "number"
|
|
@@ -9067,19 +9154,6 @@ Object.freeze({
|
|
|
9067
9154
|
{
|
|
9068
9155
|
"path": "step",
|
|
9069
9156
|
"valueType": "number"
|
|
9070
|
-
},
|
|
9071
|
-
{
|
|
9072
|
-
"path": "precision",
|
|
9073
|
-
"valueType": "number"
|
|
9074
|
-
},
|
|
9075
|
-
{
|
|
9076
|
-
"path": "format",
|
|
9077
|
-
"valueType": "enum",
|
|
9078
|
-
"enumValues": [
|
|
9079
|
-
"date",
|
|
9080
|
-
"time",
|
|
9081
|
-
"datetime"
|
|
9082
|
-
]
|
|
9083
9157
|
}
|
|
9084
9158
|
],
|
|
9085
9159
|
"cover": [
|
|
@@ -9320,13 +9394,8 @@ Object.freeze({
|
|
|
9320
9394
|
"path": "value",
|
|
9321
9395
|
"valueType": "string"
|
|
9322
9396
|
}, {
|
|
9323
|
-
"path": "
|
|
9324
|
-
"valueType": "
|
|
9325
|
-
"enumValues": [
|
|
9326
|
-
"date",
|
|
9327
|
-
"time",
|
|
9328
|
-
"datetime"
|
|
9329
|
-
]
|
|
9397
|
+
"path": "timestamp",
|
|
9398
|
+
"valueType": "boolean"
|
|
9330
9399
|
}],
|
|
9331
9400
|
"event-emitter": [
|
|
9332
9401
|
{
|
|
@@ -9399,6 +9468,24 @@ Object.freeze({
|
|
|
9399
9468
|
"path": "detected",
|
|
9400
9469
|
"valueType": "boolean"
|
|
9401
9470
|
}],
|
|
9471
|
+
"group-active": [{
|
|
9472
|
+
"path": "active",
|
|
9473
|
+
"valueType": "boolean"
|
|
9474
|
+
}],
|
|
9475
|
+
"group-status": [
|
|
9476
|
+
{
|
|
9477
|
+
"path": "included",
|
|
9478
|
+
"valueType": "number"
|
|
9479
|
+
},
|
|
9480
|
+
{
|
|
9481
|
+
"path": "excluded",
|
|
9482
|
+
"valueType": "number"
|
|
9483
|
+
},
|
|
9484
|
+
{
|
|
9485
|
+
"path": "total",
|
|
9486
|
+
"valueType": "number"
|
|
9487
|
+
}
|
|
9488
|
+
],
|
|
9402
9489
|
"heating-valve": [{
|
|
9403
9490
|
"path": "position",
|
|
9404
9491
|
"valueType": "number"
|
|
@@ -9433,20 +9520,10 @@ Object.freeze({
|
|
|
9433
9520
|
"valueType": "number"
|
|
9434
9521
|
}
|
|
9435
9522
|
],
|
|
9436
|
-
"humidity-sensor": [
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
},
|
|
9441
|
-
{
|
|
9442
|
-
"path": "unit",
|
|
9443
|
-
"valueType": "string"
|
|
9444
|
-
},
|
|
9445
|
-
{
|
|
9446
|
-
"path": "precision",
|
|
9447
|
-
"valueType": "number"
|
|
9448
|
-
}
|
|
9449
|
-
],
|
|
9523
|
+
"humidity-sensor": [{
|
|
9524
|
+
"path": "percent",
|
|
9525
|
+
"valueType": "number"
|
|
9526
|
+
}],
|
|
9450
9527
|
"image": [{
|
|
9451
9528
|
"path": "url",
|
|
9452
9529
|
"valueType": "string"
|
|
@@ -9654,6 +9731,10 @@ Object.freeze({
|
|
|
9654
9731
|
]
|
|
9655
9732
|
}
|
|
9656
9733
|
],
|
|
9734
|
+
"meter": [{
|
|
9735
|
+
"path": "value",
|
|
9736
|
+
"valueType": "number"
|
|
9737
|
+
}],
|
|
9657
9738
|
"motion": [
|
|
9658
9739
|
{
|
|
9659
9740
|
"path": "detected",
|
|
@@ -9785,20 +9866,10 @@ Object.freeze({
|
|
|
9785
9866
|
"valueType": "boolean"
|
|
9786
9867
|
}
|
|
9787
9868
|
],
|
|
9788
|
-
"numeric-sensor": [
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
},
|
|
9793
|
-
{
|
|
9794
|
-
"path": "unit",
|
|
9795
|
-
"valueType": "string"
|
|
9796
|
-
},
|
|
9797
|
-
{
|
|
9798
|
-
"path": "precision",
|
|
9799
|
-
"valueType": "number"
|
|
9800
|
-
}
|
|
9801
|
-
],
|
|
9869
|
+
"numeric-sensor": [{
|
|
9870
|
+
"path": "value",
|
|
9871
|
+
"valueType": "number"
|
|
9872
|
+
}],
|
|
9802
9873
|
"pet-feeder": [
|
|
9803
9874
|
{
|
|
9804
9875
|
"path": "foodLevel",
|
|
@@ -9890,14 +9961,6 @@ Object.freeze({
|
|
|
9890
9961
|
{
|
|
9891
9962
|
"path": "powerFactor",
|
|
9892
9963
|
"valueType": "number"
|
|
9893
|
-
},
|
|
9894
|
-
{
|
|
9895
|
-
"path": "unit",
|
|
9896
|
-
"valueType": "string"
|
|
9897
|
-
},
|
|
9898
|
-
{
|
|
9899
|
-
"path": "precision",
|
|
9900
|
-
"valueType": "number"
|
|
9901
9964
|
}
|
|
9902
9965
|
],
|
|
9903
9966
|
"presence": [
|
|
@@ -9926,20 +9989,10 @@ Object.freeze({
|
|
|
9926
9989
|
"valueType": "number"
|
|
9927
9990
|
}
|
|
9928
9991
|
],
|
|
9929
|
-
"pressure-sensor": [
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
},
|
|
9934
|
-
{
|
|
9935
|
-
"path": "unit",
|
|
9936
|
-
"valueType": "string"
|
|
9937
|
-
},
|
|
9938
|
-
{
|
|
9939
|
-
"path": "precision",
|
|
9940
|
-
"valueType": "number"
|
|
9941
|
-
}
|
|
9942
|
-
],
|
|
9992
|
+
"pressure-sensor": [{
|
|
9993
|
+
"path": "hpa",
|
|
9994
|
+
"valueType": "number"
|
|
9995
|
+
}],
|
|
9943
9996
|
"privacy-mask": [{
|
|
9944
9997
|
"path": "enabled",
|
|
9945
9998
|
"valueType": "boolean"
|
|
@@ -10250,20 +10303,10 @@ Object.freeze({
|
|
|
10250
10303
|
"path": "tampered",
|
|
10251
10304
|
"valueType": "boolean"
|
|
10252
10305
|
}],
|
|
10253
|
-
"temperature-sensor": [
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
},
|
|
10258
|
-
{
|
|
10259
|
-
"path": "unit",
|
|
10260
|
-
"valueType": "string"
|
|
10261
|
-
},
|
|
10262
|
-
{
|
|
10263
|
-
"path": "precision",
|
|
10264
|
-
"valueType": "number"
|
|
10265
|
-
}
|
|
10266
|
-
],
|
|
10306
|
+
"temperature-sensor": [{
|
|
10307
|
+
"path": "celsius",
|
|
10308
|
+
"valueType": "number"
|
|
10309
|
+
}],
|
|
10267
10310
|
"update": [
|
|
10268
10311
|
{
|
|
10269
10312
|
"path": "currentVersion",
|
|
@@ -10374,10 +10417,6 @@ Object.freeze({
|
|
|
10374
10417
|
"path": "temperature",
|
|
10375
10418
|
"valueType": "number"
|
|
10376
10419
|
},
|
|
10377
|
-
{
|
|
10378
|
-
"path": "temperatureUnit",
|
|
10379
|
-
"valueType": "string"
|
|
10380
|
-
},
|
|
10381
10420
|
{
|
|
10382
10421
|
"path": "humidity",
|
|
10383
10422
|
"valueType": "number"
|
|
@@ -10386,18 +10425,10 @@ Object.freeze({
|
|
|
10386
10425
|
"path": "pressure",
|
|
10387
10426
|
"valueType": "number"
|
|
10388
10427
|
},
|
|
10389
|
-
{
|
|
10390
|
-
"path": "pressureUnit",
|
|
10391
|
-
"valueType": "string"
|
|
10392
|
-
},
|
|
10393
10428
|
{
|
|
10394
10429
|
"path": "windSpeed",
|
|
10395
10430
|
"valueType": "number"
|
|
10396
10431
|
},
|
|
10397
|
-
{
|
|
10398
|
-
"path": "windSpeedUnit",
|
|
10399
|
-
"valueType": "string"
|
|
10400
|
-
},
|
|
10401
10432
|
{
|
|
10402
10433
|
"path": "windBearing",
|
|
10403
10434
|
"valueType": "number"
|
|
@@ -10461,7 +10492,7 @@ function userError(code, params, englishFallback) {
|
|
|
10461
10492
|
return new CamstackError(code, params, englishFallback);
|
|
10462
10493
|
}
|
|
10463
10494
|
//#endregion
|
|
10464
|
-
//#region ../types/dist/err-msg-
|
|
10495
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10465
10496
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10466
10497
|
DeviceType["Camera"] = "camera";
|
|
10467
10498
|
DeviceType["Hub"] = "hub";
|
|
@@ -10555,8 +10586,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10555
10586
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10556
10587
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10557
10588
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10558
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10589
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10590
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10559
10591
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10592
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10593
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10594
|
+
DeviceType["Washer"] = "washer";
|
|
10595
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10596
|
+
DeviceType["Dryer"] = "dryer";
|
|
10560
10597
|
return DeviceType;
|
|
10561
10598
|
}({});
|
|
10562
10599
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10814,7 +10851,7 @@ function errMsg(err) {
|
|
|
10814
10851
|
return String(err);
|
|
10815
10852
|
}
|
|
10816
10853
|
//#endregion
|
|
10817
|
-
//#region ../types/dist/composition-
|
|
10854
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10818
10855
|
/**
|
|
10819
10856
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10820
10857
|
*
|
|
@@ -11129,6 +11166,13 @@ var table = {
|
|
|
11129
11166
|
apply: () => {
|
|
11130
11167
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11131
11168
|
}
|
|
11169
|
+
},
|
|
11170
|
+
schmitt: {
|
|
11171
|
+
minArgs: 3,
|
|
11172
|
+
maxArgs: 5,
|
|
11173
|
+
apply: () => {
|
|
11174
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11175
|
+
}
|
|
11132
11176
|
}
|
|
11133
11177
|
};
|
|
11134
11178
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11569,15 +11613,232 @@ function validateExpressionSource(src) {
|
|
|
11569
11613
|
}
|
|
11570
11614
|
return null;
|
|
11571
11615
|
}
|
|
11572
|
-
/**
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11616
|
+
/**
|
|
11617
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11618
|
+
*
|
|
11619
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11620
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11621
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11622
|
+
*
|
|
11623
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11624
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11625
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11626
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11627
|
+
* can move later without moving the others.
|
|
11628
|
+
*/
|
|
11629
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11630
|
+
var APPLIANCE_KINDS = [
|
|
11631
|
+
"washer",
|
|
11632
|
+
"dryer",
|
|
11633
|
+
"dishwasher"
|
|
11634
|
+
];
|
|
11635
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11636
|
+
/**
|
|
11637
|
+
* Statistics and integrals over a history read (D944).
|
|
11638
|
+
*
|
|
11639
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11640
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11641
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11642
|
+
* as zero. A truncated read is not published.
|
|
11643
|
+
*/
|
|
11644
|
+
var STATISTIC_STATS = [
|
|
11645
|
+
"min",
|
|
11646
|
+
"max",
|
|
11647
|
+
"mean",
|
|
11648
|
+
"sum",
|
|
11649
|
+
"count",
|
|
11650
|
+
"change"
|
|
11651
|
+
];
|
|
11652
|
+
/**
|
|
11653
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11654
|
+
*
|
|
11655
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11656
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11657
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11658
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11659
|
+
*/
|
|
11660
|
+
var MINUTE_MS = 6e4;
|
|
11661
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11662
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11663
|
+
var ROLLING_SPANS = [
|
|
11664
|
+
"1h",
|
|
11665
|
+
"24h",
|
|
11666
|
+
"2d",
|
|
11667
|
+
"7d",
|
|
11668
|
+
"30d",
|
|
11669
|
+
"custom"
|
|
11670
|
+
];
|
|
11671
|
+
var CALENDAR_PERIODS = [
|
|
11672
|
+
"today",
|
|
11673
|
+
"yesterday",
|
|
11674
|
+
"this-week",
|
|
11675
|
+
"this-month"
|
|
11676
|
+
];
|
|
11677
|
+
var RESET_PERIODS = [
|
|
11678
|
+
"never",
|
|
11679
|
+
"daily",
|
|
11680
|
+
"weekly",
|
|
11681
|
+
"monthly"
|
|
11682
|
+
];
|
|
11683
|
+
5 * MINUTE_MS;
|
|
11684
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11685
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11686
|
+
var rollingWindowObject = object({
|
|
11687
|
+
kind: literal("rolling"),
|
|
11688
|
+
span: _enum(ROLLING_SPANS),
|
|
11689
|
+
customMinutes: number().int().min(5).optional()
|
|
11690
|
+
}).check((payload) => {
|
|
11691
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11692
|
+
code: "custom",
|
|
11693
|
+
message: "a custom range needs a duration in minutes",
|
|
11694
|
+
path: ["customMinutes"],
|
|
11695
|
+
input: payload.value
|
|
11696
|
+
});
|
|
11697
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11698
|
+
code: "custom",
|
|
11699
|
+
message: "only a custom range carries a duration",
|
|
11700
|
+
path: ["customMinutes"],
|
|
11701
|
+
input: payload.value
|
|
11702
|
+
});
|
|
11703
|
+
});
|
|
11704
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11705
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11706
|
+
kind: literal("calendar"),
|
|
11707
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11708
|
+
})]);
|
|
11709
|
+
/**
|
|
11710
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11711
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11712
|
+
* `composition.ts` (D659).
|
|
11713
|
+
*/
|
|
11576
11714
|
var CompositionSourceRefSchema = object({
|
|
11577
11715
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11578
11716
|
addonId: string().min(1),
|
|
11579
11717
|
stableId: string().min(1)
|
|
11580
11718
|
});
|
|
11719
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11720
|
+
"temperature",
|
|
11721
|
+
"humidity",
|
|
11722
|
+
"pressure",
|
|
11723
|
+
"illuminance",
|
|
11724
|
+
"power",
|
|
11725
|
+
"energy",
|
|
11726
|
+
"battery",
|
|
11727
|
+
"numeric",
|
|
11728
|
+
"motion",
|
|
11729
|
+
"contact",
|
|
11730
|
+
"leak",
|
|
11731
|
+
"smoke",
|
|
11732
|
+
"occupancy",
|
|
11733
|
+
"binary",
|
|
11734
|
+
"switch",
|
|
11735
|
+
"light",
|
|
11736
|
+
"fan",
|
|
11737
|
+
"cover",
|
|
11738
|
+
"valve",
|
|
11739
|
+
"lock",
|
|
11740
|
+
"media-player",
|
|
11741
|
+
"climate"
|
|
11742
|
+
];
|
|
11743
|
+
var NUMERIC_AGGREGATES = [
|
|
11744
|
+
"mean",
|
|
11745
|
+
"median",
|
|
11746
|
+
"min",
|
|
11747
|
+
"max",
|
|
11748
|
+
"sum"
|
|
11749
|
+
];
|
|
11750
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11751
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11752
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11753
|
+
var AGGREGATE_REDUCERS = [
|
|
11754
|
+
"mean",
|
|
11755
|
+
"median",
|
|
11756
|
+
"min",
|
|
11757
|
+
"max",
|
|
11758
|
+
"sum",
|
|
11759
|
+
"any",
|
|
11760
|
+
"all"
|
|
11761
|
+
];
|
|
11762
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11763
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11764
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11765
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11766
|
+
var HelperMemberSchema = object({
|
|
11767
|
+
source: CompositionSourceRefSchema,
|
|
11768
|
+
cap: string().min(1),
|
|
11769
|
+
fieldPath: string().min(1)
|
|
11770
|
+
});
|
|
11771
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11772
|
+
object({
|
|
11773
|
+
kind: literal("group"),
|
|
11774
|
+
templateId: GroupTemplateIdSchema,
|
|
11775
|
+
aggregate: AggregateReducerSchema,
|
|
11776
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11777
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11778
|
+
active: ActiveCriterionSchema.optional()
|
|
11779
|
+
}),
|
|
11780
|
+
object({
|
|
11781
|
+
kind: literal("appliance"),
|
|
11782
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11783
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11784
|
+
thresholdWatts: number().positive(),
|
|
11785
|
+
startDwellMs: number().int().nonnegative(),
|
|
11786
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11787
|
+
member: HelperMemberSchema
|
|
11788
|
+
}),
|
|
11789
|
+
object({
|
|
11790
|
+
kind: literal("statistic"),
|
|
11791
|
+
stat: _enum(STATISTIC_STATS),
|
|
11792
|
+
window: StatisticWindowSchema,
|
|
11793
|
+
source: HelperMemberSchema
|
|
11794
|
+
}),
|
|
11795
|
+
object({
|
|
11796
|
+
kind: literal("integral"),
|
|
11797
|
+
reset: _enum(RESET_PERIODS),
|
|
11798
|
+
output: _enum(["energy", "meter"]),
|
|
11799
|
+
source: HelperMemberSchema
|
|
11800
|
+
}),
|
|
11801
|
+
object({
|
|
11802
|
+
kind: literal("threshold"),
|
|
11803
|
+
source: HelperMemberSchema,
|
|
11804
|
+
high: number(),
|
|
11805
|
+
low: number(),
|
|
11806
|
+
onForMs: number().int().nonnegative(),
|
|
11807
|
+
offForMs: number().int().nonnegative()
|
|
11808
|
+
}),
|
|
11809
|
+
object({
|
|
11810
|
+
kind: literal("arithmetic"),
|
|
11811
|
+
op: _enum([
|
|
11812
|
+
"sum",
|
|
11813
|
+
"difference",
|
|
11814
|
+
"ratio"
|
|
11815
|
+
]),
|
|
11816
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11817
|
+
}),
|
|
11818
|
+
object({
|
|
11819
|
+
kind: literal("expression"),
|
|
11820
|
+
expr: string().min(1),
|
|
11821
|
+
inputs: array(object({
|
|
11822
|
+
name: string().min(1),
|
|
11823
|
+
member: HelperMemberSchema
|
|
11824
|
+
})).min(1).max(64),
|
|
11825
|
+
output: _enum(["number", "boolean"])
|
|
11826
|
+
}),
|
|
11827
|
+
object({
|
|
11828
|
+
kind: literal("derivative"),
|
|
11829
|
+
window: RollingWindowSchema,
|
|
11830
|
+
per: _enum([
|
|
11831
|
+
"second",
|
|
11832
|
+
"minute",
|
|
11833
|
+
"hour"
|
|
11834
|
+
]),
|
|
11835
|
+
source: HelperMemberSchema
|
|
11836
|
+
})
|
|
11837
|
+
]);
|
|
11838
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11839
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11840
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11841
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11581
11842
|
/** One field of one capability of one source device. */
|
|
11582
11843
|
var CompositionFieldReadSchema = object({
|
|
11583
11844
|
source: CompositionSourceRefSchema,
|
|
@@ -11621,7 +11882,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11621
11882
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11622
11883
|
CompositionFromSourceSchema,
|
|
11623
11884
|
CompositionExpressionSourceSchema,
|
|
11624
|
-
CompositionCodeSourceSchema
|
|
11885
|
+
CompositionCodeSourceSchema,
|
|
11886
|
+
object({
|
|
11887
|
+
kind: literal("aggregate"),
|
|
11888
|
+
reducer: _enum([
|
|
11889
|
+
"mean",
|
|
11890
|
+
"median",
|
|
11891
|
+
"min",
|
|
11892
|
+
"max",
|
|
11893
|
+
"sum",
|
|
11894
|
+
"any",
|
|
11895
|
+
"all"
|
|
11896
|
+
]),
|
|
11897
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11898
|
+
/**
|
|
11899
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11900
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11901
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11902
|
+
*/
|
|
11903
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11904
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11905
|
+
publish: _enum([
|
|
11906
|
+
"value",
|
|
11907
|
+
"included",
|
|
11908
|
+
"excluded",
|
|
11909
|
+
"total"
|
|
11910
|
+
]),
|
|
11911
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11912
|
+
empty: _enum([
|
|
11913
|
+
"null",
|
|
11914
|
+
"omit",
|
|
11915
|
+
"offline"
|
|
11916
|
+
])
|
|
11917
|
+
}),
|
|
11918
|
+
object({
|
|
11919
|
+
kind: literal("series"),
|
|
11920
|
+
read: CompositionFieldReadSchema,
|
|
11921
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11922
|
+
publish: _enum([
|
|
11923
|
+
"value",
|
|
11924
|
+
"included",
|
|
11925
|
+
"excluded",
|
|
11926
|
+
"total"
|
|
11927
|
+
]),
|
|
11928
|
+
/**
|
|
11929
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11930
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11931
|
+
*/
|
|
11932
|
+
empty: _enum([
|
|
11933
|
+
"null",
|
|
11934
|
+
"omit",
|
|
11935
|
+
"offline"
|
|
11936
|
+
])
|
|
11937
|
+
})
|
|
11625
11938
|
]);
|
|
11626
11939
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11627
11940
|
kind: literal("forward"),
|
|
@@ -11667,7 +11980,13 @@ var CompositionSchema = object({
|
|
|
11667
11980
|
kind: literal("existing"),
|
|
11668
11981
|
device: CompositionSourceRefSchema
|
|
11669
11982
|
})]),
|
|
11670
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
11983
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
11984
|
+
/**
|
|
11985
|
+
* Present when the block is a helper template. Absent on a free
|
|
11986
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
11987
|
+
* never the compiled features.
|
|
11988
|
+
*/
|
|
11989
|
+
helper: HelperSpecSchema.optional()
|
|
11671
11990
|
}).superRefine((composition, ctx) => {
|
|
11672
11991
|
const seen = /* @__PURE__ */ new Set();
|
|
11673
11992
|
composition.features.forEach((feature, index) => {
|
|
@@ -16794,7 +17113,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16794
17113
|
*/
|
|
16795
17114
|
interactiveConnectPath: string().min(1).optional(),
|
|
16796
17115
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16797
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17116
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17117
|
+
/**
|
|
17118
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17119
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17120
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17121
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17122
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17123
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17124
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17125
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17126
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17127
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17128
|
+
* offers it as the default path; the fields the session fills are
|
|
17129
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17130
|
+
*/
|
|
17131
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16798
17132
|
}))
|
|
16799
17133
|
});
|
|
16800
17134
|
var ListInputSchema = object({
|
|
@@ -17895,7 +18229,12 @@ var CompositionProblemSchema = object({
|
|
|
17895
18229
|
"item-field-reserved",
|
|
17896
18230
|
"target-missing",
|
|
17897
18231
|
"target-unreadable",
|
|
17898
|
-
"not-replaceable"
|
|
18232
|
+
"not-replaceable",
|
|
18233
|
+
"native-capability-replace",
|
|
18234
|
+
"mixed-quantity",
|
|
18235
|
+
"helper-mismatch",
|
|
18236
|
+
"member-constraint",
|
|
18237
|
+
"retention"
|
|
17899
18238
|
]),
|
|
17900
18239
|
path: string(),
|
|
17901
18240
|
message: string()
|
|
@@ -17916,7 +18255,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17916
18255
|
"null",
|
|
17917
18256
|
"offline",
|
|
17918
18257
|
"unknown",
|
|
17919
|
-
"release"
|
|
18258
|
+
"release",
|
|
18259
|
+
"omit"
|
|
17920
18260
|
]);
|
|
17921
18261
|
/**
|
|
17922
18262
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17953,9 +18293,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17953
18293
|
reads: array(CompositionFieldReadSchema)
|
|
17954
18294
|
});
|
|
17955
18295
|
/**
|
|
17956
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17957
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17958
|
-
*
|
|
18296
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18297
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18298
|
+
* Replacing a capability the device already serves is refused
|
|
18299
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18300
|
+
* wire for a claim the hub already holds.
|
|
17959
18301
|
*/
|
|
17960
18302
|
var CompositionFeatureModeSchema = _enum([
|
|
17961
18303
|
"new",
|
|
@@ -18126,8 +18468,392 @@ Object.freeze({
|
|
|
18126
18468
|
latchedAt: {
|
|
18127
18469
|
kind: "fixed",
|
|
18128
18470
|
result: ["number", "null"]
|
|
18471
|
+
},
|
|
18472
|
+
schmitt: {
|
|
18473
|
+
kind: "fixed",
|
|
18474
|
+
result: ["boolean", "null"]
|
|
18129
18475
|
}
|
|
18130
18476
|
});
|
|
18477
|
+
/**
|
|
18478
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18479
|
+
* Data, not a form default written into the block.
|
|
18480
|
+
*/
|
|
18481
|
+
var NOW$2 = {
|
|
18482
|
+
fieldPath: "lastFetchedAt",
|
|
18483
|
+
expr: "now"
|
|
18484
|
+
};
|
|
18485
|
+
var CHANGED = {
|
|
18486
|
+
fieldPath: "lastChangedAt",
|
|
18487
|
+
expr: "now"
|
|
18488
|
+
};
|
|
18489
|
+
function numeric(input) {
|
|
18490
|
+
return {
|
|
18491
|
+
...input,
|
|
18492
|
+
family: "numeric",
|
|
18493
|
+
deviceType: DeviceType.Sensor,
|
|
18494
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18495
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18496
|
+
activeWhen: void 0,
|
|
18497
|
+
commandCaps: [],
|
|
18498
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18499
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18500
|
+
accept: [{
|
|
18501
|
+
cap: input.outputCap,
|
|
18502
|
+
fieldPath: input.outputField
|
|
18503
|
+
}]
|
|
18504
|
+
};
|
|
18505
|
+
}
|
|
18506
|
+
function binary(input) {
|
|
18507
|
+
return {
|
|
18508
|
+
...input,
|
|
18509
|
+
family: "binary",
|
|
18510
|
+
deviceType: DeviceType.Sensor,
|
|
18511
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18512
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18513
|
+
activeWhen: void 0,
|
|
18514
|
+
commandCaps: [],
|
|
18515
|
+
quantity: "none",
|
|
18516
|
+
baseUnit: void 0,
|
|
18517
|
+
aggregates: BINARY_AGGREGATES,
|
|
18518
|
+
empty: "offline"
|
|
18519
|
+
};
|
|
18520
|
+
}
|
|
18521
|
+
var GROUP_TEMPLATES = [
|
|
18522
|
+
numeric({
|
|
18523
|
+
id: "temperature",
|
|
18524
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18525
|
+
role: DeviceRole.TemperatureSensor,
|
|
18526
|
+
outputCap: "temperature-sensor",
|
|
18527
|
+
outputField: "celsius",
|
|
18528
|
+
quantity: "temperature",
|
|
18529
|
+
defaultAggregate: "mean",
|
|
18530
|
+
empty: "null",
|
|
18531
|
+
companions: [NOW$2]
|
|
18532
|
+
}),
|
|
18533
|
+
numeric({
|
|
18534
|
+
id: "humidity",
|
|
18535
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18536
|
+
role: DeviceRole.HumiditySensor,
|
|
18537
|
+
outputCap: "humidity-sensor",
|
|
18538
|
+
outputField: "percent",
|
|
18539
|
+
quantity: "humidity",
|
|
18540
|
+
defaultAggregate: "mean",
|
|
18541
|
+
empty: "null",
|
|
18542
|
+
companions: [NOW$2]
|
|
18543
|
+
}),
|
|
18544
|
+
numeric({
|
|
18545
|
+
id: "pressure",
|
|
18546
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18547
|
+
role: DeviceRole.PressureSensor,
|
|
18548
|
+
outputCap: "pressure-sensor",
|
|
18549
|
+
outputField: "hpa",
|
|
18550
|
+
quantity: "pressure",
|
|
18551
|
+
defaultAggregate: "mean",
|
|
18552
|
+
empty: "null",
|
|
18553
|
+
companions: [NOW$2]
|
|
18554
|
+
}),
|
|
18555
|
+
numeric({
|
|
18556
|
+
id: "illuminance",
|
|
18557
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18558
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18559
|
+
outputCap: "ambient-light-sensor",
|
|
18560
|
+
outputField: "lux",
|
|
18561
|
+
quantity: "illuminance",
|
|
18562
|
+
defaultAggregate: "mean",
|
|
18563
|
+
empty: "null",
|
|
18564
|
+
companions: [NOW$2]
|
|
18565
|
+
}),
|
|
18566
|
+
numeric({
|
|
18567
|
+
id: "power",
|
|
18568
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18569
|
+
role: DeviceRole.PowerSensor,
|
|
18570
|
+
outputCap: "power-meter",
|
|
18571
|
+
outputField: "watts",
|
|
18572
|
+
quantity: "power",
|
|
18573
|
+
defaultAggregate: "sum",
|
|
18574
|
+
empty: "omit",
|
|
18575
|
+
companions: [NOW$2]
|
|
18576
|
+
}),
|
|
18577
|
+
numeric({
|
|
18578
|
+
id: "energy",
|
|
18579
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18580
|
+
role: DeviceRole.EnergySensor,
|
|
18581
|
+
outputCap: "power-meter",
|
|
18582
|
+
outputField: "kwhTotal",
|
|
18583
|
+
quantity: "energy",
|
|
18584
|
+
defaultAggregate: "sum",
|
|
18585
|
+
empty: "omit",
|
|
18586
|
+
companions: [NOW$2]
|
|
18587
|
+
}),
|
|
18588
|
+
numeric({
|
|
18589
|
+
id: "battery",
|
|
18590
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18591
|
+
role: DeviceRole.BatterySensor,
|
|
18592
|
+
outputCap: "battery",
|
|
18593
|
+
outputField: "percentage",
|
|
18594
|
+
quantity: "percentage",
|
|
18595
|
+
defaultAggregate: "mean",
|
|
18596
|
+
empty: "null",
|
|
18597
|
+
companions: [
|
|
18598
|
+
{
|
|
18599
|
+
fieldPath: "charging",
|
|
18600
|
+
expr: "\"unknown\""
|
|
18601
|
+
},
|
|
18602
|
+
{
|
|
18603
|
+
fieldPath: "sleeping",
|
|
18604
|
+
expr: "false"
|
|
18605
|
+
},
|
|
18606
|
+
{
|
|
18607
|
+
fieldPath: "lastUpdated",
|
|
18608
|
+
expr: "now"
|
|
18609
|
+
}
|
|
18610
|
+
]
|
|
18611
|
+
}),
|
|
18612
|
+
numeric({
|
|
18613
|
+
id: "numeric",
|
|
18614
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18615
|
+
role: DeviceRole.NumericSensor,
|
|
18616
|
+
outputCap: "numeric-sensor",
|
|
18617
|
+
outputField: "value",
|
|
18618
|
+
quantity: "device",
|
|
18619
|
+
defaultAggregate: "mean",
|
|
18620
|
+
empty: "null",
|
|
18621
|
+
companions: [NOW$2]
|
|
18622
|
+
}),
|
|
18623
|
+
binary({
|
|
18624
|
+
id: "motion",
|
|
18625
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18626
|
+
role: DeviceRole.MotionSensor,
|
|
18627
|
+
outputCap: "motion",
|
|
18628
|
+
outputField: "detected",
|
|
18629
|
+
defaultAggregate: "any",
|
|
18630
|
+
accept: [{
|
|
18631
|
+
cap: "motion",
|
|
18632
|
+
fieldPath: "detected"
|
|
18633
|
+
}],
|
|
18634
|
+
companions: [{
|
|
18635
|
+
fieldPath: "lastDetectedAt",
|
|
18636
|
+
expr: "null"
|
|
18637
|
+
}, {
|
|
18638
|
+
fieldPath: "autoClearAfterMs",
|
|
18639
|
+
expr: "null"
|
|
18640
|
+
}]
|
|
18641
|
+
}),
|
|
18642
|
+
binary({
|
|
18643
|
+
id: "contact",
|
|
18644
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18645
|
+
role: DeviceRole.ContactSensor,
|
|
18646
|
+
outputCap: "contact",
|
|
18647
|
+
outputField: "entryOpen",
|
|
18648
|
+
defaultAggregate: "any",
|
|
18649
|
+
accept: [{
|
|
18650
|
+
cap: "contact",
|
|
18651
|
+
fieldPath: "entryOpen"
|
|
18652
|
+
}],
|
|
18653
|
+
companions: [CHANGED]
|
|
18654
|
+
}),
|
|
18655
|
+
binary({
|
|
18656
|
+
id: "leak",
|
|
18657
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18658
|
+
role: DeviceRole.LeakSensor,
|
|
18659
|
+
outputCap: "flood",
|
|
18660
|
+
outputField: "flooded",
|
|
18661
|
+
defaultAggregate: "any",
|
|
18662
|
+
accept: [{
|
|
18663
|
+
cap: "flood",
|
|
18664
|
+
fieldPath: "flooded"
|
|
18665
|
+
}],
|
|
18666
|
+
companions: [CHANGED]
|
|
18667
|
+
}),
|
|
18668
|
+
binary({
|
|
18669
|
+
id: "smoke",
|
|
18670
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18671
|
+
role: DeviceRole.SmokeSensor,
|
|
18672
|
+
outputCap: "smoke",
|
|
18673
|
+
outputField: "detected",
|
|
18674
|
+
defaultAggregate: "any",
|
|
18675
|
+
accept: [{
|
|
18676
|
+
cap: "smoke",
|
|
18677
|
+
fieldPath: "detected"
|
|
18678
|
+
}],
|
|
18679
|
+
companions: [CHANGED]
|
|
18680
|
+
}),
|
|
18681
|
+
binary({
|
|
18682
|
+
id: "occupancy",
|
|
18683
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18684
|
+
role: DeviceRole.BinarySensor,
|
|
18685
|
+
outputCap: "binary",
|
|
18686
|
+
outputField: "on",
|
|
18687
|
+
defaultAggregate: "any",
|
|
18688
|
+
accept: [{
|
|
18689
|
+
cap: "motion",
|
|
18690
|
+
fieldPath: "detected"
|
|
18691
|
+
}, {
|
|
18692
|
+
cap: "binary",
|
|
18693
|
+
fieldPath: "on"
|
|
18694
|
+
}],
|
|
18695
|
+
companions: [CHANGED]
|
|
18696
|
+
}),
|
|
18697
|
+
binary({
|
|
18698
|
+
id: "binary",
|
|
18699
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18700
|
+
role: DeviceRole.BinarySensor,
|
|
18701
|
+
outputCap: "binary",
|
|
18702
|
+
outputField: "on",
|
|
18703
|
+
defaultAggregate: "any",
|
|
18704
|
+
accept: [{
|
|
18705
|
+
cap: "binary",
|
|
18706
|
+
fieldPath: "on"
|
|
18707
|
+
}],
|
|
18708
|
+
companions: [CHANGED]
|
|
18709
|
+
}),
|
|
18710
|
+
actuator({
|
|
18711
|
+
id: "switch",
|
|
18712
|
+
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.",
|
|
18713
|
+
deviceType: DeviceType.Switch,
|
|
18714
|
+
outputCap: "switch",
|
|
18715
|
+
outputField: "on",
|
|
18716
|
+
member: {
|
|
18717
|
+
cap: "switch",
|
|
18718
|
+
fieldPath: "on"
|
|
18719
|
+
},
|
|
18720
|
+
commandCaps: ["switch"]
|
|
18721
|
+
}),
|
|
18722
|
+
actuator({
|
|
18723
|
+
id: "light",
|
|
18724
|
+
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.",
|
|
18725
|
+
deviceType: DeviceType.Light,
|
|
18726
|
+
outputCap: "switch",
|
|
18727
|
+
outputField: "on",
|
|
18728
|
+
member: {
|
|
18729
|
+
cap: "switch",
|
|
18730
|
+
fieldPath: "on"
|
|
18731
|
+
},
|
|
18732
|
+
commandCaps: [
|
|
18733
|
+
"switch",
|
|
18734
|
+
"brightness",
|
|
18735
|
+
"color"
|
|
18736
|
+
]
|
|
18737
|
+
}),
|
|
18738
|
+
actuator({
|
|
18739
|
+
id: "fan",
|
|
18740
|
+
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.",
|
|
18741
|
+
deviceType: DeviceType.Fan,
|
|
18742
|
+
outputCap: "switch",
|
|
18743
|
+
outputField: "on",
|
|
18744
|
+
member: {
|
|
18745
|
+
cap: "switch",
|
|
18746
|
+
fieldPath: "on"
|
|
18747
|
+
},
|
|
18748
|
+
commandCaps: ["switch", "fan-control"]
|
|
18749
|
+
}),
|
|
18750
|
+
actuator({
|
|
18751
|
+
id: "cover",
|
|
18752
|
+
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.",
|
|
18753
|
+
deviceType: DeviceType.Cover,
|
|
18754
|
+
outputCap: "group-active",
|
|
18755
|
+
outputField: "active",
|
|
18756
|
+
member: {
|
|
18757
|
+
cap: "cover",
|
|
18758
|
+
fieldPath: "state"
|
|
18759
|
+
},
|
|
18760
|
+
activeWhen: [
|
|
18761
|
+
"open",
|
|
18762
|
+
"opening",
|
|
18763
|
+
"stopped"
|
|
18764
|
+
],
|
|
18765
|
+
commandCaps: ["cover"]
|
|
18766
|
+
}),
|
|
18767
|
+
actuator({
|
|
18768
|
+
id: "valve",
|
|
18769
|
+
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.",
|
|
18770
|
+
deviceType: DeviceType.Valve,
|
|
18771
|
+
outputCap: "group-active",
|
|
18772
|
+
outputField: "active",
|
|
18773
|
+
member: {
|
|
18774
|
+
cap: "valve",
|
|
18775
|
+
fieldPath: "state"
|
|
18776
|
+
},
|
|
18777
|
+
activeWhen: [
|
|
18778
|
+
"open",
|
|
18779
|
+
"opening",
|
|
18780
|
+
"stopped"
|
|
18781
|
+
],
|
|
18782
|
+
commandCaps: ["valve"]
|
|
18783
|
+
}),
|
|
18784
|
+
actuator({
|
|
18785
|
+
id: "lock",
|
|
18786
|
+
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.",
|
|
18787
|
+
deviceType: DeviceType.Lock,
|
|
18788
|
+
outputCap: "group-active",
|
|
18789
|
+
outputField: "active",
|
|
18790
|
+
member: {
|
|
18791
|
+
cap: "lock-control",
|
|
18792
|
+
fieldPath: "state"
|
|
18793
|
+
},
|
|
18794
|
+
activeWhen: ["locked"],
|
|
18795
|
+
commandCaps: ["lock-control"]
|
|
18796
|
+
}),
|
|
18797
|
+
actuator({
|
|
18798
|
+
id: "media-player",
|
|
18799
|
+
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.",
|
|
18800
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18801
|
+
outputCap: "group-active",
|
|
18802
|
+
outputField: "active",
|
|
18803
|
+
member: {
|
|
18804
|
+
cap: "media-player",
|
|
18805
|
+
fieldPath: "state"
|
|
18806
|
+
},
|
|
18807
|
+
activeWhen: ["playing", "buffering"],
|
|
18808
|
+
commandCaps: ["media-player"]
|
|
18809
|
+
}),
|
|
18810
|
+
actuator({
|
|
18811
|
+
id: "climate",
|
|
18812
|
+
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.",
|
|
18813
|
+
deviceType: DeviceType.Thermostat,
|
|
18814
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18815
|
+
outputCap: "group-active",
|
|
18816
|
+
outputField: "active",
|
|
18817
|
+
member: {
|
|
18818
|
+
cap: "climate-control",
|
|
18819
|
+
fieldPath: "mode"
|
|
18820
|
+
},
|
|
18821
|
+
activeWhen: [
|
|
18822
|
+
"heat",
|
|
18823
|
+
"cool",
|
|
18824
|
+
"auto",
|
|
18825
|
+
"heat_cool",
|
|
18826
|
+
"fan_only",
|
|
18827
|
+
"dry"
|
|
18828
|
+
],
|
|
18829
|
+
commandCaps: ["climate-control"]
|
|
18830
|
+
})
|
|
18831
|
+
];
|
|
18832
|
+
function actuator(input) {
|
|
18833
|
+
return {
|
|
18834
|
+
id: input.id,
|
|
18835
|
+
summary: input.summary,
|
|
18836
|
+
deviceType: input.deviceType,
|
|
18837
|
+
outputCap: input.outputCap,
|
|
18838
|
+
outputField: input.outputField,
|
|
18839
|
+
commandCaps: input.commandCaps,
|
|
18840
|
+
family: "actuator",
|
|
18841
|
+
role: void 0,
|
|
18842
|
+
memberDeviceType: input.deviceType,
|
|
18843
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18844
|
+
activeWhen: input.activeWhen,
|
|
18845
|
+
quantity: "none",
|
|
18846
|
+
baseUnit: void 0,
|
|
18847
|
+
aggregates: BINARY_AGGREGATES,
|
|
18848
|
+
defaultAggregate: "any",
|
|
18849
|
+
empty: "offline",
|
|
18850
|
+
accept: [input.member],
|
|
18851
|
+
companions: [CHANGED]
|
|
18852
|
+
};
|
|
18853
|
+
}
|
|
18854
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18855
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18856
|
+
DeviceType.Camera;
|
|
18131
18857
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18132
18858
|
/**
|
|
18133
18859
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19841,12 +20567,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
19841
20567
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19842
20568
|
* in-place so dispatch keeps working.
|
|
19843
20569
|
*
|
|
19844
|
-
* **
|
|
19845
|
-
*
|
|
19846
|
-
*
|
|
19847
|
-
*
|
|
19848
|
-
* (`ha-domain-mapping`)
|
|
19849
|
-
* stored after that point.
|
|
20570
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20571
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20572
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20573
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20574
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20575
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19850
20576
|
*
|
|
19851
20577
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19852
20578
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19860,6 +20586,14 @@ var SourceInfoSchema = object({
|
|
|
19860
20586
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19861
20587
|
* Used to detect rename when `id` changes. */
|
|
19862
20588
|
uniqueId: string().optional(),
|
|
20589
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20590
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20591
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20592
|
+
dateTimeShape: _enum([
|
|
20593
|
+
"date",
|
|
20594
|
+
"time",
|
|
20595
|
+
"datetime"
|
|
20596
|
+
]).optional(),
|
|
19863
20597
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19864
20598
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19865
20599
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -40981,7 +41715,8 @@ method(object({
|
|
|
40981
41715
|
"enum"
|
|
40982
41716
|
]),
|
|
40983
41717
|
enumValues: array(string()).optional(),
|
|
40984
|
-
item: boolean().optional()
|
|
41718
|
+
item: boolean().optional(),
|
|
41719
|
+
quantity: ReadingQuantitySchema.optional()
|
|
40985
41720
|
})).readonly(),
|
|
40986
41721
|
itemArray: object({
|
|
40987
41722
|
path: string(),
|
|
@@ -43342,7 +44077,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43342
44077
|
});
|
|
43343
44078
|
/**
|
|
43344
44079
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43345
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44080
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43346
44081
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43347
44082
|
* the originating provider config (mode + sourcePort) so the
|
|
43348
44083
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44825,8 +45560,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44825
45560
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44826
45561
|
var MaskGridShapeSchema = object({
|
|
44827
45562
|
kind: literal("grid"),
|
|
44828
|
-
gridWidth: number(),
|
|
44829
|
-
gridHeight: number(),
|
|
45563
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45564
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44830
45565
|
cells: array(boolean())
|
|
44831
45566
|
});
|
|
44832
45567
|
discriminatedUnion("kind", [
|
|
@@ -44938,6 +45673,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44938
45673
|
"detection-blind",
|
|
44939
45674
|
"motion-noisy",
|
|
44940
45675
|
"motion-calm",
|
|
45676
|
+
"package-llm-silent",
|
|
45677
|
+
"package-llm-answered",
|
|
44941
45678
|
"recording-stalled",
|
|
44942
45679
|
"recording-healthy",
|
|
44943
45680
|
"recording-degraded",
|
|
@@ -46027,7 +46764,20 @@ var NcRuleInputSchema = object({
|
|
|
46027
46764
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46028
46765
|
* path does not run Zod defaults.
|
|
46029
46766
|
*/
|
|
46030
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46767
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46768
|
+
/**
|
|
46769
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46770
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46771
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46772
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46773
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46774
|
+
*
|
|
46775
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46776
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46777
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46778
|
+
* `false`, so it needs no `clear` key.
|
|
46779
|
+
*/
|
|
46780
|
+
askVerdict: boolean().optional()
|
|
46031
46781
|
});
|
|
46032
46782
|
/**
|
|
46033
46783
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56133,6 +56883,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56133
56883
|
deprecated: string().optional(),
|
|
56134
56884
|
distTags: array(string()).readonly()
|
|
56135
56885
|
});
|
|
56886
|
+
/**
|
|
56887
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56888
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56889
|
+
* tarball failure — never an empty string standing in for either.
|
|
56890
|
+
*/
|
|
56891
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56892
|
+
object({
|
|
56893
|
+
status: literal("ok"),
|
|
56894
|
+
markdown: string()
|
|
56895
|
+
}),
|
|
56896
|
+
object({ status: literal("missing") }),
|
|
56897
|
+
object({
|
|
56898
|
+
status: literal("error"),
|
|
56899
|
+
message: string()
|
|
56900
|
+
})
|
|
56901
|
+
]);
|
|
56902
|
+
var PackageDocsSchema = object({
|
|
56903
|
+
name: string(),
|
|
56904
|
+
version: string(),
|
|
56905
|
+
readme: PackageDocBodySchema,
|
|
56906
|
+
changelog: PackageDocBodySchema
|
|
56907
|
+
});
|
|
56136
56908
|
var SearchResultSchema = object({
|
|
56137
56909
|
name: string(),
|
|
56138
56910
|
version: string(),
|
|
@@ -56351,7 +57123,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56351
57123
|
}), object({ success: literal(true) }), {
|
|
56352
57124
|
kind: "mutation",
|
|
56353
57125
|
auth: "admin"
|
|
56354
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57126
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57127
|
+
name: string().min(1),
|
|
57128
|
+
version: string().min(1).optional()
|
|
57129
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56355
57130
|
kind: "mutation",
|
|
56356
57131
|
auth: "admin"
|
|
56357
57132
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56410,27 +57185,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56410
57185
|
*/
|
|
56411
57186
|
var AirQualitySensorStatusSchema = object({
|
|
56412
57187
|
/** Carbon dioxide concentration in ppm. */
|
|
56413
|
-
co2Ppm: number().min(0).optional(),
|
|
57188
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56414
57189
|
/** Total volatile organic compounds in ppb. */
|
|
56415
|
-
vocPpb: number().min(0).optional(),
|
|
57190
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56416
57191
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56417
|
-
pm25: number().min(0).optional(),
|
|
57192
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56418
57193
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56419
|
-
pm10: number().min(0).optional(),
|
|
57194
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56420
57195
|
/** Composite AQI value (typically 0..500). */
|
|
56421
|
-
aqi: number().optional(),
|
|
57196
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56422
57197
|
/** Ms epoch when the slice was last updated. */
|
|
56423
|
-
lastFetchedAt: number()
|
|
56424
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56425
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56426
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56427
|
-
* per slice is unambiguous. */
|
|
56428
|
-
unit: string().optional(),
|
|
56429
|
-
/** Suggested decimal places for numeric display.
|
|
56430
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56431
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56432
|
-
* auto-formatting when absent. */
|
|
56433
|
-
precision: number().int().min(0).max(10).optional()
|
|
57198
|
+
lastFetchedAt: number()
|
|
56434
57199
|
});
|
|
56435
57200
|
var airQualitySensorCapability = {
|
|
56436
57201
|
name: "air-quality-sensor",
|
|
@@ -56467,12 +57232,12 @@ var airQualitySensorCapability = {
|
|
|
56467
57232
|
},
|
|
56468
57233
|
pm25: {
|
|
56469
57234
|
kind: "gauge",
|
|
56470
|
-
unit: "
|
|
57235
|
+
unit: "µg/m³",
|
|
56471
57236
|
deadband: 1
|
|
56472
57237
|
},
|
|
56473
57238
|
pm10: {
|
|
56474
57239
|
kind: "gauge",
|
|
56475
|
-
unit: "
|
|
57240
|
+
unit: "µg/m³",
|
|
56476
57241
|
deadband: 1
|
|
56477
57242
|
},
|
|
56478
57243
|
aqi: {
|
|
@@ -56490,22 +57255,13 @@ var airQualitySensorCapability = {
|
|
|
56490
57255
|
* entries with `device_class: illuminance`.
|
|
56491
57256
|
*/
|
|
56492
57257
|
var AmbientLightSensorStatusSchema = object({
|
|
56493
|
-
/** Current illuminance in lux (lx). */
|
|
56494
|
-
lux: number().min(0).meta({
|
|
56495
|
-
|
|
57258
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57259
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57260
|
+
precision: 0,
|
|
56496
57261
|
label: "Illuminance"
|
|
56497
|
-
}),
|
|
57262
|
+
})),
|
|
56498
57263
|
/** Ms epoch when the slice was last updated. */
|
|
56499
|
-
lastFetchedAt: number()
|
|
56500
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56501
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56502
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56503
|
-
unit: string().optional(),
|
|
56504
|
-
/** Suggested decimal places for numeric display.
|
|
56505
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56506
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56507
|
-
* auto-formatting when absent. */
|
|
56508
|
-
precision: number().int().min(0).max(10).optional()
|
|
57264
|
+
lastFetchedAt: number()
|
|
56509
57265
|
});
|
|
56510
57266
|
var ambientLightSensorCapability = {
|
|
56511
57267
|
name: "ambient-light-sensor",
|
|
@@ -56537,12 +57293,7 @@ var ambientLightSensorCapability = {
|
|
|
56537
57293
|
} } },
|
|
56538
57294
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56539
57295
|
* whether persisting is worth a SQLite commit. */
|
|
56540
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56541
|
-
customize: {
|
|
56542
|
-
version: 1,
|
|
56543
|
-
advanced: "derive",
|
|
56544
|
-
targets: []
|
|
56545
|
-
}
|
|
57296
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56546
57297
|
};
|
|
56547
57298
|
/**
|
|
56548
57299
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56769,10 +57520,7 @@ var BatteryStatusSchema = object({
|
|
|
56769
57520
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56770
57521
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56771
57522
|
*/
|
|
56772
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56773
|
-
unit: "%",
|
|
56774
|
-
label: "Charge"
|
|
56775
|
-
}),
|
|
57523
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56776
57524
|
/**
|
|
56777
57525
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56778
57526
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56799,7 +57547,14 @@ var BatteryStatusSchema = object({
|
|
|
56799
57547
|
*/
|
|
56800
57548
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56801
57549
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56802
|
-
lastUpdated: number(),
|
|
57550
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57551
|
+
/**
|
|
57552
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57553
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57554
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57555
|
+
* `numeric-sensor` on the same device.
|
|
57556
|
+
*/
|
|
57557
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56803
57558
|
/**
|
|
56804
57559
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56805
57560
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56846,12 +57601,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56846
57601
|
DeviceType.Switch,
|
|
56847
57602
|
DeviceType.PetFeeder,
|
|
56848
57603
|
DeviceType.Container,
|
|
56849
|
-
DeviceType.Thermostat
|
|
57604
|
+
DeviceType.Thermostat,
|
|
57605
|
+
DeviceType.EventEmitter
|
|
56850
57606
|
];
|
|
56851
57607
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56852
57608
|
var batteryCustomize = {
|
|
56853
57609
|
version: 1,
|
|
56854
|
-
advanced: "derive",
|
|
56855
57610
|
targets: [{
|
|
56856
57611
|
id: "percentage",
|
|
56857
57612
|
cardinality: "scalar",
|
|
@@ -56860,7 +57615,7 @@ var batteryCustomize = {
|
|
|
56860
57615
|
stateField: "percentage"
|
|
56861
57616
|
},
|
|
56862
57617
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56863
|
-
apply: "add
|
|
57618
|
+
apply: "add",
|
|
56864
57619
|
path: "percentage",
|
|
56865
57620
|
sources: [{
|
|
56866
57621
|
kind: "field",
|
|
@@ -56981,10 +57736,16 @@ onStatusChanged: { data: object({
|
|
|
56981
57736
|
/**
|
|
56982
57737
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
56983
57738
|
*/
|
|
56984
|
-
history: { fields: {
|
|
56985
|
-
|
|
56986
|
-
|
|
56987
|
-
|
|
57739
|
+
history: { fields: {
|
|
57740
|
+
percentage: {
|
|
57741
|
+
kind: "gauge",
|
|
57742
|
+
unit: "%"
|
|
57743
|
+
},
|
|
57744
|
+
volts: {
|
|
57745
|
+
kind: "gauge",
|
|
57746
|
+
unit: "V"
|
|
57747
|
+
}
|
|
57748
|
+
} },
|
|
56988
57749
|
customize: batteryCustomize,
|
|
56989
57750
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56990
57751
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57031,12 +57792,7 @@ var binaryCapability = {
|
|
|
57031
57792
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57032
57793
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57033
57794
|
* whether persisting is worth a SQLite commit. */
|
|
57034
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57035
|
-
customize: {
|
|
57036
|
-
version: 1,
|
|
57037
|
-
advanced: "derive",
|
|
57038
|
-
targets: []
|
|
57039
|
-
}
|
|
57795
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57040
57796
|
};
|
|
57041
57797
|
/**
|
|
57042
57798
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57052,7 +57808,7 @@ var binaryCapability = {
|
|
|
57052
57808
|
*/
|
|
57053
57809
|
var BrightnessStatusSchema = object({
|
|
57054
57810
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57055
|
-
percentage: number().min(0).max(100),
|
|
57811
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57056
57812
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57057
57813
|
lastChangedAt: number()
|
|
57058
57814
|
});
|
|
@@ -57506,21 +58262,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57506
58262
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57507
58263
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57508
58264
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57509
|
-
target: number().nullable(),
|
|
58265
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57510
58266
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57511
58267
|
* in `heat_cool` mode. */
|
|
57512
|
-
targetHigh: number().nullable(),
|
|
58268
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57513
58269
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57514
58270
|
* in `heat_cool` mode. */
|
|
57515
|
-
targetLow: number().nullable(),
|
|
58271
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57516
58272
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57517
58273
|
* humidity control. */
|
|
57518
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58274
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57519
58275
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57520
58276
|
* the device's internal sensor. */
|
|
57521
|
-
currentTemp: number().nullable(),
|
|
58277
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57522
58278
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57523
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58279
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57524
58280
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57525
58281
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57526
58282
|
swingVertical: boolean().nullable(),
|
|
@@ -57528,11 +58284,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57528
58284
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57529
58285
|
swingHorizontal: boolean().nullable(),
|
|
57530
58286
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57531
|
-
minTemp: number().nullable().optional(),
|
|
58287
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57532
58288
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57533
|
-
maxTemp: number().nullable().optional(),
|
|
58289
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57534
58290
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57535
|
-
tempStep: number().positive().nullable().optional(),
|
|
58291
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57536
58292
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57537
58293
|
lastFetchedAt: number()
|
|
57538
58294
|
});
|
|
@@ -57674,17 +58430,17 @@ var climateControlCapability = {
|
|
|
57674
58430
|
* modes to expose in the picker without a slice fetch.
|
|
57675
58431
|
*/
|
|
57676
58432
|
var RgbTripletSchema = object({
|
|
57677
|
-
r: number().int().min(0).max(255),
|
|
57678
|
-
g: number().int().min(0).max(255),
|
|
57679
|
-
b: number().int().min(0).max(255)
|
|
58433
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58434
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58435
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57680
58436
|
});
|
|
57681
58437
|
var HsvTripletSchema = object({
|
|
57682
58438
|
/** Hue in degrees, 0..360. */
|
|
57683
|
-
h: number().min(0).max(360),
|
|
58439
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57684
58440
|
/** Saturation as 0..100 inclusive. */
|
|
57685
|
-
s: number().min(0).max(100),
|
|
58441
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57686
58442
|
/** Value/brightness as 0..100 inclusive. */
|
|
57687
|
-
v: number().min(0).max(100)
|
|
58443
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57688
58444
|
});
|
|
57689
58445
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57690
58446
|
object({
|
|
@@ -57713,7 +58469,7 @@ var ColorStatusSchema = object({
|
|
|
57713
58469
|
/** Populated when `mode === 'hsv'`. */
|
|
57714
58470
|
hsv: HsvTripletSchema.optional(),
|
|
57715
58471
|
/** Populated when `mode === 'mired'`. */
|
|
57716
|
-
mireds: number().int().optional(),
|
|
58472
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57717
58473
|
/** Ms epoch of the last operator-driven change. */
|
|
57718
58474
|
lastChangedAt: number()
|
|
57719
58475
|
});
|
|
@@ -57916,18 +58672,12 @@ _enum([
|
|
|
57916
58672
|
"empty",
|
|
57917
58673
|
"full"
|
|
57918
58674
|
]);
|
|
57919
|
-
/**
|
|
57920
|
-
|
|
57921
|
-
|
|
57922
|
-
"days",
|
|
57923
|
-
"hours",
|
|
57924
|
-
"cycles"
|
|
57925
|
-
]);
|
|
57926
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57927
|
-
* days). `value` null = unknown (D393). */
|
|
58675
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58676
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58677
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57928
58678
|
var ConsumableRemainingSchema = object({
|
|
57929
|
-
value: number().min(0).nullable(),
|
|
57930
|
-
|
|
58679
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58680
|
+
kind: ConsumableRemainingKindSchema
|
|
57931
58681
|
});
|
|
57932
58682
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
57933
58683
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -57940,7 +58690,7 @@ var ConsumableItemSchema = object({
|
|
|
57940
58690
|
/** Display name. */
|
|
57941
58691
|
label: string().min(1),
|
|
57942
58692
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57943
|
-
level: number().min(0).max(100).nullable(),
|
|
58693
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57944
58694
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57945
58695
|
status: ConsumableStatusSchema.nullable(),
|
|
57946
58696
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58022,8 +58772,8 @@ var consumablesCustomize = {
|
|
|
58022
58772
|
transforms: [{ kind: "identity" }]
|
|
58023
58773
|
}],
|
|
58024
58774
|
literals: [{
|
|
58025
|
-
path: "remaining.
|
|
58026
|
-
values: [...
|
|
58775
|
+
path: "remaining.kind",
|
|
58776
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58027
58777
|
}]
|
|
58028
58778
|
},
|
|
58029
58779
|
{
|
|
@@ -58152,7 +58902,6 @@ reset: method(object({
|
|
|
58152
58902
|
},
|
|
58153
58903
|
"remaining.value": {
|
|
58154
58904
|
kind: "gauge",
|
|
58155
|
-
unitFrom: "remaining.unit",
|
|
58156
58905
|
deadband: 1,
|
|
58157
58906
|
displayName: "Remaining"
|
|
58158
58907
|
}
|
|
@@ -58222,10 +58971,9 @@ var contactCapability = {
|
|
|
58222
58971
|
* (empty array for the other kinds). It lives in the slice because
|
|
58223
58972
|
* HA `select.*` entities may update their options at runtime.
|
|
58224
58973
|
*
|
|
58225
|
-
*
|
|
58226
|
-
*
|
|
58227
|
-
*
|
|
58228
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
58974
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
58975
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
58976
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58229
58977
|
*/
|
|
58230
58978
|
var ControlStatusSchema = object({
|
|
58231
58979
|
kind: _enum([
|
|
@@ -58237,39 +58985,17 @@ var ControlStatusSchema = object({
|
|
|
58237
58985
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58238
58986
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58239
58987
|
* or time-only — HA accepts all three forms). */
|
|
58240
|
-
value: union([number(), string()]),
|
|
58988
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58241
58989
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58242
58990
|
options: array(string()),
|
|
58243
58991
|
/** Ms epoch when the slice was last updated. */
|
|
58244
58992
|
lastChangedAt: number(),
|
|
58245
|
-
/**
|
|
58246
|
-
|
|
58247
|
-
|
|
58248
|
-
|
|
58249
|
-
/**
|
|
58250
|
-
|
|
58251
|
-
min: number().optional(),
|
|
58252
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58253
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58254
|
-
max: number().optional(),
|
|
58255
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58256
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58257
|
-
step: number().optional(),
|
|
58258
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58259
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58260
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58261
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58262
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58263
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58264
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58265
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58266
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58267
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58268
|
-
format: _enum([
|
|
58269
|
-
"date",
|
|
58270
|
-
"time",
|
|
58271
|
-
"datetime"
|
|
58272
|
-
]).optional()
|
|
58993
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58994
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58995
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58996
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58997
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58998
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58273
58999
|
});
|
|
58274
59000
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58275
59001
|
object({
|
|
@@ -58335,9 +59061,9 @@ var CoverStatusSchema = object({
|
|
|
58335
59061
|
]),
|
|
58336
59062
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58337
59063
|
* no intermediate position surface. */
|
|
58338
|
-
position: number().min(0).max(100).nullable(),
|
|
59064
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58339
59065
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58340
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59066
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58341
59067
|
/** Ms epoch when the slice was last updated. */
|
|
58342
59068
|
lastChangedAt: number()
|
|
58343
59069
|
});
|
|
@@ -58440,9 +59166,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58440
59166
|
var DayNightStatusSchema = object({
|
|
58441
59167
|
mode: DayNightModeSchema,
|
|
58442
59168
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58443
|
-
sensitivity: number().optional(),
|
|
59169
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58444
59170
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58445
|
-
switchDelaySec: number().optional(),
|
|
59171
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58446
59172
|
lastFetchedAt: number()
|
|
58447
59173
|
});
|
|
58448
59174
|
/**
|
|
@@ -58660,11 +59386,11 @@ var DishwasherStatusSchema = object({
|
|
|
58660
59386
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58661
59387
|
availablePrograms: array(string()),
|
|
58662
59388
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58663
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59389
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58664
59390
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58665
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59391
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58666
59392
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58667
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59393
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58668
59394
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58669
59395
|
doorOpen: boolean().nullable(),
|
|
58670
59396
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58688,7 +59414,7 @@ var DishwasherStatusSchema = object({
|
|
|
58688
59414
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58689
59415
|
machineCareDue: boolean().nullable(),
|
|
58690
59416
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58691
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59417
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58692
59418
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58693
59419
|
halfLoad: boolean().nullable(),
|
|
58694
59420
|
hygienePlus: boolean().nullable(),
|
|
@@ -58703,7 +59429,7 @@ var DishwasherStatusSchema = object({
|
|
|
58703
59429
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58704
59430
|
activeEvents: array(string()),
|
|
58705
59431
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58706
|
-
errorCode: number().nullable(),
|
|
59432
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58707
59433
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58708
59434
|
errorLabel: string().nullable(),
|
|
58709
59435
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58934,7 +59660,7 @@ var DoorbellStatusSchema = object({
|
|
|
58934
59660
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58935
59661
|
lastPressedAt: number().nullable(),
|
|
58936
59662
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58937
|
-
pressCountSinceStart: number()
|
|
59663
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58938
59664
|
});
|
|
58939
59665
|
var DoorbellPressEventSchema = object({
|
|
58940
59666
|
deviceId: number(),
|
|
@@ -58999,17 +59725,7 @@ onPressed: {
|
|
|
58999
59725
|
history: "none",
|
|
59000
59726
|
customize: doorbellCustomize
|
|
59001
59727
|
};
|
|
59002
|
-
|
|
59003
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
59004
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
59005
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
59006
|
-
* The option set is stable across observations; it is persisted in the
|
|
59007
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
59008
|
-
* stored in `sourceInfo`.
|
|
59009
|
-
*/
|
|
59010
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
59011
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
59012
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
59728
|
+
_enum([
|
|
59013
59729
|
"date",
|
|
59014
59730
|
"time",
|
|
59015
59731
|
"datetime"
|
|
@@ -59017,12 +59733,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59017
59733
|
var EnumSensorStatusSchema = object({
|
|
59018
59734
|
value: string(),
|
|
59019
59735
|
/**
|
|
59020
|
-
* Set
|
|
59021
|
-
* as
|
|
59022
|
-
*
|
|
59023
|
-
* a time-only sensor → `'time'`.
|
|
59736
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
59737
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
59738
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59024
59739
|
*/
|
|
59025
|
-
|
|
59740
|
+
timestamp: boolean().optional(),
|
|
59026
59741
|
/** Ms epoch when the slice was last updated. */
|
|
59027
59742
|
lastFetchedAt: number()
|
|
59028
59743
|
});
|
|
@@ -59049,11 +59764,11 @@ var enumSensorCapability = {
|
|
|
59049
59764
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59050
59765
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59051
59766
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59052
|
-
* `
|
|
59767
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59053
59768
|
*/
|
|
59054
59769
|
history: { fields: { value: {
|
|
59055
59770
|
kind: "enum",
|
|
59056
|
-
skipWhenSet: "
|
|
59771
|
+
skipWhenSet: "timestamp"
|
|
59057
59772
|
} } },
|
|
59058
59773
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59059
59774
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59073,13 +59788,13 @@ var EventFireSchema = object({
|
|
|
59073
59788
|
deviceId: number(),
|
|
59074
59789
|
eventType: string(),
|
|
59075
59790
|
data: record(string(), unknown()).nullable(),
|
|
59076
|
-
timestamp: number(),
|
|
59077
|
-
seq: number()
|
|
59791
|
+
timestamp: number().meta(readingMeta("none")),
|
|
59792
|
+
seq: number().meta(readingMeta("count"))
|
|
59078
59793
|
});
|
|
59079
59794
|
var EventEmitterStatusSchema = object({
|
|
59080
59795
|
eventTypes: array(string()),
|
|
59081
59796
|
lastEvent: EventFireSchema.nullable(),
|
|
59082
|
-
eventCountSinceStart: number()
|
|
59797
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59083
59798
|
});
|
|
59084
59799
|
var eventEmitterCapability = {
|
|
59085
59800
|
name: "event-emitter",
|
|
@@ -59492,10 +60207,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59492
60207
|
var FanControlStatusSchema = object({
|
|
59493
60208
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59494
60209
|
* speed surface (single-speed fan). */
|
|
59495
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60210
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59496
60211
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59497
60212
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59498
|
-
percentageStep: number().positive().optional(),
|
|
60213
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59499
60214
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59500
60215
|
* — empty string when no preset is active or supported. */
|
|
59501
60216
|
preset: string(),
|
|
@@ -59616,7 +60331,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59616
60331
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59617
60332
|
model: string().nullable(),
|
|
59618
60333
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59619
|
-
channelCount: number().nullable(),
|
|
60334
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59620
60335
|
/**
|
|
59621
60336
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59622
60337
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59739,9 +60454,151 @@ var gasCapability = {
|
|
|
59739
60454
|
* whether persisting is worth a SQLite commit. */
|
|
59740
60455
|
volatileStateFields: ["lastChangedAt"]
|
|
59741
60456
|
};
|
|
60457
|
+
var GroupCommandsSchema = object({
|
|
60458
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60459
|
+
results: array(object({
|
|
60460
|
+
deviceId: number().int().nonnegative(),
|
|
60461
|
+
cap: string().min(1),
|
|
60462
|
+
method: string().min(1),
|
|
60463
|
+
ok: boolean(),
|
|
60464
|
+
error: string().optional(),
|
|
60465
|
+
/** Ms epoch of the attempt. */
|
|
60466
|
+
at: number()
|
|
60467
|
+
})) });
|
|
60468
|
+
var groupCommandsCapability = {
|
|
60469
|
+
name: "group-commands",
|
|
60470
|
+
scope: "device",
|
|
60471
|
+
deviceNative: true,
|
|
60472
|
+
mode: "singleton",
|
|
60473
|
+
deviceTypes: [
|
|
60474
|
+
DeviceType.Switch,
|
|
60475
|
+
DeviceType.Light,
|
|
60476
|
+
DeviceType.Fan,
|
|
60477
|
+
DeviceType.Cover,
|
|
60478
|
+
DeviceType.Valve,
|
|
60479
|
+
DeviceType.Lock,
|
|
60480
|
+
DeviceType.MediaPlayer,
|
|
60481
|
+
DeviceType.Thermostat,
|
|
60482
|
+
DeviceType.Climate
|
|
60483
|
+
],
|
|
60484
|
+
methods: {},
|
|
60485
|
+
status: {
|
|
60486
|
+
schema: GroupCommandsSchema,
|
|
60487
|
+
kind: "push"
|
|
60488
|
+
},
|
|
60489
|
+
runtimeState: GroupCommandsSchema,
|
|
60490
|
+
/**
|
|
60491
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
60492
|
+
* failure would outlive the command that caused it.
|
|
60493
|
+
*
|
|
60494
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60495
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60496
|
+
*/
|
|
60497
|
+
durability: "session",
|
|
60498
|
+
history: "none"
|
|
60499
|
+
};
|
|
60500
|
+
/**
|
|
60501
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
60502
|
+
* included member is, or every included member is. What "active" means is the
|
|
60503
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
60504
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
60505
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
60506
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
60507
|
+
* empty included set takes the device offline, never `active: false`.
|
|
60508
|
+
*/
|
|
60509
|
+
var GroupActiveSchema = object({
|
|
60510
|
+
active: boolean().meta({ label: "Active" }),
|
|
60511
|
+
/** Ms epoch when the slice was last updated. */
|
|
60512
|
+
lastChangedAt: number()
|
|
60513
|
+
});
|
|
60514
|
+
var groupActiveCapability = {
|
|
60515
|
+
name: "group-active",
|
|
60516
|
+
scope: "device",
|
|
60517
|
+
deviceNative: true,
|
|
60518
|
+
mode: "singleton",
|
|
60519
|
+
deviceTypes: [
|
|
60520
|
+
DeviceType.Cover,
|
|
60521
|
+
DeviceType.Valve,
|
|
60522
|
+
DeviceType.Lock,
|
|
60523
|
+
DeviceType.MediaPlayer,
|
|
60524
|
+
DeviceType.Climate,
|
|
60525
|
+
DeviceType.Thermostat
|
|
60526
|
+
],
|
|
60527
|
+
methods: {},
|
|
60528
|
+
status: {
|
|
60529
|
+
schema: GroupActiveSchema,
|
|
60530
|
+
kind: "push"
|
|
60531
|
+
},
|
|
60532
|
+
runtimeState: GroupActiveSchema,
|
|
60533
|
+
/**
|
|
60534
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
60535
|
+
* next source event; a restored value would outlive the members it named.
|
|
60536
|
+
*
|
|
60537
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60538
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60539
|
+
*/
|
|
60540
|
+
durability: "session",
|
|
60541
|
+
history: "none"
|
|
60542
|
+
};
|
|
60543
|
+
/**
|
|
60544
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60545
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60546
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60547
|
+
* series that later statistics read is the output cap's own history block.
|
|
60548
|
+
*/
|
|
60549
|
+
var GroupStatusSchema = object({
|
|
60550
|
+
/** Members whose current value entered the aggregate. */
|
|
60551
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60552
|
+
precision: 0,
|
|
60553
|
+
label: "Reporting"
|
|
60554
|
+
})),
|
|
60555
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60556
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60557
|
+
precision: 0,
|
|
60558
|
+
label: "Excluded"
|
|
60559
|
+
})),
|
|
60560
|
+
/** `included` + `excluded`. */
|
|
60561
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60562
|
+
precision: 0,
|
|
60563
|
+
label: "Members"
|
|
60564
|
+
}))
|
|
60565
|
+
});
|
|
60566
|
+
var groupStatusCapability = {
|
|
60567
|
+
name: "group-status",
|
|
60568
|
+
scope: "device",
|
|
60569
|
+
deviceNative: true,
|
|
60570
|
+
mode: "singleton",
|
|
60571
|
+
deviceTypes: [
|
|
60572
|
+
DeviceType.Sensor,
|
|
60573
|
+
DeviceType.Switch,
|
|
60574
|
+
DeviceType.Light,
|
|
60575
|
+
DeviceType.Fan,
|
|
60576
|
+
DeviceType.Cover,
|
|
60577
|
+
DeviceType.Valve,
|
|
60578
|
+
DeviceType.Lock,
|
|
60579
|
+
DeviceType.MediaPlayer,
|
|
60580
|
+
DeviceType.Thermostat,
|
|
60581
|
+
DeviceType.Climate
|
|
60582
|
+
],
|
|
60583
|
+
methods: {},
|
|
60584
|
+
status: {
|
|
60585
|
+
schema: GroupStatusSchema,
|
|
60586
|
+
kind: "push"
|
|
60587
|
+
},
|
|
60588
|
+
runtimeState: GroupStatusSchema,
|
|
60589
|
+
/**
|
|
60590
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60591
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60592
|
+
*
|
|
60593
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60594
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60595
|
+
*/
|
|
60596
|
+
durability: "session",
|
|
60597
|
+
history: "none"
|
|
60598
|
+
};
|
|
59742
60599
|
var HeatingValveStatusSchema = object({
|
|
59743
60600
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59744
|
-
position: number().min(0).max(100).nullable(),
|
|
60601
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59745
60602
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59746
60603
|
lastFetchedAt: number()
|
|
59747
60604
|
});
|
|
@@ -59784,9 +60641,9 @@ var HumidifierStatusSchema = object({
|
|
|
59784
60641
|
/** Whether the humidifier is currently on. */
|
|
59785
60642
|
on: boolean(),
|
|
59786
60643
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59787
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60644
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59788
60645
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59789
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60646
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59790
60647
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59791
60648
|
* device has no mode surface. */
|
|
59792
60649
|
mode: string().nullable(),
|
|
@@ -59796,9 +60653,9 @@ var HumidifierStatusSchema = object({
|
|
|
59796
60653
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59797
60654
|
action: string().nullable(),
|
|
59798
60655
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59799
|
-
minHumidity: number().nullable(),
|
|
60656
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59800
60657
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59801
|
-
maxHumidity: number().nullable(),
|
|
60658
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59802
60659
|
/** Ms epoch when the slice was last updated. */
|
|
59803
60660
|
lastChangedAt: number()
|
|
59804
60661
|
});
|
|
@@ -59868,22 +60725,13 @@ var humidifierCapability = {
|
|
|
59868
60725
|
* `sourceInfo`.
|
|
59869
60726
|
*/
|
|
59870
60727
|
var HumiditySensorStatusSchema = object({
|
|
59871
|
-
/** Current relative humidity, 0..100. */
|
|
59872
|
-
percent: number().min(0).max(100).meta({
|
|
59873
|
-
|
|
60728
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60729
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60730
|
+
precision: 0,
|
|
59874
60731
|
label: "Humidity"
|
|
59875
|
-
}),
|
|
60732
|
+
})),
|
|
59876
60733
|
/** Ms epoch when the slice was last updated. */
|
|
59877
|
-
lastFetchedAt: number()
|
|
59878
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59879
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59880
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59881
|
-
unit: string().optional(),
|
|
59882
|
-
/** Suggested decimal places for numeric display.
|
|
59883
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59884
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59885
|
-
* auto-formatting when absent. */
|
|
59886
|
-
precision: number().int().min(0).max(10).optional()
|
|
60734
|
+
lastFetchedAt: number()
|
|
59887
60735
|
});
|
|
59888
60736
|
var humiditySensorCapability = {
|
|
59889
60737
|
name: "humidity-sensor",
|
|
@@ -59914,12 +60762,7 @@ var humiditySensorCapability = {
|
|
|
59914
60762
|
} } },
|
|
59915
60763
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59916
60764
|
* whether persisting is worth a SQLite commit. */
|
|
59917
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
59918
|
-
customize: {
|
|
59919
|
-
version: 1,
|
|
59920
|
-
advanced: "derive",
|
|
59921
|
-
targets: []
|
|
59922
|
-
}
|
|
60765
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
59923
60766
|
};
|
|
59924
60767
|
/**
|
|
59925
60768
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -59940,7 +60783,7 @@ var ImageStatusSchema = object({
|
|
|
59940
60783
|
* entity exposes no `entity_picture` (yet). */
|
|
59941
60784
|
url: string().nullable(),
|
|
59942
60785
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
59943
|
-
lastUpdated: number().nullable()
|
|
60786
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
59944
60787
|
});
|
|
59945
60788
|
var imageCapability = {
|
|
59946
60789
|
name: "image",
|
|
@@ -60028,19 +60871,19 @@ var NormalizedRangeSchema = object({
|
|
|
60028
60871
|
*/
|
|
60029
60872
|
var ImageSettingsStatusSchema = object({
|
|
60030
60873
|
/** Normalized 0–100. */
|
|
60031
|
-
brightness: number().optional(),
|
|
60874
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60032
60875
|
/** Normalized 0–100. */
|
|
60033
|
-
contrast: number().optional(),
|
|
60876
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60034
60877
|
/** Normalized 0–100. */
|
|
60035
|
-
saturation: number().optional(),
|
|
60878
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60036
60879
|
/** Normalized 0–100. */
|
|
60037
|
-
sharpness: number().optional(),
|
|
60880
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60038
60881
|
mirror: boolean().optional(),
|
|
60039
60882
|
flip: boolean().optional(),
|
|
60040
60883
|
rotate: ImageRotateSchema.optional(),
|
|
60041
60884
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60042
60885
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60043
|
-
warmth: number().optional(),
|
|
60886
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60044
60887
|
exposureMode: ExposureModeSchema.optional(),
|
|
60045
60888
|
backlightMode: BacklightModeSchema.optional(),
|
|
60046
60889
|
lastFetchedAt: number()
|
|
@@ -60319,10 +61162,10 @@ var IntercomAbilitySchema = object({
|
|
|
60319
61162
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60320
61163
|
codecs: array(string()),
|
|
60321
61164
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60322
|
-
sampleRate: number(),
|
|
61165
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60323
61166
|
duplex: _enum(["half", "full"]),
|
|
60324
61167
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60325
|
-
maxBacklogMs: number()
|
|
61168
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60326
61169
|
});
|
|
60327
61170
|
var IntercomStatusSchema = object({
|
|
60328
61171
|
/** True while a talk session is open. */
|
|
@@ -60549,13 +61392,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60549
61392
|
activity: LawnMowerActivitySchema,
|
|
60550
61393
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60551
61394
|
* reading. */
|
|
60552
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61395
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60553
61396
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60554
61397
|
* task is active / progress is unavailable. */
|
|
60555
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61398
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60556
61399
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60557
61400
|
* or null when unknown. */
|
|
60558
|
-
currentCode: number().nullable(),
|
|
61401
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60559
61402
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60560
61403
|
currentCodeLabel: string().nullable(),
|
|
60561
61404
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61008,7 +61851,14 @@ var lockControlCapability = {
|
|
|
61008
61851
|
}),
|
|
61009
61852
|
unlock: method(object({
|
|
61010
61853
|
deviceId: number().int().nonnegative(),
|
|
61011
|
-
code: string().min(1).optional()
|
|
61854
|
+
code: string().min(1).optional(),
|
|
61855
|
+
/**
|
|
61856
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
61857
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
61858
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
61859
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
61860
|
+
*/
|
|
61861
|
+
confirm: boolean().optional()
|
|
61012
61862
|
}), _void(), {
|
|
61013
61863
|
kind: "mutation",
|
|
61014
61864
|
auth: "protected"
|
|
@@ -61045,6 +61895,44 @@ var lockControlCapability = {
|
|
|
61045
61895
|
volatileStateFields: ["lastChangedAt"]
|
|
61046
61896
|
};
|
|
61047
61897
|
/**
|
|
61898
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
61899
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
61900
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
61901
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
61902
|
+
*/
|
|
61903
|
+
var MeterStatusSchema = object({
|
|
61904
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
61905
|
+
lastFetchedAt: number()
|
|
61906
|
+
});
|
|
61907
|
+
var meterCapability = {
|
|
61908
|
+
name: "meter",
|
|
61909
|
+
scope: "device",
|
|
61910
|
+
deviceNative: true,
|
|
61911
|
+
mode: "singleton",
|
|
61912
|
+
deviceTypes: [DeviceType.Sensor],
|
|
61913
|
+
methods: {},
|
|
61914
|
+
status: {
|
|
61915
|
+
schema: MeterStatusSchema,
|
|
61916
|
+
kind: "push"
|
|
61917
|
+
},
|
|
61918
|
+
runtimeState: MeterStatusSchema,
|
|
61919
|
+
/**
|
|
61920
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
61921
|
+
* history integral. A restart shows it only until the history pass
|
|
61922
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
61923
|
+
*
|
|
61924
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61925
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61926
|
+
*/
|
|
61927
|
+
durability: "restored",
|
|
61928
|
+
history: { fields: { value: {
|
|
61929
|
+
kind: "counter",
|
|
61930
|
+
deadband: .001,
|
|
61931
|
+
minIntervalMs: 6e4
|
|
61932
|
+
} } },
|
|
61933
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
61934
|
+
};
|
|
61935
|
+
/**
|
|
61048
61936
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61049
61937
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61050
61938
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -61088,7 +61976,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61088
61976
|
state: MediaPlayerStateSchema,
|
|
61089
61977
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61090
61978
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61091
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
61979
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61092
61980
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61093
61981
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61094
61982
|
isMuted: boolean().nullable(),
|
|
@@ -61101,10 +61989,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61101
61989
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61102
61990
|
/** Current playback position in ms. Null when not seekable or
|
|
61103
61991
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61104
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
61992
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61105
61993
|
/** Total duration of the current media in ms. Null when unknown
|
|
61106
61994
|
* (live stream) or nothing is playing. */
|
|
61107
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
61995
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61108
61996
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61109
61997
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61110
61998
|
shuffle: boolean().nullable(),
|
|
@@ -61413,7 +62301,7 @@ var motionCustomize = {
|
|
|
61413
62301
|
eventName: "onMotionChanged"
|
|
61414
62302
|
},
|
|
61415
62303
|
deviceTypes: [DeviceType.Camera],
|
|
61416
|
-
apply: "
|
|
62304
|
+
apply: "add",
|
|
61417
62305
|
applyAuthority: {
|
|
61418
62306
|
kind: "camera-sensors",
|
|
61419
62307
|
timeoutField: "motionCooldownMs"
|
|
@@ -61485,7 +62373,7 @@ var MotionStatusSchema = object({
|
|
|
61485
62373
|
* it, every provider seeded it at boot, and every session left it
|
|
61486
62374
|
* `detected: true` after its detach.
|
|
61487
62375
|
*/
|
|
61488
|
-
autoClearAfterMs: number().nullable()
|
|
62376
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61489
62377
|
});
|
|
61490
62378
|
/**
|
|
61491
62379
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61522,12 +62410,18 @@ var motionCapability = {
|
|
|
61522
62410
|
methods: {
|
|
61523
62411
|
/**
|
|
61524
62412
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
61525
|
-
* for consumers that don't need the full status object
|
|
61526
|
-
*
|
|
61527
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
61528
|
-
* consumer.
|
|
62413
|
+
* for consumers that don't need the full status object. A composed
|
|
62414
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
61529
62415
|
*/
|
|
61530
62416
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62417
|
+
/**
|
|
62418
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62419
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62420
|
+
*/
|
|
62421
|
+
composedMethods: { isDetected: {
|
|
62422
|
+
kind: "slice",
|
|
62423
|
+
field: "detected"
|
|
62424
|
+
} },
|
|
61531
62425
|
events: {
|
|
61532
62426
|
/**
|
|
61533
62427
|
* Fires every time the runner transitions a camera between
|
|
@@ -61667,7 +62561,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61667
62561
|
* the grid region(s). */
|
|
61668
62562
|
var MotionZoneStatusSchema = object({
|
|
61669
62563
|
enabled: boolean(),
|
|
61670
|
-
sensitivity: number(),
|
|
62564
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61671
62565
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61672
62566
|
regions: array(MotionZoneRegionSchema),
|
|
61673
62567
|
lastFetchedAt: number()
|
|
@@ -62037,7 +62931,7 @@ var NavigationStatusSchema = object({
|
|
|
62037
62931
|
following: boolean(),
|
|
62038
62932
|
flash: boolean(),
|
|
62039
62933
|
lightMode: NavigationLightModeSchema,
|
|
62040
|
-
lightLevel: number().min(40).max(100),
|
|
62934
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62041
62935
|
/** Ms epoch when the slice was last updated. */
|
|
62042
62936
|
lastChangedAt: number()
|
|
62043
62937
|
});
|
|
@@ -62171,13 +63065,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62171
63065
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62172
63066
|
* SKIP a null rather than coerce it.
|
|
62173
63067
|
*/
|
|
62174
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63068
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62175
63069
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62176
|
-
rssiDbm: number().optional(),
|
|
63070
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62177
63071
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62178
63072
|
ssid: string().optional(),
|
|
62179
63073
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62180
|
-
lastUpdated: number()
|
|
63074
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62181
63075
|
});
|
|
62182
63076
|
var networkLinkCapability = {
|
|
62183
63077
|
name: "network-link",
|
|
@@ -62562,7 +63456,7 @@ var NotifierStatusSchema = object({
|
|
|
62562
63456
|
lastError: string().nullable(),
|
|
62563
63457
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62564
63458
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62565
|
-
queueDepth: number().int().nonnegative(),
|
|
63459
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62566
63460
|
/** Per-feature capability matrix — authoritative source for the
|
|
62567
63461
|
* compose-form field gating. */
|
|
62568
63462
|
supports: NotifierSupportsSchema
|
|
@@ -62654,11 +63548,9 @@ onSent: { data: object({
|
|
|
62654
63548
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62655
63549
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62656
63550
|
*
|
|
62657
|
-
* The
|
|
62658
|
-
*
|
|
62659
|
-
*
|
|
62660
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62661
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63551
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63552
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63553
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62662
63554
|
*
|
|
62663
63555
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62664
63556
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62667,15 +63559,8 @@ onSent: { data: object({
|
|
|
62667
63559
|
* numeric values land here.
|
|
62668
63560
|
*/
|
|
62669
63561
|
var NumericSensorStatusSchema = object({
|
|
62670
|
-
|
|
62671
|
-
|
|
62672
|
-
* Populated live from the upstream source on each state push.
|
|
62673
|
-
* Absent for unitless sensors. */
|
|
62674
|
-
unit: string().optional(),
|
|
62675
|
-
/** Suggested decimal places for numeric display.
|
|
62676
|
-
* Populated live from the upstream source when provided.
|
|
62677
|
-
* Falls back to auto-formatting when absent. */
|
|
62678
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63562
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63563
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62679
63564
|
/** Ms epoch when the slice was last updated. */
|
|
62680
63565
|
lastFetchedAt: number()
|
|
62681
63566
|
});
|
|
@@ -62699,11 +63584,11 @@ var numericSensorCapability = {
|
|
|
62699
63584
|
*/
|
|
62700
63585
|
durability: "restored",
|
|
62701
63586
|
/**
|
|
62702
|
-
* History (D850): recorded series. The unit is
|
|
63587
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63588
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62703
63589
|
*/
|
|
62704
63590
|
history: { fields: { value: {
|
|
62705
63591
|
kind: "gauge",
|
|
62706
|
-
unitFrom: "unit",
|
|
62707
63592
|
minIntervalMs: 3e4
|
|
62708
63593
|
} } },
|
|
62709
63594
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -62995,23 +63880,26 @@ var PetFeederStatusSchema = object({
|
|
|
62995
63880
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
62996
63881
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
62997
63882
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
62998
|
-
foodLevel: number().nullable(),
|
|
63883
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62999
63884
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63000
63885
|
* single-hopper models. */
|
|
63001
|
-
food1: number().nullable(),
|
|
63886
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63002
63887
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63003
63888
|
* single-hopper models. */
|
|
63004
|
-
food2: number().nullable(),
|
|
63889
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63005
63890
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63006
63891
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63007
63892
|
* below the feeder's low threshold. */
|
|
63008
63893
|
lowFood: boolean(),
|
|
63009
63894
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63010
63895
|
* device has no battery reading. */
|
|
63011
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63012
|
-
/**
|
|
63013
|
-
*
|
|
63014
|
-
|
|
63896
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63897
|
+
/**
|
|
63898
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
63899
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
63900
|
+
* model has no desiccant sensor.
|
|
63901
|
+
*/
|
|
63902
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63015
63903
|
/** True while a feed is in progress. */
|
|
63016
63904
|
feeding: boolean(),
|
|
63017
63905
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63022,7 +63910,7 @@ var PetFeederStatusSchema = object({
|
|
|
63022
63910
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63023
63911
|
error: string().nullable(),
|
|
63024
63912
|
/** Raw device error code (0 / null = no error). */
|
|
63025
|
-
errorCode: number().nullable(),
|
|
63913
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63026
63914
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63027
63915
|
isDualHopper: boolean(),
|
|
63028
63916
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63032,7 +63920,7 @@ var PetFeederStatusSchema = object({
|
|
|
63032
63920
|
/** Play a chime when dispensing. */
|
|
63033
63921
|
feedSound: boolean(),
|
|
63034
63922
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63035
|
-
volume: number(),
|
|
63923
|
+
volume: number().meta(readingMeta("none")),
|
|
63036
63924
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63037
63925
|
lastFetchedAt: number()
|
|
63038
63926
|
});
|
|
@@ -63151,7 +64039,7 @@ var petFeederCapability = {
|
|
|
63151
64039
|
},
|
|
63152
64040
|
desiccantLeftDays: {
|
|
63153
64041
|
kind: "gauge",
|
|
63154
|
-
unit: "
|
|
64042
|
+
unit: "s"
|
|
63155
64043
|
}
|
|
63156
64044
|
} }
|
|
63157
64045
|
};
|
|
@@ -63552,43 +64440,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63552
64440
|
*/
|
|
63553
64441
|
var PowerMeterStatusSchema = object({
|
|
63554
64442
|
/** Instantaneous power draw in watts. */
|
|
63555
|
-
watts: number().optional().meta({
|
|
63556
|
-
unit: "W",
|
|
63557
|
-
label: "Power"
|
|
63558
|
-
}),
|
|
64443
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63559
64444
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63560
|
-
kwhTotal: number().optional().meta({
|
|
63561
|
-
unit: "kWh",
|
|
63562
|
-
label: "Energy"
|
|
63563
|
-
}),
|
|
64445
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63564
64446
|
/** Voltage in volts. */
|
|
63565
|
-
volts: number().optional(),
|
|
64447
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
63566
64448
|
/** Current in amperes. */
|
|
63567
|
-
amps: number().optional(),
|
|
63568
|
-
/** Apparent power in volt-amperes
|
|
63569
|
-
va: number().optional(),
|
|
64449
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
64450
|
+
/** Apparent power in volt-amperes. */
|
|
64451
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63570
64452
|
/** Power factor (0..1) if reported. */
|
|
63571
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
64453
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63572
64454
|
/** Ms epoch when the slice was last updated. */
|
|
63573
|
-
lastFetchedAt: number()
|
|
63574
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63575
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63576
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63577
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63578
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63579
|
-
unit: string().optional(),
|
|
63580
|
-
/** Suggested decimal places for numeric display.
|
|
63581
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63582
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63583
|
-
* auto-formatting when absent. */
|
|
63584
|
-
precision: number().int().min(0).max(10).optional()
|
|
64455
|
+
lastFetchedAt: number()
|
|
63585
64456
|
});
|
|
64457
|
+
/**
|
|
64458
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
64459
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
64460
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
64461
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
64462
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
64463
|
+
*/
|
|
64464
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
64465
|
+
DeviceType.Sensor,
|
|
64466
|
+
DeviceType.Switch,
|
|
64467
|
+
DeviceType.Light,
|
|
64468
|
+
DeviceType.Fan,
|
|
64469
|
+
DeviceType.Climate,
|
|
64470
|
+
DeviceType.Thermostat,
|
|
64471
|
+
DeviceType.Humidifier,
|
|
64472
|
+
DeviceType.WaterHeater,
|
|
64473
|
+
DeviceType.MediaPlayer,
|
|
64474
|
+
DeviceType.Washer,
|
|
64475
|
+
DeviceType.Dryer,
|
|
64476
|
+
DeviceType.Dishwasher,
|
|
64477
|
+
DeviceType.Vacuum,
|
|
64478
|
+
DeviceType.LawnMower,
|
|
64479
|
+
DeviceType.PetFeeder
|
|
64480
|
+
];
|
|
64481
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
64482
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
64483
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
64484
|
+
function powerTarget(id, unit) {
|
|
64485
|
+
return {
|
|
64486
|
+
id,
|
|
64487
|
+
cardinality: "scalar",
|
|
64488
|
+
vocabulary: {
|
|
64489
|
+
cap: "power-meter",
|
|
64490
|
+
stateField: id
|
|
64491
|
+
},
|
|
64492
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
64493
|
+
apply: "add",
|
|
64494
|
+
path: id,
|
|
64495
|
+
sources: [{
|
|
64496
|
+
kind: "numeric",
|
|
64497
|
+
requiredUnit: unit,
|
|
64498
|
+
transforms: [{ kind: "identity" }]
|
|
64499
|
+
}],
|
|
64500
|
+
companions: [{
|
|
64501
|
+
kind: "clock",
|
|
64502
|
+
path: "lastFetchedAt",
|
|
64503
|
+
when: "always"
|
|
64504
|
+
}],
|
|
64505
|
+
sourceReport: { status: "assignment-status" },
|
|
64506
|
+
advancedExpression: true
|
|
64507
|
+
};
|
|
64508
|
+
}
|
|
64509
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
64510
|
+
var powerMeterCustomize = {
|
|
64511
|
+
version: 1,
|
|
64512
|
+
targets: [
|
|
64513
|
+
powerTarget("watts", "W"),
|
|
64514
|
+
powerTarget("kwhTotal", "kWh"),
|
|
64515
|
+
powerTarget("volts", "V"),
|
|
64516
|
+
powerTarget("amps", "A")
|
|
64517
|
+
]
|
|
64518
|
+
};
|
|
63586
64519
|
var powerMeterCapability = {
|
|
63587
64520
|
name: "power-meter",
|
|
63588
64521
|
scope: "device",
|
|
63589
64522
|
deviceNative: true,
|
|
63590
64523
|
mode: "singleton",
|
|
63591
|
-
deviceTypes:
|
|
64524
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
63592
64525
|
methods: {},
|
|
63593
64526
|
status: {
|
|
63594
64527
|
schema: PowerMeterStatusSchema,
|
|
@@ -63646,11 +64579,7 @@ var powerMeterCapability = {
|
|
|
63646
64579
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63647
64580
|
* whether persisting is worth a SQLite commit. */
|
|
63648
64581
|
volatileStateFields: ["lastFetchedAt"],
|
|
63649
|
-
customize:
|
|
63650
|
-
version: 1,
|
|
63651
|
-
advanced: "derive",
|
|
63652
|
-
targets: []
|
|
63653
|
-
}
|
|
64582
|
+
customize: powerMeterCustomize
|
|
63654
64583
|
};
|
|
63655
64584
|
/**
|
|
63656
64585
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63670,11 +64599,11 @@ var powerMeterCapability = {
|
|
|
63670
64599
|
*/
|
|
63671
64600
|
var GpsLocationSchema = object({
|
|
63672
64601
|
/** Latitude in decimal degrees, -90..90. */
|
|
63673
|
-
latitude: number().min(-90).max(90),
|
|
64602
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63674
64603
|
/** Longitude in decimal degrees, -180..180. */
|
|
63675
|
-
longitude: number().min(-180).max(180),
|
|
64604
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63676
64605
|
/** Reported accuracy in meters (lower = better). */
|
|
63677
|
-
accuracyMeters: number().nonnegative()
|
|
64606
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63678
64607
|
});
|
|
63679
64608
|
var PresenceStatusSchema = object({
|
|
63680
64609
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63686,7 +64615,7 @@ var PresenceStatusSchema = object({
|
|
|
63686
64615
|
gps: GpsLocationSchema.nullable(),
|
|
63687
64616
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63688
64617
|
* when not reported. */
|
|
63689
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64618
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63690
64619
|
/** Ms epoch when the slice was last updated. */
|
|
63691
64620
|
lastChangedAt: number()
|
|
63692
64621
|
});
|
|
@@ -63736,19 +64665,10 @@ var presenceCapability = {
|
|
|
63736
64665
|
* `sourceInfo`.
|
|
63737
64666
|
*/
|
|
63738
64667
|
var PressureSensorStatusSchema = object({
|
|
63739
|
-
/** Current pressure in hPa. */
|
|
63740
|
-
hpa: number(),
|
|
64668
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64669
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63741
64670
|
/** Ms epoch when the slice was last updated. */
|
|
63742
|
-
lastFetchedAt: number()
|
|
63743
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63744
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63745
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63746
|
-
unit: string().optional(),
|
|
63747
|
-
/** Suggested decimal places for numeric display.
|
|
63748
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63749
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63750
|
-
* auto-formatting when absent. */
|
|
63751
|
-
precision: number().int().min(0).max(10).optional()
|
|
64671
|
+
lastFetchedAt: number()
|
|
63752
64672
|
});
|
|
63753
64673
|
var pressureSensorCapability = {
|
|
63754
64674
|
name: "pressure-sensor",
|
|
@@ -64162,8 +65082,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64162
65082
|
}), _void(), { kind: "mutation" });
|
|
64163
65083
|
var PtzAutotrackSettingsSchema = object({
|
|
64164
65084
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64165
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64166
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65085
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65086
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64167
65087
|
});
|
|
64168
65088
|
/**
|
|
64169
65089
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64317,7 +65237,7 @@ var RunningStateStatusSchema = object({
|
|
|
64317
65237
|
/** null = unknown — never coerced to false (D393). */
|
|
64318
65238
|
running: boolean().nullable(),
|
|
64319
65239
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64320
|
-
since: number().nullable(),
|
|
65240
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64321
65241
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64322
65242
|
phase: string().nullable(),
|
|
64323
65243
|
/** null until a reading has been published (D393). */
|
|
@@ -64332,7 +65252,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64332
65252
|
/** Generic Customize target for the running boolean (D936). */
|
|
64333
65253
|
var runningCustomize = {
|
|
64334
65254
|
version: 1,
|
|
64335
|
-
advanced: "derive",
|
|
64336
65255
|
targets: [{
|
|
64337
65256
|
id: "running",
|
|
64338
65257
|
cardinality: "scalar",
|
|
@@ -64341,6 +65260,8 @@ var runningCustomize = {
|
|
|
64341
65260
|
stateField: "running"
|
|
64342
65261
|
},
|
|
64343
65262
|
deviceTypes: [
|
|
65263
|
+
DeviceType.Washer,
|
|
65264
|
+
DeviceType.Dryer,
|
|
64344
65265
|
DeviceType.Dishwasher,
|
|
64345
65266
|
DeviceType.Vacuum,
|
|
64346
65267
|
DeviceType.LawnMower,
|
|
@@ -64352,7 +65273,7 @@ var runningCustomize = {
|
|
|
64352
65273
|
DeviceType.Thermostat,
|
|
64353
65274
|
DeviceType.PetFeeder
|
|
64354
65275
|
],
|
|
64355
|
-
apply: "add
|
|
65276
|
+
apply: "add",
|
|
64356
65277
|
path: "running",
|
|
64357
65278
|
sources: [
|
|
64358
65279
|
{
|
|
@@ -65616,9 +66537,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65616
66537
|
*/
|
|
65617
66538
|
var RecordWindowSchema = object({
|
|
65618
66539
|
trigger: RecordTriggerSchema,
|
|
65619
|
-
day: number().int().min(0).max(6),
|
|
65620
|
-
startMinute: number().int().min(0).max(1439),
|
|
65621
|
-
endMinute: number().int().min(1).max(1440)
|
|
66540
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
66541
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
66542
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65622
66543
|
});
|
|
65623
66544
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65624
66545
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65694,10 +66615,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65694
66615
|
/** Master "record to the card at all" switch. */
|
|
65695
66616
|
enabled: boolean().nullable(),
|
|
65696
66617
|
overwriteWhenFull: boolean().nullable(),
|
|
65697
|
-
preRecordSec: number().nullable(),
|
|
65698
|
-
postRecordSec: number().nullable(),
|
|
66618
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66619
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65699
66620
|
/** Length of one recorded file, in minutes. */
|
|
65700
|
-
segmentMinutes: number().nullable(),
|
|
66621
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65701
66622
|
/** The primary track's weekly windows, flattened. */
|
|
65702
66623
|
windows: array(RecordWindowSchema),
|
|
65703
66624
|
/**
|
|
@@ -65713,7 +66634,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65713
66634
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65714
66635
|
* writable.
|
|
65715
66636
|
*/
|
|
65716
|
-
unreadableWindows: number(),
|
|
66637
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65717
66638
|
/**
|
|
65718
66639
|
* The camera is scheduled to record and has NO usable storage.
|
|
65719
66640
|
*
|
|
@@ -66558,7 +67479,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66558
67479
|
url: string().optional(),
|
|
66559
67480
|
codec: string().optional(),
|
|
66560
67481
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66561
|
-
fps: number().positive().optional(),
|
|
67482
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66562
67483
|
label: string().optional(),
|
|
66563
67484
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66564
67485
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66645,18 +67566,18 @@ var StreamProfileSchema = _enum([
|
|
|
66645
67566
|
]);
|
|
66646
67567
|
/** The current encoding config of one stream profile. */
|
|
66647
67568
|
var StreamProfileConfigSchema = object({
|
|
66648
|
-
width: number(),
|
|
66649
|
-
height: number(),
|
|
67569
|
+
width: number().meta(readingMeta("none")),
|
|
67570
|
+
height: number().meta(readingMeta("none")),
|
|
66650
67571
|
codec: _enum(["h264", "h265"]),
|
|
66651
|
-
framerate: number(),
|
|
66652
|
-
bitrate: number(),
|
|
67572
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67573
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66653
67574
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66654
67575
|
encoderProfile: _enum([
|
|
66655
67576
|
"high",
|
|
66656
67577
|
"main",
|
|
66657
67578
|
"baseline"
|
|
66658
67579
|
]).optional(),
|
|
66659
|
-
gop: number().optional(),
|
|
67580
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66660
67581
|
/**
|
|
66661
67582
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66662
67583
|
*
|
|
@@ -66830,7 +67751,8 @@ var switchCapability = {
|
|
|
66830
67751
|
deviceTypes: [
|
|
66831
67752
|
DeviceType.Switch,
|
|
66832
67753
|
DeviceType.Siren,
|
|
66833
|
-
DeviceType.Light
|
|
67754
|
+
DeviceType.Light,
|
|
67755
|
+
DeviceType.Fan
|
|
66834
67756
|
],
|
|
66835
67757
|
methods: { setState: method(object({
|
|
66836
67758
|
deviceId: number(),
|
|
@@ -66877,12 +67799,7 @@ var switchCapability = {
|
|
|
66877
67799
|
label: "On",
|
|
66878
67800
|
kind: "boolean"
|
|
66879
67801
|
}
|
|
66880
|
-
}] }
|
|
66881
|
-
customize: {
|
|
66882
|
-
version: 1,
|
|
66883
|
-
advanced: "derive",
|
|
66884
|
-
targets: []
|
|
66885
|
-
}
|
|
67802
|
+
}] }
|
|
66886
67803
|
};
|
|
66887
67804
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66888
67805
|
function hasControlCharacter(value) {
|
|
@@ -67465,35 +68382,21 @@ var tamperCapability = {
|
|
|
67465
68382
|
* entries with `device_class: temperature` and any future native
|
|
67466
68383
|
* thermometer.
|
|
67467
68384
|
*
|
|
67468
|
-
*
|
|
67469
|
-
*
|
|
67470
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67471
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67472
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67473
|
-
* `sourceInfo`.
|
|
68385
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
68386
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67474
68387
|
*
|
|
67475
68388
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67476
68389
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67477
68390
|
* changed" steady state.
|
|
67478
68391
|
*/
|
|
67479
68392
|
var TemperatureSensorStatusSchema = object({
|
|
67480
|
-
/** Current temperature in Celsius. */
|
|
67481
|
-
celsius: number().meta({
|
|
67482
|
-
|
|
68393
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68394
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
68395
|
+
precision: 1,
|
|
67483
68396
|
label: "Temperature"
|
|
67484
|
-
}),
|
|
68397
|
+
})),
|
|
67485
68398
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67486
|
-
lastFetchedAt: number()
|
|
67487
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67488
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67489
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67490
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67491
|
-
unit: string().optional(),
|
|
67492
|
-
/** Suggested decimal places for numeric display.
|
|
67493
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67494
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67495
|
-
* auto-formatting when absent. */
|
|
67496
|
-
precision: number().int().min(0).max(10).optional()
|
|
68399
|
+
lastFetchedAt: number()
|
|
67497
68400
|
});
|
|
67498
68401
|
var temperatureSensorCapability = {
|
|
67499
68402
|
name: "temperature-sensor",
|
|
@@ -67524,12 +68427,7 @@ var temperatureSensorCapability = {
|
|
|
67524
68427
|
} } },
|
|
67525
68428
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67526
68429
|
* whether persisting is worth a SQLite commit. */
|
|
67527
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67528
|
-
customize: {
|
|
67529
|
-
version: 1,
|
|
67530
|
-
advanced: "derive",
|
|
67531
|
-
targets: []
|
|
67532
|
-
}
|
|
68430
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67533
68431
|
};
|
|
67534
68432
|
/**
|
|
67535
68433
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67812,16 +68710,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67812
68710
|
]),
|
|
67813
68711
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67814
68712
|
* reading. */
|
|
67815
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68713
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67816
68714
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67817
68715
|
* the vacuum has no speed control. */
|
|
67818
68716
|
fanSpeed: string().nullable(),
|
|
67819
68717
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67820
68718
|
availableFanSpeeds: array(string()),
|
|
67821
68719
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67822
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68720
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67823
68721
|
/** Current error code (0 / null = no error). */
|
|
67824
|
-
errorCode: number().nullable(),
|
|
68722
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67825
68723
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67826
68724
|
errorLabel: string().nullable(),
|
|
67827
68725
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67899,7 +68797,7 @@ var ValveStatusSchema = object({
|
|
|
67899
68797
|
]),
|
|
67900
68798
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
67901
68799
|
* intermediate position surface. */
|
|
67902
|
-
position: number().min(0).max(100).nullable(),
|
|
68800
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67903
68801
|
/** Ms epoch when the slice was last updated. */
|
|
67904
68802
|
lastChangedAt: number()
|
|
67905
68803
|
});
|
|
@@ -68007,9 +68905,9 @@ var vibrationCapability = {
|
|
|
68007
68905
|
*/
|
|
68008
68906
|
var WaterHeaterStatusSchema = object({
|
|
68009
68907
|
/** Current measured temperature. Null when not reported. */
|
|
68010
|
-
currentTemp: number().nullable(),
|
|
68908
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68011
68909
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68012
|
-
targetTemp: number().nullable(),
|
|
68910
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68013
68911
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68014
68912
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68015
68913
|
* device reports an unknown state. */
|
|
@@ -68020,9 +68918,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68020
68918
|
* has no away surface. */
|
|
68021
68919
|
away: boolean().nullable(),
|
|
68022
68920
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68023
|
-
minTemp: number().nullable(),
|
|
68921
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68024
68922
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68025
|
-
maxTemp: number().nullable(),
|
|
68923
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68026
68924
|
/** Ms epoch when the slice was last updated. */
|
|
68027
68925
|
lastChangedAt: number()
|
|
68028
68926
|
});
|
|
@@ -68107,25 +69005,18 @@ var waterHeaterCapability = {
|
|
|
68107
69005
|
* Forecast deferred — current conditions only for v1.
|
|
68108
69006
|
*/
|
|
68109
69007
|
var WeatherStatusSchema = object({
|
|
68110
|
-
/** Verbatim
|
|
68111
|
-
* when no condition has been reported yet. */
|
|
69008
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68112
69009
|
condition: string().nullable(),
|
|
68113
|
-
/** Current temperature in
|
|
68114
|
-
temperature: number().nullable(),
|
|
68115
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68116
|
-
temperatureUnit: string().nullable(),
|
|
69010
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
69011
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68117
69012
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68118
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68119
|
-
/** Barometric pressure in
|
|
68120
|
-
pressure: number().nullable(),
|
|
68121
|
-
/**
|
|
68122
|
-
|
|
68123
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68124
|
-
windSpeed: number().nullable(),
|
|
68125
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68126
|
-
windSpeedUnit: string().nullable(),
|
|
69013
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
69014
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
69015
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
69016
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
69017
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68127
69018
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68128
|
-
windBearing: number().nullable(),
|
|
69019
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68129
69020
|
/** Ms epoch when the slice was last updated. */
|
|
68130
69021
|
lastFetchedAt: number()
|
|
68131
69022
|
});
|
|
@@ -68153,12 +69044,12 @@ var weatherCapability = {
|
|
|
68153
69044
|
*/
|
|
68154
69045
|
durability: "session",
|
|
68155
69046
|
/**
|
|
68156
|
-
* History (D850): recorded series.
|
|
69047
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68157
69048
|
*/
|
|
68158
69049
|
history: { fields: {
|
|
68159
69050
|
temperature: {
|
|
68160
69051
|
kind: "gauge",
|
|
68161
|
-
|
|
69052
|
+
unit: "°C",
|
|
68162
69053
|
deadband: .2
|
|
68163
69054
|
},
|
|
68164
69055
|
humidity: {
|
|
@@ -68168,12 +69059,12 @@ var weatherCapability = {
|
|
|
68168
69059
|
},
|
|
68169
69060
|
pressure: {
|
|
68170
69061
|
kind: "gauge",
|
|
68171
|
-
|
|
69062
|
+
unit: "hPa",
|
|
68172
69063
|
deadband: .5
|
|
68173
69064
|
},
|
|
68174
69065
|
windSpeed: {
|
|
68175
69066
|
kind: "gauge",
|
|
68176
|
-
|
|
69067
|
+
unit: "m/s",
|
|
68177
69068
|
deadband: .5
|
|
68178
69069
|
}
|
|
68179
69070
|
} }
|
|
@@ -69074,8 +69965,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
69074
69965
|
kind: "mutation",
|
|
69075
69966
|
auth: "admin"
|
|
69076
69967
|
});
|
|
69968
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
69077
69969
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
69078
|
-
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;
|
|
69970
|
+
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;
|
|
69079
69971
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
69080
69972
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
69081
69973
|
new Set(CAP_NAMES);
|
|
@@ -69404,6 +70296,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69404
70296
|
featureProbe: featureProbeCapability,
|
|
69405
70297
|
flood: floodCapability,
|
|
69406
70298
|
gas: gasCapability,
|
|
70299
|
+
groupActive: groupActiveCapability,
|
|
70300
|
+
groupCommands: groupCommandsCapability,
|
|
70301
|
+
groupStatus: groupStatusCapability,
|
|
69407
70302
|
heatingValve: heatingValveCapability,
|
|
69408
70303
|
humidifier: humidifierCapability,
|
|
69409
70304
|
humiditySensor: humiditySensorCapability,
|
|
@@ -69413,6 +70308,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69413
70308
|
lawnMowerControl: lawnMowerControlCapability,
|
|
69414
70309
|
lockControl: lockControlCapability,
|
|
69415
70310
|
mediaPlayer: mediaPlayerCapability,
|
|
70311
|
+
meter: meterCapability,
|
|
69416
70312
|
motion: motionCapability,
|
|
69417
70313
|
motionTrigger: motionTriggerCapability,
|
|
69418
70314
|
motionZones: motionZonesCapability,
|
|
@@ -70672,7 +71568,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
70672
71568
|
return toDeviceSummary(device, this.addonId);
|
|
70673
71569
|
}
|
|
70674
71570
|
};
|
|
70675
|
-
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;
|
|
71571
|
+
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;
|
|
70676
71572
|
new Set(Object.values(DeviceType));
|
|
70677
71573
|
Object.freeze({
|
|
70678
71574
|
"accessories.getStatus": {
|
|
@@ -70780,6 +71676,13 @@ Object.freeze({
|
|
|
70780
71676
|
access: "view",
|
|
70781
71677
|
role: "admin"
|
|
70782
71678
|
},
|
|
71679
|
+
"addons.getPackageDocs": {
|
|
71680
|
+
capName: "addons",
|
|
71681
|
+
capScope: "system",
|
|
71682
|
+
addonId: null,
|
|
71683
|
+
access: "view",
|
|
71684
|
+
role: "admin"
|
|
71685
|
+
},
|
|
70783
71686
|
"addons.getVersions": {
|
|
70784
71687
|
capName: "addons",
|
|
70785
71688
|
capScope: "system",
|
|
@@ -73888,6 +74791,27 @@ Object.freeze({
|
|
|
73888
74791
|
access: "view",
|
|
73889
74792
|
role: "viewer"
|
|
73890
74793
|
},
|
|
74794
|
+
"groupActive.getStatus": {
|
|
74795
|
+
capName: "group-active",
|
|
74796
|
+
capScope: "device",
|
|
74797
|
+
addonId: null,
|
|
74798
|
+
access: "view",
|
|
74799
|
+
role: "viewer"
|
|
74800
|
+
},
|
|
74801
|
+
"groupCommands.getStatus": {
|
|
74802
|
+
capName: "group-commands",
|
|
74803
|
+
capScope: "device",
|
|
74804
|
+
addonId: null,
|
|
74805
|
+
access: "view",
|
|
74806
|
+
role: "viewer"
|
|
74807
|
+
},
|
|
74808
|
+
"groupStatus.getStatus": {
|
|
74809
|
+
capName: "group-status",
|
|
74810
|
+
capScope: "device",
|
|
74811
|
+
addonId: null,
|
|
74812
|
+
access: "view",
|
|
74813
|
+
role: "viewer"
|
|
74814
|
+
},
|
|
73891
74815
|
"heatingValve.getStatus": {
|
|
73892
74816
|
capName: "heating-valve",
|
|
73893
74817
|
capScope: "device",
|
|
@@ -74840,6 +75764,13 @@ Object.freeze({
|
|
|
74840
75764
|
access: "create",
|
|
74841
75765
|
role: "admin"
|
|
74842
75766
|
},
|
|
75767
|
+
"meter.getStatus": {
|
|
75768
|
+
capName: "meter",
|
|
75769
|
+
capScope: "device",
|
|
75770
|
+
addonId: null,
|
|
75771
|
+
access: "view",
|
|
75772
|
+
role: "viewer"
|
|
75773
|
+
},
|
|
74843
75774
|
"metricsProvider.collectSnapshot": {
|
|
74844
75775
|
capName: "metrics-provider",
|
|
74845
75776
|
capScope: "system",
|
|
@@ -82938,7 +83869,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
82938
83869
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
82939
83870
|
icon: "square"
|
|
82940
83871
|
}
|
|
82941
|
-
}
|
|
83872
|
+
},
|
|
83873
|
+
overrides: { byType: {
|
|
83874
|
+
[DeviceType.Washer]: {
|
|
83875
|
+
state: { running: {
|
|
83876
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
83877
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
83878
|
+
} },
|
|
83879
|
+
events: {
|
|
83880
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
83881
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
83882
|
+
}
|
|
83883
|
+
},
|
|
83884
|
+
[DeviceType.Dryer]: {
|
|
83885
|
+
state: { running: {
|
|
83886
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
83887
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
83888
|
+
} },
|
|
83889
|
+
events: {
|
|
83890
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
83891
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
83892
|
+
}
|
|
83893
|
+
},
|
|
83894
|
+
[DeviceType.Dishwasher]: {
|
|
83895
|
+
state: { running: {
|
|
83896
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
83897
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
83898
|
+
} },
|
|
83899
|
+
events: {
|
|
83900
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
83901
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
83902
|
+
}
|
|
83903
|
+
}
|
|
83904
|
+
} }
|
|
82942
83905
|
},
|
|
82943
83906
|
update: {
|
|
82944
83907
|
scope: "device",
|
|
@@ -83710,6 +84673,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83710
84673
|
icon: "flame"
|
|
83711
84674
|
}]
|
|
83712
84675
|
},
|
|
84676
|
+
"group-active": {
|
|
84677
|
+
scope: "device",
|
|
84678
|
+
noun: t("Group state", "Stato del gruppo")
|
|
84679
|
+
},
|
|
84680
|
+
"group-commands": {
|
|
84681
|
+
scope: "device",
|
|
84682
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84683
|
+
},
|
|
84684
|
+
"group-status": {
|
|
84685
|
+
scope: "device",
|
|
84686
|
+
noun: t("Group", "Gruppo"),
|
|
84687
|
+
state: [
|
|
84688
|
+
{
|
|
84689
|
+
kind: "numeric",
|
|
84690
|
+
field: "included",
|
|
84691
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84692
|
+
label: t("Reporting", "Rispondono"),
|
|
84693
|
+
icon: "users"
|
|
84694
|
+
},
|
|
84695
|
+
{
|
|
84696
|
+
kind: "numeric",
|
|
84697
|
+
field: "excluded",
|
|
84698
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84699
|
+
label: t("Excluded", "Esclusi"),
|
|
84700
|
+
icon: "users"
|
|
84701
|
+
},
|
|
84702
|
+
{
|
|
84703
|
+
kind: "numeric",
|
|
84704
|
+
field: "total",
|
|
84705
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84706
|
+
label: t("Members", "Membri"),
|
|
84707
|
+
icon: "sigma"
|
|
84708
|
+
}
|
|
84709
|
+
]
|
|
84710
|
+
},
|
|
83713
84711
|
"humidity-sensor": {
|
|
83714
84712
|
scope: "device",
|
|
83715
84713
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83735,6 +84733,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83735
84733
|
}],
|
|
83736
84734
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
83737
84735
|
},
|
|
84736
|
+
meter: {
|
|
84737
|
+
scope: "device",
|
|
84738
|
+
noun: t("Meter", "Contatore"),
|
|
84739
|
+
state: [{
|
|
84740
|
+
kind: "numeric",
|
|
84741
|
+
field: "value",
|
|
84742
|
+
quantity: t("the total", "il totale"),
|
|
84743
|
+
label: t("Total", "Totale"),
|
|
84744
|
+
icon: "gauge"
|
|
84745
|
+
}]
|
|
84746
|
+
},
|
|
83738
84747
|
"numeric-sensor": {
|
|
83739
84748
|
scope: "device",
|
|
83740
84749
|
noun: t("Sensor", "Sensore"),
|
|
@@ -83743,7 +84752,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83743
84752
|
field: "value",
|
|
83744
84753
|
quantity: t("the reading", "il valore"),
|
|
83745
84754
|
label: t("Reading", "Valore"),
|
|
83746
|
-
unitField: "unit",
|
|
83747
84755
|
icon: "gauge"
|
|
83748
84756
|
}]
|
|
83749
84757
|
},
|
|
@@ -83879,7 +84887,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83879
84887
|
field: "temperature",
|
|
83880
84888
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
83881
84889
|
label: t("Temperature", "Temperatura"),
|
|
83882
|
-
|
|
84890
|
+
unit: "°C",
|
|
83883
84891
|
icon: "thermometer"
|
|
83884
84892
|
},
|
|
83885
84893
|
{
|
|
@@ -83895,7 +84903,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83895
84903
|
field: "windSpeed",
|
|
83896
84904
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
83897
84905
|
label: t("Wind", "Vento"),
|
|
83898
|
-
|
|
84906
|
+
unit: "m/s",
|
|
83899
84907
|
icon: "wind"
|
|
83900
84908
|
},
|
|
83901
84909
|
{
|
|
@@ -83903,7 +84911,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83903
84911
|
field: "pressure",
|
|
83904
84912
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
83905
84913
|
label: t("Pressure", "Pressione"),
|
|
83906
|
-
|
|
84914
|
+
unit: "hPa",
|
|
83907
84915
|
icon: "gauge"
|
|
83908
84916
|
}
|
|
83909
84917
|
]
|
|
@@ -84208,8 +85216,47 @@ function projectAction(cap, action) {
|
|
|
84208
85216
|
};
|
|
84209
85217
|
}
|
|
84210
85218
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
84211
|
-
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;
|
|
85219
|
+
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;
|
|
84212
85220
|
DeviceFeature.BatteryOperated;
|
|
85221
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
85222
|
+
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.";
|
|
85223
|
+
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.";
|
|
85224
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
85225
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
85226
|
+
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.";
|
|
85227
|
+
function withheld(reason) {
|
|
85228
|
+
return {
|
|
85229
|
+
[DeviceType.Washer]: {
|
|
85230
|
+
exported: false,
|
|
85231
|
+
reason
|
|
85232
|
+
},
|
|
85233
|
+
[DeviceType.Dryer]: {
|
|
85234
|
+
exported: false,
|
|
85235
|
+
reason
|
|
85236
|
+
},
|
|
85237
|
+
[DeviceType.Dishwasher]: {
|
|
85238
|
+
exported: false,
|
|
85239
|
+
reason
|
|
85240
|
+
}
|
|
85241
|
+
};
|
|
85242
|
+
}
|
|
85243
|
+
function offered(received) {
|
|
85244
|
+
return {
|
|
85245
|
+
[DeviceType.Washer]: {
|
|
85246
|
+
exported: true,
|
|
85247
|
+
as: received
|
|
85248
|
+
},
|
|
85249
|
+
[DeviceType.Dryer]: {
|
|
85250
|
+
exported: true,
|
|
85251
|
+
as: received
|
|
85252
|
+
},
|
|
85253
|
+
[DeviceType.Dishwasher]: {
|
|
85254
|
+
exported: true,
|
|
85255
|
+
as: received
|
|
85256
|
+
}
|
|
85257
|
+
};
|
|
85258
|
+
}
|
|
85259
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
84213
85260
|
Object.freeze({
|
|
84214
85261
|
"accessories.getStatus": [{
|
|
84215
85262
|
name: "deviceId",
|
|
@@ -85176,6 +86223,21 @@ Object.freeze({
|
|
|
85176
86223
|
form: "single",
|
|
85177
86224
|
optional: false
|
|
85178
86225
|
}],
|
|
86226
|
+
"groupActive.getStatus": [{
|
|
86227
|
+
name: "deviceId",
|
|
86228
|
+
form: "single",
|
|
86229
|
+
optional: false
|
|
86230
|
+
}],
|
|
86231
|
+
"groupCommands.getStatus": [{
|
|
86232
|
+
name: "deviceId",
|
|
86233
|
+
form: "single",
|
|
86234
|
+
optional: false
|
|
86235
|
+
}],
|
|
86236
|
+
"groupStatus.getStatus": [{
|
|
86237
|
+
name: "deviceId",
|
|
86238
|
+
form: "single",
|
|
86239
|
+
optional: false
|
|
86240
|
+
}],
|
|
85179
86241
|
"heatingValve.getStatus": [{
|
|
85180
86242
|
name: "deviceId",
|
|
85181
86243
|
form: "single",
|
|
@@ -85376,6 +86438,11 @@ Object.freeze({
|
|
|
85376
86438
|
form: "single",
|
|
85377
86439
|
optional: false
|
|
85378
86440
|
}],
|
|
86441
|
+
"meter.getStatus": [{
|
|
86442
|
+
name: "deviceId",
|
|
86443
|
+
form: "single",
|
|
86444
|
+
optional: false
|
|
86445
|
+
}],
|
|
85379
86446
|
"motion.getStatus": [{
|
|
85380
86447
|
name: "deviceId",
|
|
85381
86448
|
form: "single",
|
|
@@ -86983,7 +88050,6 @@ Object.freeze({
|
|
|
86983
88050
|
"network-access": "ingress",
|
|
86984
88051
|
"smtp-provider": "email"
|
|
86985
88052
|
});
|
|
86986
|
-
DeviceType.Camera;
|
|
86987
88053
|
/**
|
|
86988
88054
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
86989
88055
|
* `z.infer`, they do not restate the shape.
|
|
@@ -87160,6 +88226,8 @@ new Map(Object.entries({
|
|
|
87160
88226
|
"detection-blind": "device-events",
|
|
87161
88227
|
"motion-noisy": "device-events",
|
|
87162
88228
|
"motion-calm": "device-events",
|
|
88229
|
+
"package-llm-silent": "device-events",
|
|
88230
|
+
"package-llm-answered": "device-events",
|
|
87163
88231
|
"recording-stalled": "device-events",
|
|
87164
88232
|
"recording-healthy": "device-events",
|
|
87165
88233
|
"recording-degraded": "device-events",
|
|
@@ -87243,6 +88311,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
87243
88311
|
label: "Motion without a subject",
|
|
87244
88312
|
kinds: ["motion-noisy", "motion-calm"]
|
|
87245
88313
|
},
|
|
88314
|
+
{
|
|
88315
|
+
id: "package-llm",
|
|
88316
|
+
family: "device-events",
|
|
88317
|
+
label: "Package confirm",
|
|
88318
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
88319
|
+
},
|
|
87246
88320
|
{
|
|
87247
88321
|
id: "recording",
|
|
87248
88322
|
family: "device-events",
|
|
@@ -87424,6 +88498,8 @@ var DEVICE_EVENTS = [
|
|
|
87424
88498
|
"detection-blind",
|
|
87425
88499
|
"motion-noisy",
|
|
87426
88500
|
"motion-calm",
|
|
88501
|
+
"package-llm-silent",
|
|
88502
|
+
"package-llm-answered",
|
|
87427
88503
|
"recording-stalled",
|
|
87428
88504
|
"recording-healthy",
|
|
87429
88505
|
"recording-degraded",
|
|
@@ -87692,6 +88768,15 @@ new Map([
|
|
|
87692
88768
|
snapshotLabel: "Cameras with constant motion now",
|
|
87693
88769
|
snapshotSection: null
|
|
87694
88770
|
},
|
|
88771
|
+
{
|
|
88772
|
+
id: "package-llm-confirm",
|
|
88773
|
+
family: "device-events",
|
|
88774
|
+
label: "Package confirm (not answering / answering again)",
|
|
88775
|
+
bad: ["package-llm-silent"],
|
|
88776
|
+
recovery: ["package-llm-answered"],
|
|
88777
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88778
|
+
snapshotSection: null
|
|
88779
|
+
},
|
|
87695
88780
|
{
|
|
87696
88781
|
id: "recording-health",
|
|
87697
88782
|
family: "device-events",
|