@camstack/addon-provider-amcrest 0.2.160 → 0.2.162
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 +40 -0
- package/dist/addon.js +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import { networkInterfaces } from "node:os";
|
|
|
14
14
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
15
15
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
16
16
|
//#endregion
|
|
17
|
-
//#region ../types/dist/event-category-
|
|
17
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
18
18
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
19
19
|
EventCategory["SystemBoot"] = "system.boot";
|
|
20
20
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -340,6 +340,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
340
340
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
341
341
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
342
342
|
/**
|
|
343
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
344
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
345
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
346
|
+
*/
|
|
347
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
348
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
349
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
350
|
+
/**
|
|
343
351
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
344
352
|
* (a settings change via `setAgentInferenceDevices` /
|
|
345
353
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5449,7 +5457,7 @@ var ZodIssueCode = {
|
|
|
5449
5457
|
var ZodFirstPartyTypeKind;
|
|
5450
5458
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5451
5459
|
//#endregion
|
|
5452
|
-
//#region ../types/dist/sleep
|
|
5460
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5453
5461
|
/**
|
|
5454
5462
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5455
5463
|
* window to float samples (D455).
|
|
@@ -8003,6 +8011,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
8003
8011
|
}).strict();
|
|
8004
8012
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8005
8013
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8014
|
+
var READING_QUANTITIES = [
|
|
8015
|
+
"temperature",
|
|
8016
|
+
"pressure",
|
|
8017
|
+
"speed",
|
|
8018
|
+
"precipitation",
|
|
8019
|
+
"precipitation-rate",
|
|
8020
|
+
"length",
|
|
8021
|
+
"area",
|
|
8022
|
+
"illuminance",
|
|
8023
|
+
"irradiance",
|
|
8024
|
+
"power",
|
|
8025
|
+
"energy",
|
|
8026
|
+
"voltage",
|
|
8027
|
+
"current",
|
|
8028
|
+
"apparent-power",
|
|
8029
|
+
"humidity",
|
|
8030
|
+
"percentage",
|
|
8031
|
+
"concentration-volume",
|
|
8032
|
+
"concentration-mass",
|
|
8033
|
+
"concentration-ppb",
|
|
8034
|
+
"volume",
|
|
8035
|
+
"duration",
|
|
8036
|
+
"duration-ms",
|
|
8037
|
+
"information",
|
|
8038
|
+
"sound-level",
|
|
8039
|
+
"signal-level",
|
|
8040
|
+
"colour-temperature",
|
|
8041
|
+
"angle",
|
|
8042
|
+
"bitrate",
|
|
8043
|
+
"rate",
|
|
8044
|
+
"mass",
|
|
8045
|
+
"index",
|
|
8046
|
+
"ratio",
|
|
8047
|
+
"count",
|
|
8048
|
+
"none",
|
|
8049
|
+
"device"
|
|
8050
|
+
];
|
|
8051
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8052
|
+
new Set(READING_QUANTITIES);
|
|
8053
|
+
/**
|
|
8054
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8055
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8056
|
+
*/
|
|
8057
|
+
var QUANTITY_BASE = {
|
|
8058
|
+
temperature: "°C",
|
|
8059
|
+
pressure: "hPa",
|
|
8060
|
+
speed: "m/s",
|
|
8061
|
+
precipitation: "mm",
|
|
8062
|
+
"precipitation-rate": "mm/h",
|
|
8063
|
+
length: "m",
|
|
8064
|
+
area: "m²",
|
|
8065
|
+
illuminance: "lx",
|
|
8066
|
+
irradiance: "W/m²",
|
|
8067
|
+
power: "W",
|
|
8068
|
+
energy: "kWh",
|
|
8069
|
+
voltage: "V",
|
|
8070
|
+
current: "A",
|
|
8071
|
+
"apparent-power": "VA",
|
|
8072
|
+
humidity: "%",
|
|
8073
|
+
percentage: "%",
|
|
8074
|
+
"concentration-volume": "ppm",
|
|
8075
|
+
"concentration-mass": "µg/m³",
|
|
8076
|
+
"concentration-ppb": "ppb",
|
|
8077
|
+
volume: "L",
|
|
8078
|
+
duration: "s",
|
|
8079
|
+
"duration-ms": "ms",
|
|
8080
|
+
information: "B",
|
|
8081
|
+
"sound-level": "dBFS",
|
|
8082
|
+
"signal-level": "dBm",
|
|
8083
|
+
"colour-temperature": "mired",
|
|
8084
|
+
angle: "°",
|
|
8085
|
+
bitrate: "kbps",
|
|
8086
|
+
rate: "fps",
|
|
8087
|
+
mass: "kg",
|
|
8088
|
+
index: "none",
|
|
8089
|
+
ratio: "none",
|
|
8090
|
+
count: "none",
|
|
8091
|
+
none: "none",
|
|
8092
|
+
device: "device"
|
|
8093
|
+
};
|
|
8094
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8095
|
+
function baseUnitOf(quantity) {
|
|
8096
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8097
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8098
|
+
return symbol;
|
|
8099
|
+
}
|
|
8100
|
+
function readingMeta(quantity, extras) {
|
|
8101
|
+
return {
|
|
8102
|
+
quantity,
|
|
8103
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8104
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8105
|
+
};
|
|
8106
|
+
}
|
|
8006
8107
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8007
8108
|
var CamProfileSchema = _enum([
|
|
8008
8109
|
"high",
|
|
@@ -8030,8 +8131,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8030
8131
|
"derived"
|
|
8031
8132
|
]);
|
|
8032
8133
|
var CamStreamResolutionSchema = object({
|
|
8033
|
-
width: number().int().positive(),
|
|
8034
|
-
height: number().int().positive()
|
|
8134
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8135
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8035
8136
|
});
|
|
8036
8137
|
var CameraStreamSchema = object({
|
|
8037
8138
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8549,6 +8650,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8549
8650
|
"filesystem-browse",
|
|
8550
8651
|
"flood",
|
|
8551
8652
|
"gas",
|
|
8653
|
+
"group-active",
|
|
8654
|
+
"group-commands",
|
|
8655
|
+
"group-status",
|
|
8552
8656
|
"heating-valve",
|
|
8553
8657
|
"humidifier",
|
|
8554
8658
|
"humidity-sensor",
|
|
@@ -8569,6 +8673,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8569
8673
|
"login-method",
|
|
8570
8674
|
"media-player",
|
|
8571
8675
|
"mesh-network",
|
|
8676
|
+
"meter",
|
|
8572
8677
|
"metrics-provider",
|
|
8573
8678
|
"model-convert",
|
|
8574
8679
|
"model-distributor",
|
|
@@ -8678,14 +8783,6 @@ Object.freeze({
|
|
|
8678
8783
|
{
|
|
8679
8784
|
"path": "aqi",
|
|
8680
8785
|
"valueType": "number"
|
|
8681
|
-
},
|
|
8682
|
-
{
|
|
8683
|
-
"path": "unit",
|
|
8684
|
-
"valueType": "string"
|
|
8685
|
-
},
|
|
8686
|
-
{
|
|
8687
|
-
"path": "precision",
|
|
8688
|
-
"valueType": "number"
|
|
8689
8786
|
}
|
|
8690
8787
|
],
|
|
8691
8788
|
"alarm-panel": [
|
|
@@ -8721,20 +8818,10 @@ Object.freeze({
|
|
|
8721
8818
|
"valueType": "boolean"
|
|
8722
8819
|
}
|
|
8723
8820
|
],
|
|
8724
|
-
"ambient-light-sensor": [
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
},
|
|
8729
|
-
{
|
|
8730
|
-
"path": "unit",
|
|
8731
|
-
"valueType": "string"
|
|
8732
|
-
},
|
|
8733
|
-
{
|
|
8734
|
-
"path": "precision",
|
|
8735
|
-
"valueType": "number"
|
|
8736
|
-
}
|
|
8737
|
-
],
|
|
8821
|
+
"ambient-light-sensor": [{
|
|
8822
|
+
"path": "lux",
|
|
8823
|
+
"valueType": "number"
|
|
8824
|
+
}],
|
|
8738
8825
|
"audio-metrics": [
|
|
8739
8826
|
{
|
|
8740
8827
|
"path": "ts",
|
|
@@ -8814,6 +8901,10 @@ Object.freeze({
|
|
|
8814
8901
|
"path": "lastUpdated",
|
|
8815
8902
|
"valueType": "number"
|
|
8816
8903
|
},
|
|
8904
|
+
{
|
|
8905
|
+
"path": "volts",
|
|
8906
|
+
"valueType": "number"
|
|
8907
|
+
},
|
|
8817
8908
|
{
|
|
8818
8909
|
"path": "lastContactAt",
|
|
8819
8910
|
"valueType": "number"
|
|
@@ -9056,10 +9147,6 @@ Object.freeze({
|
|
|
9056
9147
|
"datetime"
|
|
9057
9148
|
]
|
|
9058
9149
|
},
|
|
9059
|
-
{
|
|
9060
|
-
"path": "unit",
|
|
9061
|
-
"valueType": "string"
|
|
9062
|
-
},
|
|
9063
9150
|
{
|
|
9064
9151
|
"path": "min",
|
|
9065
9152
|
"valueType": "number"
|
|
@@ -9071,19 +9158,6 @@ Object.freeze({
|
|
|
9071
9158
|
{
|
|
9072
9159
|
"path": "step",
|
|
9073
9160
|
"valueType": "number"
|
|
9074
|
-
},
|
|
9075
|
-
{
|
|
9076
|
-
"path": "precision",
|
|
9077
|
-
"valueType": "number"
|
|
9078
|
-
},
|
|
9079
|
-
{
|
|
9080
|
-
"path": "format",
|
|
9081
|
-
"valueType": "enum",
|
|
9082
|
-
"enumValues": [
|
|
9083
|
-
"date",
|
|
9084
|
-
"time",
|
|
9085
|
-
"datetime"
|
|
9086
|
-
]
|
|
9087
9161
|
}
|
|
9088
9162
|
],
|
|
9089
9163
|
"cover": [
|
|
@@ -9324,13 +9398,8 @@ Object.freeze({
|
|
|
9324
9398
|
"path": "value",
|
|
9325
9399
|
"valueType": "string"
|
|
9326
9400
|
}, {
|
|
9327
|
-
"path": "
|
|
9328
|
-
"valueType": "
|
|
9329
|
-
"enumValues": [
|
|
9330
|
-
"date",
|
|
9331
|
-
"time",
|
|
9332
|
-
"datetime"
|
|
9333
|
-
]
|
|
9401
|
+
"path": "timestamp",
|
|
9402
|
+
"valueType": "boolean"
|
|
9334
9403
|
}],
|
|
9335
9404
|
"event-emitter": [
|
|
9336
9405
|
{
|
|
@@ -9403,6 +9472,24 @@ Object.freeze({
|
|
|
9403
9472
|
"path": "detected",
|
|
9404
9473
|
"valueType": "boolean"
|
|
9405
9474
|
}],
|
|
9475
|
+
"group-active": [{
|
|
9476
|
+
"path": "active",
|
|
9477
|
+
"valueType": "boolean"
|
|
9478
|
+
}],
|
|
9479
|
+
"group-status": [
|
|
9480
|
+
{
|
|
9481
|
+
"path": "included",
|
|
9482
|
+
"valueType": "number"
|
|
9483
|
+
},
|
|
9484
|
+
{
|
|
9485
|
+
"path": "excluded",
|
|
9486
|
+
"valueType": "number"
|
|
9487
|
+
},
|
|
9488
|
+
{
|
|
9489
|
+
"path": "total",
|
|
9490
|
+
"valueType": "number"
|
|
9491
|
+
}
|
|
9492
|
+
],
|
|
9406
9493
|
"heating-valve": [{
|
|
9407
9494
|
"path": "position",
|
|
9408
9495
|
"valueType": "number"
|
|
@@ -9437,20 +9524,10 @@ Object.freeze({
|
|
|
9437
9524
|
"valueType": "number"
|
|
9438
9525
|
}
|
|
9439
9526
|
],
|
|
9440
|
-
"humidity-sensor": [
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
},
|
|
9445
|
-
{
|
|
9446
|
-
"path": "unit",
|
|
9447
|
-
"valueType": "string"
|
|
9448
|
-
},
|
|
9449
|
-
{
|
|
9450
|
-
"path": "precision",
|
|
9451
|
-
"valueType": "number"
|
|
9452
|
-
}
|
|
9453
|
-
],
|
|
9527
|
+
"humidity-sensor": [{
|
|
9528
|
+
"path": "percent",
|
|
9529
|
+
"valueType": "number"
|
|
9530
|
+
}],
|
|
9454
9531
|
"image": [{
|
|
9455
9532
|
"path": "url",
|
|
9456
9533
|
"valueType": "string"
|
|
@@ -9658,6 +9735,10 @@ Object.freeze({
|
|
|
9658
9735
|
]
|
|
9659
9736
|
}
|
|
9660
9737
|
],
|
|
9738
|
+
"meter": [{
|
|
9739
|
+
"path": "value",
|
|
9740
|
+
"valueType": "number"
|
|
9741
|
+
}],
|
|
9661
9742
|
"motion": [
|
|
9662
9743
|
{
|
|
9663
9744
|
"path": "detected",
|
|
@@ -9789,20 +9870,10 @@ Object.freeze({
|
|
|
9789
9870
|
"valueType": "boolean"
|
|
9790
9871
|
}
|
|
9791
9872
|
],
|
|
9792
|
-
"numeric-sensor": [
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
},
|
|
9797
|
-
{
|
|
9798
|
-
"path": "unit",
|
|
9799
|
-
"valueType": "string"
|
|
9800
|
-
},
|
|
9801
|
-
{
|
|
9802
|
-
"path": "precision",
|
|
9803
|
-
"valueType": "number"
|
|
9804
|
-
}
|
|
9805
|
-
],
|
|
9873
|
+
"numeric-sensor": [{
|
|
9874
|
+
"path": "value",
|
|
9875
|
+
"valueType": "number"
|
|
9876
|
+
}],
|
|
9806
9877
|
"pet-feeder": [
|
|
9807
9878
|
{
|
|
9808
9879
|
"path": "foodLevel",
|
|
@@ -9894,14 +9965,6 @@ Object.freeze({
|
|
|
9894
9965
|
{
|
|
9895
9966
|
"path": "powerFactor",
|
|
9896
9967
|
"valueType": "number"
|
|
9897
|
-
},
|
|
9898
|
-
{
|
|
9899
|
-
"path": "unit",
|
|
9900
|
-
"valueType": "string"
|
|
9901
|
-
},
|
|
9902
|
-
{
|
|
9903
|
-
"path": "precision",
|
|
9904
|
-
"valueType": "number"
|
|
9905
9968
|
}
|
|
9906
9969
|
],
|
|
9907
9970
|
"presence": [
|
|
@@ -9930,20 +9993,10 @@ Object.freeze({
|
|
|
9930
9993
|
"valueType": "number"
|
|
9931
9994
|
}
|
|
9932
9995
|
],
|
|
9933
|
-
"pressure-sensor": [
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
},
|
|
9938
|
-
{
|
|
9939
|
-
"path": "unit",
|
|
9940
|
-
"valueType": "string"
|
|
9941
|
-
},
|
|
9942
|
-
{
|
|
9943
|
-
"path": "precision",
|
|
9944
|
-
"valueType": "number"
|
|
9945
|
-
}
|
|
9946
|
-
],
|
|
9996
|
+
"pressure-sensor": [{
|
|
9997
|
+
"path": "hpa",
|
|
9998
|
+
"valueType": "number"
|
|
9999
|
+
}],
|
|
9947
10000
|
"privacy-mask": [{
|
|
9948
10001
|
"path": "enabled",
|
|
9949
10002
|
"valueType": "boolean"
|
|
@@ -10254,20 +10307,10 @@ Object.freeze({
|
|
|
10254
10307
|
"path": "tampered",
|
|
10255
10308
|
"valueType": "boolean"
|
|
10256
10309
|
}],
|
|
10257
|
-
"temperature-sensor": [
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
},
|
|
10262
|
-
{
|
|
10263
|
-
"path": "unit",
|
|
10264
|
-
"valueType": "string"
|
|
10265
|
-
},
|
|
10266
|
-
{
|
|
10267
|
-
"path": "precision",
|
|
10268
|
-
"valueType": "number"
|
|
10269
|
-
}
|
|
10270
|
-
],
|
|
10310
|
+
"temperature-sensor": [{
|
|
10311
|
+
"path": "celsius",
|
|
10312
|
+
"valueType": "number"
|
|
10313
|
+
}],
|
|
10271
10314
|
"update": [
|
|
10272
10315
|
{
|
|
10273
10316
|
"path": "currentVersion",
|
|
@@ -10378,10 +10421,6 @@ Object.freeze({
|
|
|
10378
10421
|
"path": "temperature",
|
|
10379
10422
|
"valueType": "number"
|
|
10380
10423
|
},
|
|
10381
|
-
{
|
|
10382
|
-
"path": "temperatureUnit",
|
|
10383
|
-
"valueType": "string"
|
|
10384
|
-
},
|
|
10385
10424
|
{
|
|
10386
10425
|
"path": "humidity",
|
|
10387
10426
|
"valueType": "number"
|
|
@@ -10390,18 +10429,10 @@ Object.freeze({
|
|
|
10390
10429
|
"path": "pressure",
|
|
10391
10430
|
"valueType": "number"
|
|
10392
10431
|
},
|
|
10393
|
-
{
|
|
10394
|
-
"path": "pressureUnit",
|
|
10395
|
-
"valueType": "string"
|
|
10396
|
-
},
|
|
10397
10432
|
{
|
|
10398
10433
|
"path": "windSpeed",
|
|
10399
10434
|
"valueType": "number"
|
|
10400
10435
|
},
|
|
10401
|
-
{
|
|
10402
|
-
"path": "windSpeedUnit",
|
|
10403
|
-
"valueType": "string"
|
|
10404
|
-
},
|
|
10405
10436
|
{
|
|
10406
10437
|
"path": "windBearing",
|
|
10407
10438
|
"valueType": "number"
|
|
@@ -10465,7 +10496,7 @@ function userError(code, params, englishFallback) {
|
|
|
10465
10496
|
return new CamstackError(code, params, englishFallback);
|
|
10466
10497
|
}
|
|
10467
10498
|
//#endregion
|
|
10468
|
-
//#region ../types/dist/err-msg-
|
|
10499
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10469
10500
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10470
10501
|
DeviceType["Camera"] = "camera";
|
|
10471
10502
|
DeviceType["Hub"] = "hub";
|
|
@@ -10559,8 +10590,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10559
10590
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10560
10591
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10561
10592
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10562
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10593
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10594
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10563
10595
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10596
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10597
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10598
|
+
DeviceType["Washer"] = "washer";
|
|
10599
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10600
|
+
DeviceType["Dryer"] = "dryer";
|
|
10564
10601
|
return DeviceType;
|
|
10565
10602
|
}({});
|
|
10566
10603
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10808,7 +10845,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
10808
10845
|
return DeviceRole;
|
|
10809
10846
|
}({});
|
|
10810
10847
|
//#endregion
|
|
10811
|
-
//#region ../types/dist/composition-
|
|
10848
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10812
10849
|
/**
|
|
10813
10850
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10814
10851
|
*
|
|
@@ -11123,6 +11160,13 @@ var table = {
|
|
|
11123
11160
|
apply: () => {
|
|
11124
11161
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11125
11162
|
}
|
|
11163
|
+
},
|
|
11164
|
+
schmitt: {
|
|
11165
|
+
minArgs: 3,
|
|
11166
|
+
maxArgs: 5,
|
|
11167
|
+
apply: () => {
|
|
11168
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11169
|
+
}
|
|
11126
11170
|
}
|
|
11127
11171
|
};
|
|
11128
11172
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11563,15 +11607,232 @@ function validateExpressionSource(src) {
|
|
|
11563
11607
|
}
|
|
11564
11608
|
return null;
|
|
11565
11609
|
}
|
|
11566
|
-
/**
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11610
|
+
/**
|
|
11611
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11612
|
+
*
|
|
11613
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11614
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11615
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11616
|
+
*
|
|
11617
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11618
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11619
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11620
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11621
|
+
* can move later without moving the others.
|
|
11622
|
+
*/
|
|
11623
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11624
|
+
var APPLIANCE_KINDS = [
|
|
11625
|
+
"washer",
|
|
11626
|
+
"dryer",
|
|
11627
|
+
"dishwasher"
|
|
11628
|
+
];
|
|
11629
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11630
|
+
/**
|
|
11631
|
+
* Statistics and integrals over a history read (D944).
|
|
11632
|
+
*
|
|
11633
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11634
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11635
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11636
|
+
* as zero. A truncated read is not published.
|
|
11637
|
+
*/
|
|
11638
|
+
var STATISTIC_STATS = [
|
|
11639
|
+
"min",
|
|
11640
|
+
"max",
|
|
11641
|
+
"mean",
|
|
11642
|
+
"sum",
|
|
11643
|
+
"count",
|
|
11644
|
+
"change"
|
|
11645
|
+
];
|
|
11646
|
+
/**
|
|
11647
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11648
|
+
*
|
|
11649
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11650
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11651
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11652
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11653
|
+
*/
|
|
11654
|
+
var MINUTE_MS = 6e4;
|
|
11655
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11656
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11657
|
+
var ROLLING_SPANS = [
|
|
11658
|
+
"1h",
|
|
11659
|
+
"24h",
|
|
11660
|
+
"2d",
|
|
11661
|
+
"7d",
|
|
11662
|
+
"30d",
|
|
11663
|
+
"custom"
|
|
11664
|
+
];
|
|
11665
|
+
var CALENDAR_PERIODS = [
|
|
11666
|
+
"today",
|
|
11667
|
+
"yesterday",
|
|
11668
|
+
"this-week",
|
|
11669
|
+
"this-month"
|
|
11670
|
+
];
|
|
11671
|
+
var RESET_PERIODS = [
|
|
11672
|
+
"never",
|
|
11673
|
+
"daily",
|
|
11674
|
+
"weekly",
|
|
11675
|
+
"monthly"
|
|
11676
|
+
];
|
|
11677
|
+
5 * MINUTE_MS;
|
|
11678
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11679
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11680
|
+
var rollingWindowObject = object({
|
|
11681
|
+
kind: literal("rolling"),
|
|
11682
|
+
span: _enum(ROLLING_SPANS),
|
|
11683
|
+
customMinutes: number().int().min(5).optional()
|
|
11684
|
+
}).check((payload) => {
|
|
11685
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11686
|
+
code: "custom",
|
|
11687
|
+
message: "a custom range needs a duration in minutes",
|
|
11688
|
+
path: ["customMinutes"],
|
|
11689
|
+
input: payload.value
|
|
11690
|
+
});
|
|
11691
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11692
|
+
code: "custom",
|
|
11693
|
+
message: "only a custom range carries a duration",
|
|
11694
|
+
path: ["customMinutes"],
|
|
11695
|
+
input: payload.value
|
|
11696
|
+
});
|
|
11697
|
+
});
|
|
11698
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11699
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11700
|
+
kind: literal("calendar"),
|
|
11701
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11702
|
+
})]);
|
|
11703
|
+
/**
|
|
11704
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11705
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11706
|
+
* `composition.ts` (D659).
|
|
11707
|
+
*/
|
|
11570
11708
|
var CompositionSourceRefSchema = object({
|
|
11571
11709
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11572
11710
|
addonId: string().min(1),
|
|
11573
11711
|
stableId: string().min(1)
|
|
11574
11712
|
});
|
|
11713
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11714
|
+
"temperature",
|
|
11715
|
+
"humidity",
|
|
11716
|
+
"pressure",
|
|
11717
|
+
"illuminance",
|
|
11718
|
+
"power",
|
|
11719
|
+
"energy",
|
|
11720
|
+
"battery",
|
|
11721
|
+
"numeric",
|
|
11722
|
+
"motion",
|
|
11723
|
+
"contact",
|
|
11724
|
+
"leak",
|
|
11725
|
+
"smoke",
|
|
11726
|
+
"occupancy",
|
|
11727
|
+
"binary",
|
|
11728
|
+
"switch",
|
|
11729
|
+
"light",
|
|
11730
|
+
"fan",
|
|
11731
|
+
"cover",
|
|
11732
|
+
"valve",
|
|
11733
|
+
"lock",
|
|
11734
|
+
"media-player",
|
|
11735
|
+
"climate"
|
|
11736
|
+
];
|
|
11737
|
+
var NUMERIC_AGGREGATES = [
|
|
11738
|
+
"mean",
|
|
11739
|
+
"median",
|
|
11740
|
+
"min",
|
|
11741
|
+
"max",
|
|
11742
|
+
"sum"
|
|
11743
|
+
];
|
|
11744
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11745
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11746
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11747
|
+
var AGGREGATE_REDUCERS = [
|
|
11748
|
+
"mean",
|
|
11749
|
+
"median",
|
|
11750
|
+
"min",
|
|
11751
|
+
"max",
|
|
11752
|
+
"sum",
|
|
11753
|
+
"any",
|
|
11754
|
+
"all"
|
|
11755
|
+
];
|
|
11756
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11757
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11758
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11759
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11760
|
+
var HelperMemberSchema = object({
|
|
11761
|
+
source: CompositionSourceRefSchema,
|
|
11762
|
+
cap: string().min(1),
|
|
11763
|
+
fieldPath: string().min(1)
|
|
11764
|
+
});
|
|
11765
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11766
|
+
object({
|
|
11767
|
+
kind: literal("group"),
|
|
11768
|
+
templateId: GroupTemplateIdSchema,
|
|
11769
|
+
aggregate: AggregateReducerSchema,
|
|
11770
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11771
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11772
|
+
active: ActiveCriterionSchema.optional()
|
|
11773
|
+
}),
|
|
11774
|
+
object({
|
|
11775
|
+
kind: literal("appliance"),
|
|
11776
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11777
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11778
|
+
thresholdWatts: number().positive(),
|
|
11779
|
+
startDwellMs: number().int().nonnegative(),
|
|
11780
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11781
|
+
member: HelperMemberSchema
|
|
11782
|
+
}),
|
|
11783
|
+
object({
|
|
11784
|
+
kind: literal("statistic"),
|
|
11785
|
+
stat: _enum(STATISTIC_STATS),
|
|
11786
|
+
window: StatisticWindowSchema,
|
|
11787
|
+
source: HelperMemberSchema
|
|
11788
|
+
}),
|
|
11789
|
+
object({
|
|
11790
|
+
kind: literal("integral"),
|
|
11791
|
+
reset: _enum(RESET_PERIODS),
|
|
11792
|
+
output: _enum(["energy", "meter"]),
|
|
11793
|
+
source: HelperMemberSchema
|
|
11794
|
+
}),
|
|
11795
|
+
object({
|
|
11796
|
+
kind: literal("threshold"),
|
|
11797
|
+
source: HelperMemberSchema,
|
|
11798
|
+
high: number(),
|
|
11799
|
+
low: number(),
|
|
11800
|
+
onForMs: number().int().nonnegative(),
|
|
11801
|
+
offForMs: number().int().nonnegative()
|
|
11802
|
+
}),
|
|
11803
|
+
object({
|
|
11804
|
+
kind: literal("arithmetic"),
|
|
11805
|
+
op: _enum([
|
|
11806
|
+
"sum",
|
|
11807
|
+
"difference",
|
|
11808
|
+
"ratio"
|
|
11809
|
+
]),
|
|
11810
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11811
|
+
}),
|
|
11812
|
+
object({
|
|
11813
|
+
kind: literal("expression"),
|
|
11814
|
+
expr: string().min(1),
|
|
11815
|
+
inputs: array(object({
|
|
11816
|
+
name: string().min(1),
|
|
11817
|
+
member: HelperMemberSchema
|
|
11818
|
+
})).min(1).max(64),
|
|
11819
|
+
output: _enum(["number", "boolean"])
|
|
11820
|
+
}),
|
|
11821
|
+
object({
|
|
11822
|
+
kind: literal("derivative"),
|
|
11823
|
+
window: RollingWindowSchema,
|
|
11824
|
+
per: _enum([
|
|
11825
|
+
"second",
|
|
11826
|
+
"minute",
|
|
11827
|
+
"hour"
|
|
11828
|
+
]),
|
|
11829
|
+
source: HelperMemberSchema
|
|
11830
|
+
})
|
|
11831
|
+
]);
|
|
11832
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11833
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11834
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11835
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11575
11836
|
/** One field of one capability of one source device. */
|
|
11576
11837
|
var CompositionFieldReadSchema = object({
|
|
11577
11838
|
source: CompositionSourceRefSchema,
|
|
@@ -11615,7 +11876,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11615
11876
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11616
11877
|
CompositionFromSourceSchema,
|
|
11617
11878
|
CompositionExpressionSourceSchema,
|
|
11618
|
-
CompositionCodeSourceSchema
|
|
11879
|
+
CompositionCodeSourceSchema,
|
|
11880
|
+
object({
|
|
11881
|
+
kind: literal("aggregate"),
|
|
11882
|
+
reducer: _enum([
|
|
11883
|
+
"mean",
|
|
11884
|
+
"median",
|
|
11885
|
+
"min",
|
|
11886
|
+
"max",
|
|
11887
|
+
"sum",
|
|
11888
|
+
"any",
|
|
11889
|
+
"all"
|
|
11890
|
+
]),
|
|
11891
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11892
|
+
/**
|
|
11893
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11894
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11895
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11896
|
+
*/
|
|
11897
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11898
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11899
|
+
publish: _enum([
|
|
11900
|
+
"value",
|
|
11901
|
+
"included",
|
|
11902
|
+
"excluded",
|
|
11903
|
+
"total"
|
|
11904
|
+
]),
|
|
11905
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11906
|
+
empty: _enum([
|
|
11907
|
+
"null",
|
|
11908
|
+
"omit",
|
|
11909
|
+
"offline"
|
|
11910
|
+
])
|
|
11911
|
+
}),
|
|
11912
|
+
object({
|
|
11913
|
+
kind: literal("series"),
|
|
11914
|
+
read: CompositionFieldReadSchema,
|
|
11915
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11916
|
+
publish: _enum([
|
|
11917
|
+
"value",
|
|
11918
|
+
"included",
|
|
11919
|
+
"excluded",
|
|
11920
|
+
"total"
|
|
11921
|
+
]),
|
|
11922
|
+
/**
|
|
11923
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11924
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11925
|
+
*/
|
|
11926
|
+
empty: _enum([
|
|
11927
|
+
"null",
|
|
11928
|
+
"omit",
|
|
11929
|
+
"offline"
|
|
11930
|
+
])
|
|
11931
|
+
})
|
|
11619
11932
|
]);
|
|
11620
11933
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11621
11934
|
kind: literal("forward"),
|
|
@@ -11661,7 +11974,13 @@ var CompositionSchema = object({
|
|
|
11661
11974
|
kind: literal("existing"),
|
|
11662
11975
|
device: CompositionSourceRefSchema
|
|
11663
11976
|
})]),
|
|
11664
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
11977
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
11978
|
+
/**
|
|
11979
|
+
* Present when the block is a helper template. Absent on a free
|
|
11980
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
11981
|
+
* never the compiled features.
|
|
11982
|
+
*/
|
|
11983
|
+
helper: HelperSpecSchema.optional()
|
|
11665
11984
|
}).superRefine((composition, ctx) => {
|
|
11666
11985
|
const seen = /* @__PURE__ */ new Set();
|
|
11667
11986
|
composition.features.forEach((feature, index) => {
|
|
@@ -16806,7 +17125,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16806
17125
|
*/
|
|
16807
17126
|
interactiveConnectPath: string().min(1).optional(),
|
|
16808
17127
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16809
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17128
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17129
|
+
/**
|
|
17130
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17131
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17132
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17133
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17134
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17135
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17136
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17137
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17138
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17139
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17140
|
+
* offers it as the default path; the fields the session fills are
|
|
17141
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17142
|
+
*/
|
|
17143
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16810
17144
|
}))
|
|
16811
17145
|
});
|
|
16812
17146
|
var ListInputSchema = object({
|
|
@@ -17907,7 +18241,12 @@ var CompositionProblemSchema = object({
|
|
|
17907
18241
|
"item-field-reserved",
|
|
17908
18242
|
"target-missing",
|
|
17909
18243
|
"target-unreadable",
|
|
17910
|
-
"not-replaceable"
|
|
18244
|
+
"not-replaceable",
|
|
18245
|
+
"native-capability-replace",
|
|
18246
|
+
"mixed-quantity",
|
|
18247
|
+
"helper-mismatch",
|
|
18248
|
+
"member-constraint",
|
|
18249
|
+
"retention"
|
|
17911
18250
|
]),
|
|
17912
18251
|
path: string(),
|
|
17913
18252
|
message: string()
|
|
@@ -17928,7 +18267,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17928
18267
|
"null",
|
|
17929
18268
|
"offline",
|
|
17930
18269
|
"unknown",
|
|
17931
|
-
"release"
|
|
18270
|
+
"release",
|
|
18271
|
+
"omit"
|
|
17932
18272
|
]);
|
|
17933
18273
|
/**
|
|
17934
18274
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17965,9 +18305,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17965
18305
|
reads: array(CompositionFieldReadSchema)
|
|
17966
18306
|
});
|
|
17967
18307
|
/**
|
|
17968
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17969
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17970
|
-
*
|
|
18308
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18309
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18310
|
+
* Replacing a capability the device already serves is refused
|
|
18311
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18312
|
+
* wire for a claim the hub already holds.
|
|
17971
18313
|
*/
|
|
17972
18314
|
var CompositionFeatureModeSchema = _enum([
|
|
17973
18315
|
"new",
|
|
@@ -18138,8 +18480,392 @@ Object.freeze({
|
|
|
18138
18480
|
latchedAt: {
|
|
18139
18481
|
kind: "fixed",
|
|
18140
18482
|
result: ["number", "null"]
|
|
18483
|
+
},
|
|
18484
|
+
schmitt: {
|
|
18485
|
+
kind: "fixed",
|
|
18486
|
+
result: ["boolean", "null"]
|
|
18141
18487
|
}
|
|
18142
18488
|
});
|
|
18489
|
+
/**
|
|
18490
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18491
|
+
* Data, not a form default written into the block.
|
|
18492
|
+
*/
|
|
18493
|
+
var NOW$2 = {
|
|
18494
|
+
fieldPath: "lastFetchedAt",
|
|
18495
|
+
expr: "now"
|
|
18496
|
+
};
|
|
18497
|
+
var CHANGED = {
|
|
18498
|
+
fieldPath: "lastChangedAt",
|
|
18499
|
+
expr: "now"
|
|
18500
|
+
};
|
|
18501
|
+
function numeric(input) {
|
|
18502
|
+
return {
|
|
18503
|
+
...input,
|
|
18504
|
+
family: "numeric",
|
|
18505
|
+
deviceType: DeviceType.Sensor,
|
|
18506
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18507
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18508
|
+
activeWhen: void 0,
|
|
18509
|
+
commandCaps: [],
|
|
18510
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18511
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18512
|
+
accept: [{
|
|
18513
|
+
cap: input.outputCap,
|
|
18514
|
+
fieldPath: input.outputField
|
|
18515
|
+
}]
|
|
18516
|
+
};
|
|
18517
|
+
}
|
|
18518
|
+
function binary(input) {
|
|
18519
|
+
return {
|
|
18520
|
+
...input,
|
|
18521
|
+
family: "binary",
|
|
18522
|
+
deviceType: DeviceType.Sensor,
|
|
18523
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18524
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18525
|
+
activeWhen: void 0,
|
|
18526
|
+
commandCaps: [],
|
|
18527
|
+
quantity: "none",
|
|
18528
|
+
baseUnit: void 0,
|
|
18529
|
+
aggregates: BINARY_AGGREGATES,
|
|
18530
|
+
empty: "offline"
|
|
18531
|
+
};
|
|
18532
|
+
}
|
|
18533
|
+
var GROUP_TEMPLATES = [
|
|
18534
|
+
numeric({
|
|
18535
|
+
id: "temperature",
|
|
18536
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18537
|
+
role: DeviceRole.TemperatureSensor,
|
|
18538
|
+
outputCap: "temperature-sensor",
|
|
18539
|
+
outputField: "celsius",
|
|
18540
|
+
quantity: "temperature",
|
|
18541
|
+
defaultAggregate: "mean",
|
|
18542
|
+
empty: "null",
|
|
18543
|
+
companions: [NOW$2]
|
|
18544
|
+
}),
|
|
18545
|
+
numeric({
|
|
18546
|
+
id: "humidity",
|
|
18547
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18548
|
+
role: DeviceRole.HumiditySensor,
|
|
18549
|
+
outputCap: "humidity-sensor",
|
|
18550
|
+
outputField: "percent",
|
|
18551
|
+
quantity: "humidity",
|
|
18552
|
+
defaultAggregate: "mean",
|
|
18553
|
+
empty: "null",
|
|
18554
|
+
companions: [NOW$2]
|
|
18555
|
+
}),
|
|
18556
|
+
numeric({
|
|
18557
|
+
id: "pressure",
|
|
18558
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18559
|
+
role: DeviceRole.PressureSensor,
|
|
18560
|
+
outputCap: "pressure-sensor",
|
|
18561
|
+
outputField: "hpa",
|
|
18562
|
+
quantity: "pressure",
|
|
18563
|
+
defaultAggregate: "mean",
|
|
18564
|
+
empty: "null",
|
|
18565
|
+
companions: [NOW$2]
|
|
18566
|
+
}),
|
|
18567
|
+
numeric({
|
|
18568
|
+
id: "illuminance",
|
|
18569
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18570
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18571
|
+
outputCap: "ambient-light-sensor",
|
|
18572
|
+
outputField: "lux",
|
|
18573
|
+
quantity: "illuminance",
|
|
18574
|
+
defaultAggregate: "mean",
|
|
18575
|
+
empty: "null",
|
|
18576
|
+
companions: [NOW$2]
|
|
18577
|
+
}),
|
|
18578
|
+
numeric({
|
|
18579
|
+
id: "power",
|
|
18580
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18581
|
+
role: DeviceRole.PowerSensor,
|
|
18582
|
+
outputCap: "power-meter",
|
|
18583
|
+
outputField: "watts",
|
|
18584
|
+
quantity: "power",
|
|
18585
|
+
defaultAggregate: "sum",
|
|
18586
|
+
empty: "omit",
|
|
18587
|
+
companions: [NOW$2]
|
|
18588
|
+
}),
|
|
18589
|
+
numeric({
|
|
18590
|
+
id: "energy",
|
|
18591
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18592
|
+
role: DeviceRole.EnergySensor,
|
|
18593
|
+
outputCap: "power-meter",
|
|
18594
|
+
outputField: "kwhTotal",
|
|
18595
|
+
quantity: "energy",
|
|
18596
|
+
defaultAggregate: "sum",
|
|
18597
|
+
empty: "omit",
|
|
18598
|
+
companions: [NOW$2]
|
|
18599
|
+
}),
|
|
18600
|
+
numeric({
|
|
18601
|
+
id: "battery",
|
|
18602
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18603
|
+
role: DeviceRole.BatterySensor,
|
|
18604
|
+
outputCap: "battery",
|
|
18605
|
+
outputField: "percentage",
|
|
18606
|
+
quantity: "percentage",
|
|
18607
|
+
defaultAggregate: "mean",
|
|
18608
|
+
empty: "null",
|
|
18609
|
+
companions: [
|
|
18610
|
+
{
|
|
18611
|
+
fieldPath: "charging",
|
|
18612
|
+
expr: "\"unknown\""
|
|
18613
|
+
},
|
|
18614
|
+
{
|
|
18615
|
+
fieldPath: "sleeping",
|
|
18616
|
+
expr: "false"
|
|
18617
|
+
},
|
|
18618
|
+
{
|
|
18619
|
+
fieldPath: "lastUpdated",
|
|
18620
|
+
expr: "now"
|
|
18621
|
+
}
|
|
18622
|
+
]
|
|
18623
|
+
}),
|
|
18624
|
+
numeric({
|
|
18625
|
+
id: "numeric",
|
|
18626
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18627
|
+
role: DeviceRole.NumericSensor,
|
|
18628
|
+
outputCap: "numeric-sensor",
|
|
18629
|
+
outputField: "value",
|
|
18630
|
+
quantity: "device",
|
|
18631
|
+
defaultAggregate: "mean",
|
|
18632
|
+
empty: "null",
|
|
18633
|
+
companions: [NOW$2]
|
|
18634
|
+
}),
|
|
18635
|
+
binary({
|
|
18636
|
+
id: "motion",
|
|
18637
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18638
|
+
role: DeviceRole.MotionSensor,
|
|
18639
|
+
outputCap: "motion",
|
|
18640
|
+
outputField: "detected",
|
|
18641
|
+
defaultAggregate: "any",
|
|
18642
|
+
accept: [{
|
|
18643
|
+
cap: "motion",
|
|
18644
|
+
fieldPath: "detected"
|
|
18645
|
+
}],
|
|
18646
|
+
companions: [{
|
|
18647
|
+
fieldPath: "lastDetectedAt",
|
|
18648
|
+
expr: "null"
|
|
18649
|
+
}, {
|
|
18650
|
+
fieldPath: "autoClearAfterMs",
|
|
18651
|
+
expr: "null"
|
|
18652
|
+
}]
|
|
18653
|
+
}),
|
|
18654
|
+
binary({
|
|
18655
|
+
id: "contact",
|
|
18656
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18657
|
+
role: DeviceRole.ContactSensor,
|
|
18658
|
+
outputCap: "contact",
|
|
18659
|
+
outputField: "entryOpen",
|
|
18660
|
+
defaultAggregate: "any",
|
|
18661
|
+
accept: [{
|
|
18662
|
+
cap: "contact",
|
|
18663
|
+
fieldPath: "entryOpen"
|
|
18664
|
+
}],
|
|
18665
|
+
companions: [CHANGED]
|
|
18666
|
+
}),
|
|
18667
|
+
binary({
|
|
18668
|
+
id: "leak",
|
|
18669
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18670
|
+
role: DeviceRole.LeakSensor,
|
|
18671
|
+
outputCap: "flood",
|
|
18672
|
+
outputField: "flooded",
|
|
18673
|
+
defaultAggregate: "any",
|
|
18674
|
+
accept: [{
|
|
18675
|
+
cap: "flood",
|
|
18676
|
+
fieldPath: "flooded"
|
|
18677
|
+
}],
|
|
18678
|
+
companions: [CHANGED]
|
|
18679
|
+
}),
|
|
18680
|
+
binary({
|
|
18681
|
+
id: "smoke",
|
|
18682
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18683
|
+
role: DeviceRole.SmokeSensor,
|
|
18684
|
+
outputCap: "smoke",
|
|
18685
|
+
outputField: "detected",
|
|
18686
|
+
defaultAggregate: "any",
|
|
18687
|
+
accept: [{
|
|
18688
|
+
cap: "smoke",
|
|
18689
|
+
fieldPath: "detected"
|
|
18690
|
+
}],
|
|
18691
|
+
companions: [CHANGED]
|
|
18692
|
+
}),
|
|
18693
|
+
binary({
|
|
18694
|
+
id: "occupancy",
|
|
18695
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18696
|
+
role: DeviceRole.BinarySensor,
|
|
18697
|
+
outputCap: "binary",
|
|
18698
|
+
outputField: "on",
|
|
18699
|
+
defaultAggregate: "any",
|
|
18700
|
+
accept: [{
|
|
18701
|
+
cap: "motion",
|
|
18702
|
+
fieldPath: "detected"
|
|
18703
|
+
}, {
|
|
18704
|
+
cap: "binary",
|
|
18705
|
+
fieldPath: "on"
|
|
18706
|
+
}],
|
|
18707
|
+
companions: [CHANGED]
|
|
18708
|
+
}),
|
|
18709
|
+
binary({
|
|
18710
|
+
id: "binary",
|
|
18711
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18712
|
+
role: DeviceRole.BinarySensor,
|
|
18713
|
+
outputCap: "binary",
|
|
18714
|
+
outputField: "on",
|
|
18715
|
+
defaultAggregate: "any",
|
|
18716
|
+
accept: [{
|
|
18717
|
+
cap: "binary",
|
|
18718
|
+
fieldPath: "on"
|
|
18719
|
+
}],
|
|
18720
|
+
companions: [CHANGED]
|
|
18721
|
+
}),
|
|
18722
|
+
actuator({
|
|
18723
|
+
id: "switch",
|
|
18724
|
+
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.",
|
|
18725
|
+
deviceType: DeviceType.Switch,
|
|
18726
|
+
outputCap: "switch",
|
|
18727
|
+
outputField: "on",
|
|
18728
|
+
member: {
|
|
18729
|
+
cap: "switch",
|
|
18730
|
+
fieldPath: "on"
|
|
18731
|
+
},
|
|
18732
|
+
commandCaps: ["switch"]
|
|
18733
|
+
}),
|
|
18734
|
+
actuator({
|
|
18735
|
+
id: "light",
|
|
18736
|
+
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.",
|
|
18737
|
+
deviceType: DeviceType.Light,
|
|
18738
|
+
outputCap: "switch",
|
|
18739
|
+
outputField: "on",
|
|
18740
|
+
member: {
|
|
18741
|
+
cap: "switch",
|
|
18742
|
+
fieldPath: "on"
|
|
18743
|
+
},
|
|
18744
|
+
commandCaps: [
|
|
18745
|
+
"switch",
|
|
18746
|
+
"brightness",
|
|
18747
|
+
"color"
|
|
18748
|
+
]
|
|
18749
|
+
}),
|
|
18750
|
+
actuator({
|
|
18751
|
+
id: "fan",
|
|
18752
|
+
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.",
|
|
18753
|
+
deviceType: DeviceType.Fan,
|
|
18754
|
+
outputCap: "switch",
|
|
18755
|
+
outputField: "on",
|
|
18756
|
+
member: {
|
|
18757
|
+
cap: "switch",
|
|
18758
|
+
fieldPath: "on"
|
|
18759
|
+
},
|
|
18760
|
+
commandCaps: ["switch", "fan-control"]
|
|
18761
|
+
}),
|
|
18762
|
+
actuator({
|
|
18763
|
+
id: "cover",
|
|
18764
|
+
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.",
|
|
18765
|
+
deviceType: DeviceType.Cover,
|
|
18766
|
+
outputCap: "group-active",
|
|
18767
|
+
outputField: "active",
|
|
18768
|
+
member: {
|
|
18769
|
+
cap: "cover",
|
|
18770
|
+
fieldPath: "state"
|
|
18771
|
+
},
|
|
18772
|
+
activeWhen: [
|
|
18773
|
+
"open",
|
|
18774
|
+
"opening",
|
|
18775
|
+
"stopped"
|
|
18776
|
+
],
|
|
18777
|
+
commandCaps: ["cover"]
|
|
18778
|
+
}),
|
|
18779
|
+
actuator({
|
|
18780
|
+
id: "valve",
|
|
18781
|
+
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.",
|
|
18782
|
+
deviceType: DeviceType.Valve,
|
|
18783
|
+
outputCap: "group-active",
|
|
18784
|
+
outputField: "active",
|
|
18785
|
+
member: {
|
|
18786
|
+
cap: "valve",
|
|
18787
|
+
fieldPath: "state"
|
|
18788
|
+
},
|
|
18789
|
+
activeWhen: [
|
|
18790
|
+
"open",
|
|
18791
|
+
"opening",
|
|
18792
|
+
"stopped"
|
|
18793
|
+
],
|
|
18794
|
+
commandCaps: ["valve"]
|
|
18795
|
+
}),
|
|
18796
|
+
actuator({
|
|
18797
|
+
id: "lock",
|
|
18798
|
+
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.",
|
|
18799
|
+
deviceType: DeviceType.Lock,
|
|
18800
|
+
outputCap: "group-active",
|
|
18801
|
+
outputField: "active",
|
|
18802
|
+
member: {
|
|
18803
|
+
cap: "lock-control",
|
|
18804
|
+
fieldPath: "state"
|
|
18805
|
+
},
|
|
18806
|
+
activeWhen: ["locked"],
|
|
18807
|
+
commandCaps: ["lock-control"]
|
|
18808
|
+
}),
|
|
18809
|
+
actuator({
|
|
18810
|
+
id: "media-player",
|
|
18811
|
+
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.",
|
|
18812
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18813
|
+
outputCap: "group-active",
|
|
18814
|
+
outputField: "active",
|
|
18815
|
+
member: {
|
|
18816
|
+
cap: "media-player",
|
|
18817
|
+
fieldPath: "state"
|
|
18818
|
+
},
|
|
18819
|
+
activeWhen: ["playing", "buffering"],
|
|
18820
|
+
commandCaps: ["media-player"]
|
|
18821
|
+
}),
|
|
18822
|
+
actuator({
|
|
18823
|
+
id: "climate",
|
|
18824
|
+
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.",
|
|
18825
|
+
deviceType: DeviceType.Thermostat,
|
|
18826
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18827
|
+
outputCap: "group-active",
|
|
18828
|
+
outputField: "active",
|
|
18829
|
+
member: {
|
|
18830
|
+
cap: "climate-control",
|
|
18831
|
+
fieldPath: "mode"
|
|
18832
|
+
},
|
|
18833
|
+
activeWhen: [
|
|
18834
|
+
"heat",
|
|
18835
|
+
"cool",
|
|
18836
|
+
"auto",
|
|
18837
|
+
"heat_cool",
|
|
18838
|
+
"fan_only",
|
|
18839
|
+
"dry"
|
|
18840
|
+
],
|
|
18841
|
+
commandCaps: ["climate-control"]
|
|
18842
|
+
})
|
|
18843
|
+
];
|
|
18844
|
+
function actuator(input) {
|
|
18845
|
+
return {
|
|
18846
|
+
id: input.id,
|
|
18847
|
+
summary: input.summary,
|
|
18848
|
+
deviceType: input.deviceType,
|
|
18849
|
+
outputCap: input.outputCap,
|
|
18850
|
+
outputField: input.outputField,
|
|
18851
|
+
commandCaps: input.commandCaps,
|
|
18852
|
+
family: "actuator",
|
|
18853
|
+
role: void 0,
|
|
18854
|
+
memberDeviceType: input.deviceType,
|
|
18855
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18856
|
+
activeWhen: input.activeWhen,
|
|
18857
|
+
quantity: "none",
|
|
18858
|
+
baseUnit: void 0,
|
|
18859
|
+
aggregates: BINARY_AGGREGATES,
|
|
18860
|
+
defaultAggregate: "any",
|
|
18861
|
+
empty: "offline",
|
|
18862
|
+
accept: [input.member],
|
|
18863
|
+
companions: [CHANGED]
|
|
18864
|
+
};
|
|
18865
|
+
}
|
|
18866
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18867
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18868
|
+
DeviceType.Camera;
|
|
18143
18869
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18144
18870
|
/**
|
|
18145
18871
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19966,12 +20692,12 @@ function buildDeviceAdminUrl(parts) {
|
|
|
19966
20692
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19967
20693
|
* in-place so dispatch keeps working.
|
|
19968
20694
|
*
|
|
19969
|
-
* **
|
|
19970
|
-
*
|
|
19971
|
-
*
|
|
19972
|
-
*
|
|
19973
|
-
* (`ha-domain-mapping`)
|
|
19974
|
-
* stored after that point.
|
|
20695
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20696
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20697
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20698
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20699
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20700
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19975
20701
|
*
|
|
19976
20702
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19977
20703
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19985,6 +20711,14 @@ var SourceInfoSchema = object({
|
|
|
19985
20711
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19986
20712
|
* Used to detect rename when `id` changes. */
|
|
19987
20713
|
uniqueId: string().optional(),
|
|
20714
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20715
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20716
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20717
|
+
dateTimeShape: _enum([
|
|
20718
|
+
"date",
|
|
20719
|
+
"time",
|
|
20720
|
+
"datetime"
|
|
20721
|
+
]).optional(),
|
|
19988
20722
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19989
20723
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19990
20724
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41089,7 +41823,8 @@ method(object({
|
|
|
41089
41823
|
"enum"
|
|
41090
41824
|
]),
|
|
41091
41825
|
enumValues: array(string()).optional(),
|
|
41092
|
-
item: boolean().optional()
|
|
41826
|
+
item: boolean().optional(),
|
|
41827
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41093
41828
|
})).readonly(),
|
|
41094
41829
|
itemArray: object({
|
|
41095
41830
|
path: string(),
|
|
@@ -43450,7 +44185,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43450
44185
|
});
|
|
43451
44186
|
/**
|
|
43452
44187
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43453
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44188
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43454
44189
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43455
44190
|
* the originating provider config (mode + sourcePort) so the
|
|
43456
44191
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44933,8 +45668,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44933
45668
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44934
45669
|
var MaskGridShapeSchema = object({
|
|
44935
45670
|
kind: literal("grid"),
|
|
44936
|
-
gridWidth: number(),
|
|
44937
|
-
gridHeight: number(),
|
|
45671
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45672
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44938
45673
|
cells: array(boolean())
|
|
44939
45674
|
});
|
|
44940
45675
|
discriminatedUnion("kind", [
|
|
@@ -45046,6 +45781,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45046
45781
|
"detection-blind",
|
|
45047
45782
|
"motion-noisy",
|
|
45048
45783
|
"motion-calm",
|
|
45784
|
+
"package-llm-silent",
|
|
45785
|
+
"package-llm-answered",
|
|
45049
45786
|
"recording-stalled",
|
|
45050
45787
|
"recording-healthy",
|
|
45051
45788
|
"recording-degraded",
|
|
@@ -46135,7 +46872,20 @@ var NcRuleInputSchema = object({
|
|
|
46135
46872
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46136
46873
|
* path does not run Zod defaults.
|
|
46137
46874
|
*/
|
|
46138
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46875
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46876
|
+
/**
|
|
46877
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46878
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46879
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46880
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46881
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46882
|
+
*
|
|
46883
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46884
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46885
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46886
|
+
* `false`, so it needs no `clear` key.
|
|
46887
|
+
*/
|
|
46888
|
+
askVerdict: boolean().optional()
|
|
46139
46889
|
});
|
|
46140
46890
|
/**
|
|
46141
46891
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56650,6 +57400,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56650
57400
|
deprecated: string().optional(),
|
|
56651
57401
|
distTags: array(string()).readonly()
|
|
56652
57402
|
});
|
|
57403
|
+
/**
|
|
57404
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
57405
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
57406
|
+
* tarball failure — never an empty string standing in for either.
|
|
57407
|
+
*/
|
|
57408
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
57409
|
+
object({
|
|
57410
|
+
status: literal("ok"),
|
|
57411
|
+
markdown: string()
|
|
57412
|
+
}),
|
|
57413
|
+
object({ status: literal("missing") }),
|
|
57414
|
+
object({
|
|
57415
|
+
status: literal("error"),
|
|
57416
|
+
message: string()
|
|
57417
|
+
})
|
|
57418
|
+
]);
|
|
57419
|
+
var PackageDocsSchema = object({
|
|
57420
|
+
name: string(),
|
|
57421
|
+
version: string(),
|
|
57422
|
+
readme: PackageDocBodySchema,
|
|
57423
|
+
changelog: PackageDocBodySchema
|
|
57424
|
+
});
|
|
56653
57425
|
var SearchResultSchema = object({
|
|
56654
57426
|
name: string(),
|
|
56655
57427
|
version: string(),
|
|
@@ -56868,7 +57640,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56868
57640
|
}), object({ success: literal(true) }), {
|
|
56869
57641
|
kind: "mutation",
|
|
56870
57642
|
auth: "admin"
|
|
56871
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57643
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57644
|
+
name: string().min(1),
|
|
57645
|
+
version: string().min(1).optional()
|
|
57646
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56872
57647
|
kind: "mutation",
|
|
56873
57648
|
auth: "admin"
|
|
56874
57649
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56927,27 +57702,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56927
57702
|
*/
|
|
56928
57703
|
var AirQualitySensorStatusSchema = object({
|
|
56929
57704
|
/** Carbon dioxide concentration in ppm. */
|
|
56930
|
-
co2Ppm: number().min(0).optional(),
|
|
57705
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56931
57706
|
/** Total volatile organic compounds in ppb. */
|
|
56932
|
-
vocPpb: number().min(0).optional(),
|
|
57707
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56933
57708
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56934
|
-
pm25: number().min(0).optional(),
|
|
57709
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56935
57710
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56936
|
-
pm10: number().min(0).optional(),
|
|
57711
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56937
57712
|
/** Composite AQI value (typically 0..500). */
|
|
56938
|
-
aqi: number().optional(),
|
|
57713
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56939
57714
|
/** Ms epoch when the slice was last updated. */
|
|
56940
|
-
lastFetchedAt: number()
|
|
56941
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56942
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56943
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56944
|
-
* per slice is unambiguous. */
|
|
56945
|
-
unit: string().optional(),
|
|
56946
|
-
/** Suggested decimal places for numeric display.
|
|
56947
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56948
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56949
|
-
* auto-formatting when absent. */
|
|
56950
|
-
precision: number().int().min(0).max(10).optional()
|
|
57715
|
+
lastFetchedAt: number()
|
|
56951
57716
|
});
|
|
56952
57717
|
var airQualitySensorCapability = {
|
|
56953
57718
|
name: "air-quality-sensor",
|
|
@@ -56984,12 +57749,12 @@ var airQualitySensorCapability = {
|
|
|
56984
57749
|
},
|
|
56985
57750
|
pm25: {
|
|
56986
57751
|
kind: "gauge",
|
|
56987
|
-
unit: "
|
|
57752
|
+
unit: "µg/m³",
|
|
56988
57753
|
deadband: 1
|
|
56989
57754
|
},
|
|
56990
57755
|
pm10: {
|
|
56991
57756
|
kind: "gauge",
|
|
56992
|
-
unit: "
|
|
57757
|
+
unit: "µg/m³",
|
|
56993
57758
|
deadband: 1
|
|
56994
57759
|
},
|
|
56995
57760
|
aqi: {
|
|
@@ -57007,22 +57772,13 @@ var airQualitySensorCapability = {
|
|
|
57007
57772
|
* entries with `device_class: illuminance`.
|
|
57008
57773
|
*/
|
|
57009
57774
|
var AmbientLightSensorStatusSchema = object({
|
|
57010
|
-
/** Current illuminance in lux (lx). */
|
|
57011
|
-
lux: number().min(0).meta({
|
|
57012
|
-
|
|
57775
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57776
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57777
|
+
precision: 0,
|
|
57013
57778
|
label: "Illuminance"
|
|
57014
|
-
}),
|
|
57779
|
+
})),
|
|
57015
57780
|
/** Ms epoch when the slice was last updated. */
|
|
57016
|
-
lastFetchedAt: number()
|
|
57017
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
57018
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
57019
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
57020
|
-
unit: string().optional(),
|
|
57021
|
-
/** Suggested decimal places for numeric display.
|
|
57022
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57023
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57024
|
-
* auto-formatting when absent. */
|
|
57025
|
-
precision: number().int().min(0).max(10).optional()
|
|
57781
|
+
lastFetchedAt: number()
|
|
57026
57782
|
});
|
|
57027
57783
|
var ambientLightSensorCapability = {
|
|
57028
57784
|
name: "ambient-light-sensor",
|
|
@@ -57054,12 +57810,7 @@ var ambientLightSensorCapability = {
|
|
|
57054
57810
|
} } },
|
|
57055
57811
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57056
57812
|
* whether persisting is worth a SQLite commit. */
|
|
57057
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
57058
|
-
customize: {
|
|
57059
|
-
version: 1,
|
|
57060
|
-
advanced: "derive",
|
|
57061
|
-
targets: []
|
|
57062
|
-
}
|
|
57813
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
57063
57814
|
};
|
|
57064
57815
|
/**
|
|
57065
57816
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -57286,10 +58037,7 @@ var BatteryStatusSchema = object({
|
|
|
57286
58037
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
57287
58038
|
* declines to band a non-finite reading, which is the correct shape.
|
|
57288
58039
|
*/
|
|
57289
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
57290
|
-
unit: "%",
|
|
57291
|
-
label: "Charge"
|
|
57292
|
-
}),
|
|
58040
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
57293
58041
|
/**
|
|
57294
58042
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
57295
58043
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -57316,7 +58064,14 @@ var BatteryStatusSchema = object({
|
|
|
57316
58064
|
*/
|
|
57317
58065
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
57318
58066
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
57319
|
-
lastUpdated: number(),
|
|
58067
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
58068
|
+
/**
|
|
58069
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
58070
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
58071
|
+
* that only report charge. A second reading on this cap, not a second
|
|
58072
|
+
* `numeric-sensor` on the same device.
|
|
58073
|
+
*/
|
|
58074
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
57320
58075
|
/**
|
|
57321
58076
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
57322
58077
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -57363,12 +58118,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
57363
58118
|
DeviceType.Switch,
|
|
57364
58119
|
DeviceType.PetFeeder,
|
|
57365
58120
|
DeviceType.Container,
|
|
57366
|
-
DeviceType.Thermostat
|
|
58121
|
+
DeviceType.Thermostat,
|
|
58122
|
+
DeviceType.EventEmitter
|
|
57367
58123
|
];
|
|
57368
58124
|
/** Generic Customize target for the percentage reading (D936). */
|
|
57369
58125
|
var batteryCustomize = {
|
|
57370
58126
|
version: 1,
|
|
57371
|
-
advanced: "derive",
|
|
57372
58127
|
targets: [{
|
|
57373
58128
|
id: "percentage",
|
|
57374
58129
|
cardinality: "scalar",
|
|
@@ -57377,7 +58132,7 @@ var batteryCustomize = {
|
|
|
57377
58132
|
stateField: "percentage"
|
|
57378
58133
|
},
|
|
57379
58134
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
57380
|
-
apply: "add
|
|
58135
|
+
apply: "add",
|
|
57381
58136
|
path: "percentage",
|
|
57382
58137
|
sources: [{
|
|
57383
58138
|
kind: "field",
|
|
@@ -57498,10 +58253,16 @@ onStatusChanged: { data: object({
|
|
|
57498
58253
|
/**
|
|
57499
58254
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
57500
58255
|
*/
|
|
57501
|
-
history: { fields: {
|
|
57502
|
-
|
|
57503
|
-
|
|
57504
|
-
|
|
58256
|
+
history: { fields: {
|
|
58257
|
+
percentage: {
|
|
58258
|
+
kind: "gauge",
|
|
58259
|
+
unit: "%"
|
|
58260
|
+
},
|
|
58261
|
+
volts: {
|
|
58262
|
+
kind: "gauge",
|
|
58263
|
+
unit: "V"
|
|
58264
|
+
}
|
|
58265
|
+
} },
|
|
57505
58266
|
customize: batteryCustomize,
|
|
57506
58267
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57507
58268
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57548,12 +58309,7 @@ var binaryCapability = {
|
|
|
57548
58309
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57549
58310
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57550
58311
|
* whether persisting is worth a SQLite commit. */
|
|
57551
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57552
|
-
customize: {
|
|
57553
|
-
version: 1,
|
|
57554
|
-
advanced: "derive",
|
|
57555
|
-
targets: []
|
|
57556
|
-
}
|
|
58312
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57557
58313
|
};
|
|
57558
58314
|
/**
|
|
57559
58315
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57569,7 +58325,7 @@ var binaryCapability = {
|
|
|
57569
58325
|
*/
|
|
57570
58326
|
var BrightnessStatusSchema = object({
|
|
57571
58327
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57572
|
-
percentage: number().min(0).max(100),
|
|
58328
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57573
58329
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57574
58330
|
lastChangedAt: number()
|
|
57575
58331
|
});
|
|
@@ -58023,21 +58779,21 @@ var ClimateControlStatusSchema = object({
|
|
|
58023
58779
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
58024
58780
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
58025
58781
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
58026
|
-
target: number().nullable(),
|
|
58782
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
58027
58783
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
58028
58784
|
* in `heat_cool` mode. */
|
|
58029
|
-
targetHigh: number().nullable(),
|
|
58785
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
58030
58786
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
58031
58787
|
* in `heat_cool` mode. */
|
|
58032
|
-
targetLow: number().nullable(),
|
|
58788
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
58033
58789
|
/** Target relative humidity (0..100). Null when the device has no
|
|
58034
58790
|
* humidity control. */
|
|
58035
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58791
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58036
58792
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
58037
58793
|
* the device's internal sensor. */
|
|
58038
|
-
currentTemp: number().nullable(),
|
|
58794
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
58039
58795
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
58040
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58796
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58041
58797
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
58042
58798
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
58043
58799
|
swingVertical: boolean().nullable(),
|
|
@@ -58045,11 +58801,11 @@ var ClimateControlStatusSchema = object({
|
|
|
58045
58801
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
58046
58802
|
swingHorizontal: boolean().nullable(),
|
|
58047
58803
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58048
|
-
minTemp: number().nullable().optional(),
|
|
58804
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58049
58805
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58050
|
-
maxTemp: number().nullable().optional(),
|
|
58806
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58051
58807
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
58052
|
-
tempStep: number().positive().nullable().optional(),
|
|
58808
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
58053
58809
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
58054
58810
|
lastFetchedAt: number()
|
|
58055
58811
|
});
|
|
@@ -58191,17 +58947,17 @@ var climateControlCapability = {
|
|
|
58191
58947
|
* modes to expose in the picker without a slice fetch.
|
|
58192
58948
|
*/
|
|
58193
58949
|
var RgbTripletSchema = object({
|
|
58194
|
-
r: number().int().min(0).max(255),
|
|
58195
|
-
g: number().int().min(0).max(255),
|
|
58196
|
-
b: number().int().min(0).max(255)
|
|
58950
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58951
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58952
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
58197
58953
|
});
|
|
58198
58954
|
var HsvTripletSchema = object({
|
|
58199
58955
|
/** Hue in degrees, 0..360. */
|
|
58200
|
-
h: number().min(0).max(360),
|
|
58956
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
58201
58957
|
/** Saturation as 0..100 inclusive. */
|
|
58202
|
-
s: number().min(0).max(100),
|
|
58958
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
58203
58959
|
/** Value/brightness as 0..100 inclusive. */
|
|
58204
|
-
v: number().min(0).max(100)
|
|
58960
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
58205
58961
|
});
|
|
58206
58962
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
58207
58963
|
object({
|
|
@@ -58230,7 +58986,7 @@ var ColorStatusSchema = object({
|
|
|
58230
58986
|
/** Populated when `mode === 'hsv'`. */
|
|
58231
58987
|
hsv: HsvTripletSchema.optional(),
|
|
58232
58988
|
/** Populated when `mode === 'mired'`. */
|
|
58233
|
-
mireds: number().int().optional(),
|
|
58989
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
58234
58990
|
/** Ms epoch of the last operator-driven change. */
|
|
58235
58991
|
lastChangedAt: number()
|
|
58236
58992
|
});
|
|
@@ -58425,18 +59181,12 @@ _enum([
|
|
|
58425
59181
|
"empty",
|
|
58426
59182
|
"full"
|
|
58427
59183
|
]);
|
|
58428
|
-
/**
|
|
58429
|
-
|
|
58430
|
-
|
|
58431
|
-
"days",
|
|
58432
|
-
"hours",
|
|
58433
|
-
"cycles"
|
|
58434
|
-
]);
|
|
58435
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
58436
|
-
* days). `value` null = unknown (D393). */
|
|
59184
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
59185
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
59186
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
58437
59187
|
var ConsumableRemainingSchema = object({
|
|
58438
|
-
value: number().min(0).nullable(),
|
|
58439
|
-
|
|
59188
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
59189
|
+
kind: ConsumableRemainingKindSchema
|
|
58440
59190
|
});
|
|
58441
59191
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
58442
59192
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -58449,7 +59199,7 @@ var ConsumableItemSchema = object({
|
|
|
58449
59199
|
/** Display name. */
|
|
58450
59200
|
label: string().min(1),
|
|
58451
59201
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
58452
|
-
level: number().min(0).max(100).nullable(),
|
|
59202
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58453
59203
|
/** The provider's discrete verdict when known (binary mode). */
|
|
58454
59204
|
status: ConsumableStatusSchema.nullable(),
|
|
58455
59205
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58531,8 +59281,8 @@ var consumablesCustomize = {
|
|
|
58531
59281
|
transforms: [{ kind: "identity" }]
|
|
58532
59282
|
}],
|
|
58533
59283
|
literals: [{
|
|
58534
|
-
path: "remaining.
|
|
58535
|
-
values: [...
|
|
59284
|
+
path: "remaining.kind",
|
|
59285
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58536
59286
|
}]
|
|
58537
59287
|
},
|
|
58538
59288
|
{
|
|
@@ -58661,7 +59411,6 @@ reset: method(object({
|
|
|
58661
59411
|
},
|
|
58662
59412
|
"remaining.value": {
|
|
58663
59413
|
kind: "gauge",
|
|
58664
|
-
unitFrom: "remaining.unit",
|
|
58665
59414
|
deadband: 1,
|
|
58666
59415
|
displayName: "Remaining"
|
|
58667
59416
|
}
|
|
@@ -58731,10 +59480,9 @@ var contactCapability = {
|
|
|
58731
59480
|
* (empty array for the other kinds). It lives in the slice because
|
|
58732
59481
|
* HA `select.*` entities may update their options at runtime.
|
|
58733
59482
|
*
|
|
58734
|
-
*
|
|
58735
|
-
*
|
|
58736
|
-
*
|
|
58737
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
59483
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
59484
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
59485
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58738
59486
|
*/
|
|
58739
59487
|
var ControlStatusSchema = object({
|
|
58740
59488
|
kind: _enum([
|
|
@@ -58746,39 +59494,17 @@ var ControlStatusSchema = object({
|
|
|
58746
59494
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58747
59495
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58748
59496
|
* or time-only — HA accepts all three forms). */
|
|
58749
|
-
value: union([number(), string()]),
|
|
59497
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58750
59498
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58751
59499
|
options: array(string()),
|
|
58752
59500
|
/** Ms epoch when the slice was last updated. */
|
|
58753
59501
|
lastChangedAt: number(),
|
|
58754
|
-
/**
|
|
58755
|
-
|
|
58756
|
-
|
|
58757
|
-
|
|
58758
|
-
/**
|
|
58759
|
-
|
|
58760
|
-
min: number().optional(),
|
|
58761
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58762
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58763
|
-
max: number().optional(),
|
|
58764
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58765
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58766
|
-
step: number().optional(),
|
|
58767
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58768
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58769
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58770
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58771
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58772
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58773
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58774
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58775
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58776
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58777
|
-
format: _enum([
|
|
58778
|
-
"date",
|
|
58779
|
-
"time",
|
|
58780
|
-
"datetime"
|
|
58781
|
-
]).optional()
|
|
59502
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
59503
|
+
min: number().optional().meta(readingMeta("device")),
|
|
59504
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
59505
|
+
max: number().optional().meta(readingMeta("device")),
|
|
59506
|
+
/** Step increment, in the device quantity's base unit. */
|
|
59507
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58782
59508
|
});
|
|
58783
59509
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58784
59510
|
object({
|
|
@@ -58844,9 +59570,9 @@ var CoverStatusSchema = object({
|
|
|
58844
59570
|
]),
|
|
58845
59571
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58846
59572
|
* no intermediate position surface. */
|
|
58847
|
-
position: number().min(0).max(100).nullable(),
|
|
59573
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58848
59574
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58849
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59575
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58850
59576
|
/** Ms epoch when the slice was last updated. */
|
|
58851
59577
|
lastChangedAt: number()
|
|
58852
59578
|
});
|
|
@@ -58949,9 +59675,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58949
59675
|
var DayNightStatusSchema = object({
|
|
58950
59676
|
mode: DayNightModeSchema,
|
|
58951
59677
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58952
|
-
sensitivity: number().optional(),
|
|
59678
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58953
59679
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58954
|
-
switchDelaySec: number().optional(),
|
|
59680
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58955
59681
|
lastFetchedAt: number()
|
|
58956
59682
|
});
|
|
58957
59683
|
/**
|
|
@@ -59169,11 +59895,11 @@ var DishwasherStatusSchema = object({
|
|
|
59169
59895
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
59170
59896
|
availablePrograms: array(string()),
|
|
59171
59897
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
59172
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59898
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59173
59899
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
59174
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59900
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59175
59901
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
59176
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59902
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59177
59903
|
/** True when the door is reported open; null when the door state is not known. */
|
|
59178
59904
|
doorOpen: boolean().nullable(),
|
|
59179
59905
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -59197,7 +59923,7 @@ var DishwasherStatusSchema = object({
|
|
|
59197
59923
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
59198
59924
|
machineCareDue: boolean().nullable(),
|
|
59199
59925
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
59200
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59926
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
59201
59927
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
59202
59928
|
halfLoad: boolean().nullable(),
|
|
59203
59929
|
hygienePlus: boolean().nullable(),
|
|
@@ -59212,7 +59938,7 @@ var DishwasherStatusSchema = object({
|
|
|
59212
59938
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
59213
59939
|
activeEvents: array(string()),
|
|
59214
59940
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
59215
|
-
errorCode: number().nullable(),
|
|
59941
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
59216
59942
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
59217
59943
|
errorLabel: string().nullable(),
|
|
59218
59944
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -59443,7 +60169,7 @@ var DoorbellStatusSchema = object({
|
|
|
59443
60169
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
59444
60170
|
lastPressedAt: number().nullable(),
|
|
59445
60171
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
59446
|
-
pressCountSinceStart: number()
|
|
60172
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
59447
60173
|
});
|
|
59448
60174
|
var DoorbellPressEventSchema = object({
|
|
59449
60175
|
deviceId: number(),
|
|
@@ -59508,17 +60234,7 @@ onPressed: {
|
|
|
59508
60234
|
history: "none",
|
|
59509
60235
|
customize: doorbellCustomize
|
|
59510
60236
|
};
|
|
59511
|
-
|
|
59512
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
59513
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
59514
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
59515
|
-
* The option set is stable across observations; it is persisted in the
|
|
59516
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
59517
|
-
* stored in `sourceInfo`.
|
|
59518
|
-
*/
|
|
59519
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
59520
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
59521
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
60237
|
+
_enum([
|
|
59522
60238
|
"date",
|
|
59523
60239
|
"time",
|
|
59524
60240
|
"datetime"
|
|
@@ -59526,12 +60242,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59526
60242
|
var EnumSensorStatusSchema = object({
|
|
59527
60243
|
value: string(),
|
|
59528
60244
|
/**
|
|
59529
|
-
* Set
|
|
59530
|
-
* as
|
|
59531
|
-
*
|
|
59532
|
-
* a time-only sensor → `'time'`.
|
|
60245
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
60246
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
60247
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59533
60248
|
*/
|
|
59534
|
-
|
|
60249
|
+
timestamp: boolean().optional(),
|
|
59535
60250
|
/** Ms epoch when the slice was last updated. */
|
|
59536
60251
|
lastFetchedAt: number()
|
|
59537
60252
|
});
|
|
@@ -59558,11 +60273,11 @@ var enumSensorCapability = {
|
|
|
59558
60273
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59559
60274
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59560
60275
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59561
|
-
* `
|
|
60276
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59562
60277
|
*/
|
|
59563
60278
|
history: { fields: { value: {
|
|
59564
60279
|
kind: "enum",
|
|
59565
|
-
skipWhenSet: "
|
|
60280
|
+
skipWhenSet: "timestamp"
|
|
59566
60281
|
} } },
|
|
59567
60282
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59568
60283
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59582,13 +60297,13 @@ var EventFireSchema = object({
|
|
|
59582
60297
|
deviceId: number(),
|
|
59583
60298
|
eventType: string(),
|
|
59584
60299
|
data: record(string(), unknown()).nullable(),
|
|
59585
|
-
timestamp: number(),
|
|
59586
|
-
seq: number()
|
|
60300
|
+
timestamp: number().meta(readingMeta("none")),
|
|
60301
|
+
seq: number().meta(readingMeta("count"))
|
|
59587
60302
|
});
|
|
59588
60303
|
var EventEmitterStatusSchema = object({
|
|
59589
60304
|
eventTypes: array(string()),
|
|
59590
60305
|
lastEvent: EventFireSchema.nullable(),
|
|
59591
|
-
eventCountSinceStart: number()
|
|
60306
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59592
60307
|
});
|
|
59593
60308
|
var eventEmitterCapability = {
|
|
59594
60309
|
name: "event-emitter",
|
|
@@ -60001,10 +60716,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
60001
60716
|
var FanControlStatusSchema = object({
|
|
60002
60717
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
60003
60718
|
* speed surface (single-speed fan). */
|
|
60004
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60719
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60005
60720
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
60006
60721
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
60007
|
-
percentageStep: number().positive().optional(),
|
|
60722
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
60008
60723
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
60009
60724
|
* — empty string when no preset is active or supported. */
|
|
60010
60725
|
preset: string(),
|
|
@@ -60125,7 +60840,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
60125
60840
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
60126
60841
|
model: string().nullable(),
|
|
60127
60842
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
60128
|
-
channelCount: number().nullable(),
|
|
60843
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
60129
60844
|
/**
|
|
60130
60845
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
60131
60846
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -60248,9 +60963,151 @@ var gasCapability = {
|
|
|
60248
60963
|
* whether persisting is worth a SQLite commit. */
|
|
60249
60964
|
volatileStateFields: ["lastChangedAt"]
|
|
60250
60965
|
};
|
|
60966
|
+
var GroupCommandsSchema = object({
|
|
60967
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60968
|
+
results: array(object({
|
|
60969
|
+
deviceId: number().int().nonnegative(),
|
|
60970
|
+
cap: string().min(1),
|
|
60971
|
+
method: string().min(1),
|
|
60972
|
+
ok: boolean(),
|
|
60973
|
+
error: string().optional(),
|
|
60974
|
+
/** Ms epoch of the attempt. */
|
|
60975
|
+
at: number()
|
|
60976
|
+
})) });
|
|
60977
|
+
var groupCommandsCapability = {
|
|
60978
|
+
name: "group-commands",
|
|
60979
|
+
scope: "device",
|
|
60980
|
+
deviceNative: true,
|
|
60981
|
+
mode: "singleton",
|
|
60982
|
+
deviceTypes: [
|
|
60983
|
+
DeviceType.Switch,
|
|
60984
|
+
DeviceType.Light,
|
|
60985
|
+
DeviceType.Fan,
|
|
60986
|
+
DeviceType.Cover,
|
|
60987
|
+
DeviceType.Valve,
|
|
60988
|
+
DeviceType.Lock,
|
|
60989
|
+
DeviceType.MediaPlayer,
|
|
60990
|
+
DeviceType.Thermostat,
|
|
60991
|
+
DeviceType.Climate
|
|
60992
|
+
],
|
|
60993
|
+
methods: {},
|
|
60994
|
+
status: {
|
|
60995
|
+
schema: GroupCommandsSchema,
|
|
60996
|
+
kind: "push"
|
|
60997
|
+
},
|
|
60998
|
+
runtimeState: GroupCommandsSchema,
|
|
60999
|
+
/**
|
|
61000
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
61001
|
+
* failure would outlive the command that caused it.
|
|
61002
|
+
*
|
|
61003
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61004
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61005
|
+
*/
|
|
61006
|
+
durability: "session",
|
|
61007
|
+
history: "none"
|
|
61008
|
+
};
|
|
61009
|
+
/**
|
|
61010
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
61011
|
+
* included member is, or every included member is. What "active" means is the
|
|
61012
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
61013
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
61014
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
61015
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
61016
|
+
* empty included set takes the device offline, never `active: false`.
|
|
61017
|
+
*/
|
|
61018
|
+
var GroupActiveSchema = object({
|
|
61019
|
+
active: boolean().meta({ label: "Active" }),
|
|
61020
|
+
/** Ms epoch when the slice was last updated. */
|
|
61021
|
+
lastChangedAt: number()
|
|
61022
|
+
});
|
|
61023
|
+
var groupActiveCapability = {
|
|
61024
|
+
name: "group-active",
|
|
61025
|
+
scope: "device",
|
|
61026
|
+
deviceNative: true,
|
|
61027
|
+
mode: "singleton",
|
|
61028
|
+
deviceTypes: [
|
|
61029
|
+
DeviceType.Cover,
|
|
61030
|
+
DeviceType.Valve,
|
|
61031
|
+
DeviceType.Lock,
|
|
61032
|
+
DeviceType.MediaPlayer,
|
|
61033
|
+
DeviceType.Climate,
|
|
61034
|
+
DeviceType.Thermostat
|
|
61035
|
+
],
|
|
61036
|
+
methods: {},
|
|
61037
|
+
status: {
|
|
61038
|
+
schema: GroupActiveSchema,
|
|
61039
|
+
kind: "push"
|
|
61040
|
+
},
|
|
61041
|
+
runtimeState: GroupActiveSchema,
|
|
61042
|
+
/**
|
|
61043
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
61044
|
+
* next source event; a restored value would outlive the members it named.
|
|
61045
|
+
*
|
|
61046
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61047
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61048
|
+
*/
|
|
61049
|
+
durability: "session",
|
|
61050
|
+
history: "none"
|
|
61051
|
+
};
|
|
61052
|
+
/**
|
|
61053
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
61054
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
61055
|
+
* The reading itself stays on the output capability. History is none — the
|
|
61056
|
+
* series that later statistics read is the output cap's own history block.
|
|
61057
|
+
*/
|
|
61058
|
+
var GroupStatusSchema = object({
|
|
61059
|
+
/** Members whose current value entered the aggregate. */
|
|
61060
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
61061
|
+
precision: 0,
|
|
61062
|
+
label: "Reporting"
|
|
61063
|
+
})),
|
|
61064
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
61065
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
61066
|
+
precision: 0,
|
|
61067
|
+
label: "Excluded"
|
|
61068
|
+
})),
|
|
61069
|
+
/** `included` + `excluded`. */
|
|
61070
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
61071
|
+
precision: 0,
|
|
61072
|
+
label: "Members"
|
|
61073
|
+
}))
|
|
61074
|
+
});
|
|
61075
|
+
var groupStatusCapability = {
|
|
61076
|
+
name: "group-status",
|
|
61077
|
+
scope: "device",
|
|
61078
|
+
deviceNative: true,
|
|
61079
|
+
mode: "singleton",
|
|
61080
|
+
deviceTypes: [
|
|
61081
|
+
DeviceType.Sensor,
|
|
61082
|
+
DeviceType.Switch,
|
|
61083
|
+
DeviceType.Light,
|
|
61084
|
+
DeviceType.Fan,
|
|
61085
|
+
DeviceType.Cover,
|
|
61086
|
+
DeviceType.Valve,
|
|
61087
|
+
DeviceType.Lock,
|
|
61088
|
+
DeviceType.MediaPlayer,
|
|
61089
|
+
DeviceType.Thermostat,
|
|
61090
|
+
DeviceType.Climate
|
|
61091
|
+
],
|
|
61092
|
+
methods: {},
|
|
61093
|
+
status: {
|
|
61094
|
+
schema: GroupStatusSchema,
|
|
61095
|
+
kind: "push"
|
|
61096
|
+
},
|
|
61097
|
+
runtimeState: GroupStatusSchema,
|
|
61098
|
+
/**
|
|
61099
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
61100
|
+
* next source event; a restored count would outlive the readings it named.
|
|
61101
|
+
*
|
|
61102
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61103
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61104
|
+
*/
|
|
61105
|
+
durability: "session",
|
|
61106
|
+
history: "none"
|
|
61107
|
+
};
|
|
60251
61108
|
var HeatingValveStatusSchema = object({
|
|
60252
61109
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
60253
|
-
position: number().min(0).max(100).nullable(),
|
|
61110
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60254
61111
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
60255
61112
|
lastFetchedAt: number()
|
|
60256
61113
|
});
|
|
@@ -60293,9 +61150,9 @@ var HumidifierStatusSchema = object({
|
|
|
60293
61150
|
/** Whether the humidifier is currently on. */
|
|
60294
61151
|
on: boolean(),
|
|
60295
61152
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
60296
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
61153
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60297
61154
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
60298
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
61155
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60299
61156
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
60300
61157
|
* device has no mode surface. */
|
|
60301
61158
|
mode: string().nullable(),
|
|
@@ -60305,9 +61162,9 @@ var HumidifierStatusSchema = object({
|
|
|
60305
61162
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
60306
61163
|
action: string().nullable(),
|
|
60307
61164
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
60308
|
-
minHumidity: number().nullable(),
|
|
61165
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60309
61166
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
60310
|
-
maxHumidity: number().nullable(),
|
|
61167
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60311
61168
|
/** Ms epoch when the slice was last updated. */
|
|
60312
61169
|
lastChangedAt: number()
|
|
60313
61170
|
});
|
|
@@ -60377,22 +61234,13 @@ var humidifierCapability = {
|
|
|
60377
61234
|
* `sourceInfo`.
|
|
60378
61235
|
*/
|
|
60379
61236
|
var HumiditySensorStatusSchema = object({
|
|
60380
|
-
/** Current relative humidity, 0..100. */
|
|
60381
|
-
percent: number().min(0).max(100).meta({
|
|
60382
|
-
|
|
61237
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
61238
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
61239
|
+
precision: 0,
|
|
60383
61240
|
label: "Humidity"
|
|
60384
|
-
}),
|
|
61241
|
+
})),
|
|
60385
61242
|
/** Ms epoch when the slice was last updated. */
|
|
60386
|
-
lastFetchedAt: number()
|
|
60387
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
60388
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
60389
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
60390
|
-
unit: string().optional(),
|
|
60391
|
-
/** Suggested decimal places for numeric display.
|
|
60392
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
60393
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
60394
|
-
* auto-formatting when absent. */
|
|
60395
|
-
precision: number().int().min(0).max(10).optional()
|
|
61243
|
+
lastFetchedAt: number()
|
|
60396
61244
|
});
|
|
60397
61245
|
var humiditySensorCapability = {
|
|
60398
61246
|
name: "humidity-sensor",
|
|
@@ -60423,12 +61271,7 @@ var humiditySensorCapability = {
|
|
|
60423
61271
|
} } },
|
|
60424
61272
|
/** Clock fields: written, but excluded from the compare that decides
|
|
60425
61273
|
* whether persisting is worth a SQLite commit. */
|
|
60426
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
60427
|
-
customize: {
|
|
60428
|
-
version: 1,
|
|
60429
|
-
advanced: "derive",
|
|
60430
|
-
targets: []
|
|
60431
|
-
}
|
|
61274
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
60432
61275
|
};
|
|
60433
61276
|
/**
|
|
60434
61277
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -60449,7 +61292,7 @@ var ImageStatusSchema = object({
|
|
|
60449
61292
|
* entity exposes no `entity_picture` (yet). */
|
|
60450
61293
|
url: string().nullable(),
|
|
60451
61294
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
60452
|
-
lastUpdated: number().nullable()
|
|
61295
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
60453
61296
|
});
|
|
60454
61297
|
var imageCapability = {
|
|
60455
61298
|
name: "image",
|
|
@@ -60537,19 +61380,19 @@ var NormalizedRangeSchema = object({
|
|
|
60537
61380
|
*/
|
|
60538
61381
|
var ImageSettingsStatusSchema = object({
|
|
60539
61382
|
/** Normalized 0–100. */
|
|
60540
|
-
brightness: number().optional(),
|
|
61383
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60541
61384
|
/** Normalized 0–100. */
|
|
60542
|
-
contrast: number().optional(),
|
|
61385
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60543
61386
|
/** Normalized 0–100. */
|
|
60544
|
-
saturation: number().optional(),
|
|
61387
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60545
61388
|
/** Normalized 0–100. */
|
|
60546
|
-
sharpness: number().optional(),
|
|
61389
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60547
61390
|
mirror: boolean().optional(),
|
|
60548
61391
|
flip: boolean().optional(),
|
|
60549
61392
|
rotate: ImageRotateSchema.optional(),
|
|
60550
61393
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60551
61394
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60552
|
-
warmth: number().optional(),
|
|
61395
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60553
61396
|
exposureMode: ExposureModeSchema.optional(),
|
|
60554
61397
|
backlightMode: BacklightModeSchema.optional(),
|
|
60555
61398
|
lastFetchedAt: number()
|
|
@@ -60828,10 +61671,10 @@ var IntercomAbilitySchema = object({
|
|
|
60828
61671
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60829
61672
|
codecs: array(string()),
|
|
60830
61673
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60831
|
-
sampleRate: number(),
|
|
61674
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60832
61675
|
duplex: _enum(["half", "full"]),
|
|
60833
61676
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60834
|
-
maxBacklogMs: number()
|
|
61677
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60835
61678
|
});
|
|
60836
61679
|
var IntercomStatusSchema = object({
|
|
60837
61680
|
/** True while a talk session is open. */
|
|
@@ -61058,13 +61901,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
61058
61901
|
activity: LawnMowerActivitySchema,
|
|
61059
61902
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
61060
61903
|
* reading. */
|
|
61061
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61904
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61062
61905
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
61063
61906
|
* task is active / progress is unavailable. */
|
|
61064
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61907
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61065
61908
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
61066
61909
|
* or null when unknown. */
|
|
61067
|
-
currentCode: number().nullable(),
|
|
61910
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
61068
61911
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
61069
61912
|
currentCodeLabel: string().nullable(),
|
|
61070
61913
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61517,7 +62360,14 @@ var lockControlCapability = {
|
|
|
61517
62360
|
}),
|
|
61518
62361
|
unlock: method(object({
|
|
61519
62362
|
deviceId: number().int().nonnegative(),
|
|
61520
|
-
code: string().min(1).optional()
|
|
62363
|
+
code: string().min(1).optional(),
|
|
62364
|
+
/**
|
|
62365
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
62366
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
62367
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
62368
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
62369
|
+
*/
|
|
62370
|
+
confirm: boolean().optional()
|
|
61521
62371
|
}), _void(), {
|
|
61522
62372
|
kind: "mutation",
|
|
61523
62373
|
auth: "protected"
|
|
@@ -61554,6 +62404,44 @@ var lockControlCapability = {
|
|
|
61554
62404
|
volatileStateFields: ["lastChangedAt"]
|
|
61555
62405
|
};
|
|
61556
62406
|
/**
|
|
62407
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
62408
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
62409
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
62410
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
62411
|
+
*/
|
|
62412
|
+
var MeterStatusSchema = object({
|
|
62413
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
62414
|
+
lastFetchedAt: number()
|
|
62415
|
+
});
|
|
62416
|
+
var meterCapability = {
|
|
62417
|
+
name: "meter",
|
|
62418
|
+
scope: "device",
|
|
62419
|
+
deviceNative: true,
|
|
62420
|
+
mode: "singleton",
|
|
62421
|
+
deviceTypes: [DeviceType.Sensor],
|
|
62422
|
+
methods: {},
|
|
62423
|
+
status: {
|
|
62424
|
+
schema: MeterStatusSchema,
|
|
62425
|
+
kind: "push"
|
|
62426
|
+
},
|
|
62427
|
+
runtimeState: MeterStatusSchema,
|
|
62428
|
+
/**
|
|
62429
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
62430
|
+
* history integral. A restart shows it only until the history pass
|
|
62431
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
62432
|
+
*
|
|
62433
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
62434
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
62435
|
+
*/
|
|
62436
|
+
durability: "restored",
|
|
62437
|
+
history: { fields: { value: {
|
|
62438
|
+
kind: "counter",
|
|
62439
|
+
deadband: .001,
|
|
62440
|
+
minIntervalMs: 6e4
|
|
62441
|
+
} } },
|
|
62442
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
62443
|
+
};
|
|
62444
|
+
/**
|
|
61557
62445
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61558
62446
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61559
62447
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -61597,7 +62485,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61597
62485
|
state: MediaPlayerStateSchema,
|
|
61598
62486
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61599
62487
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61600
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
62488
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61601
62489
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61602
62490
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61603
62491
|
isMuted: boolean().nullable(),
|
|
@@ -61610,10 +62498,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61610
62498
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61611
62499
|
/** Current playback position in ms. Null when not seekable or
|
|
61612
62500
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61613
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
62501
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61614
62502
|
/** Total duration of the current media in ms. Null when unknown
|
|
61615
62503
|
* (live stream) or nothing is playing. */
|
|
61616
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
62504
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61617
62505
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61618
62506
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61619
62507
|
shuffle: boolean().nullable(),
|
|
@@ -61922,7 +62810,7 @@ var motionCustomize = {
|
|
|
61922
62810
|
eventName: "onMotionChanged"
|
|
61923
62811
|
},
|
|
61924
62812
|
deviceTypes: [DeviceType.Camera],
|
|
61925
|
-
apply: "
|
|
62813
|
+
apply: "add",
|
|
61926
62814
|
applyAuthority: {
|
|
61927
62815
|
kind: "camera-sensors",
|
|
61928
62816
|
timeoutField: "motionCooldownMs"
|
|
@@ -61994,7 +62882,7 @@ var MotionStatusSchema = object({
|
|
|
61994
62882
|
* it, every provider seeded it at boot, and every session left it
|
|
61995
62883
|
* `detected: true` after its detach.
|
|
61996
62884
|
*/
|
|
61997
|
-
autoClearAfterMs: number().nullable()
|
|
62885
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61998
62886
|
});
|
|
61999
62887
|
/**
|
|
62000
62888
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -62031,12 +62919,18 @@ var motionCapability = {
|
|
|
62031
62919
|
methods: {
|
|
62032
62920
|
/**
|
|
62033
62921
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
62034
|
-
* for consumers that don't need the full status object
|
|
62035
|
-
*
|
|
62036
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
62037
|
-
* consumer.
|
|
62922
|
+
* for consumers that don't need the full status object. A composed
|
|
62923
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
62038
62924
|
*/
|
|
62039
62925
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62926
|
+
/**
|
|
62927
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62928
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62929
|
+
*/
|
|
62930
|
+
composedMethods: { isDetected: {
|
|
62931
|
+
kind: "slice",
|
|
62932
|
+
field: "detected"
|
|
62933
|
+
} },
|
|
62040
62934
|
events: {
|
|
62041
62935
|
/**
|
|
62042
62936
|
* Fires every time the runner transitions a camera between
|
|
@@ -62176,7 +63070,7 @@ var MotionZoneRegionSchema = object({
|
|
|
62176
63070
|
* the grid region(s). */
|
|
62177
63071
|
var MotionZoneStatusSchema = object({
|
|
62178
63072
|
enabled: boolean(),
|
|
62179
|
-
sensitivity: number(),
|
|
63073
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
62180
63074
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
62181
63075
|
regions: array(MotionZoneRegionSchema),
|
|
62182
63076
|
lastFetchedAt: number()
|
|
@@ -62546,7 +63440,7 @@ var NavigationStatusSchema = object({
|
|
|
62546
63440
|
following: boolean(),
|
|
62547
63441
|
flash: boolean(),
|
|
62548
63442
|
lightMode: NavigationLightModeSchema,
|
|
62549
|
-
lightLevel: number().min(40).max(100),
|
|
63443
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62550
63444
|
/** Ms epoch when the slice was last updated. */
|
|
62551
63445
|
lastChangedAt: number()
|
|
62552
63446
|
});
|
|
@@ -62680,13 +63574,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62680
63574
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62681
63575
|
* SKIP a null rather than coerce it.
|
|
62682
63576
|
*/
|
|
62683
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63577
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62684
63578
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62685
|
-
rssiDbm: number().optional(),
|
|
63579
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62686
63580
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62687
63581
|
ssid: string().optional(),
|
|
62688
63582
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62689
|
-
lastUpdated: number()
|
|
63583
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62690
63584
|
});
|
|
62691
63585
|
var networkLinkCapability = {
|
|
62692
63586
|
name: "network-link",
|
|
@@ -63071,7 +63965,7 @@ var NotifierStatusSchema = object({
|
|
|
63071
63965
|
lastError: string().nullable(),
|
|
63072
63966
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
63073
63967
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
63074
|
-
queueDepth: number().int().nonnegative(),
|
|
63968
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
63075
63969
|
/** Per-feature capability matrix — authoritative source for the
|
|
63076
63970
|
* compose-form field gating. */
|
|
63077
63971
|
supports: NotifierSupportsSchema
|
|
@@ -63163,11 +64057,9 @@ onSent: { data: object({
|
|
|
63163
64057
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
63164
64058
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
63165
64059
|
*
|
|
63166
|
-
* The
|
|
63167
|
-
*
|
|
63168
|
-
*
|
|
63169
|
-
* The UI reads them directly from the slice — they are the single source
|
|
63170
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
64060
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
64061
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
64062
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
63171
64063
|
*
|
|
63172
64064
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
63173
64065
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -63176,15 +64068,8 @@ onSent: { data: object({
|
|
|
63176
64068
|
* numeric values land here.
|
|
63177
64069
|
*/
|
|
63178
64070
|
var NumericSensorStatusSchema = object({
|
|
63179
|
-
|
|
63180
|
-
|
|
63181
|
-
* Populated live from the upstream source on each state push.
|
|
63182
|
-
* Absent for unitless sensors. */
|
|
63183
|
-
unit: string().optional(),
|
|
63184
|
-
/** Suggested decimal places for numeric display.
|
|
63185
|
-
* Populated live from the upstream source when provided.
|
|
63186
|
-
* Falls back to auto-formatting when absent. */
|
|
63187
|
-
precision: number().int().min(0).max(10).optional(),
|
|
64071
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
64072
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
63188
64073
|
/** Ms epoch when the slice was last updated. */
|
|
63189
64074
|
lastFetchedAt: number()
|
|
63190
64075
|
});
|
|
@@ -63208,11 +64093,11 @@ var numericSensorCapability = {
|
|
|
63208
64093
|
*/
|
|
63209
64094
|
durability: "restored",
|
|
63210
64095
|
/**
|
|
63211
|
-
* History (D850): recorded series. The unit is
|
|
64096
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
64097
|
+
* resolved when the series is read — the cap has no single unit.
|
|
63212
64098
|
*/
|
|
63213
64099
|
history: { fields: { value: {
|
|
63214
64100
|
kind: "gauge",
|
|
63215
|
-
unitFrom: "unit",
|
|
63216
64101
|
minIntervalMs: 3e4
|
|
63217
64102
|
} } },
|
|
63218
64103
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -63550,23 +64435,26 @@ var PetFeederStatusSchema = object({
|
|
|
63550
64435
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
63551
64436
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
63552
64437
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
63553
|
-
foodLevel: number().nullable(),
|
|
64438
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
63554
64439
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63555
64440
|
* single-hopper models. */
|
|
63556
|
-
food1: number().nullable(),
|
|
64441
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63557
64442
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63558
64443
|
* single-hopper models. */
|
|
63559
|
-
food2: number().nullable(),
|
|
64444
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63560
64445
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63561
64446
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63562
64447
|
* below the feeder's low threshold. */
|
|
63563
64448
|
lowFood: boolean(),
|
|
63564
64449
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63565
64450
|
* device has no battery reading. */
|
|
63566
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63567
|
-
/**
|
|
63568
|
-
*
|
|
63569
|
-
|
|
64451
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64452
|
+
/**
|
|
64453
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
64454
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
64455
|
+
* model has no desiccant sensor.
|
|
64456
|
+
*/
|
|
64457
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63570
64458
|
/** True while a feed is in progress. */
|
|
63571
64459
|
feeding: boolean(),
|
|
63572
64460
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63577,7 +64465,7 @@ var PetFeederStatusSchema = object({
|
|
|
63577
64465
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63578
64466
|
error: string().nullable(),
|
|
63579
64467
|
/** Raw device error code (0 / null = no error). */
|
|
63580
|
-
errorCode: number().nullable(),
|
|
64468
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63581
64469
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63582
64470
|
isDualHopper: boolean(),
|
|
63583
64471
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63587,7 +64475,7 @@ var PetFeederStatusSchema = object({
|
|
|
63587
64475
|
/** Play a chime when dispensing. */
|
|
63588
64476
|
feedSound: boolean(),
|
|
63589
64477
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63590
|
-
volume: number(),
|
|
64478
|
+
volume: number().meta(readingMeta("none")),
|
|
63591
64479
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63592
64480
|
lastFetchedAt: number()
|
|
63593
64481
|
});
|
|
@@ -63706,7 +64594,7 @@ var petFeederCapability = {
|
|
|
63706
64594
|
},
|
|
63707
64595
|
desiccantLeftDays: {
|
|
63708
64596
|
kind: "gauge",
|
|
63709
|
-
unit: "
|
|
64597
|
+
unit: "s"
|
|
63710
64598
|
}
|
|
63711
64599
|
} }
|
|
63712
64600
|
};
|
|
@@ -64107,43 +64995,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
64107
64995
|
*/
|
|
64108
64996
|
var PowerMeterStatusSchema = object({
|
|
64109
64997
|
/** Instantaneous power draw in watts. */
|
|
64110
|
-
watts: number().optional().meta({
|
|
64111
|
-
unit: "W",
|
|
64112
|
-
label: "Power"
|
|
64113
|
-
}),
|
|
64998
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
64114
64999
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
64115
|
-
kwhTotal: number().optional().meta({
|
|
64116
|
-
unit: "kWh",
|
|
64117
|
-
label: "Energy"
|
|
64118
|
-
}),
|
|
65000
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
64119
65001
|
/** Voltage in volts. */
|
|
64120
|
-
volts: number().optional(),
|
|
65002
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
64121
65003
|
/** Current in amperes. */
|
|
64122
|
-
amps: number().optional(),
|
|
64123
|
-
/** Apparent power in volt-amperes
|
|
64124
|
-
va: number().optional(),
|
|
65004
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
65005
|
+
/** Apparent power in volt-amperes. */
|
|
65006
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
64125
65007
|
/** Power factor (0..1) if reported. */
|
|
64126
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
65008
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
64127
65009
|
/** Ms epoch when the slice was last updated. */
|
|
64128
|
-
lastFetchedAt: number()
|
|
64129
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
64130
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
64131
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
64132
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
64133
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
64134
|
-
unit: string().optional(),
|
|
64135
|
-
/** Suggested decimal places for numeric display.
|
|
64136
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64137
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64138
|
-
* auto-formatting when absent. */
|
|
64139
|
-
precision: number().int().min(0).max(10).optional()
|
|
65010
|
+
lastFetchedAt: number()
|
|
64140
65011
|
});
|
|
65012
|
+
/**
|
|
65013
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
65014
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
65015
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
65016
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
65017
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
65018
|
+
*/
|
|
65019
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
65020
|
+
DeviceType.Sensor,
|
|
65021
|
+
DeviceType.Switch,
|
|
65022
|
+
DeviceType.Light,
|
|
65023
|
+
DeviceType.Fan,
|
|
65024
|
+
DeviceType.Climate,
|
|
65025
|
+
DeviceType.Thermostat,
|
|
65026
|
+
DeviceType.Humidifier,
|
|
65027
|
+
DeviceType.WaterHeater,
|
|
65028
|
+
DeviceType.MediaPlayer,
|
|
65029
|
+
DeviceType.Washer,
|
|
65030
|
+
DeviceType.Dryer,
|
|
65031
|
+
DeviceType.Dishwasher,
|
|
65032
|
+
DeviceType.Vacuum,
|
|
65033
|
+
DeviceType.LawnMower,
|
|
65034
|
+
DeviceType.PetFeeder
|
|
65035
|
+
];
|
|
65036
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
65037
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
65038
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
65039
|
+
function powerTarget(id, unit) {
|
|
65040
|
+
return {
|
|
65041
|
+
id,
|
|
65042
|
+
cardinality: "scalar",
|
|
65043
|
+
vocabulary: {
|
|
65044
|
+
cap: "power-meter",
|
|
65045
|
+
stateField: id
|
|
65046
|
+
},
|
|
65047
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
65048
|
+
apply: "add",
|
|
65049
|
+
path: id,
|
|
65050
|
+
sources: [{
|
|
65051
|
+
kind: "numeric",
|
|
65052
|
+
requiredUnit: unit,
|
|
65053
|
+
transforms: [{ kind: "identity" }]
|
|
65054
|
+
}],
|
|
65055
|
+
companions: [{
|
|
65056
|
+
kind: "clock",
|
|
65057
|
+
path: "lastFetchedAt",
|
|
65058
|
+
when: "always"
|
|
65059
|
+
}],
|
|
65060
|
+
sourceReport: { status: "assignment-status" },
|
|
65061
|
+
advancedExpression: true
|
|
65062
|
+
};
|
|
65063
|
+
}
|
|
65064
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
65065
|
+
var powerMeterCustomize = {
|
|
65066
|
+
version: 1,
|
|
65067
|
+
targets: [
|
|
65068
|
+
powerTarget("watts", "W"),
|
|
65069
|
+
powerTarget("kwhTotal", "kWh"),
|
|
65070
|
+
powerTarget("volts", "V"),
|
|
65071
|
+
powerTarget("amps", "A")
|
|
65072
|
+
]
|
|
65073
|
+
};
|
|
64141
65074
|
var powerMeterCapability = {
|
|
64142
65075
|
name: "power-meter",
|
|
64143
65076
|
scope: "device",
|
|
64144
65077
|
deviceNative: true,
|
|
64145
65078
|
mode: "singleton",
|
|
64146
|
-
deviceTypes:
|
|
65079
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
64147
65080
|
methods: {},
|
|
64148
65081
|
status: {
|
|
64149
65082
|
schema: PowerMeterStatusSchema,
|
|
@@ -64201,11 +65134,7 @@ var powerMeterCapability = {
|
|
|
64201
65134
|
/** Clock fields: written, but excluded from the compare that decides
|
|
64202
65135
|
* whether persisting is worth a SQLite commit. */
|
|
64203
65136
|
volatileStateFields: ["lastFetchedAt"],
|
|
64204
|
-
customize:
|
|
64205
|
-
version: 1,
|
|
64206
|
-
advanced: "derive",
|
|
64207
|
-
targets: []
|
|
64208
|
-
}
|
|
65137
|
+
customize: powerMeterCustomize
|
|
64209
65138
|
};
|
|
64210
65139
|
/**
|
|
64211
65140
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -64225,11 +65154,11 @@ var powerMeterCapability = {
|
|
|
64225
65154
|
*/
|
|
64226
65155
|
var GpsLocationSchema = object({
|
|
64227
65156
|
/** Latitude in decimal degrees, -90..90. */
|
|
64228
|
-
latitude: number().min(-90).max(90),
|
|
65157
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
64229
65158
|
/** Longitude in decimal degrees, -180..180. */
|
|
64230
|
-
longitude: number().min(-180).max(180),
|
|
65159
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
64231
65160
|
/** Reported accuracy in meters (lower = better). */
|
|
64232
|
-
accuracyMeters: number().nonnegative()
|
|
65161
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
64233
65162
|
});
|
|
64234
65163
|
var PresenceStatusSchema = object({
|
|
64235
65164
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -64241,7 +65170,7 @@ var PresenceStatusSchema = object({
|
|
|
64241
65170
|
gps: GpsLocationSchema.nullable(),
|
|
64242
65171
|
/** Optional battery level of the tracking device (0..100). Null
|
|
64243
65172
|
* when not reported. */
|
|
64244
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
65173
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64245
65174
|
/** Ms epoch when the slice was last updated. */
|
|
64246
65175
|
lastChangedAt: number()
|
|
64247
65176
|
});
|
|
@@ -64291,19 +65220,10 @@ var presenceCapability = {
|
|
|
64291
65220
|
* `sourceInfo`.
|
|
64292
65221
|
*/
|
|
64293
65222
|
var PressureSensorStatusSchema = object({
|
|
64294
|
-
/** Current pressure in hPa. */
|
|
64295
|
-
hpa: number(),
|
|
65223
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
65224
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
64296
65225
|
/** Ms epoch when the slice was last updated. */
|
|
64297
|
-
lastFetchedAt: number()
|
|
64298
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64299
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64300
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
64301
|
-
unit: string().optional(),
|
|
64302
|
-
/** Suggested decimal places for numeric display.
|
|
64303
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64304
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64305
|
-
* auto-formatting when absent. */
|
|
64306
|
-
precision: number().int().min(0).max(10).optional()
|
|
65226
|
+
lastFetchedAt: number()
|
|
64307
65227
|
});
|
|
64308
65228
|
var pressureSensorCapability = {
|
|
64309
65229
|
name: "pressure-sensor",
|
|
@@ -64829,8 +65749,8 @@ var ptzCapability = {
|
|
|
64829
65749
|
};
|
|
64830
65750
|
var PtzAutotrackSettingsSchema = object({
|
|
64831
65751
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64832
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64833
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65752
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65753
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64834
65754
|
});
|
|
64835
65755
|
/**
|
|
64836
65756
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64984,7 +65904,7 @@ var RunningStateStatusSchema = object({
|
|
|
64984
65904
|
/** null = unknown — never coerced to false (D393). */
|
|
64985
65905
|
running: boolean().nullable(),
|
|
64986
65906
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64987
|
-
since: number().nullable(),
|
|
65907
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64988
65908
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64989
65909
|
phase: string().nullable(),
|
|
64990
65910
|
/** null until a reading has been published (D393). */
|
|
@@ -64999,7 +65919,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64999
65919
|
/** Generic Customize target for the running boolean (D936). */
|
|
65000
65920
|
var runningCustomize = {
|
|
65001
65921
|
version: 1,
|
|
65002
|
-
advanced: "derive",
|
|
65003
65922
|
targets: [{
|
|
65004
65923
|
id: "running",
|
|
65005
65924
|
cardinality: "scalar",
|
|
@@ -65008,6 +65927,8 @@ var runningCustomize = {
|
|
|
65008
65927
|
stateField: "running"
|
|
65009
65928
|
},
|
|
65010
65929
|
deviceTypes: [
|
|
65930
|
+
DeviceType.Washer,
|
|
65931
|
+
DeviceType.Dryer,
|
|
65011
65932
|
DeviceType.Dishwasher,
|
|
65012
65933
|
DeviceType.Vacuum,
|
|
65013
65934
|
DeviceType.LawnMower,
|
|
@@ -65019,7 +65940,7 @@ var runningCustomize = {
|
|
|
65019
65940
|
DeviceType.Thermostat,
|
|
65020
65941
|
DeviceType.PetFeeder
|
|
65021
65942
|
],
|
|
65022
|
-
apply: "add
|
|
65943
|
+
apply: "add",
|
|
65023
65944
|
path: "running",
|
|
65024
65945
|
sources: [
|
|
65025
65946
|
{
|
|
@@ -66287,9 +67208,9 @@ var RecordTriggerSchema = _enum([
|
|
|
66287
67208
|
*/
|
|
66288
67209
|
var RecordWindowSchema = object({
|
|
66289
67210
|
trigger: RecordTriggerSchema,
|
|
66290
|
-
day: number().int().min(0).max(6),
|
|
66291
|
-
startMinute: number().int().min(0).max(1439),
|
|
66292
|
-
endMinute: number().int().min(1).max(1440)
|
|
67211
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
67212
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
67213
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
66293
67214
|
});
|
|
66294
67215
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
66295
67216
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -66365,10 +67286,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
66365
67286
|
/** Master "record to the card at all" switch. */
|
|
66366
67287
|
enabled: boolean().nullable(),
|
|
66367
67288
|
overwriteWhenFull: boolean().nullable(),
|
|
66368
|
-
preRecordSec: number().nullable(),
|
|
66369
|
-
postRecordSec: number().nullable(),
|
|
67289
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
67290
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66370
67291
|
/** Length of one recorded file, in minutes. */
|
|
66371
|
-
segmentMinutes: number().nullable(),
|
|
67292
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
66372
67293
|
/** The primary track's weekly windows, flattened. */
|
|
66373
67294
|
windows: array(RecordWindowSchema),
|
|
66374
67295
|
/**
|
|
@@ -66384,7 +67305,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
66384
67305
|
* provider reporting a non-zero count also reports the schedule as not
|
|
66385
67306
|
* writable.
|
|
66386
67307
|
*/
|
|
66387
|
-
unreadableWindows: number(),
|
|
67308
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
66388
67309
|
/**
|
|
66389
67310
|
* The camera is scheduled to record and has NO usable storage.
|
|
66390
67311
|
*
|
|
@@ -67331,7 +68252,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
67331
68252
|
url: string().optional(),
|
|
67332
68253
|
codec: string().optional(),
|
|
67333
68254
|
resolution: CamStreamResolutionSchema.optional(),
|
|
67334
|
-
fps: number().positive().optional(),
|
|
68255
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
67335
68256
|
label: string().optional(),
|
|
67336
68257
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
67337
68258
|
deviceFeatures: array(string()).optional(),
|
|
@@ -67418,18 +68339,18 @@ var StreamProfileSchema = _enum([
|
|
|
67418
68339
|
]);
|
|
67419
68340
|
/** The current encoding config of one stream profile. */
|
|
67420
68341
|
var StreamProfileConfigSchema = object({
|
|
67421
|
-
width: number(),
|
|
67422
|
-
height: number(),
|
|
68342
|
+
width: number().meta(readingMeta("none")),
|
|
68343
|
+
height: number().meta(readingMeta("none")),
|
|
67423
68344
|
codec: _enum(["h264", "h265"]),
|
|
67424
|
-
framerate: number(),
|
|
67425
|
-
bitrate: number(),
|
|
68345
|
+
framerate: number().meta(readingMeta("rate")),
|
|
68346
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
67426
68347
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
67427
68348
|
encoderProfile: _enum([
|
|
67428
68349
|
"high",
|
|
67429
68350
|
"main",
|
|
67430
68351
|
"baseline"
|
|
67431
68352
|
]).optional(),
|
|
67432
|
-
gop: number().optional(),
|
|
68353
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
67433
68354
|
/**
|
|
67434
68355
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
67435
68356
|
*
|
|
@@ -67801,7 +68722,8 @@ var switchCapability = {
|
|
|
67801
68722
|
deviceTypes: [
|
|
67802
68723
|
DeviceType.Switch,
|
|
67803
68724
|
DeviceType.Siren,
|
|
67804
|
-
DeviceType.Light
|
|
68725
|
+
DeviceType.Light,
|
|
68726
|
+
DeviceType.Fan
|
|
67805
68727
|
],
|
|
67806
68728
|
methods: { setState: method(object({
|
|
67807
68729
|
deviceId: number(),
|
|
@@ -67848,12 +68770,7 @@ var switchCapability = {
|
|
|
67848
68770
|
label: "On",
|
|
67849
68771
|
kind: "boolean"
|
|
67850
68772
|
}
|
|
67851
|
-
}] }
|
|
67852
|
-
customize: {
|
|
67853
|
-
version: 1,
|
|
67854
|
-
advanced: "derive",
|
|
67855
|
-
targets: []
|
|
67856
|
-
}
|
|
68773
|
+
}] }
|
|
67857
68774
|
};
|
|
67858
68775
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
67859
68776
|
function hasControlCharacter(value) {
|
|
@@ -68436,35 +69353,21 @@ var tamperCapability = {
|
|
|
68436
69353
|
* entries with `device_class: temperature` and any future native
|
|
68437
69354
|
* thermometer.
|
|
68438
69355
|
*
|
|
68439
|
-
*
|
|
68440
|
-
*
|
|
68441
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
68442
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
68443
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
68444
|
-
* `sourceInfo`.
|
|
69356
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
69357
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
68445
69358
|
*
|
|
68446
69359
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
68447
69360
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
68448
69361
|
* changed" steady state.
|
|
68449
69362
|
*/
|
|
68450
69363
|
var TemperatureSensorStatusSchema = object({
|
|
68451
|
-
/** Current temperature in Celsius. */
|
|
68452
|
-
celsius: number().meta({
|
|
68453
|
-
|
|
69364
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
69365
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
69366
|
+
precision: 1,
|
|
68454
69367
|
label: "Temperature"
|
|
68455
|
-
}),
|
|
69368
|
+
})),
|
|
68456
69369
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
68457
|
-
lastFetchedAt: number()
|
|
68458
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
68459
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
68460
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
68461
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
68462
|
-
unit: string().optional(),
|
|
68463
|
-
/** Suggested decimal places for numeric display.
|
|
68464
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
68465
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
68466
|
-
* auto-formatting when absent. */
|
|
68467
|
-
precision: number().int().min(0).max(10).optional()
|
|
69370
|
+
lastFetchedAt: number()
|
|
68468
69371
|
});
|
|
68469
69372
|
var temperatureSensorCapability = {
|
|
68470
69373
|
name: "temperature-sensor",
|
|
@@ -68495,12 +69398,7 @@ var temperatureSensorCapability = {
|
|
|
68495
69398
|
} } },
|
|
68496
69399
|
/** Clock fields: written, but excluded from the compare that decides
|
|
68497
69400
|
* whether persisting is worth a SQLite commit. */
|
|
68498
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
68499
|
-
customize: {
|
|
68500
|
-
version: 1,
|
|
68501
|
-
advanced: "derive",
|
|
68502
|
-
targets: []
|
|
68503
|
-
}
|
|
69401
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
68504
69402
|
};
|
|
68505
69403
|
/**
|
|
68506
69404
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -68783,16 +69681,16 @@ var VacuumControlStatusSchema = object({
|
|
|
68783
69681
|
]),
|
|
68784
69682
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
68785
69683
|
* reading. */
|
|
68786
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
69684
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68787
69685
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
68788
69686
|
* the vacuum has no speed control. */
|
|
68789
69687
|
fanSpeed: string().nullable(),
|
|
68790
69688
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
68791
69689
|
availableFanSpeeds: array(string()),
|
|
68792
69690
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
68793
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
69691
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68794
69692
|
/** Current error code (0 / null = no error). */
|
|
68795
|
-
errorCode: number().nullable(),
|
|
69693
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
68796
69694
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
68797
69695
|
errorLabel: string().nullable(),
|
|
68798
69696
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -68870,7 +69768,7 @@ var ValveStatusSchema = object({
|
|
|
68870
69768
|
]),
|
|
68871
69769
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
68872
69770
|
* intermediate position surface. */
|
|
68873
|
-
position: number().min(0).max(100).nullable(),
|
|
69771
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68874
69772
|
/** Ms epoch when the slice was last updated. */
|
|
68875
69773
|
lastChangedAt: number()
|
|
68876
69774
|
});
|
|
@@ -68978,9 +69876,9 @@ var vibrationCapability = {
|
|
|
68978
69876
|
*/
|
|
68979
69877
|
var WaterHeaterStatusSchema = object({
|
|
68980
69878
|
/** Current measured temperature. Null when not reported. */
|
|
68981
|
-
currentTemp: number().nullable(),
|
|
69879
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68982
69880
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68983
|
-
targetTemp: number().nullable(),
|
|
69881
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68984
69882
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68985
69883
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68986
69884
|
* device reports an unknown state. */
|
|
@@ -68991,9 +69889,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68991
69889
|
* has no away surface. */
|
|
68992
69890
|
away: boolean().nullable(),
|
|
68993
69891
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68994
|
-
minTemp: number().nullable(),
|
|
69892
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68995
69893
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68996
|
-
maxTemp: number().nullable(),
|
|
69894
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68997
69895
|
/** Ms epoch when the slice was last updated. */
|
|
68998
69896
|
lastChangedAt: number()
|
|
68999
69897
|
});
|
|
@@ -69078,25 +69976,18 @@ var waterHeaterCapability = {
|
|
|
69078
69976
|
* Forecast deferred — current conditions only for v1.
|
|
69079
69977
|
*/
|
|
69080
69978
|
var WeatherStatusSchema = object({
|
|
69081
|
-
/** Verbatim
|
|
69082
|
-
* when no condition has been reported yet. */
|
|
69979
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
69083
69980
|
condition: string().nullable(),
|
|
69084
|
-
/** Current temperature in
|
|
69085
|
-
temperature: number().nullable(),
|
|
69086
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
69087
|
-
temperatureUnit: string().nullable(),
|
|
69981
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
69982
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
69088
69983
|
/** Relative humidity (0..100). Null when not provided. */
|
|
69089
|
-
humidity: number().min(0).max(100).nullable(),
|
|
69090
|
-
/** Barometric pressure in
|
|
69091
|
-
pressure: number().nullable(),
|
|
69092
|
-
/**
|
|
69093
|
-
|
|
69094
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
69095
|
-
windSpeed: number().nullable(),
|
|
69096
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
69097
|
-
windSpeedUnit: string().nullable(),
|
|
69984
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
69985
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
69986
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
69987
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
69988
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
69098
69989
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
69099
|
-
windBearing: number().nullable(),
|
|
69990
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
69100
69991
|
/** Ms epoch when the slice was last updated. */
|
|
69101
69992
|
lastFetchedAt: number()
|
|
69102
69993
|
});
|
|
@@ -69124,12 +70015,12 @@ var weatherCapability = {
|
|
|
69124
70015
|
*/
|
|
69125
70016
|
durability: "session",
|
|
69126
70017
|
/**
|
|
69127
|
-
* History (D850): recorded series.
|
|
70018
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
69128
70019
|
*/
|
|
69129
70020
|
history: { fields: {
|
|
69130
70021
|
temperature: {
|
|
69131
70022
|
kind: "gauge",
|
|
69132
|
-
|
|
70023
|
+
unit: "°C",
|
|
69133
70024
|
deadband: .2
|
|
69134
70025
|
},
|
|
69135
70026
|
humidity: {
|
|
@@ -69139,12 +70030,12 @@ var weatherCapability = {
|
|
|
69139
70030
|
},
|
|
69140
70031
|
pressure: {
|
|
69141
70032
|
kind: "gauge",
|
|
69142
|
-
|
|
70033
|
+
unit: "hPa",
|
|
69143
70034
|
deadband: .5
|
|
69144
70035
|
},
|
|
69145
70036
|
windSpeed: {
|
|
69146
70037
|
kind: "gauge",
|
|
69147
|
-
|
|
70038
|
+
unit: "m/s",
|
|
69148
70039
|
deadband: .5
|
|
69149
70040
|
}
|
|
69150
70041
|
} }
|
|
@@ -70178,8 +71069,9 @@ function withClipEventLabels(provider, deps) {
|
|
|
70178
71069
|
listClips
|
|
70179
71070
|
};
|
|
70180
71071
|
}
|
|
71072
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
70181
71073
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
70182
|
-
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;
|
|
71074
|
+
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;
|
|
70183
71075
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
70184
71076
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
70185
71077
|
new Set(CAP_NAMES);
|
|
@@ -70508,6 +71400,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70508
71400
|
featureProbe: featureProbeCapability,
|
|
70509
71401
|
flood: floodCapability,
|
|
70510
71402
|
gas: gasCapability,
|
|
71403
|
+
groupActive: groupActiveCapability,
|
|
71404
|
+
groupCommands: groupCommandsCapability,
|
|
71405
|
+
groupStatus: groupStatusCapability,
|
|
70511
71406
|
heatingValve: heatingValveCapability,
|
|
70512
71407
|
humidifier: humidifierCapability,
|
|
70513
71408
|
humiditySensor: humiditySensorCapability,
|
|
@@ -70517,6 +71412,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70517
71412
|
lawnMowerControl: lawnMowerControlCapability,
|
|
70518
71413
|
lockControl: lockControlCapability,
|
|
70519
71414
|
mediaPlayer: mediaPlayerCapability,
|
|
71415
|
+
meter: meterCapability,
|
|
70520
71416
|
motion: motionCapability,
|
|
70521
71417
|
motionTrigger: motionTriggerCapability,
|
|
70522
71418
|
motionZones: motionZonesCapability,
|
|
@@ -71780,7 +72676,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
71780
72676
|
function widenDeviceConstructor(ctor) {
|
|
71781
72677
|
return ctor;
|
|
71782
72678
|
}
|
|
71783
|
-
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;
|
|
72679
|
+
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;
|
|
71784
72680
|
new Set(Object.values(DeviceType));
|
|
71785
72681
|
Object.freeze({
|
|
71786
72682
|
"accessories.getStatus": {
|
|
@@ -71888,6 +72784,13 @@ Object.freeze({
|
|
|
71888
72784
|
access: "view",
|
|
71889
72785
|
role: "admin"
|
|
71890
72786
|
},
|
|
72787
|
+
"addons.getPackageDocs": {
|
|
72788
|
+
capName: "addons",
|
|
72789
|
+
capScope: "system",
|
|
72790
|
+
addonId: null,
|
|
72791
|
+
access: "view",
|
|
72792
|
+
role: "admin"
|
|
72793
|
+
},
|
|
71891
72794
|
"addons.getVersions": {
|
|
71892
72795
|
capName: "addons",
|
|
71893
72796
|
capScope: "system",
|
|
@@ -74996,6 +75899,27 @@ Object.freeze({
|
|
|
74996
75899
|
access: "view",
|
|
74997
75900
|
role: "viewer"
|
|
74998
75901
|
},
|
|
75902
|
+
"groupActive.getStatus": {
|
|
75903
|
+
capName: "group-active",
|
|
75904
|
+
capScope: "device",
|
|
75905
|
+
addonId: null,
|
|
75906
|
+
access: "view",
|
|
75907
|
+
role: "viewer"
|
|
75908
|
+
},
|
|
75909
|
+
"groupCommands.getStatus": {
|
|
75910
|
+
capName: "group-commands",
|
|
75911
|
+
capScope: "device",
|
|
75912
|
+
addonId: null,
|
|
75913
|
+
access: "view",
|
|
75914
|
+
role: "viewer"
|
|
75915
|
+
},
|
|
75916
|
+
"groupStatus.getStatus": {
|
|
75917
|
+
capName: "group-status",
|
|
75918
|
+
capScope: "device",
|
|
75919
|
+
addonId: null,
|
|
75920
|
+
access: "view",
|
|
75921
|
+
role: "viewer"
|
|
75922
|
+
},
|
|
74999
75923
|
"heatingValve.getStatus": {
|
|
75000
75924
|
capName: "heating-valve",
|
|
75001
75925
|
capScope: "device",
|
|
@@ -75948,6 +76872,13 @@ Object.freeze({
|
|
|
75948
76872
|
access: "create",
|
|
75949
76873
|
role: "admin"
|
|
75950
76874
|
},
|
|
76875
|
+
"meter.getStatus": {
|
|
76876
|
+
capName: "meter",
|
|
76877
|
+
capScope: "device",
|
|
76878
|
+
addonId: null,
|
|
76879
|
+
access: "view",
|
|
76880
|
+
role: "viewer"
|
|
76881
|
+
},
|
|
75951
76882
|
"metricsProvider.collectSnapshot": {
|
|
75952
76883
|
capName: "metrics-provider",
|
|
75953
76884
|
capScope: "system",
|
|
@@ -84046,7 +84977,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
84046
84977
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
84047
84978
|
icon: "square"
|
|
84048
84979
|
}
|
|
84049
|
-
}
|
|
84980
|
+
},
|
|
84981
|
+
overrides: { byType: {
|
|
84982
|
+
[DeviceType.Washer]: {
|
|
84983
|
+
state: { running: {
|
|
84984
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
84985
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
84986
|
+
} },
|
|
84987
|
+
events: {
|
|
84988
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
84989
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
84990
|
+
}
|
|
84991
|
+
},
|
|
84992
|
+
[DeviceType.Dryer]: {
|
|
84993
|
+
state: { running: {
|
|
84994
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
84995
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
84996
|
+
} },
|
|
84997
|
+
events: {
|
|
84998
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
84999
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
85000
|
+
}
|
|
85001
|
+
},
|
|
85002
|
+
[DeviceType.Dishwasher]: {
|
|
85003
|
+
state: { running: {
|
|
85004
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
85005
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
85006
|
+
} },
|
|
85007
|
+
events: {
|
|
85008
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
85009
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
85010
|
+
}
|
|
85011
|
+
}
|
|
85012
|
+
} }
|
|
84050
85013
|
},
|
|
84051
85014
|
update: {
|
|
84052
85015
|
scope: "device",
|
|
@@ -84818,6 +85781,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84818
85781
|
icon: "flame"
|
|
84819
85782
|
}]
|
|
84820
85783
|
},
|
|
85784
|
+
"group-active": {
|
|
85785
|
+
scope: "device",
|
|
85786
|
+
noun: t("Group state", "Stato del gruppo")
|
|
85787
|
+
},
|
|
85788
|
+
"group-commands": {
|
|
85789
|
+
scope: "device",
|
|
85790
|
+
noun: t("Group command", "Comando di gruppo")
|
|
85791
|
+
},
|
|
85792
|
+
"group-status": {
|
|
85793
|
+
scope: "device",
|
|
85794
|
+
noun: t("Group", "Gruppo"),
|
|
85795
|
+
state: [
|
|
85796
|
+
{
|
|
85797
|
+
kind: "numeric",
|
|
85798
|
+
field: "included",
|
|
85799
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
85800
|
+
label: t("Reporting", "Rispondono"),
|
|
85801
|
+
icon: "users"
|
|
85802
|
+
},
|
|
85803
|
+
{
|
|
85804
|
+
kind: "numeric",
|
|
85805
|
+
field: "excluded",
|
|
85806
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
85807
|
+
label: t("Excluded", "Esclusi"),
|
|
85808
|
+
icon: "users"
|
|
85809
|
+
},
|
|
85810
|
+
{
|
|
85811
|
+
kind: "numeric",
|
|
85812
|
+
field: "total",
|
|
85813
|
+
quantity: t("the member count", "il numero di membri"),
|
|
85814
|
+
label: t("Members", "Membri"),
|
|
85815
|
+
icon: "sigma"
|
|
85816
|
+
}
|
|
85817
|
+
]
|
|
85818
|
+
},
|
|
84821
85819
|
"humidity-sensor": {
|
|
84822
85820
|
scope: "device",
|
|
84823
85821
|
noun: t("Humidity", "Umidità"),
|
|
@@ -84843,6 +85841,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84843
85841
|
}],
|
|
84844
85842
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
84845
85843
|
},
|
|
85844
|
+
meter: {
|
|
85845
|
+
scope: "device",
|
|
85846
|
+
noun: t("Meter", "Contatore"),
|
|
85847
|
+
state: [{
|
|
85848
|
+
kind: "numeric",
|
|
85849
|
+
field: "value",
|
|
85850
|
+
quantity: t("the total", "il totale"),
|
|
85851
|
+
label: t("Total", "Totale"),
|
|
85852
|
+
icon: "gauge"
|
|
85853
|
+
}]
|
|
85854
|
+
},
|
|
84846
85855
|
"numeric-sensor": {
|
|
84847
85856
|
scope: "device",
|
|
84848
85857
|
noun: t("Sensor", "Sensore"),
|
|
@@ -84851,7 +85860,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84851
85860
|
field: "value",
|
|
84852
85861
|
quantity: t("the reading", "il valore"),
|
|
84853
85862
|
label: t("Reading", "Valore"),
|
|
84854
|
-
unitField: "unit",
|
|
84855
85863
|
icon: "gauge"
|
|
84856
85864
|
}]
|
|
84857
85865
|
},
|
|
@@ -84987,7 +85995,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84987
85995
|
field: "temperature",
|
|
84988
85996
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
84989
85997
|
label: t("Temperature", "Temperatura"),
|
|
84990
|
-
|
|
85998
|
+
unit: "°C",
|
|
84991
85999
|
icon: "thermometer"
|
|
84992
86000
|
},
|
|
84993
86001
|
{
|
|
@@ -85003,7 +86011,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85003
86011
|
field: "windSpeed",
|
|
85004
86012
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
85005
86013
|
label: t("Wind", "Vento"),
|
|
85006
|
-
|
|
86014
|
+
unit: "m/s",
|
|
85007
86015
|
icon: "wind"
|
|
85008
86016
|
},
|
|
85009
86017
|
{
|
|
@@ -85011,7 +86019,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85011
86019
|
field: "pressure",
|
|
85012
86020
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
85013
86021
|
label: t("Pressure", "Pressione"),
|
|
85014
|
-
|
|
86022
|
+
unit: "hPa",
|
|
85015
86023
|
icon: "gauge"
|
|
85016
86024
|
}
|
|
85017
86025
|
]
|
|
@@ -85316,8 +86324,47 @@ function projectAction(cap, action) {
|
|
|
85316
86324
|
};
|
|
85317
86325
|
}
|
|
85318
86326
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
85319
|
-
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;
|
|
86327
|
+
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;
|
|
85320
86328
|
DeviceFeature.BatteryOperated;
|
|
86329
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
86330
|
+
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.";
|
|
86331
|
+
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.";
|
|
86332
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
86333
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
86334
|
+
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.";
|
|
86335
|
+
function withheld(reason) {
|
|
86336
|
+
return {
|
|
86337
|
+
[DeviceType.Washer]: {
|
|
86338
|
+
exported: false,
|
|
86339
|
+
reason
|
|
86340
|
+
},
|
|
86341
|
+
[DeviceType.Dryer]: {
|
|
86342
|
+
exported: false,
|
|
86343
|
+
reason
|
|
86344
|
+
},
|
|
86345
|
+
[DeviceType.Dishwasher]: {
|
|
86346
|
+
exported: false,
|
|
86347
|
+
reason
|
|
86348
|
+
}
|
|
86349
|
+
};
|
|
86350
|
+
}
|
|
86351
|
+
function offered(received) {
|
|
86352
|
+
return {
|
|
86353
|
+
[DeviceType.Washer]: {
|
|
86354
|
+
exported: true,
|
|
86355
|
+
as: received
|
|
86356
|
+
},
|
|
86357
|
+
[DeviceType.Dryer]: {
|
|
86358
|
+
exported: true,
|
|
86359
|
+
as: received
|
|
86360
|
+
},
|
|
86361
|
+
[DeviceType.Dishwasher]: {
|
|
86362
|
+
exported: true,
|
|
86363
|
+
as: received
|
|
86364
|
+
}
|
|
86365
|
+
};
|
|
86366
|
+
}
|
|
86367
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
85321
86368
|
/** Reject after `ms`; always clears its own timer. */
|
|
85322
86369
|
async function withTimeout$1(promise, ms, label) {
|
|
85323
86370
|
let timer;
|
|
@@ -86490,6 +87537,21 @@ Object.freeze({
|
|
|
86490
87537
|
form: "single",
|
|
86491
87538
|
optional: false
|
|
86492
87539
|
}],
|
|
87540
|
+
"groupActive.getStatus": [{
|
|
87541
|
+
name: "deviceId",
|
|
87542
|
+
form: "single",
|
|
87543
|
+
optional: false
|
|
87544
|
+
}],
|
|
87545
|
+
"groupCommands.getStatus": [{
|
|
87546
|
+
name: "deviceId",
|
|
87547
|
+
form: "single",
|
|
87548
|
+
optional: false
|
|
87549
|
+
}],
|
|
87550
|
+
"groupStatus.getStatus": [{
|
|
87551
|
+
name: "deviceId",
|
|
87552
|
+
form: "single",
|
|
87553
|
+
optional: false
|
|
87554
|
+
}],
|
|
86493
87555
|
"heatingValve.getStatus": [{
|
|
86494
87556
|
name: "deviceId",
|
|
86495
87557
|
form: "single",
|
|
@@ -86690,6 +87752,11 @@ Object.freeze({
|
|
|
86690
87752
|
form: "single",
|
|
86691
87753
|
optional: false
|
|
86692
87754
|
}],
|
|
87755
|
+
"meter.getStatus": [{
|
|
87756
|
+
name: "deviceId",
|
|
87757
|
+
form: "single",
|
|
87758
|
+
optional: false
|
|
87759
|
+
}],
|
|
86693
87760
|
"motion.getStatus": [{
|
|
86694
87761
|
name: "deviceId",
|
|
86695
87762
|
form: "single",
|
|
@@ -88297,7 +89364,6 @@ Object.freeze({
|
|
|
88297
89364
|
"network-access": "ingress",
|
|
88298
89365
|
"smtp-provider": "email"
|
|
88299
89366
|
});
|
|
88300
|
-
DeviceType.Camera;
|
|
88301
89367
|
/**
|
|
88302
89368
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
88303
89369
|
* `z.infer`, they do not restate the shape.
|
|
@@ -88474,6 +89540,8 @@ new Map(Object.entries({
|
|
|
88474
89540
|
"detection-blind": "device-events",
|
|
88475
89541
|
"motion-noisy": "device-events",
|
|
88476
89542
|
"motion-calm": "device-events",
|
|
89543
|
+
"package-llm-silent": "device-events",
|
|
89544
|
+
"package-llm-answered": "device-events",
|
|
88477
89545
|
"recording-stalled": "device-events",
|
|
88478
89546
|
"recording-healthy": "device-events",
|
|
88479
89547
|
"recording-degraded": "device-events",
|
|
@@ -88557,6 +89625,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
88557
89625
|
label: "Motion without a subject",
|
|
88558
89626
|
kinds: ["motion-noisy", "motion-calm"]
|
|
88559
89627
|
},
|
|
89628
|
+
{
|
|
89629
|
+
id: "package-llm",
|
|
89630
|
+
family: "device-events",
|
|
89631
|
+
label: "Package confirm",
|
|
89632
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
89633
|
+
},
|
|
88560
89634
|
{
|
|
88561
89635
|
id: "recording",
|
|
88562
89636
|
family: "device-events",
|
|
@@ -88738,6 +89812,8 @@ var DEVICE_EVENTS = [
|
|
|
88738
89812
|
"detection-blind",
|
|
88739
89813
|
"motion-noisy",
|
|
88740
89814
|
"motion-calm",
|
|
89815
|
+
"package-llm-silent",
|
|
89816
|
+
"package-llm-answered",
|
|
88741
89817
|
"recording-stalled",
|
|
88742
89818
|
"recording-healthy",
|
|
88743
89819
|
"recording-degraded",
|
|
@@ -89006,6 +90082,15 @@ new Map([
|
|
|
89006
90082
|
snapshotLabel: "Cameras with constant motion now",
|
|
89007
90083
|
snapshotSection: null
|
|
89008
90084
|
},
|
|
90085
|
+
{
|
|
90086
|
+
id: "package-llm-confirm",
|
|
90087
|
+
family: "device-events",
|
|
90088
|
+
label: "Package confirm (not answering / answering again)",
|
|
90089
|
+
bad: ["package-llm-silent"],
|
|
90090
|
+
recovery: ["package-llm-answered"],
|
|
90091
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
90092
|
+
snapshotSection: null
|
|
90093
|
+
},
|
|
89009
90094
|
{
|
|
89010
90095
|
id: "recording-health",
|
|
89011
90096
|
family: "device-events",
|