@camstack/addon-terminal 0.1.153 → 0.1.155
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 +26 -0
- package/dist/addon.js +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { createServer } from "node:http";
|
|
|
8
8
|
//#region \0rolldown/runtime.js
|
|
9
9
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
10
10
|
//#endregion
|
|
11
|
-
//#region ../types/dist/event-category-
|
|
11
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
12
12
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
13
13
|
EventCategory["SystemBoot"] = "system.boot";
|
|
14
14
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -334,6 +334,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
334
334
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
335
335
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
336
336
|
/**
|
|
337
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
338
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
339
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
340
|
+
*/
|
|
341
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
342
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
343
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
344
|
+
/**
|
|
337
345
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
338
346
|
* (a settings change via `setAgentInferenceDevices` /
|
|
339
347
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5443,7 +5451,7 @@ var ZodIssueCode = {
|
|
|
5443
5451
|
var ZodFirstPartyTypeKind;
|
|
5444
5452
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5445
5453
|
//#endregion
|
|
5446
|
-
//#region ../types/dist/sleep
|
|
5454
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5447
5455
|
/**
|
|
5448
5456
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5449
5457
|
* window to float samples (D455).
|
|
@@ -7997,6 +8005,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
7997
8005
|
}).strict();
|
|
7998
8006
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
7999
8007
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8008
|
+
var READING_QUANTITIES = [
|
|
8009
|
+
"temperature",
|
|
8010
|
+
"pressure",
|
|
8011
|
+
"speed",
|
|
8012
|
+
"precipitation",
|
|
8013
|
+
"precipitation-rate",
|
|
8014
|
+
"length",
|
|
8015
|
+
"area",
|
|
8016
|
+
"illuminance",
|
|
8017
|
+
"irradiance",
|
|
8018
|
+
"power",
|
|
8019
|
+
"energy",
|
|
8020
|
+
"voltage",
|
|
8021
|
+
"current",
|
|
8022
|
+
"apparent-power",
|
|
8023
|
+
"humidity",
|
|
8024
|
+
"percentage",
|
|
8025
|
+
"concentration-volume",
|
|
8026
|
+
"concentration-mass",
|
|
8027
|
+
"concentration-ppb",
|
|
8028
|
+
"volume",
|
|
8029
|
+
"duration",
|
|
8030
|
+
"duration-ms",
|
|
8031
|
+
"information",
|
|
8032
|
+
"sound-level",
|
|
8033
|
+
"signal-level",
|
|
8034
|
+
"colour-temperature",
|
|
8035
|
+
"angle",
|
|
8036
|
+
"bitrate",
|
|
8037
|
+
"rate",
|
|
8038
|
+
"mass",
|
|
8039
|
+
"index",
|
|
8040
|
+
"ratio",
|
|
8041
|
+
"count",
|
|
8042
|
+
"none",
|
|
8043
|
+
"device"
|
|
8044
|
+
];
|
|
8045
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8046
|
+
new Set(READING_QUANTITIES);
|
|
8047
|
+
/**
|
|
8048
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8049
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8050
|
+
*/
|
|
8051
|
+
var QUANTITY_BASE = {
|
|
8052
|
+
temperature: "°C",
|
|
8053
|
+
pressure: "hPa",
|
|
8054
|
+
speed: "m/s",
|
|
8055
|
+
precipitation: "mm",
|
|
8056
|
+
"precipitation-rate": "mm/h",
|
|
8057
|
+
length: "m",
|
|
8058
|
+
area: "m²",
|
|
8059
|
+
illuminance: "lx",
|
|
8060
|
+
irradiance: "W/m²",
|
|
8061
|
+
power: "W",
|
|
8062
|
+
energy: "kWh",
|
|
8063
|
+
voltage: "V",
|
|
8064
|
+
current: "A",
|
|
8065
|
+
"apparent-power": "VA",
|
|
8066
|
+
humidity: "%",
|
|
8067
|
+
percentage: "%",
|
|
8068
|
+
"concentration-volume": "ppm",
|
|
8069
|
+
"concentration-mass": "µg/m³",
|
|
8070
|
+
"concentration-ppb": "ppb",
|
|
8071
|
+
volume: "L",
|
|
8072
|
+
duration: "s",
|
|
8073
|
+
"duration-ms": "ms",
|
|
8074
|
+
information: "B",
|
|
8075
|
+
"sound-level": "dBFS",
|
|
8076
|
+
"signal-level": "dBm",
|
|
8077
|
+
"colour-temperature": "mired",
|
|
8078
|
+
angle: "°",
|
|
8079
|
+
bitrate: "kbps",
|
|
8080
|
+
rate: "fps",
|
|
8081
|
+
mass: "kg",
|
|
8082
|
+
index: "none",
|
|
8083
|
+
ratio: "none",
|
|
8084
|
+
count: "none",
|
|
8085
|
+
none: "none",
|
|
8086
|
+
device: "device"
|
|
8087
|
+
};
|
|
8088
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8089
|
+
function baseUnitOf(quantity) {
|
|
8090
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8091
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8092
|
+
return symbol;
|
|
8093
|
+
}
|
|
8094
|
+
function readingMeta(quantity, extras) {
|
|
8095
|
+
return {
|
|
8096
|
+
quantity,
|
|
8097
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8098
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8099
|
+
};
|
|
8100
|
+
}
|
|
8000
8101
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8001
8102
|
var CamProfileSchema = _enum([
|
|
8002
8103
|
"high",
|
|
@@ -8024,8 +8125,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8024
8125
|
"derived"
|
|
8025
8126
|
]);
|
|
8026
8127
|
var CamStreamResolutionSchema = object({
|
|
8027
|
-
width: number().int().positive(),
|
|
8028
|
-
height: number().int().positive()
|
|
8128
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8129
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8029
8130
|
});
|
|
8030
8131
|
var CameraStreamSchema = object({
|
|
8031
8132
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8602,6 +8703,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8602
8703
|
"filesystem-browse",
|
|
8603
8704
|
"flood",
|
|
8604
8705
|
"gas",
|
|
8706
|
+
"group-active",
|
|
8707
|
+
"group-commands",
|
|
8708
|
+
"group-status",
|
|
8605
8709
|
"heating-valve",
|
|
8606
8710
|
"humidifier",
|
|
8607
8711
|
"humidity-sensor",
|
|
@@ -8622,6 +8726,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8622
8726
|
"login-method",
|
|
8623
8727
|
"media-player",
|
|
8624
8728
|
"mesh-network",
|
|
8729
|
+
"meter",
|
|
8625
8730
|
"metrics-provider",
|
|
8626
8731
|
"model-convert",
|
|
8627
8732
|
"model-distributor",
|
|
@@ -8731,14 +8836,6 @@ Object.freeze({
|
|
|
8731
8836
|
{
|
|
8732
8837
|
"path": "aqi",
|
|
8733
8838
|
"valueType": "number"
|
|
8734
|
-
},
|
|
8735
|
-
{
|
|
8736
|
-
"path": "unit",
|
|
8737
|
-
"valueType": "string"
|
|
8738
|
-
},
|
|
8739
|
-
{
|
|
8740
|
-
"path": "precision",
|
|
8741
|
-
"valueType": "number"
|
|
8742
8839
|
}
|
|
8743
8840
|
],
|
|
8744
8841
|
"alarm-panel": [
|
|
@@ -8774,20 +8871,10 @@ Object.freeze({
|
|
|
8774
8871
|
"valueType": "boolean"
|
|
8775
8872
|
}
|
|
8776
8873
|
],
|
|
8777
|
-
"ambient-light-sensor": [
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
},
|
|
8782
|
-
{
|
|
8783
|
-
"path": "unit",
|
|
8784
|
-
"valueType": "string"
|
|
8785
|
-
},
|
|
8786
|
-
{
|
|
8787
|
-
"path": "precision",
|
|
8788
|
-
"valueType": "number"
|
|
8789
|
-
}
|
|
8790
|
-
],
|
|
8874
|
+
"ambient-light-sensor": [{
|
|
8875
|
+
"path": "lux",
|
|
8876
|
+
"valueType": "number"
|
|
8877
|
+
}],
|
|
8791
8878
|
"audio-metrics": [
|
|
8792
8879
|
{
|
|
8793
8880
|
"path": "ts",
|
|
@@ -8867,6 +8954,10 @@ Object.freeze({
|
|
|
8867
8954
|
"path": "lastUpdated",
|
|
8868
8955
|
"valueType": "number"
|
|
8869
8956
|
},
|
|
8957
|
+
{
|
|
8958
|
+
"path": "volts",
|
|
8959
|
+
"valueType": "number"
|
|
8960
|
+
},
|
|
8870
8961
|
{
|
|
8871
8962
|
"path": "lastContactAt",
|
|
8872
8963
|
"valueType": "number"
|
|
@@ -9109,10 +9200,6 @@ Object.freeze({
|
|
|
9109
9200
|
"datetime"
|
|
9110
9201
|
]
|
|
9111
9202
|
},
|
|
9112
|
-
{
|
|
9113
|
-
"path": "unit",
|
|
9114
|
-
"valueType": "string"
|
|
9115
|
-
},
|
|
9116
9203
|
{
|
|
9117
9204
|
"path": "min",
|
|
9118
9205
|
"valueType": "number"
|
|
@@ -9124,19 +9211,6 @@ Object.freeze({
|
|
|
9124
9211
|
{
|
|
9125
9212
|
"path": "step",
|
|
9126
9213
|
"valueType": "number"
|
|
9127
|
-
},
|
|
9128
|
-
{
|
|
9129
|
-
"path": "precision",
|
|
9130
|
-
"valueType": "number"
|
|
9131
|
-
},
|
|
9132
|
-
{
|
|
9133
|
-
"path": "format",
|
|
9134
|
-
"valueType": "enum",
|
|
9135
|
-
"enumValues": [
|
|
9136
|
-
"date",
|
|
9137
|
-
"time",
|
|
9138
|
-
"datetime"
|
|
9139
|
-
]
|
|
9140
9214
|
}
|
|
9141
9215
|
],
|
|
9142
9216
|
"cover": [
|
|
@@ -9377,13 +9451,8 @@ Object.freeze({
|
|
|
9377
9451
|
"path": "value",
|
|
9378
9452
|
"valueType": "string"
|
|
9379
9453
|
}, {
|
|
9380
|
-
"path": "
|
|
9381
|
-
"valueType": "
|
|
9382
|
-
"enumValues": [
|
|
9383
|
-
"date",
|
|
9384
|
-
"time",
|
|
9385
|
-
"datetime"
|
|
9386
|
-
]
|
|
9454
|
+
"path": "timestamp",
|
|
9455
|
+
"valueType": "boolean"
|
|
9387
9456
|
}],
|
|
9388
9457
|
"event-emitter": [
|
|
9389
9458
|
{
|
|
@@ -9456,6 +9525,24 @@ Object.freeze({
|
|
|
9456
9525
|
"path": "detected",
|
|
9457
9526
|
"valueType": "boolean"
|
|
9458
9527
|
}],
|
|
9528
|
+
"group-active": [{
|
|
9529
|
+
"path": "active",
|
|
9530
|
+
"valueType": "boolean"
|
|
9531
|
+
}],
|
|
9532
|
+
"group-status": [
|
|
9533
|
+
{
|
|
9534
|
+
"path": "included",
|
|
9535
|
+
"valueType": "number"
|
|
9536
|
+
},
|
|
9537
|
+
{
|
|
9538
|
+
"path": "excluded",
|
|
9539
|
+
"valueType": "number"
|
|
9540
|
+
},
|
|
9541
|
+
{
|
|
9542
|
+
"path": "total",
|
|
9543
|
+
"valueType": "number"
|
|
9544
|
+
}
|
|
9545
|
+
],
|
|
9459
9546
|
"heating-valve": [{
|
|
9460
9547
|
"path": "position",
|
|
9461
9548
|
"valueType": "number"
|
|
@@ -9490,20 +9577,10 @@ Object.freeze({
|
|
|
9490
9577
|
"valueType": "number"
|
|
9491
9578
|
}
|
|
9492
9579
|
],
|
|
9493
|
-
"humidity-sensor": [
|
|
9494
|
-
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
},
|
|
9498
|
-
{
|
|
9499
|
-
"path": "unit",
|
|
9500
|
-
"valueType": "string"
|
|
9501
|
-
},
|
|
9502
|
-
{
|
|
9503
|
-
"path": "precision",
|
|
9504
|
-
"valueType": "number"
|
|
9505
|
-
}
|
|
9506
|
-
],
|
|
9580
|
+
"humidity-sensor": [{
|
|
9581
|
+
"path": "percent",
|
|
9582
|
+
"valueType": "number"
|
|
9583
|
+
}],
|
|
9507
9584
|
"image": [{
|
|
9508
9585
|
"path": "url",
|
|
9509
9586
|
"valueType": "string"
|
|
@@ -9711,6 +9788,10 @@ Object.freeze({
|
|
|
9711
9788
|
]
|
|
9712
9789
|
}
|
|
9713
9790
|
],
|
|
9791
|
+
"meter": [{
|
|
9792
|
+
"path": "value",
|
|
9793
|
+
"valueType": "number"
|
|
9794
|
+
}],
|
|
9714
9795
|
"motion": [
|
|
9715
9796
|
{
|
|
9716
9797
|
"path": "detected",
|
|
@@ -9842,20 +9923,10 @@ Object.freeze({
|
|
|
9842
9923
|
"valueType": "boolean"
|
|
9843
9924
|
}
|
|
9844
9925
|
],
|
|
9845
|
-
"numeric-sensor": [
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
},
|
|
9850
|
-
{
|
|
9851
|
-
"path": "unit",
|
|
9852
|
-
"valueType": "string"
|
|
9853
|
-
},
|
|
9854
|
-
{
|
|
9855
|
-
"path": "precision",
|
|
9856
|
-
"valueType": "number"
|
|
9857
|
-
}
|
|
9858
|
-
],
|
|
9926
|
+
"numeric-sensor": [{
|
|
9927
|
+
"path": "value",
|
|
9928
|
+
"valueType": "number"
|
|
9929
|
+
}],
|
|
9859
9930
|
"pet-feeder": [
|
|
9860
9931
|
{
|
|
9861
9932
|
"path": "foodLevel",
|
|
@@ -9947,14 +10018,6 @@ Object.freeze({
|
|
|
9947
10018
|
{
|
|
9948
10019
|
"path": "powerFactor",
|
|
9949
10020
|
"valueType": "number"
|
|
9950
|
-
},
|
|
9951
|
-
{
|
|
9952
|
-
"path": "unit",
|
|
9953
|
-
"valueType": "string"
|
|
9954
|
-
},
|
|
9955
|
-
{
|
|
9956
|
-
"path": "precision",
|
|
9957
|
-
"valueType": "number"
|
|
9958
10021
|
}
|
|
9959
10022
|
],
|
|
9960
10023
|
"presence": [
|
|
@@ -9983,20 +10046,10 @@ Object.freeze({
|
|
|
9983
10046
|
"valueType": "number"
|
|
9984
10047
|
}
|
|
9985
10048
|
],
|
|
9986
|
-
"pressure-sensor": [
|
|
9987
|
-
|
|
9988
|
-
|
|
9989
|
-
|
|
9990
|
-
},
|
|
9991
|
-
{
|
|
9992
|
-
"path": "unit",
|
|
9993
|
-
"valueType": "string"
|
|
9994
|
-
},
|
|
9995
|
-
{
|
|
9996
|
-
"path": "precision",
|
|
9997
|
-
"valueType": "number"
|
|
9998
|
-
}
|
|
9999
|
-
],
|
|
10049
|
+
"pressure-sensor": [{
|
|
10050
|
+
"path": "hpa",
|
|
10051
|
+
"valueType": "number"
|
|
10052
|
+
}],
|
|
10000
10053
|
"privacy-mask": [{
|
|
10001
10054
|
"path": "enabled",
|
|
10002
10055
|
"valueType": "boolean"
|
|
@@ -10307,20 +10360,10 @@ Object.freeze({
|
|
|
10307
10360
|
"path": "tampered",
|
|
10308
10361
|
"valueType": "boolean"
|
|
10309
10362
|
}],
|
|
10310
|
-
"temperature-sensor": [
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
},
|
|
10315
|
-
{
|
|
10316
|
-
"path": "unit",
|
|
10317
|
-
"valueType": "string"
|
|
10318
|
-
},
|
|
10319
|
-
{
|
|
10320
|
-
"path": "precision",
|
|
10321
|
-
"valueType": "number"
|
|
10322
|
-
}
|
|
10323
|
-
],
|
|
10363
|
+
"temperature-sensor": [{
|
|
10364
|
+
"path": "celsius",
|
|
10365
|
+
"valueType": "number"
|
|
10366
|
+
}],
|
|
10324
10367
|
"update": [
|
|
10325
10368
|
{
|
|
10326
10369
|
"path": "currentVersion",
|
|
@@ -10431,10 +10474,6 @@ Object.freeze({
|
|
|
10431
10474
|
"path": "temperature",
|
|
10432
10475
|
"valueType": "number"
|
|
10433
10476
|
},
|
|
10434
|
-
{
|
|
10435
|
-
"path": "temperatureUnit",
|
|
10436
|
-
"valueType": "string"
|
|
10437
|
-
},
|
|
10438
10477
|
{
|
|
10439
10478
|
"path": "humidity",
|
|
10440
10479
|
"valueType": "number"
|
|
@@ -10443,18 +10482,10 @@ Object.freeze({
|
|
|
10443
10482
|
"path": "pressure",
|
|
10444
10483
|
"valueType": "number"
|
|
10445
10484
|
},
|
|
10446
|
-
{
|
|
10447
|
-
"path": "pressureUnit",
|
|
10448
|
-
"valueType": "string"
|
|
10449
|
-
},
|
|
10450
10485
|
{
|
|
10451
10486
|
"path": "windSpeed",
|
|
10452
10487
|
"valueType": "number"
|
|
10453
10488
|
},
|
|
10454
|
-
{
|
|
10455
|
-
"path": "windSpeedUnit",
|
|
10456
|
-
"valueType": "string"
|
|
10457
|
-
},
|
|
10458
10489
|
{
|
|
10459
10490
|
"path": "windBearing",
|
|
10460
10491
|
"valueType": "number"
|
|
@@ -10504,7 +10535,7 @@ object({
|
|
|
10504
10535
|
params: record(string(), union([string(), number()])).optional()
|
|
10505
10536
|
});
|
|
10506
10537
|
//#endregion
|
|
10507
|
-
//#region ../types/dist/err-msg-
|
|
10538
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10508
10539
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10509
10540
|
DeviceType["Camera"] = "camera";
|
|
10510
10541
|
DeviceType["Hub"] = "hub";
|
|
@@ -10598,8 +10629,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10598
10629
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10599
10630
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10600
10631
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10601
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10632
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10633
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10602
10634
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10635
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10636
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10637
|
+
DeviceType["Washer"] = "washer";
|
|
10638
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10639
|
+
DeviceType["Dryer"] = "dryer";
|
|
10603
10640
|
return DeviceType;
|
|
10604
10641
|
}({});
|
|
10605
10642
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10857,7 +10894,7 @@ function errMsg(err) {
|
|
|
10857
10894
|
return String(err);
|
|
10858
10895
|
}
|
|
10859
10896
|
//#endregion
|
|
10860
|
-
//#region ../types/dist/composition-
|
|
10897
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10861
10898
|
/**
|
|
10862
10899
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10863
10900
|
*
|
|
@@ -11172,6 +11209,13 @@ var table = {
|
|
|
11172
11209
|
apply: () => {
|
|
11173
11210
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11174
11211
|
}
|
|
11212
|
+
},
|
|
11213
|
+
schmitt: {
|
|
11214
|
+
minArgs: 3,
|
|
11215
|
+
maxArgs: 5,
|
|
11216
|
+
apply: () => {
|
|
11217
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11218
|
+
}
|
|
11175
11219
|
}
|
|
11176
11220
|
};
|
|
11177
11221
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11612,15 +11656,232 @@ function validateExpressionSource(src) {
|
|
|
11612
11656
|
}
|
|
11613
11657
|
return null;
|
|
11614
11658
|
}
|
|
11615
|
-
/**
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11659
|
+
/**
|
|
11660
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11661
|
+
*
|
|
11662
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11663
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11664
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11665
|
+
*
|
|
11666
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11667
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11668
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11669
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11670
|
+
* can move later without moving the others.
|
|
11671
|
+
*/
|
|
11672
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11673
|
+
var APPLIANCE_KINDS = [
|
|
11674
|
+
"washer",
|
|
11675
|
+
"dryer",
|
|
11676
|
+
"dishwasher"
|
|
11677
|
+
];
|
|
11678
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11679
|
+
/**
|
|
11680
|
+
* Statistics and integrals over a history read (D944).
|
|
11681
|
+
*
|
|
11682
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11683
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11684
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11685
|
+
* as zero. A truncated read is not published.
|
|
11686
|
+
*/
|
|
11687
|
+
var STATISTIC_STATS = [
|
|
11688
|
+
"min",
|
|
11689
|
+
"max",
|
|
11690
|
+
"mean",
|
|
11691
|
+
"sum",
|
|
11692
|
+
"count",
|
|
11693
|
+
"change"
|
|
11694
|
+
];
|
|
11695
|
+
/**
|
|
11696
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11697
|
+
*
|
|
11698
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11699
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11700
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11701
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11702
|
+
*/
|
|
11703
|
+
var MINUTE_MS = 6e4;
|
|
11704
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11705
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11706
|
+
var ROLLING_SPANS = [
|
|
11707
|
+
"1h",
|
|
11708
|
+
"24h",
|
|
11709
|
+
"2d",
|
|
11710
|
+
"7d",
|
|
11711
|
+
"30d",
|
|
11712
|
+
"custom"
|
|
11713
|
+
];
|
|
11714
|
+
var CALENDAR_PERIODS = [
|
|
11715
|
+
"today",
|
|
11716
|
+
"yesterday",
|
|
11717
|
+
"this-week",
|
|
11718
|
+
"this-month"
|
|
11719
|
+
];
|
|
11720
|
+
var RESET_PERIODS = [
|
|
11721
|
+
"never",
|
|
11722
|
+
"daily",
|
|
11723
|
+
"weekly",
|
|
11724
|
+
"monthly"
|
|
11725
|
+
];
|
|
11726
|
+
5 * MINUTE_MS;
|
|
11727
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11728
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11729
|
+
var rollingWindowObject = object({
|
|
11730
|
+
kind: literal("rolling"),
|
|
11731
|
+
span: _enum(ROLLING_SPANS),
|
|
11732
|
+
customMinutes: number().int().min(5).optional()
|
|
11733
|
+
}).check((payload) => {
|
|
11734
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11735
|
+
code: "custom",
|
|
11736
|
+
message: "a custom range needs a duration in minutes",
|
|
11737
|
+
path: ["customMinutes"],
|
|
11738
|
+
input: payload.value
|
|
11739
|
+
});
|
|
11740
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11741
|
+
code: "custom",
|
|
11742
|
+
message: "only a custom range carries a duration",
|
|
11743
|
+
path: ["customMinutes"],
|
|
11744
|
+
input: payload.value
|
|
11745
|
+
});
|
|
11746
|
+
});
|
|
11747
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11748
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11749
|
+
kind: literal("calendar"),
|
|
11750
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11751
|
+
})]);
|
|
11752
|
+
/**
|
|
11753
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11754
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11755
|
+
* `composition.ts` (D659).
|
|
11756
|
+
*/
|
|
11619
11757
|
var CompositionSourceRefSchema = object({
|
|
11620
11758
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11621
11759
|
addonId: string().min(1),
|
|
11622
11760
|
stableId: string().min(1)
|
|
11623
11761
|
});
|
|
11762
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11763
|
+
"temperature",
|
|
11764
|
+
"humidity",
|
|
11765
|
+
"pressure",
|
|
11766
|
+
"illuminance",
|
|
11767
|
+
"power",
|
|
11768
|
+
"energy",
|
|
11769
|
+
"battery",
|
|
11770
|
+
"numeric",
|
|
11771
|
+
"motion",
|
|
11772
|
+
"contact",
|
|
11773
|
+
"leak",
|
|
11774
|
+
"smoke",
|
|
11775
|
+
"occupancy",
|
|
11776
|
+
"binary",
|
|
11777
|
+
"switch",
|
|
11778
|
+
"light",
|
|
11779
|
+
"fan",
|
|
11780
|
+
"cover",
|
|
11781
|
+
"valve",
|
|
11782
|
+
"lock",
|
|
11783
|
+
"media-player",
|
|
11784
|
+
"climate"
|
|
11785
|
+
];
|
|
11786
|
+
var NUMERIC_AGGREGATES = [
|
|
11787
|
+
"mean",
|
|
11788
|
+
"median",
|
|
11789
|
+
"min",
|
|
11790
|
+
"max",
|
|
11791
|
+
"sum"
|
|
11792
|
+
];
|
|
11793
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11794
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11795
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11796
|
+
var AGGREGATE_REDUCERS = [
|
|
11797
|
+
"mean",
|
|
11798
|
+
"median",
|
|
11799
|
+
"min",
|
|
11800
|
+
"max",
|
|
11801
|
+
"sum",
|
|
11802
|
+
"any",
|
|
11803
|
+
"all"
|
|
11804
|
+
];
|
|
11805
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11806
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11807
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11808
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11809
|
+
var HelperMemberSchema = object({
|
|
11810
|
+
source: CompositionSourceRefSchema,
|
|
11811
|
+
cap: string().min(1),
|
|
11812
|
+
fieldPath: string().min(1)
|
|
11813
|
+
});
|
|
11814
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11815
|
+
object({
|
|
11816
|
+
kind: literal("group"),
|
|
11817
|
+
templateId: GroupTemplateIdSchema,
|
|
11818
|
+
aggregate: AggregateReducerSchema,
|
|
11819
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11820
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11821
|
+
active: ActiveCriterionSchema.optional()
|
|
11822
|
+
}),
|
|
11823
|
+
object({
|
|
11824
|
+
kind: literal("appliance"),
|
|
11825
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11826
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11827
|
+
thresholdWatts: number().positive(),
|
|
11828
|
+
startDwellMs: number().int().nonnegative(),
|
|
11829
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11830
|
+
member: HelperMemberSchema
|
|
11831
|
+
}),
|
|
11832
|
+
object({
|
|
11833
|
+
kind: literal("statistic"),
|
|
11834
|
+
stat: _enum(STATISTIC_STATS),
|
|
11835
|
+
window: StatisticWindowSchema,
|
|
11836
|
+
source: HelperMemberSchema
|
|
11837
|
+
}),
|
|
11838
|
+
object({
|
|
11839
|
+
kind: literal("integral"),
|
|
11840
|
+
reset: _enum(RESET_PERIODS),
|
|
11841
|
+
output: _enum(["energy", "meter"]),
|
|
11842
|
+
source: HelperMemberSchema
|
|
11843
|
+
}),
|
|
11844
|
+
object({
|
|
11845
|
+
kind: literal("threshold"),
|
|
11846
|
+
source: HelperMemberSchema,
|
|
11847
|
+
high: number(),
|
|
11848
|
+
low: number(),
|
|
11849
|
+
onForMs: number().int().nonnegative(),
|
|
11850
|
+
offForMs: number().int().nonnegative()
|
|
11851
|
+
}),
|
|
11852
|
+
object({
|
|
11853
|
+
kind: literal("arithmetic"),
|
|
11854
|
+
op: _enum([
|
|
11855
|
+
"sum",
|
|
11856
|
+
"difference",
|
|
11857
|
+
"ratio"
|
|
11858
|
+
]),
|
|
11859
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11860
|
+
}),
|
|
11861
|
+
object({
|
|
11862
|
+
kind: literal("expression"),
|
|
11863
|
+
expr: string().min(1),
|
|
11864
|
+
inputs: array(object({
|
|
11865
|
+
name: string().min(1),
|
|
11866
|
+
member: HelperMemberSchema
|
|
11867
|
+
})).min(1).max(64),
|
|
11868
|
+
output: _enum(["number", "boolean"])
|
|
11869
|
+
}),
|
|
11870
|
+
object({
|
|
11871
|
+
kind: literal("derivative"),
|
|
11872
|
+
window: RollingWindowSchema,
|
|
11873
|
+
per: _enum([
|
|
11874
|
+
"second",
|
|
11875
|
+
"minute",
|
|
11876
|
+
"hour"
|
|
11877
|
+
]),
|
|
11878
|
+
source: HelperMemberSchema
|
|
11879
|
+
})
|
|
11880
|
+
]);
|
|
11881
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11882
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11883
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11884
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11624
11885
|
/** One field of one capability of one source device. */
|
|
11625
11886
|
var CompositionFieldReadSchema = object({
|
|
11626
11887
|
source: CompositionSourceRefSchema,
|
|
@@ -11664,7 +11925,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11664
11925
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11665
11926
|
CompositionFromSourceSchema,
|
|
11666
11927
|
CompositionExpressionSourceSchema,
|
|
11667
|
-
CompositionCodeSourceSchema
|
|
11928
|
+
CompositionCodeSourceSchema,
|
|
11929
|
+
object({
|
|
11930
|
+
kind: literal("aggregate"),
|
|
11931
|
+
reducer: _enum([
|
|
11932
|
+
"mean",
|
|
11933
|
+
"median",
|
|
11934
|
+
"min",
|
|
11935
|
+
"max",
|
|
11936
|
+
"sum",
|
|
11937
|
+
"any",
|
|
11938
|
+
"all"
|
|
11939
|
+
]),
|
|
11940
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11941
|
+
/**
|
|
11942
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11943
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11944
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11945
|
+
*/
|
|
11946
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11947
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11948
|
+
publish: _enum([
|
|
11949
|
+
"value",
|
|
11950
|
+
"included",
|
|
11951
|
+
"excluded",
|
|
11952
|
+
"total"
|
|
11953
|
+
]),
|
|
11954
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11955
|
+
empty: _enum([
|
|
11956
|
+
"null",
|
|
11957
|
+
"omit",
|
|
11958
|
+
"offline"
|
|
11959
|
+
])
|
|
11960
|
+
}),
|
|
11961
|
+
object({
|
|
11962
|
+
kind: literal("series"),
|
|
11963
|
+
read: CompositionFieldReadSchema,
|
|
11964
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11965
|
+
publish: _enum([
|
|
11966
|
+
"value",
|
|
11967
|
+
"included",
|
|
11968
|
+
"excluded",
|
|
11969
|
+
"total"
|
|
11970
|
+
]),
|
|
11971
|
+
/**
|
|
11972
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11973
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11974
|
+
*/
|
|
11975
|
+
empty: _enum([
|
|
11976
|
+
"null",
|
|
11977
|
+
"omit",
|
|
11978
|
+
"offline"
|
|
11979
|
+
])
|
|
11980
|
+
})
|
|
11668
11981
|
]);
|
|
11669
11982
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11670
11983
|
kind: literal("forward"),
|
|
@@ -11710,7 +12023,13 @@ var CompositionSchema = object({
|
|
|
11710
12023
|
kind: literal("existing"),
|
|
11711
12024
|
device: CompositionSourceRefSchema
|
|
11712
12025
|
})]),
|
|
11713
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12026
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12027
|
+
/**
|
|
12028
|
+
* Present when the block is a helper template. Absent on a free
|
|
12029
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12030
|
+
* never the compiled features.
|
|
12031
|
+
*/
|
|
12032
|
+
helper: HelperSpecSchema.optional()
|
|
11714
12033
|
}).superRefine((composition, ctx) => {
|
|
11715
12034
|
const seen = /* @__PURE__ */ new Set();
|
|
11716
12035
|
composition.features.forEach((feature, index) => {
|
|
@@ -16849,7 +17168,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16849
17168
|
*/
|
|
16850
17169
|
interactiveConnectPath: string().min(1).optional(),
|
|
16851
17170
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16852
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17171
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17172
|
+
/**
|
|
17173
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17174
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17175
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17176
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17177
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17178
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17179
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17180
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17181
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17182
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17183
|
+
* offers it as the default path; the fields the session fills are
|
|
17184
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17185
|
+
*/
|
|
17186
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16853
17187
|
}))
|
|
16854
17188
|
});
|
|
16855
17189
|
var ListInputSchema = object({
|
|
@@ -17950,7 +18284,12 @@ var CompositionProblemSchema = object({
|
|
|
17950
18284
|
"item-field-reserved",
|
|
17951
18285
|
"target-missing",
|
|
17952
18286
|
"target-unreadable",
|
|
17953
|
-
"not-replaceable"
|
|
18287
|
+
"not-replaceable",
|
|
18288
|
+
"native-capability-replace",
|
|
18289
|
+
"mixed-quantity",
|
|
18290
|
+
"helper-mismatch",
|
|
18291
|
+
"member-constraint",
|
|
18292
|
+
"retention"
|
|
17954
18293
|
]),
|
|
17955
18294
|
path: string(),
|
|
17956
18295
|
message: string()
|
|
@@ -17971,7 +18310,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17971
18310
|
"null",
|
|
17972
18311
|
"offline",
|
|
17973
18312
|
"unknown",
|
|
17974
|
-
"release"
|
|
18313
|
+
"release",
|
|
18314
|
+
"omit"
|
|
17975
18315
|
]);
|
|
17976
18316
|
/**
|
|
17977
18317
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18008,9 +18348,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18008
18348
|
reads: array(CompositionFieldReadSchema)
|
|
18009
18349
|
});
|
|
18010
18350
|
/**
|
|
18011
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18012
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18013
|
-
*
|
|
18351
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18352
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18353
|
+
* Replacing a capability the device already serves is refused
|
|
18354
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18355
|
+
* wire for a claim the hub already holds.
|
|
18014
18356
|
*/
|
|
18015
18357
|
var CompositionFeatureModeSchema = _enum([
|
|
18016
18358
|
"new",
|
|
@@ -18181,8 +18523,392 @@ Object.freeze({
|
|
|
18181
18523
|
latchedAt: {
|
|
18182
18524
|
kind: "fixed",
|
|
18183
18525
|
result: ["number", "null"]
|
|
18526
|
+
},
|
|
18527
|
+
schmitt: {
|
|
18528
|
+
kind: "fixed",
|
|
18529
|
+
result: ["boolean", "null"]
|
|
18184
18530
|
}
|
|
18185
18531
|
});
|
|
18532
|
+
/**
|
|
18533
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18534
|
+
* Data, not a form default written into the block.
|
|
18535
|
+
*/
|
|
18536
|
+
var NOW$2 = {
|
|
18537
|
+
fieldPath: "lastFetchedAt",
|
|
18538
|
+
expr: "now"
|
|
18539
|
+
};
|
|
18540
|
+
var CHANGED = {
|
|
18541
|
+
fieldPath: "lastChangedAt",
|
|
18542
|
+
expr: "now"
|
|
18543
|
+
};
|
|
18544
|
+
function numeric(input) {
|
|
18545
|
+
return {
|
|
18546
|
+
...input,
|
|
18547
|
+
family: "numeric",
|
|
18548
|
+
deviceType: DeviceType.Sensor,
|
|
18549
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18550
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18551
|
+
activeWhen: void 0,
|
|
18552
|
+
commandCaps: [],
|
|
18553
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18554
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18555
|
+
accept: [{
|
|
18556
|
+
cap: input.outputCap,
|
|
18557
|
+
fieldPath: input.outputField
|
|
18558
|
+
}]
|
|
18559
|
+
};
|
|
18560
|
+
}
|
|
18561
|
+
function binary(input) {
|
|
18562
|
+
return {
|
|
18563
|
+
...input,
|
|
18564
|
+
family: "binary",
|
|
18565
|
+
deviceType: DeviceType.Sensor,
|
|
18566
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18567
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18568
|
+
activeWhen: void 0,
|
|
18569
|
+
commandCaps: [],
|
|
18570
|
+
quantity: "none",
|
|
18571
|
+
baseUnit: void 0,
|
|
18572
|
+
aggregates: BINARY_AGGREGATES,
|
|
18573
|
+
empty: "offline"
|
|
18574
|
+
};
|
|
18575
|
+
}
|
|
18576
|
+
var GROUP_TEMPLATES = [
|
|
18577
|
+
numeric({
|
|
18578
|
+
id: "temperature",
|
|
18579
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18580
|
+
role: DeviceRole.TemperatureSensor,
|
|
18581
|
+
outputCap: "temperature-sensor",
|
|
18582
|
+
outputField: "celsius",
|
|
18583
|
+
quantity: "temperature",
|
|
18584
|
+
defaultAggregate: "mean",
|
|
18585
|
+
empty: "null",
|
|
18586
|
+
companions: [NOW$2]
|
|
18587
|
+
}),
|
|
18588
|
+
numeric({
|
|
18589
|
+
id: "humidity",
|
|
18590
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18591
|
+
role: DeviceRole.HumiditySensor,
|
|
18592
|
+
outputCap: "humidity-sensor",
|
|
18593
|
+
outputField: "percent",
|
|
18594
|
+
quantity: "humidity",
|
|
18595
|
+
defaultAggregate: "mean",
|
|
18596
|
+
empty: "null",
|
|
18597
|
+
companions: [NOW$2]
|
|
18598
|
+
}),
|
|
18599
|
+
numeric({
|
|
18600
|
+
id: "pressure",
|
|
18601
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18602
|
+
role: DeviceRole.PressureSensor,
|
|
18603
|
+
outputCap: "pressure-sensor",
|
|
18604
|
+
outputField: "hpa",
|
|
18605
|
+
quantity: "pressure",
|
|
18606
|
+
defaultAggregate: "mean",
|
|
18607
|
+
empty: "null",
|
|
18608
|
+
companions: [NOW$2]
|
|
18609
|
+
}),
|
|
18610
|
+
numeric({
|
|
18611
|
+
id: "illuminance",
|
|
18612
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18613
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18614
|
+
outputCap: "ambient-light-sensor",
|
|
18615
|
+
outputField: "lux",
|
|
18616
|
+
quantity: "illuminance",
|
|
18617
|
+
defaultAggregate: "mean",
|
|
18618
|
+
empty: "null",
|
|
18619
|
+
companions: [NOW$2]
|
|
18620
|
+
}),
|
|
18621
|
+
numeric({
|
|
18622
|
+
id: "power",
|
|
18623
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18624
|
+
role: DeviceRole.PowerSensor,
|
|
18625
|
+
outputCap: "power-meter",
|
|
18626
|
+
outputField: "watts",
|
|
18627
|
+
quantity: "power",
|
|
18628
|
+
defaultAggregate: "sum",
|
|
18629
|
+
empty: "omit",
|
|
18630
|
+
companions: [NOW$2]
|
|
18631
|
+
}),
|
|
18632
|
+
numeric({
|
|
18633
|
+
id: "energy",
|
|
18634
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18635
|
+
role: DeviceRole.EnergySensor,
|
|
18636
|
+
outputCap: "power-meter",
|
|
18637
|
+
outputField: "kwhTotal",
|
|
18638
|
+
quantity: "energy",
|
|
18639
|
+
defaultAggregate: "sum",
|
|
18640
|
+
empty: "omit",
|
|
18641
|
+
companions: [NOW$2]
|
|
18642
|
+
}),
|
|
18643
|
+
numeric({
|
|
18644
|
+
id: "battery",
|
|
18645
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18646
|
+
role: DeviceRole.BatterySensor,
|
|
18647
|
+
outputCap: "battery",
|
|
18648
|
+
outputField: "percentage",
|
|
18649
|
+
quantity: "percentage",
|
|
18650
|
+
defaultAggregate: "mean",
|
|
18651
|
+
empty: "null",
|
|
18652
|
+
companions: [
|
|
18653
|
+
{
|
|
18654
|
+
fieldPath: "charging",
|
|
18655
|
+
expr: "\"unknown\""
|
|
18656
|
+
},
|
|
18657
|
+
{
|
|
18658
|
+
fieldPath: "sleeping",
|
|
18659
|
+
expr: "false"
|
|
18660
|
+
},
|
|
18661
|
+
{
|
|
18662
|
+
fieldPath: "lastUpdated",
|
|
18663
|
+
expr: "now"
|
|
18664
|
+
}
|
|
18665
|
+
]
|
|
18666
|
+
}),
|
|
18667
|
+
numeric({
|
|
18668
|
+
id: "numeric",
|
|
18669
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18670
|
+
role: DeviceRole.NumericSensor,
|
|
18671
|
+
outputCap: "numeric-sensor",
|
|
18672
|
+
outputField: "value",
|
|
18673
|
+
quantity: "device",
|
|
18674
|
+
defaultAggregate: "mean",
|
|
18675
|
+
empty: "null",
|
|
18676
|
+
companions: [NOW$2]
|
|
18677
|
+
}),
|
|
18678
|
+
binary({
|
|
18679
|
+
id: "motion",
|
|
18680
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18681
|
+
role: DeviceRole.MotionSensor,
|
|
18682
|
+
outputCap: "motion",
|
|
18683
|
+
outputField: "detected",
|
|
18684
|
+
defaultAggregate: "any",
|
|
18685
|
+
accept: [{
|
|
18686
|
+
cap: "motion",
|
|
18687
|
+
fieldPath: "detected"
|
|
18688
|
+
}],
|
|
18689
|
+
companions: [{
|
|
18690
|
+
fieldPath: "lastDetectedAt",
|
|
18691
|
+
expr: "null"
|
|
18692
|
+
}, {
|
|
18693
|
+
fieldPath: "autoClearAfterMs",
|
|
18694
|
+
expr: "null"
|
|
18695
|
+
}]
|
|
18696
|
+
}),
|
|
18697
|
+
binary({
|
|
18698
|
+
id: "contact",
|
|
18699
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18700
|
+
role: DeviceRole.ContactSensor,
|
|
18701
|
+
outputCap: "contact",
|
|
18702
|
+
outputField: "entryOpen",
|
|
18703
|
+
defaultAggregate: "any",
|
|
18704
|
+
accept: [{
|
|
18705
|
+
cap: "contact",
|
|
18706
|
+
fieldPath: "entryOpen"
|
|
18707
|
+
}],
|
|
18708
|
+
companions: [CHANGED]
|
|
18709
|
+
}),
|
|
18710
|
+
binary({
|
|
18711
|
+
id: "leak",
|
|
18712
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18713
|
+
role: DeviceRole.LeakSensor,
|
|
18714
|
+
outputCap: "flood",
|
|
18715
|
+
outputField: "flooded",
|
|
18716
|
+
defaultAggregate: "any",
|
|
18717
|
+
accept: [{
|
|
18718
|
+
cap: "flood",
|
|
18719
|
+
fieldPath: "flooded"
|
|
18720
|
+
}],
|
|
18721
|
+
companions: [CHANGED]
|
|
18722
|
+
}),
|
|
18723
|
+
binary({
|
|
18724
|
+
id: "smoke",
|
|
18725
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18726
|
+
role: DeviceRole.SmokeSensor,
|
|
18727
|
+
outputCap: "smoke",
|
|
18728
|
+
outputField: "detected",
|
|
18729
|
+
defaultAggregate: "any",
|
|
18730
|
+
accept: [{
|
|
18731
|
+
cap: "smoke",
|
|
18732
|
+
fieldPath: "detected"
|
|
18733
|
+
}],
|
|
18734
|
+
companions: [CHANGED]
|
|
18735
|
+
}),
|
|
18736
|
+
binary({
|
|
18737
|
+
id: "occupancy",
|
|
18738
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18739
|
+
role: DeviceRole.BinarySensor,
|
|
18740
|
+
outputCap: "binary",
|
|
18741
|
+
outputField: "on",
|
|
18742
|
+
defaultAggregate: "any",
|
|
18743
|
+
accept: [{
|
|
18744
|
+
cap: "motion",
|
|
18745
|
+
fieldPath: "detected"
|
|
18746
|
+
}, {
|
|
18747
|
+
cap: "binary",
|
|
18748
|
+
fieldPath: "on"
|
|
18749
|
+
}],
|
|
18750
|
+
companions: [CHANGED]
|
|
18751
|
+
}),
|
|
18752
|
+
binary({
|
|
18753
|
+
id: "binary",
|
|
18754
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18755
|
+
role: DeviceRole.BinarySensor,
|
|
18756
|
+
outputCap: "binary",
|
|
18757
|
+
outputField: "on",
|
|
18758
|
+
defaultAggregate: "any",
|
|
18759
|
+
accept: [{
|
|
18760
|
+
cap: "binary",
|
|
18761
|
+
fieldPath: "on"
|
|
18762
|
+
}],
|
|
18763
|
+
companions: [CHANGED]
|
|
18764
|
+
}),
|
|
18765
|
+
actuator({
|
|
18766
|
+
id: "switch",
|
|
18767
|
+
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.",
|
|
18768
|
+
deviceType: DeviceType.Switch,
|
|
18769
|
+
outputCap: "switch",
|
|
18770
|
+
outputField: "on",
|
|
18771
|
+
member: {
|
|
18772
|
+
cap: "switch",
|
|
18773
|
+
fieldPath: "on"
|
|
18774
|
+
},
|
|
18775
|
+
commandCaps: ["switch"]
|
|
18776
|
+
}),
|
|
18777
|
+
actuator({
|
|
18778
|
+
id: "light",
|
|
18779
|
+
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.",
|
|
18780
|
+
deviceType: DeviceType.Light,
|
|
18781
|
+
outputCap: "switch",
|
|
18782
|
+
outputField: "on",
|
|
18783
|
+
member: {
|
|
18784
|
+
cap: "switch",
|
|
18785
|
+
fieldPath: "on"
|
|
18786
|
+
},
|
|
18787
|
+
commandCaps: [
|
|
18788
|
+
"switch",
|
|
18789
|
+
"brightness",
|
|
18790
|
+
"color"
|
|
18791
|
+
]
|
|
18792
|
+
}),
|
|
18793
|
+
actuator({
|
|
18794
|
+
id: "fan",
|
|
18795
|
+
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.",
|
|
18796
|
+
deviceType: DeviceType.Fan,
|
|
18797
|
+
outputCap: "switch",
|
|
18798
|
+
outputField: "on",
|
|
18799
|
+
member: {
|
|
18800
|
+
cap: "switch",
|
|
18801
|
+
fieldPath: "on"
|
|
18802
|
+
},
|
|
18803
|
+
commandCaps: ["switch", "fan-control"]
|
|
18804
|
+
}),
|
|
18805
|
+
actuator({
|
|
18806
|
+
id: "cover",
|
|
18807
|
+
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.",
|
|
18808
|
+
deviceType: DeviceType.Cover,
|
|
18809
|
+
outputCap: "group-active",
|
|
18810
|
+
outputField: "active",
|
|
18811
|
+
member: {
|
|
18812
|
+
cap: "cover",
|
|
18813
|
+
fieldPath: "state"
|
|
18814
|
+
},
|
|
18815
|
+
activeWhen: [
|
|
18816
|
+
"open",
|
|
18817
|
+
"opening",
|
|
18818
|
+
"stopped"
|
|
18819
|
+
],
|
|
18820
|
+
commandCaps: ["cover"]
|
|
18821
|
+
}),
|
|
18822
|
+
actuator({
|
|
18823
|
+
id: "valve",
|
|
18824
|
+
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.",
|
|
18825
|
+
deviceType: DeviceType.Valve,
|
|
18826
|
+
outputCap: "group-active",
|
|
18827
|
+
outputField: "active",
|
|
18828
|
+
member: {
|
|
18829
|
+
cap: "valve",
|
|
18830
|
+
fieldPath: "state"
|
|
18831
|
+
},
|
|
18832
|
+
activeWhen: [
|
|
18833
|
+
"open",
|
|
18834
|
+
"opening",
|
|
18835
|
+
"stopped"
|
|
18836
|
+
],
|
|
18837
|
+
commandCaps: ["valve"]
|
|
18838
|
+
}),
|
|
18839
|
+
actuator({
|
|
18840
|
+
id: "lock",
|
|
18841
|
+
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.",
|
|
18842
|
+
deviceType: DeviceType.Lock,
|
|
18843
|
+
outputCap: "group-active",
|
|
18844
|
+
outputField: "active",
|
|
18845
|
+
member: {
|
|
18846
|
+
cap: "lock-control",
|
|
18847
|
+
fieldPath: "state"
|
|
18848
|
+
},
|
|
18849
|
+
activeWhen: ["locked"],
|
|
18850
|
+
commandCaps: ["lock-control"]
|
|
18851
|
+
}),
|
|
18852
|
+
actuator({
|
|
18853
|
+
id: "media-player",
|
|
18854
|
+
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.",
|
|
18855
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18856
|
+
outputCap: "group-active",
|
|
18857
|
+
outputField: "active",
|
|
18858
|
+
member: {
|
|
18859
|
+
cap: "media-player",
|
|
18860
|
+
fieldPath: "state"
|
|
18861
|
+
},
|
|
18862
|
+
activeWhen: ["playing", "buffering"],
|
|
18863
|
+
commandCaps: ["media-player"]
|
|
18864
|
+
}),
|
|
18865
|
+
actuator({
|
|
18866
|
+
id: "climate",
|
|
18867
|
+
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.",
|
|
18868
|
+
deviceType: DeviceType.Thermostat,
|
|
18869
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18870
|
+
outputCap: "group-active",
|
|
18871
|
+
outputField: "active",
|
|
18872
|
+
member: {
|
|
18873
|
+
cap: "climate-control",
|
|
18874
|
+
fieldPath: "mode"
|
|
18875
|
+
},
|
|
18876
|
+
activeWhen: [
|
|
18877
|
+
"heat",
|
|
18878
|
+
"cool",
|
|
18879
|
+
"auto",
|
|
18880
|
+
"heat_cool",
|
|
18881
|
+
"fan_only",
|
|
18882
|
+
"dry"
|
|
18883
|
+
],
|
|
18884
|
+
commandCaps: ["climate-control"]
|
|
18885
|
+
})
|
|
18886
|
+
];
|
|
18887
|
+
function actuator(input) {
|
|
18888
|
+
return {
|
|
18889
|
+
id: input.id,
|
|
18890
|
+
summary: input.summary,
|
|
18891
|
+
deviceType: input.deviceType,
|
|
18892
|
+
outputCap: input.outputCap,
|
|
18893
|
+
outputField: input.outputField,
|
|
18894
|
+
commandCaps: input.commandCaps,
|
|
18895
|
+
family: "actuator",
|
|
18896
|
+
role: void 0,
|
|
18897
|
+
memberDeviceType: input.deviceType,
|
|
18898
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18899
|
+
activeWhen: input.activeWhen,
|
|
18900
|
+
quantity: "none",
|
|
18901
|
+
baseUnit: void 0,
|
|
18902
|
+
aggregates: BINARY_AGGREGATES,
|
|
18903
|
+
defaultAggregate: "any",
|
|
18904
|
+
empty: "offline",
|
|
18905
|
+
accept: [input.member],
|
|
18906
|
+
companions: [CHANGED]
|
|
18907
|
+
};
|
|
18908
|
+
}
|
|
18909
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18910
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18911
|
+
DeviceType.Camera;
|
|
18186
18912
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18187
18913
|
/**
|
|
18188
18914
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19896,12 +20622,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
19896
20622
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19897
20623
|
* in-place so dispatch keeps working.
|
|
19898
20624
|
*
|
|
19899
|
-
* **
|
|
19900
|
-
*
|
|
19901
|
-
*
|
|
19902
|
-
*
|
|
19903
|
-
* (`ha-domain-mapping`)
|
|
19904
|
-
* stored after that point.
|
|
20625
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20626
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20627
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20628
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20629
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20630
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19905
20631
|
*
|
|
19906
20632
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19907
20633
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19915,6 +20641,14 @@ var SourceInfoSchema = object({
|
|
|
19915
20641
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19916
20642
|
* Used to detect rename when `id` changes. */
|
|
19917
20643
|
uniqueId: string().optional(),
|
|
20644
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20645
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20646
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20647
|
+
dateTimeShape: _enum([
|
|
20648
|
+
"date",
|
|
20649
|
+
"time",
|
|
20650
|
+
"datetime"
|
|
20651
|
+
]).optional(),
|
|
19918
20652
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19919
20653
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19920
20654
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -40938,7 +41672,8 @@ method(object({
|
|
|
40938
41672
|
"enum"
|
|
40939
41673
|
]),
|
|
40940
41674
|
enumValues: array(string()).optional(),
|
|
40941
|
-
item: boolean().optional()
|
|
41675
|
+
item: boolean().optional(),
|
|
41676
|
+
quantity: ReadingQuantitySchema.optional()
|
|
40942
41677
|
})).readonly(),
|
|
40943
41678
|
itemArray: object({
|
|
40944
41679
|
path: string(),
|
|
@@ -43299,7 +44034,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43299
44034
|
});
|
|
43300
44035
|
/**
|
|
43301
44036
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43302
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44037
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43303
44038
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43304
44039
|
* the originating provider config (mode + sourcePort) so the
|
|
43305
44040
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44782,8 +45517,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44782
45517
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44783
45518
|
var MaskGridShapeSchema = object({
|
|
44784
45519
|
kind: literal("grid"),
|
|
44785
|
-
gridWidth: number(),
|
|
44786
|
-
gridHeight: number(),
|
|
45520
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45521
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44787
45522
|
cells: array(boolean())
|
|
44788
45523
|
});
|
|
44789
45524
|
discriminatedUnion("kind", [
|
|
@@ -44895,6 +45630,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44895
45630
|
"detection-blind",
|
|
44896
45631
|
"motion-noisy",
|
|
44897
45632
|
"motion-calm",
|
|
45633
|
+
"package-llm-silent",
|
|
45634
|
+
"package-llm-answered",
|
|
44898
45635
|
"recording-stalled",
|
|
44899
45636
|
"recording-healthy",
|
|
44900
45637
|
"recording-degraded",
|
|
@@ -45984,7 +46721,20 @@ var NcRuleInputSchema = object({
|
|
|
45984
46721
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
45985
46722
|
* path does not run Zod defaults.
|
|
45986
46723
|
*/
|
|
45987
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46724
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46725
|
+
/**
|
|
46726
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46727
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46728
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46729
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46730
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46731
|
+
*
|
|
46732
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46733
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46734
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46735
|
+
* `false`, so it needs no `clear` key.
|
|
46736
|
+
*/
|
|
46737
|
+
askVerdict: boolean().optional()
|
|
45988
46738
|
});
|
|
45989
46739
|
/**
|
|
45990
46740
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56134,6 +56884,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56134
56884
|
deprecated: string().optional(),
|
|
56135
56885
|
distTags: array(string()).readonly()
|
|
56136
56886
|
});
|
|
56887
|
+
/**
|
|
56888
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56889
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56890
|
+
* tarball failure — never an empty string standing in for either.
|
|
56891
|
+
*/
|
|
56892
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56893
|
+
object({
|
|
56894
|
+
status: literal("ok"),
|
|
56895
|
+
markdown: string()
|
|
56896
|
+
}),
|
|
56897
|
+
object({ status: literal("missing") }),
|
|
56898
|
+
object({
|
|
56899
|
+
status: literal("error"),
|
|
56900
|
+
message: string()
|
|
56901
|
+
})
|
|
56902
|
+
]);
|
|
56903
|
+
var PackageDocsSchema = object({
|
|
56904
|
+
name: string(),
|
|
56905
|
+
version: string(),
|
|
56906
|
+
readme: PackageDocBodySchema,
|
|
56907
|
+
changelog: PackageDocBodySchema
|
|
56908
|
+
});
|
|
56137
56909
|
var SearchResultSchema = object({
|
|
56138
56910
|
name: string(),
|
|
56139
56911
|
version: string(),
|
|
@@ -56352,7 +57124,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56352
57124
|
}), object({ success: literal(true) }), {
|
|
56353
57125
|
kind: "mutation",
|
|
56354
57126
|
auth: "admin"
|
|
56355
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57127
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57128
|
+
name: string().min(1),
|
|
57129
|
+
version: string().min(1).optional()
|
|
57130
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56356
57131
|
kind: "mutation",
|
|
56357
57132
|
auth: "admin"
|
|
56358
57133
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56411,27 +57186,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56411
57186
|
*/
|
|
56412
57187
|
var AirQualitySensorStatusSchema = object({
|
|
56413
57188
|
/** Carbon dioxide concentration in ppm. */
|
|
56414
|
-
co2Ppm: number().min(0).optional(),
|
|
57189
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56415
57190
|
/** Total volatile organic compounds in ppb. */
|
|
56416
|
-
vocPpb: number().min(0).optional(),
|
|
57191
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56417
57192
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56418
|
-
pm25: number().min(0).optional(),
|
|
57193
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56419
57194
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56420
|
-
pm10: number().min(0).optional(),
|
|
57195
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56421
57196
|
/** Composite AQI value (typically 0..500). */
|
|
56422
|
-
aqi: number().optional(),
|
|
57197
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56423
57198
|
/** Ms epoch when the slice was last updated. */
|
|
56424
|
-
lastFetchedAt: number()
|
|
56425
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56426
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56427
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56428
|
-
* per slice is unambiguous. */
|
|
56429
|
-
unit: string().optional(),
|
|
56430
|
-
/** Suggested decimal places for numeric display.
|
|
56431
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56432
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56433
|
-
* auto-formatting when absent. */
|
|
56434
|
-
precision: number().int().min(0).max(10).optional()
|
|
57199
|
+
lastFetchedAt: number()
|
|
56435
57200
|
});
|
|
56436
57201
|
var airQualitySensorCapability = {
|
|
56437
57202
|
name: "air-quality-sensor",
|
|
@@ -56468,12 +57233,12 @@ var airQualitySensorCapability = {
|
|
|
56468
57233
|
},
|
|
56469
57234
|
pm25: {
|
|
56470
57235
|
kind: "gauge",
|
|
56471
|
-
unit: "
|
|
57236
|
+
unit: "µg/m³",
|
|
56472
57237
|
deadband: 1
|
|
56473
57238
|
},
|
|
56474
57239
|
pm10: {
|
|
56475
57240
|
kind: "gauge",
|
|
56476
|
-
unit: "
|
|
57241
|
+
unit: "µg/m³",
|
|
56477
57242
|
deadband: 1
|
|
56478
57243
|
},
|
|
56479
57244
|
aqi: {
|
|
@@ -56491,22 +57256,13 @@ var airQualitySensorCapability = {
|
|
|
56491
57256
|
* entries with `device_class: illuminance`.
|
|
56492
57257
|
*/
|
|
56493
57258
|
var AmbientLightSensorStatusSchema = object({
|
|
56494
|
-
/** Current illuminance in lux (lx). */
|
|
56495
|
-
lux: number().min(0).meta({
|
|
56496
|
-
|
|
57259
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57260
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57261
|
+
precision: 0,
|
|
56497
57262
|
label: "Illuminance"
|
|
56498
|
-
}),
|
|
57263
|
+
})),
|
|
56499
57264
|
/** Ms epoch when the slice was last updated. */
|
|
56500
|
-
lastFetchedAt: number()
|
|
56501
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56502
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56503
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56504
|
-
unit: string().optional(),
|
|
56505
|
-
/** Suggested decimal places for numeric display.
|
|
56506
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56507
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56508
|
-
* auto-formatting when absent. */
|
|
56509
|
-
precision: number().int().min(0).max(10).optional()
|
|
57265
|
+
lastFetchedAt: number()
|
|
56510
57266
|
});
|
|
56511
57267
|
var ambientLightSensorCapability = {
|
|
56512
57268
|
name: "ambient-light-sensor",
|
|
@@ -56538,12 +57294,7 @@ var ambientLightSensorCapability = {
|
|
|
56538
57294
|
} } },
|
|
56539
57295
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56540
57296
|
* whether persisting is worth a SQLite commit. */
|
|
56541
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56542
|
-
customize: {
|
|
56543
|
-
version: 1,
|
|
56544
|
-
advanced: "derive",
|
|
56545
|
-
targets: []
|
|
56546
|
-
}
|
|
57297
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56547
57298
|
};
|
|
56548
57299
|
/**
|
|
56549
57300
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56770,10 +57521,7 @@ var BatteryStatusSchema = object({
|
|
|
56770
57521
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56771
57522
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56772
57523
|
*/
|
|
56773
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56774
|
-
unit: "%",
|
|
56775
|
-
label: "Charge"
|
|
56776
|
-
}),
|
|
57524
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56777
57525
|
/**
|
|
56778
57526
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56779
57527
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56800,7 +57548,14 @@ var BatteryStatusSchema = object({
|
|
|
56800
57548
|
*/
|
|
56801
57549
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56802
57550
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56803
|
-
lastUpdated: number(),
|
|
57551
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57552
|
+
/**
|
|
57553
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57554
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57555
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57556
|
+
* `numeric-sensor` on the same device.
|
|
57557
|
+
*/
|
|
57558
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56804
57559
|
/**
|
|
56805
57560
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56806
57561
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56847,12 +57602,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56847
57602
|
DeviceType.Switch,
|
|
56848
57603
|
DeviceType.PetFeeder,
|
|
56849
57604
|
DeviceType.Container,
|
|
56850
|
-
DeviceType.Thermostat
|
|
57605
|
+
DeviceType.Thermostat,
|
|
57606
|
+
DeviceType.EventEmitter
|
|
56851
57607
|
];
|
|
56852
57608
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56853
57609
|
var batteryCustomize = {
|
|
56854
57610
|
version: 1,
|
|
56855
|
-
advanced: "derive",
|
|
56856
57611
|
targets: [{
|
|
56857
57612
|
id: "percentage",
|
|
56858
57613
|
cardinality: "scalar",
|
|
@@ -56861,7 +57616,7 @@ var batteryCustomize = {
|
|
|
56861
57616
|
stateField: "percentage"
|
|
56862
57617
|
},
|
|
56863
57618
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56864
|
-
apply: "add
|
|
57619
|
+
apply: "add",
|
|
56865
57620
|
path: "percentage",
|
|
56866
57621
|
sources: [{
|
|
56867
57622
|
kind: "field",
|
|
@@ -56982,10 +57737,16 @@ onStatusChanged: { data: object({
|
|
|
56982
57737
|
/**
|
|
56983
57738
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
56984
57739
|
*/
|
|
56985
|
-
history: { fields: {
|
|
56986
|
-
|
|
56987
|
-
|
|
56988
|
-
|
|
57740
|
+
history: { fields: {
|
|
57741
|
+
percentage: {
|
|
57742
|
+
kind: "gauge",
|
|
57743
|
+
unit: "%"
|
|
57744
|
+
},
|
|
57745
|
+
volts: {
|
|
57746
|
+
kind: "gauge",
|
|
57747
|
+
unit: "V"
|
|
57748
|
+
}
|
|
57749
|
+
} },
|
|
56989
57750
|
customize: batteryCustomize,
|
|
56990
57751
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56991
57752
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57032,12 +57793,7 @@ var binaryCapability = {
|
|
|
57032
57793
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57033
57794
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57034
57795
|
* whether persisting is worth a SQLite commit. */
|
|
57035
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57036
|
-
customize: {
|
|
57037
|
-
version: 1,
|
|
57038
|
-
advanced: "derive",
|
|
57039
|
-
targets: []
|
|
57040
|
-
}
|
|
57796
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57041
57797
|
};
|
|
57042
57798
|
/**
|
|
57043
57799
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57053,7 +57809,7 @@ var binaryCapability = {
|
|
|
57053
57809
|
*/
|
|
57054
57810
|
var BrightnessStatusSchema = object({
|
|
57055
57811
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57056
|
-
percentage: number().min(0).max(100),
|
|
57812
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57057
57813
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57058
57814
|
lastChangedAt: number()
|
|
57059
57815
|
});
|
|
@@ -57507,21 +58263,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57507
58263
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57508
58264
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57509
58265
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57510
|
-
target: number().nullable(),
|
|
58266
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57511
58267
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57512
58268
|
* in `heat_cool` mode. */
|
|
57513
|
-
targetHigh: number().nullable(),
|
|
58269
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57514
58270
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57515
58271
|
* in `heat_cool` mode. */
|
|
57516
|
-
targetLow: number().nullable(),
|
|
58272
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57517
58273
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57518
58274
|
* humidity control. */
|
|
57519
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58275
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57520
58276
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57521
58277
|
* the device's internal sensor. */
|
|
57522
|
-
currentTemp: number().nullable(),
|
|
58278
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57523
58279
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57524
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58280
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57525
58281
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57526
58282
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57527
58283
|
swingVertical: boolean().nullable(),
|
|
@@ -57529,11 +58285,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57529
58285
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57530
58286
|
swingHorizontal: boolean().nullable(),
|
|
57531
58287
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57532
|
-
minTemp: number().nullable().optional(),
|
|
58288
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57533
58289
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57534
|
-
maxTemp: number().nullable().optional(),
|
|
58290
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57535
58291
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57536
|
-
tempStep: number().positive().nullable().optional(),
|
|
58292
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57537
58293
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57538
58294
|
lastFetchedAt: number()
|
|
57539
58295
|
});
|
|
@@ -57675,17 +58431,17 @@ var climateControlCapability = {
|
|
|
57675
58431
|
* modes to expose in the picker without a slice fetch.
|
|
57676
58432
|
*/
|
|
57677
58433
|
var RgbTripletSchema = object({
|
|
57678
|
-
r: number().int().min(0).max(255),
|
|
57679
|
-
g: number().int().min(0).max(255),
|
|
57680
|
-
b: number().int().min(0).max(255)
|
|
58434
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58435
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58436
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57681
58437
|
});
|
|
57682
58438
|
var HsvTripletSchema = object({
|
|
57683
58439
|
/** Hue in degrees, 0..360. */
|
|
57684
|
-
h: number().min(0).max(360),
|
|
58440
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57685
58441
|
/** Saturation as 0..100 inclusive. */
|
|
57686
|
-
s: number().min(0).max(100),
|
|
58442
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57687
58443
|
/** Value/brightness as 0..100 inclusive. */
|
|
57688
|
-
v: number().min(0).max(100)
|
|
58444
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57689
58445
|
});
|
|
57690
58446
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57691
58447
|
object({
|
|
@@ -57714,7 +58470,7 @@ var ColorStatusSchema = object({
|
|
|
57714
58470
|
/** Populated when `mode === 'hsv'`. */
|
|
57715
58471
|
hsv: HsvTripletSchema.optional(),
|
|
57716
58472
|
/** Populated when `mode === 'mired'`. */
|
|
57717
|
-
mireds: number().int().optional(),
|
|
58473
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57718
58474
|
/** Ms epoch of the last operator-driven change. */
|
|
57719
58475
|
lastChangedAt: number()
|
|
57720
58476
|
});
|
|
@@ -57909,18 +58665,12 @@ _enum([
|
|
|
57909
58665
|
"empty",
|
|
57910
58666
|
"full"
|
|
57911
58667
|
]);
|
|
57912
|
-
/**
|
|
57913
|
-
|
|
57914
|
-
|
|
57915
|
-
"days",
|
|
57916
|
-
"hours",
|
|
57917
|
-
"cycles"
|
|
57918
|
-
]);
|
|
57919
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57920
|
-
* days). `value` null = unknown (D393). */
|
|
58668
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58669
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58670
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57921
58671
|
var ConsumableRemainingSchema = object({
|
|
57922
|
-
value: number().min(0).nullable(),
|
|
57923
|
-
|
|
58672
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58673
|
+
kind: ConsumableRemainingKindSchema
|
|
57924
58674
|
});
|
|
57925
58675
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
57926
58676
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -57933,7 +58683,7 @@ var ConsumableItemSchema = object({
|
|
|
57933
58683
|
/** Display name. */
|
|
57934
58684
|
label: string().min(1),
|
|
57935
58685
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57936
|
-
level: number().min(0).max(100).nullable(),
|
|
58686
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57937
58687
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57938
58688
|
status: ConsumableStatusSchema.nullable(),
|
|
57939
58689
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58015,8 +58765,8 @@ var consumablesCustomize = {
|
|
|
58015
58765
|
transforms: [{ kind: "identity" }]
|
|
58016
58766
|
}],
|
|
58017
58767
|
literals: [{
|
|
58018
|
-
path: "remaining.
|
|
58019
|
-
values: [...
|
|
58768
|
+
path: "remaining.kind",
|
|
58769
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58020
58770
|
}]
|
|
58021
58771
|
},
|
|
58022
58772
|
{
|
|
@@ -58145,7 +58895,6 @@ reset: method(object({
|
|
|
58145
58895
|
},
|
|
58146
58896
|
"remaining.value": {
|
|
58147
58897
|
kind: "gauge",
|
|
58148
|
-
unitFrom: "remaining.unit",
|
|
58149
58898
|
deadband: 1,
|
|
58150
58899
|
displayName: "Remaining"
|
|
58151
58900
|
}
|
|
@@ -58215,10 +58964,9 @@ var contactCapability = {
|
|
|
58215
58964
|
* (empty array for the other kinds). It lives in the slice because
|
|
58216
58965
|
* HA `select.*` entities may update their options at runtime.
|
|
58217
58966
|
*
|
|
58218
|
-
*
|
|
58219
|
-
*
|
|
58220
|
-
*
|
|
58221
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
58967
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
58968
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
58969
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58222
58970
|
*/
|
|
58223
58971
|
var ControlStatusSchema = object({
|
|
58224
58972
|
kind: _enum([
|
|
@@ -58230,39 +58978,17 @@ var ControlStatusSchema = object({
|
|
|
58230
58978
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58231
58979
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58232
58980
|
* or time-only — HA accepts all three forms). */
|
|
58233
|
-
value: union([number(), string()]),
|
|
58981
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58234
58982
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58235
58983
|
options: array(string()),
|
|
58236
58984
|
/** Ms epoch when the slice was last updated. */
|
|
58237
58985
|
lastChangedAt: number(),
|
|
58238
|
-
/**
|
|
58239
|
-
|
|
58240
|
-
|
|
58241
|
-
|
|
58242
|
-
/**
|
|
58243
|
-
|
|
58244
|
-
min: number().optional(),
|
|
58245
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58246
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58247
|
-
max: number().optional(),
|
|
58248
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58249
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58250
|
-
step: number().optional(),
|
|
58251
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58252
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58253
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58254
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58255
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58256
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58257
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58258
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58259
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58260
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58261
|
-
format: _enum([
|
|
58262
|
-
"date",
|
|
58263
|
-
"time",
|
|
58264
|
-
"datetime"
|
|
58265
|
-
]).optional()
|
|
58986
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58987
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58988
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58989
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58990
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58991
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58266
58992
|
});
|
|
58267
58993
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58268
58994
|
object({
|
|
@@ -58328,9 +59054,9 @@ var CoverStatusSchema = object({
|
|
|
58328
59054
|
]),
|
|
58329
59055
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58330
59056
|
* no intermediate position surface. */
|
|
58331
|
-
position: number().min(0).max(100).nullable(),
|
|
59057
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58332
59058
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58333
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59059
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58334
59060
|
/** Ms epoch when the slice was last updated. */
|
|
58335
59061
|
lastChangedAt: number()
|
|
58336
59062
|
});
|
|
@@ -58433,9 +59159,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58433
59159
|
var DayNightStatusSchema = object({
|
|
58434
59160
|
mode: DayNightModeSchema,
|
|
58435
59161
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58436
|
-
sensitivity: number().optional(),
|
|
59162
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58437
59163
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58438
|
-
switchDelaySec: number().optional(),
|
|
59164
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58439
59165
|
lastFetchedAt: number()
|
|
58440
59166
|
});
|
|
58441
59167
|
/**
|
|
@@ -58653,11 +59379,11 @@ var DishwasherStatusSchema = object({
|
|
|
58653
59379
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58654
59380
|
availablePrograms: array(string()),
|
|
58655
59381
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58656
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59382
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58657
59383
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58658
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59384
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58659
59385
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58660
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59386
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58661
59387
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58662
59388
|
doorOpen: boolean().nullable(),
|
|
58663
59389
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58681,7 +59407,7 @@ var DishwasherStatusSchema = object({
|
|
|
58681
59407
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58682
59408
|
machineCareDue: boolean().nullable(),
|
|
58683
59409
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58684
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59410
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58685
59411
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58686
59412
|
halfLoad: boolean().nullable(),
|
|
58687
59413
|
hygienePlus: boolean().nullable(),
|
|
@@ -58696,7 +59422,7 @@ var DishwasherStatusSchema = object({
|
|
|
58696
59422
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58697
59423
|
activeEvents: array(string()),
|
|
58698
59424
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58699
|
-
errorCode: number().nullable(),
|
|
59425
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58700
59426
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58701
59427
|
errorLabel: string().nullable(),
|
|
58702
59428
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58927,7 +59653,7 @@ var DoorbellStatusSchema = object({
|
|
|
58927
59653
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58928
59654
|
lastPressedAt: number().nullable(),
|
|
58929
59655
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58930
|
-
pressCountSinceStart: number()
|
|
59656
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58931
59657
|
});
|
|
58932
59658
|
var DoorbellPressEventSchema = object({
|
|
58933
59659
|
deviceId: number(),
|
|
@@ -58992,17 +59718,7 @@ onPressed: {
|
|
|
58992
59718
|
history: "none",
|
|
58993
59719
|
customize: doorbellCustomize
|
|
58994
59720
|
};
|
|
58995
|
-
|
|
58996
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
58997
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
58998
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
58999
|
-
* The option set is stable across observations; it is persisted in the
|
|
59000
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
59001
|
-
* stored in `sourceInfo`.
|
|
59002
|
-
*/
|
|
59003
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
59004
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
59005
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
59721
|
+
_enum([
|
|
59006
59722
|
"date",
|
|
59007
59723
|
"time",
|
|
59008
59724
|
"datetime"
|
|
@@ -59010,12 +59726,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59010
59726
|
var EnumSensorStatusSchema = object({
|
|
59011
59727
|
value: string(),
|
|
59012
59728
|
/**
|
|
59013
|
-
* Set
|
|
59014
|
-
* as
|
|
59015
|
-
*
|
|
59016
|
-
* a time-only sensor → `'time'`.
|
|
59729
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
59730
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
59731
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59017
59732
|
*/
|
|
59018
|
-
|
|
59733
|
+
timestamp: boolean().optional(),
|
|
59019
59734
|
/** Ms epoch when the slice was last updated. */
|
|
59020
59735
|
lastFetchedAt: number()
|
|
59021
59736
|
});
|
|
@@ -59042,11 +59757,11 @@ var enumSensorCapability = {
|
|
|
59042
59757
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59043
59758
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59044
59759
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59045
|
-
* `
|
|
59760
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59046
59761
|
*/
|
|
59047
59762
|
history: { fields: { value: {
|
|
59048
59763
|
kind: "enum",
|
|
59049
|
-
skipWhenSet: "
|
|
59764
|
+
skipWhenSet: "timestamp"
|
|
59050
59765
|
} } },
|
|
59051
59766
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59052
59767
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59066,13 +59781,13 @@ var EventFireSchema = object({
|
|
|
59066
59781
|
deviceId: number(),
|
|
59067
59782
|
eventType: string(),
|
|
59068
59783
|
data: record(string(), unknown()).nullable(),
|
|
59069
|
-
timestamp: number(),
|
|
59070
|
-
seq: number()
|
|
59784
|
+
timestamp: number().meta(readingMeta("none")),
|
|
59785
|
+
seq: number().meta(readingMeta("count"))
|
|
59071
59786
|
});
|
|
59072
59787
|
var EventEmitterStatusSchema = object({
|
|
59073
59788
|
eventTypes: array(string()),
|
|
59074
59789
|
lastEvent: EventFireSchema.nullable(),
|
|
59075
|
-
eventCountSinceStart: number()
|
|
59790
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59076
59791
|
});
|
|
59077
59792
|
var eventEmitterCapability = {
|
|
59078
59793
|
name: "event-emitter",
|
|
@@ -59485,10 +60200,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59485
60200
|
var FanControlStatusSchema = object({
|
|
59486
60201
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59487
60202
|
* speed surface (single-speed fan). */
|
|
59488
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60203
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59489
60204
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59490
60205
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59491
|
-
percentageStep: number().positive().optional(),
|
|
60206
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59492
60207
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59493
60208
|
* — empty string when no preset is active or supported. */
|
|
59494
60209
|
preset: string(),
|
|
@@ -59609,7 +60324,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59609
60324
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59610
60325
|
model: string().nullable(),
|
|
59611
60326
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59612
|
-
channelCount: number().nullable(),
|
|
60327
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59613
60328
|
/**
|
|
59614
60329
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59615
60330
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59732,9 +60447,151 @@ var gasCapability = {
|
|
|
59732
60447
|
* whether persisting is worth a SQLite commit. */
|
|
59733
60448
|
volatileStateFields: ["lastChangedAt"]
|
|
59734
60449
|
};
|
|
60450
|
+
var GroupCommandsSchema = object({
|
|
60451
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60452
|
+
results: array(object({
|
|
60453
|
+
deviceId: number().int().nonnegative(),
|
|
60454
|
+
cap: string().min(1),
|
|
60455
|
+
method: string().min(1),
|
|
60456
|
+
ok: boolean(),
|
|
60457
|
+
error: string().optional(),
|
|
60458
|
+
/** Ms epoch of the attempt. */
|
|
60459
|
+
at: number()
|
|
60460
|
+
})) });
|
|
60461
|
+
var groupCommandsCapability = {
|
|
60462
|
+
name: "group-commands",
|
|
60463
|
+
scope: "device",
|
|
60464
|
+
deviceNative: true,
|
|
60465
|
+
mode: "singleton",
|
|
60466
|
+
deviceTypes: [
|
|
60467
|
+
DeviceType.Switch,
|
|
60468
|
+
DeviceType.Light,
|
|
60469
|
+
DeviceType.Fan,
|
|
60470
|
+
DeviceType.Cover,
|
|
60471
|
+
DeviceType.Valve,
|
|
60472
|
+
DeviceType.Lock,
|
|
60473
|
+
DeviceType.MediaPlayer,
|
|
60474
|
+
DeviceType.Thermostat,
|
|
60475
|
+
DeviceType.Climate
|
|
60476
|
+
],
|
|
60477
|
+
methods: {},
|
|
60478
|
+
status: {
|
|
60479
|
+
schema: GroupCommandsSchema,
|
|
60480
|
+
kind: "push"
|
|
60481
|
+
},
|
|
60482
|
+
runtimeState: GroupCommandsSchema,
|
|
60483
|
+
/**
|
|
60484
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
60485
|
+
* failure would outlive the command that caused it.
|
|
60486
|
+
*
|
|
60487
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60488
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60489
|
+
*/
|
|
60490
|
+
durability: "session",
|
|
60491
|
+
history: "none"
|
|
60492
|
+
};
|
|
60493
|
+
/**
|
|
60494
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
60495
|
+
* included member is, or every included member is. What "active" means is the
|
|
60496
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
60497
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
60498
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
60499
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
60500
|
+
* empty included set takes the device offline, never `active: false`.
|
|
60501
|
+
*/
|
|
60502
|
+
var GroupActiveSchema = object({
|
|
60503
|
+
active: boolean().meta({ label: "Active" }),
|
|
60504
|
+
/** Ms epoch when the slice was last updated. */
|
|
60505
|
+
lastChangedAt: number()
|
|
60506
|
+
});
|
|
60507
|
+
var groupActiveCapability = {
|
|
60508
|
+
name: "group-active",
|
|
60509
|
+
scope: "device",
|
|
60510
|
+
deviceNative: true,
|
|
60511
|
+
mode: "singleton",
|
|
60512
|
+
deviceTypes: [
|
|
60513
|
+
DeviceType.Cover,
|
|
60514
|
+
DeviceType.Valve,
|
|
60515
|
+
DeviceType.Lock,
|
|
60516
|
+
DeviceType.MediaPlayer,
|
|
60517
|
+
DeviceType.Climate,
|
|
60518
|
+
DeviceType.Thermostat
|
|
60519
|
+
],
|
|
60520
|
+
methods: {},
|
|
60521
|
+
status: {
|
|
60522
|
+
schema: GroupActiveSchema,
|
|
60523
|
+
kind: "push"
|
|
60524
|
+
},
|
|
60525
|
+
runtimeState: GroupActiveSchema,
|
|
60526
|
+
/**
|
|
60527
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
60528
|
+
* next source event; a restored value would outlive the members it named.
|
|
60529
|
+
*
|
|
60530
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60531
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60532
|
+
*/
|
|
60533
|
+
durability: "session",
|
|
60534
|
+
history: "none"
|
|
60535
|
+
};
|
|
60536
|
+
/**
|
|
60537
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60538
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60539
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60540
|
+
* series that later statistics read is the output cap's own history block.
|
|
60541
|
+
*/
|
|
60542
|
+
var GroupStatusSchema = object({
|
|
60543
|
+
/** Members whose current value entered the aggregate. */
|
|
60544
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60545
|
+
precision: 0,
|
|
60546
|
+
label: "Reporting"
|
|
60547
|
+
})),
|
|
60548
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60549
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60550
|
+
precision: 0,
|
|
60551
|
+
label: "Excluded"
|
|
60552
|
+
})),
|
|
60553
|
+
/** `included` + `excluded`. */
|
|
60554
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60555
|
+
precision: 0,
|
|
60556
|
+
label: "Members"
|
|
60557
|
+
}))
|
|
60558
|
+
});
|
|
60559
|
+
var groupStatusCapability = {
|
|
60560
|
+
name: "group-status",
|
|
60561
|
+
scope: "device",
|
|
60562
|
+
deviceNative: true,
|
|
60563
|
+
mode: "singleton",
|
|
60564
|
+
deviceTypes: [
|
|
60565
|
+
DeviceType.Sensor,
|
|
60566
|
+
DeviceType.Switch,
|
|
60567
|
+
DeviceType.Light,
|
|
60568
|
+
DeviceType.Fan,
|
|
60569
|
+
DeviceType.Cover,
|
|
60570
|
+
DeviceType.Valve,
|
|
60571
|
+
DeviceType.Lock,
|
|
60572
|
+
DeviceType.MediaPlayer,
|
|
60573
|
+
DeviceType.Thermostat,
|
|
60574
|
+
DeviceType.Climate
|
|
60575
|
+
],
|
|
60576
|
+
methods: {},
|
|
60577
|
+
status: {
|
|
60578
|
+
schema: GroupStatusSchema,
|
|
60579
|
+
kind: "push"
|
|
60580
|
+
},
|
|
60581
|
+
runtimeState: GroupStatusSchema,
|
|
60582
|
+
/**
|
|
60583
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60584
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60585
|
+
*
|
|
60586
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60587
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60588
|
+
*/
|
|
60589
|
+
durability: "session",
|
|
60590
|
+
history: "none"
|
|
60591
|
+
};
|
|
59735
60592
|
var HeatingValveStatusSchema = object({
|
|
59736
60593
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59737
|
-
position: number().min(0).max(100).nullable(),
|
|
60594
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59738
60595
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59739
60596
|
lastFetchedAt: number()
|
|
59740
60597
|
});
|
|
@@ -59777,9 +60634,9 @@ var HumidifierStatusSchema = object({
|
|
|
59777
60634
|
/** Whether the humidifier is currently on. */
|
|
59778
60635
|
on: boolean(),
|
|
59779
60636
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59780
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60637
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59781
60638
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59782
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60639
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59783
60640
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59784
60641
|
* device has no mode surface. */
|
|
59785
60642
|
mode: string().nullable(),
|
|
@@ -59789,9 +60646,9 @@ var HumidifierStatusSchema = object({
|
|
|
59789
60646
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59790
60647
|
action: string().nullable(),
|
|
59791
60648
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59792
|
-
minHumidity: number().nullable(),
|
|
60649
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59793
60650
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59794
|
-
maxHumidity: number().nullable(),
|
|
60651
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59795
60652
|
/** Ms epoch when the slice was last updated. */
|
|
59796
60653
|
lastChangedAt: number()
|
|
59797
60654
|
});
|
|
@@ -59861,22 +60718,13 @@ var humidifierCapability = {
|
|
|
59861
60718
|
* `sourceInfo`.
|
|
59862
60719
|
*/
|
|
59863
60720
|
var HumiditySensorStatusSchema = object({
|
|
59864
|
-
/** Current relative humidity, 0..100. */
|
|
59865
|
-
percent: number().min(0).max(100).meta({
|
|
59866
|
-
|
|
60721
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60722
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60723
|
+
precision: 0,
|
|
59867
60724
|
label: "Humidity"
|
|
59868
|
-
}),
|
|
60725
|
+
})),
|
|
59869
60726
|
/** Ms epoch when the slice was last updated. */
|
|
59870
|
-
lastFetchedAt: number()
|
|
59871
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59872
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59873
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59874
|
-
unit: string().optional(),
|
|
59875
|
-
/** Suggested decimal places for numeric display.
|
|
59876
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59877
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59878
|
-
* auto-formatting when absent. */
|
|
59879
|
-
precision: number().int().min(0).max(10).optional()
|
|
60727
|
+
lastFetchedAt: number()
|
|
59880
60728
|
});
|
|
59881
60729
|
var humiditySensorCapability = {
|
|
59882
60730
|
name: "humidity-sensor",
|
|
@@ -59907,12 +60755,7 @@ var humiditySensorCapability = {
|
|
|
59907
60755
|
} } },
|
|
59908
60756
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59909
60757
|
* whether persisting is worth a SQLite commit. */
|
|
59910
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
59911
|
-
customize: {
|
|
59912
|
-
version: 1,
|
|
59913
|
-
advanced: "derive",
|
|
59914
|
-
targets: []
|
|
59915
|
-
}
|
|
60758
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
59916
60759
|
};
|
|
59917
60760
|
/**
|
|
59918
60761
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -59933,7 +60776,7 @@ var ImageStatusSchema = object({
|
|
|
59933
60776
|
* entity exposes no `entity_picture` (yet). */
|
|
59934
60777
|
url: string().nullable(),
|
|
59935
60778
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
59936
|
-
lastUpdated: number().nullable()
|
|
60779
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
59937
60780
|
});
|
|
59938
60781
|
var imageCapability = {
|
|
59939
60782
|
name: "image",
|
|
@@ -60021,19 +60864,19 @@ var NormalizedRangeSchema = object({
|
|
|
60021
60864
|
*/
|
|
60022
60865
|
var ImageSettingsStatusSchema = object({
|
|
60023
60866
|
/** Normalized 0–100. */
|
|
60024
|
-
brightness: number().optional(),
|
|
60867
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60025
60868
|
/** Normalized 0–100. */
|
|
60026
|
-
contrast: number().optional(),
|
|
60869
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60027
60870
|
/** Normalized 0–100. */
|
|
60028
|
-
saturation: number().optional(),
|
|
60871
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60029
60872
|
/** Normalized 0–100. */
|
|
60030
|
-
sharpness: number().optional(),
|
|
60873
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60031
60874
|
mirror: boolean().optional(),
|
|
60032
60875
|
flip: boolean().optional(),
|
|
60033
60876
|
rotate: ImageRotateSchema.optional(),
|
|
60034
60877
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60035
60878
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60036
|
-
warmth: number().optional(),
|
|
60879
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60037
60880
|
exposureMode: ExposureModeSchema.optional(),
|
|
60038
60881
|
backlightMode: BacklightModeSchema.optional(),
|
|
60039
60882
|
lastFetchedAt: number()
|
|
@@ -60312,10 +61155,10 @@ var IntercomAbilitySchema = object({
|
|
|
60312
61155
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60313
61156
|
codecs: array(string()),
|
|
60314
61157
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60315
|
-
sampleRate: number(),
|
|
61158
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60316
61159
|
duplex: _enum(["half", "full"]),
|
|
60317
61160
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60318
|
-
maxBacklogMs: number()
|
|
61161
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60319
61162
|
});
|
|
60320
61163
|
var IntercomStatusSchema = object({
|
|
60321
61164
|
/** True while a talk session is open. */
|
|
@@ -60542,13 +61385,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60542
61385
|
activity: LawnMowerActivitySchema,
|
|
60543
61386
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60544
61387
|
* reading. */
|
|
60545
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61388
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60546
61389
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60547
61390
|
* task is active / progress is unavailable. */
|
|
60548
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61391
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60549
61392
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60550
61393
|
* or null when unknown. */
|
|
60551
|
-
currentCode: number().nullable(),
|
|
61394
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60552
61395
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60553
61396
|
currentCodeLabel: string().nullable(),
|
|
60554
61397
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61001,7 +61844,14 @@ var lockControlCapability = {
|
|
|
61001
61844
|
}),
|
|
61002
61845
|
unlock: method(object({
|
|
61003
61846
|
deviceId: number().int().nonnegative(),
|
|
61004
|
-
code: string().min(1).optional()
|
|
61847
|
+
code: string().min(1).optional(),
|
|
61848
|
+
/**
|
|
61849
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
61850
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
61851
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
61852
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
61853
|
+
*/
|
|
61854
|
+
confirm: boolean().optional()
|
|
61005
61855
|
}), _void(), {
|
|
61006
61856
|
kind: "mutation",
|
|
61007
61857
|
auth: "protected"
|
|
@@ -61038,6 +61888,44 @@ var lockControlCapability = {
|
|
|
61038
61888
|
volatileStateFields: ["lastChangedAt"]
|
|
61039
61889
|
};
|
|
61040
61890
|
/**
|
|
61891
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
61892
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
61893
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
61894
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
61895
|
+
*/
|
|
61896
|
+
var MeterStatusSchema = object({
|
|
61897
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
61898
|
+
lastFetchedAt: number()
|
|
61899
|
+
});
|
|
61900
|
+
var meterCapability = {
|
|
61901
|
+
name: "meter",
|
|
61902
|
+
scope: "device",
|
|
61903
|
+
deviceNative: true,
|
|
61904
|
+
mode: "singleton",
|
|
61905
|
+
deviceTypes: [DeviceType.Sensor],
|
|
61906
|
+
methods: {},
|
|
61907
|
+
status: {
|
|
61908
|
+
schema: MeterStatusSchema,
|
|
61909
|
+
kind: "push"
|
|
61910
|
+
},
|
|
61911
|
+
runtimeState: MeterStatusSchema,
|
|
61912
|
+
/**
|
|
61913
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
61914
|
+
* history integral. A restart shows it only until the history pass
|
|
61915
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
61916
|
+
*
|
|
61917
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61918
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61919
|
+
*/
|
|
61920
|
+
durability: "restored",
|
|
61921
|
+
history: { fields: { value: {
|
|
61922
|
+
kind: "counter",
|
|
61923
|
+
deadband: .001,
|
|
61924
|
+
minIntervalMs: 6e4
|
|
61925
|
+
} } },
|
|
61926
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
61927
|
+
};
|
|
61928
|
+
/**
|
|
61041
61929
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61042
61930
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61043
61931
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -61081,7 +61969,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61081
61969
|
state: MediaPlayerStateSchema,
|
|
61082
61970
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61083
61971
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61084
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
61972
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61085
61973
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61086
61974
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61087
61975
|
isMuted: boolean().nullable(),
|
|
@@ -61094,10 +61982,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61094
61982
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61095
61983
|
/** Current playback position in ms. Null when not seekable or
|
|
61096
61984
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61097
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
61985
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61098
61986
|
/** Total duration of the current media in ms. Null when unknown
|
|
61099
61987
|
* (live stream) or nothing is playing. */
|
|
61100
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
61988
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61101
61989
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61102
61990
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61103
61991
|
shuffle: boolean().nullable(),
|
|
@@ -61406,7 +62294,7 @@ var motionCustomize = {
|
|
|
61406
62294
|
eventName: "onMotionChanged"
|
|
61407
62295
|
},
|
|
61408
62296
|
deviceTypes: [DeviceType.Camera],
|
|
61409
|
-
apply: "
|
|
62297
|
+
apply: "add",
|
|
61410
62298
|
applyAuthority: {
|
|
61411
62299
|
kind: "camera-sensors",
|
|
61412
62300
|
timeoutField: "motionCooldownMs"
|
|
@@ -61478,7 +62366,7 @@ var MotionStatusSchema = object({
|
|
|
61478
62366
|
* it, every provider seeded it at boot, and every session left it
|
|
61479
62367
|
* `detected: true` after its detach.
|
|
61480
62368
|
*/
|
|
61481
|
-
autoClearAfterMs: number().nullable()
|
|
62369
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61482
62370
|
});
|
|
61483
62371
|
/**
|
|
61484
62372
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61515,12 +62403,18 @@ var motionCapability = {
|
|
|
61515
62403
|
methods: {
|
|
61516
62404
|
/**
|
|
61517
62405
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
61518
|
-
* for consumers that don't need the full status object
|
|
61519
|
-
*
|
|
61520
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
61521
|
-
* consumer.
|
|
62406
|
+
* for consumers that don't need the full status object. A composed
|
|
62407
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
61522
62408
|
*/
|
|
61523
62409
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62410
|
+
/**
|
|
62411
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62412
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62413
|
+
*/
|
|
62414
|
+
composedMethods: { isDetected: {
|
|
62415
|
+
kind: "slice",
|
|
62416
|
+
field: "detected"
|
|
62417
|
+
} },
|
|
61524
62418
|
events: {
|
|
61525
62419
|
/**
|
|
61526
62420
|
* Fires every time the runner transitions a camera between
|
|
@@ -61660,7 +62554,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61660
62554
|
* the grid region(s). */
|
|
61661
62555
|
var MotionZoneStatusSchema = object({
|
|
61662
62556
|
enabled: boolean(),
|
|
61663
|
-
sensitivity: number(),
|
|
62557
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61664
62558
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61665
62559
|
regions: array(MotionZoneRegionSchema),
|
|
61666
62560
|
lastFetchedAt: number()
|
|
@@ -62030,7 +62924,7 @@ var NavigationStatusSchema = object({
|
|
|
62030
62924
|
following: boolean(),
|
|
62031
62925
|
flash: boolean(),
|
|
62032
62926
|
lightMode: NavigationLightModeSchema,
|
|
62033
|
-
lightLevel: number().min(40).max(100),
|
|
62927
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62034
62928
|
/** Ms epoch when the slice was last updated. */
|
|
62035
62929
|
lastChangedAt: number()
|
|
62036
62930
|
});
|
|
@@ -62164,13 +63058,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62164
63058
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62165
63059
|
* SKIP a null rather than coerce it.
|
|
62166
63060
|
*/
|
|
62167
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63061
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62168
63062
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62169
|
-
rssiDbm: number().optional(),
|
|
63063
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62170
63064
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62171
63065
|
ssid: string().optional(),
|
|
62172
63066
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62173
|
-
lastUpdated: number()
|
|
63067
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62174
63068
|
});
|
|
62175
63069
|
var networkLinkCapability = {
|
|
62176
63070
|
name: "network-link",
|
|
@@ -62555,7 +63449,7 @@ var NotifierStatusSchema = object({
|
|
|
62555
63449
|
lastError: string().nullable(),
|
|
62556
63450
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62557
63451
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62558
|
-
queueDepth: number().int().nonnegative(),
|
|
63452
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62559
63453
|
/** Per-feature capability matrix — authoritative source for the
|
|
62560
63454
|
* compose-form field gating. */
|
|
62561
63455
|
supports: NotifierSupportsSchema
|
|
@@ -62647,11 +63541,9 @@ onSent: { data: object({
|
|
|
62647
63541
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62648
63542
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62649
63543
|
*
|
|
62650
|
-
* The
|
|
62651
|
-
*
|
|
62652
|
-
*
|
|
62653
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62654
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63544
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63545
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63546
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62655
63547
|
*
|
|
62656
63548
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62657
63549
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62660,15 +63552,8 @@ onSent: { data: object({
|
|
|
62660
63552
|
* numeric values land here.
|
|
62661
63553
|
*/
|
|
62662
63554
|
var NumericSensorStatusSchema = object({
|
|
62663
|
-
|
|
62664
|
-
|
|
62665
|
-
* Populated live from the upstream source on each state push.
|
|
62666
|
-
* Absent for unitless sensors. */
|
|
62667
|
-
unit: string().optional(),
|
|
62668
|
-
/** Suggested decimal places for numeric display.
|
|
62669
|
-
* Populated live from the upstream source when provided.
|
|
62670
|
-
* Falls back to auto-formatting when absent. */
|
|
62671
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63555
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63556
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62672
63557
|
/** Ms epoch when the slice was last updated. */
|
|
62673
63558
|
lastFetchedAt: number()
|
|
62674
63559
|
});
|
|
@@ -62692,11 +63577,11 @@ var numericSensorCapability = {
|
|
|
62692
63577
|
*/
|
|
62693
63578
|
durability: "restored",
|
|
62694
63579
|
/**
|
|
62695
|
-
* History (D850): recorded series. The unit is
|
|
63580
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63581
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62696
63582
|
*/
|
|
62697
63583
|
history: { fields: { value: {
|
|
62698
63584
|
kind: "gauge",
|
|
62699
|
-
unitFrom: "unit",
|
|
62700
63585
|
minIntervalMs: 3e4
|
|
62701
63586
|
} } },
|
|
62702
63587
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -62988,23 +63873,26 @@ var PetFeederStatusSchema = object({
|
|
|
62988
63873
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
62989
63874
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
62990
63875
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
62991
|
-
foodLevel: number().nullable(),
|
|
63876
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62992
63877
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
62993
63878
|
* single-hopper models. */
|
|
62994
|
-
food1: number().nullable(),
|
|
63879
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
62995
63880
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
62996
63881
|
* single-hopper models. */
|
|
62997
|
-
food2: number().nullable(),
|
|
63882
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
62998
63883
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
62999
63884
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63000
63885
|
* below the feeder's low threshold. */
|
|
63001
63886
|
lowFood: boolean(),
|
|
63002
63887
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63003
63888
|
* device has no battery reading. */
|
|
63004
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63005
|
-
/**
|
|
63006
|
-
*
|
|
63007
|
-
|
|
63889
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63890
|
+
/**
|
|
63891
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
63892
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
63893
|
+
* model has no desiccant sensor.
|
|
63894
|
+
*/
|
|
63895
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63008
63896
|
/** True while a feed is in progress. */
|
|
63009
63897
|
feeding: boolean(),
|
|
63010
63898
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63015,7 +63903,7 @@ var PetFeederStatusSchema = object({
|
|
|
63015
63903
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63016
63904
|
error: string().nullable(),
|
|
63017
63905
|
/** Raw device error code (0 / null = no error). */
|
|
63018
|
-
errorCode: number().nullable(),
|
|
63906
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63019
63907
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63020
63908
|
isDualHopper: boolean(),
|
|
63021
63909
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63025,7 +63913,7 @@ var PetFeederStatusSchema = object({
|
|
|
63025
63913
|
/** Play a chime when dispensing. */
|
|
63026
63914
|
feedSound: boolean(),
|
|
63027
63915
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63028
|
-
volume: number(),
|
|
63916
|
+
volume: number().meta(readingMeta("none")),
|
|
63029
63917
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63030
63918
|
lastFetchedAt: number()
|
|
63031
63919
|
});
|
|
@@ -63144,7 +64032,7 @@ var petFeederCapability = {
|
|
|
63144
64032
|
},
|
|
63145
64033
|
desiccantLeftDays: {
|
|
63146
64034
|
kind: "gauge",
|
|
63147
|
-
unit: "
|
|
64035
|
+
unit: "s"
|
|
63148
64036
|
}
|
|
63149
64037
|
} }
|
|
63150
64038
|
};
|
|
@@ -63545,43 +64433,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63545
64433
|
*/
|
|
63546
64434
|
var PowerMeterStatusSchema = object({
|
|
63547
64435
|
/** Instantaneous power draw in watts. */
|
|
63548
|
-
watts: number().optional().meta({
|
|
63549
|
-
unit: "W",
|
|
63550
|
-
label: "Power"
|
|
63551
|
-
}),
|
|
64436
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63552
64437
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63553
|
-
kwhTotal: number().optional().meta({
|
|
63554
|
-
unit: "kWh",
|
|
63555
|
-
label: "Energy"
|
|
63556
|
-
}),
|
|
64438
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63557
64439
|
/** Voltage in volts. */
|
|
63558
|
-
volts: number().optional(),
|
|
64440
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
63559
64441
|
/** Current in amperes. */
|
|
63560
|
-
amps: number().optional(),
|
|
63561
|
-
/** Apparent power in volt-amperes
|
|
63562
|
-
va: number().optional(),
|
|
64442
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
64443
|
+
/** Apparent power in volt-amperes. */
|
|
64444
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63563
64445
|
/** Power factor (0..1) if reported. */
|
|
63564
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
64446
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63565
64447
|
/** Ms epoch when the slice was last updated. */
|
|
63566
|
-
lastFetchedAt: number()
|
|
63567
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63568
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63569
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63570
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63571
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63572
|
-
unit: string().optional(),
|
|
63573
|
-
/** Suggested decimal places for numeric display.
|
|
63574
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63575
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63576
|
-
* auto-formatting when absent. */
|
|
63577
|
-
precision: number().int().min(0).max(10).optional()
|
|
64448
|
+
lastFetchedAt: number()
|
|
63578
64449
|
});
|
|
64450
|
+
/**
|
|
64451
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
64452
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
64453
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
64454
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
64455
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
64456
|
+
*/
|
|
64457
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
64458
|
+
DeviceType.Sensor,
|
|
64459
|
+
DeviceType.Switch,
|
|
64460
|
+
DeviceType.Light,
|
|
64461
|
+
DeviceType.Fan,
|
|
64462
|
+
DeviceType.Climate,
|
|
64463
|
+
DeviceType.Thermostat,
|
|
64464
|
+
DeviceType.Humidifier,
|
|
64465
|
+
DeviceType.WaterHeater,
|
|
64466
|
+
DeviceType.MediaPlayer,
|
|
64467
|
+
DeviceType.Washer,
|
|
64468
|
+
DeviceType.Dryer,
|
|
64469
|
+
DeviceType.Dishwasher,
|
|
64470
|
+
DeviceType.Vacuum,
|
|
64471
|
+
DeviceType.LawnMower,
|
|
64472
|
+
DeviceType.PetFeeder
|
|
64473
|
+
];
|
|
64474
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
64475
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
64476
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
64477
|
+
function powerTarget(id, unit) {
|
|
64478
|
+
return {
|
|
64479
|
+
id,
|
|
64480
|
+
cardinality: "scalar",
|
|
64481
|
+
vocabulary: {
|
|
64482
|
+
cap: "power-meter",
|
|
64483
|
+
stateField: id
|
|
64484
|
+
},
|
|
64485
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
64486
|
+
apply: "add",
|
|
64487
|
+
path: id,
|
|
64488
|
+
sources: [{
|
|
64489
|
+
kind: "numeric",
|
|
64490
|
+
requiredUnit: unit,
|
|
64491
|
+
transforms: [{ kind: "identity" }]
|
|
64492
|
+
}],
|
|
64493
|
+
companions: [{
|
|
64494
|
+
kind: "clock",
|
|
64495
|
+
path: "lastFetchedAt",
|
|
64496
|
+
when: "always"
|
|
64497
|
+
}],
|
|
64498
|
+
sourceReport: { status: "assignment-status" },
|
|
64499
|
+
advancedExpression: true
|
|
64500
|
+
};
|
|
64501
|
+
}
|
|
64502
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
64503
|
+
var powerMeterCustomize = {
|
|
64504
|
+
version: 1,
|
|
64505
|
+
targets: [
|
|
64506
|
+
powerTarget("watts", "W"),
|
|
64507
|
+
powerTarget("kwhTotal", "kWh"),
|
|
64508
|
+
powerTarget("volts", "V"),
|
|
64509
|
+
powerTarget("amps", "A")
|
|
64510
|
+
]
|
|
64511
|
+
};
|
|
63579
64512
|
var powerMeterCapability = {
|
|
63580
64513
|
name: "power-meter",
|
|
63581
64514
|
scope: "device",
|
|
63582
64515
|
deviceNative: true,
|
|
63583
64516
|
mode: "singleton",
|
|
63584
|
-
deviceTypes:
|
|
64517
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
63585
64518
|
methods: {},
|
|
63586
64519
|
status: {
|
|
63587
64520
|
schema: PowerMeterStatusSchema,
|
|
@@ -63639,11 +64572,7 @@ var powerMeterCapability = {
|
|
|
63639
64572
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63640
64573
|
* whether persisting is worth a SQLite commit. */
|
|
63641
64574
|
volatileStateFields: ["lastFetchedAt"],
|
|
63642
|
-
customize:
|
|
63643
|
-
version: 1,
|
|
63644
|
-
advanced: "derive",
|
|
63645
|
-
targets: []
|
|
63646
|
-
}
|
|
64575
|
+
customize: powerMeterCustomize
|
|
63647
64576
|
};
|
|
63648
64577
|
/**
|
|
63649
64578
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63663,11 +64592,11 @@ var powerMeterCapability = {
|
|
|
63663
64592
|
*/
|
|
63664
64593
|
var GpsLocationSchema = object({
|
|
63665
64594
|
/** Latitude in decimal degrees, -90..90. */
|
|
63666
|
-
latitude: number().min(-90).max(90),
|
|
64595
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63667
64596
|
/** Longitude in decimal degrees, -180..180. */
|
|
63668
|
-
longitude: number().min(-180).max(180),
|
|
64597
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63669
64598
|
/** Reported accuracy in meters (lower = better). */
|
|
63670
|
-
accuracyMeters: number().nonnegative()
|
|
64599
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63671
64600
|
});
|
|
63672
64601
|
var PresenceStatusSchema = object({
|
|
63673
64602
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63679,7 +64608,7 @@ var PresenceStatusSchema = object({
|
|
|
63679
64608
|
gps: GpsLocationSchema.nullable(),
|
|
63680
64609
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63681
64610
|
* when not reported. */
|
|
63682
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64611
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63683
64612
|
/** Ms epoch when the slice was last updated. */
|
|
63684
64613
|
lastChangedAt: number()
|
|
63685
64614
|
});
|
|
@@ -63729,19 +64658,10 @@ var presenceCapability = {
|
|
|
63729
64658
|
* `sourceInfo`.
|
|
63730
64659
|
*/
|
|
63731
64660
|
var PressureSensorStatusSchema = object({
|
|
63732
|
-
/** Current pressure in hPa. */
|
|
63733
|
-
hpa: number(),
|
|
64661
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64662
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63734
64663
|
/** Ms epoch when the slice was last updated. */
|
|
63735
|
-
lastFetchedAt: number()
|
|
63736
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63737
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63738
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63739
|
-
unit: string().optional(),
|
|
63740
|
-
/** Suggested decimal places for numeric display.
|
|
63741
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63742
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63743
|
-
* auto-formatting when absent. */
|
|
63744
|
-
precision: number().int().min(0).max(10).optional()
|
|
64664
|
+
lastFetchedAt: number()
|
|
63745
64665
|
});
|
|
63746
64666
|
var pressureSensorCapability = {
|
|
63747
64667
|
name: "pressure-sensor",
|
|
@@ -64155,8 +65075,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64155
65075
|
}), _void(), { kind: "mutation" });
|
|
64156
65076
|
var PtzAutotrackSettingsSchema = object({
|
|
64157
65077
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64158
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64159
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65078
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65079
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64160
65080
|
});
|
|
64161
65081
|
/**
|
|
64162
65082
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64310,7 +65230,7 @@ var RunningStateStatusSchema = object({
|
|
|
64310
65230
|
/** null = unknown — never coerced to false (D393). */
|
|
64311
65231
|
running: boolean().nullable(),
|
|
64312
65232
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64313
|
-
since: number().nullable(),
|
|
65233
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64314
65234
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64315
65235
|
phase: string().nullable(),
|
|
64316
65236
|
/** null until a reading has been published (D393). */
|
|
@@ -64325,7 +65245,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64325
65245
|
/** Generic Customize target for the running boolean (D936). */
|
|
64326
65246
|
var runningCustomize = {
|
|
64327
65247
|
version: 1,
|
|
64328
|
-
advanced: "derive",
|
|
64329
65248
|
targets: [{
|
|
64330
65249
|
id: "running",
|
|
64331
65250
|
cardinality: "scalar",
|
|
@@ -64334,6 +65253,8 @@ var runningCustomize = {
|
|
|
64334
65253
|
stateField: "running"
|
|
64335
65254
|
},
|
|
64336
65255
|
deviceTypes: [
|
|
65256
|
+
DeviceType.Washer,
|
|
65257
|
+
DeviceType.Dryer,
|
|
64337
65258
|
DeviceType.Dishwasher,
|
|
64338
65259
|
DeviceType.Vacuum,
|
|
64339
65260
|
DeviceType.LawnMower,
|
|
@@ -64345,7 +65266,7 @@ var runningCustomize = {
|
|
|
64345
65266
|
DeviceType.Thermostat,
|
|
64346
65267
|
DeviceType.PetFeeder
|
|
64347
65268
|
],
|
|
64348
|
-
apply: "add
|
|
65269
|
+
apply: "add",
|
|
64349
65270
|
path: "running",
|
|
64350
65271
|
sources: [
|
|
64351
65272
|
{
|
|
@@ -65609,9 +66530,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65609
66530
|
*/
|
|
65610
66531
|
var RecordWindowSchema = object({
|
|
65611
66532
|
trigger: RecordTriggerSchema,
|
|
65612
|
-
day: number().int().min(0).max(6),
|
|
65613
|
-
startMinute: number().int().min(0).max(1439),
|
|
65614
|
-
endMinute: number().int().min(1).max(1440)
|
|
66533
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
66534
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
66535
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65615
66536
|
});
|
|
65616
66537
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65617
66538
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65687,10 +66608,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65687
66608
|
/** Master "record to the card at all" switch. */
|
|
65688
66609
|
enabled: boolean().nullable(),
|
|
65689
66610
|
overwriteWhenFull: boolean().nullable(),
|
|
65690
|
-
preRecordSec: number().nullable(),
|
|
65691
|
-
postRecordSec: number().nullable(),
|
|
66611
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66612
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65692
66613
|
/** Length of one recorded file, in minutes. */
|
|
65693
|
-
segmentMinutes: number().nullable(),
|
|
66614
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65694
66615
|
/** The primary track's weekly windows, flattened. */
|
|
65695
66616
|
windows: array(RecordWindowSchema),
|
|
65696
66617
|
/**
|
|
@@ -65706,7 +66627,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65706
66627
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65707
66628
|
* writable.
|
|
65708
66629
|
*/
|
|
65709
|
-
unreadableWindows: number(),
|
|
66630
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65710
66631
|
/**
|
|
65711
66632
|
* The camera is scheduled to record and has NO usable storage.
|
|
65712
66633
|
*
|
|
@@ -66551,7 +67472,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66551
67472
|
url: string().optional(),
|
|
66552
67473
|
codec: string().optional(),
|
|
66553
67474
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66554
|
-
fps: number().positive().optional(),
|
|
67475
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66555
67476
|
label: string().optional(),
|
|
66556
67477
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66557
67478
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66638,18 +67559,18 @@ var StreamProfileSchema = _enum([
|
|
|
66638
67559
|
]);
|
|
66639
67560
|
/** The current encoding config of one stream profile. */
|
|
66640
67561
|
var StreamProfileConfigSchema = object({
|
|
66641
|
-
width: number(),
|
|
66642
|
-
height: number(),
|
|
67562
|
+
width: number().meta(readingMeta("none")),
|
|
67563
|
+
height: number().meta(readingMeta("none")),
|
|
66643
67564
|
codec: _enum(["h264", "h265"]),
|
|
66644
|
-
framerate: number(),
|
|
66645
|
-
bitrate: number(),
|
|
67565
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67566
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66646
67567
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66647
67568
|
encoderProfile: _enum([
|
|
66648
67569
|
"high",
|
|
66649
67570
|
"main",
|
|
66650
67571
|
"baseline"
|
|
66651
67572
|
]).optional(),
|
|
66652
|
-
gop: number().optional(),
|
|
67573
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66653
67574
|
/**
|
|
66654
67575
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66655
67576
|
*
|
|
@@ -66823,7 +67744,8 @@ var switchCapability = {
|
|
|
66823
67744
|
deviceTypes: [
|
|
66824
67745
|
DeviceType.Switch,
|
|
66825
67746
|
DeviceType.Siren,
|
|
66826
|
-
DeviceType.Light
|
|
67747
|
+
DeviceType.Light,
|
|
67748
|
+
DeviceType.Fan
|
|
66827
67749
|
],
|
|
66828
67750
|
methods: { setState: method(object({
|
|
66829
67751
|
deviceId: number(),
|
|
@@ -66870,12 +67792,7 @@ var switchCapability = {
|
|
|
66870
67792
|
label: "On",
|
|
66871
67793
|
kind: "boolean"
|
|
66872
67794
|
}
|
|
66873
|
-
}] }
|
|
66874
|
-
customize: {
|
|
66875
|
-
version: 1,
|
|
66876
|
-
advanced: "derive",
|
|
66877
|
-
targets: []
|
|
66878
|
-
}
|
|
67795
|
+
}] }
|
|
66879
67796
|
};
|
|
66880
67797
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66881
67798
|
function hasControlCharacter(value) {
|
|
@@ -67458,35 +68375,21 @@ var tamperCapability = {
|
|
|
67458
68375
|
* entries with `device_class: temperature` and any future native
|
|
67459
68376
|
* thermometer.
|
|
67460
68377
|
*
|
|
67461
|
-
*
|
|
67462
|
-
*
|
|
67463
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67464
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67465
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67466
|
-
* `sourceInfo`.
|
|
68378
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
68379
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67467
68380
|
*
|
|
67468
68381
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67469
68382
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67470
68383
|
* changed" steady state.
|
|
67471
68384
|
*/
|
|
67472
68385
|
var TemperatureSensorStatusSchema = object({
|
|
67473
|
-
/** Current temperature in Celsius. */
|
|
67474
|
-
celsius: number().meta({
|
|
67475
|
-
|
|
68386
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68387
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
68388
|
+
precision: 1,
|
|
67476
68389
|
label: "Temperature"
|
|
67477
|
-
}),
|
|
68390
|
+
})),
|
|
67478
68391
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67479
|
-
lastFetchedAt: number()
|
|
67480
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67481
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67482
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67483
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67484
|
-
unit: string().optional(),
|
|
67485
|
-
/** Suggested decimal places for numeric display.
|
|
67486
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67487
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67488
|
-
* auto-formatting when absent. */
|
|
67489
|
-
precision: number().int().min(0).max(10).optional()
|
|
68392
|
+
lastFetchedAt: number()
|
|
67490
68393
|
});
|
|
67491
68394
|
var temperatureSensorCapability = {
|
|
67492
68395
|
name: "temperature-sensor",
|
|
@@ -67517,12 +68420,7 @@ var temperatureSensorCapability = {
|
|
|
67517
68420
|
} } },
|
|
67518
68421
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67519
68422
|
* whether persisting is worth a SQLite commit. */
|
|
67520
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67521
|
-
customize: {
|
|
67522
|
-
version: 1,
|
|
67523
|
-
advanced: "derive",
|
|
67524
|
-
targets: []
|
|
67525
|
-
}
|
|
68423
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67526
68424
|
};
|
|
67527
68425
|
/**
|
|
67528
68426
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67805,16 +68703,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67805
68703
|
]),
|
|
67806
68704
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67807
68705
|
* reading. */
|
|
67808
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68706
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67809
68707
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67810
68708
|
* the vacuum has no speed control. */
|
|
67811
68709
|
fanSpeed: string().nullable(),
|
|
67812
68710
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67813
68711
|
availableFanSpeeds: array(string()),
|
|
67814
68712
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67815
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68713
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67816
68714
|
/** Current error code (0 / null = no error). */
|
|
67817
|
-
errorCode: number().nullable(),
|
|
68715
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67818
68716
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67819
68717
|
errorLabel: string().nullable(),
|
|
67820
68718
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67892,7 +68790,7 @@ var ValveStatusSchema = object({
|
|
|
67892
68790
|
]),
|
|
67893
68791
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
67894
68792
|
* intermediate position surface. */
|
|
67895
|
-
position: number().min(0).max(100).nullable(),
|
|
68793
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67896
68794
|
/** Ms epoch when the slice was last updated. */
|
|
67897
68795
|
lastChangedAt: number()
|
|
67898
68796
|
});
|
|
@@ -68000,9 +68898,9 @@ var vibrationCapability = {
|
|
|
68000
68898
|
*/
|
|
68001
68899
|
var WaterHeaterStatusSchema = object({
|
|
68002
68900
|
/** Current measured temperature. Null when not reported. */
|
|
68003
|
-
currentTemp: number().nullable(),
|
|
68901
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68004
68902
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68005
|
-
targetTemp: number().nullable(),
|
|
68903
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68006
68904
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68007
68905
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68008
68906
|
* device reports an unknown state. */
|
|
@@ -68013,9 +68911,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68013
68911
|
* has no away surface. */
|
|
68014
68912
|
away: boolean().nullable(),
|
|
68015
68913
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68016
|
-
minTemp: number().nullable(),
|
|
68914
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68017
68915
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68018
|
-
maxTemp: number().nullable(),
|
|
68916
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68019
68917
|
/** Ms epoch when the slice was last updated. */
|
|
68020
68918
|
lastChangedAt: number()
|
|
68021
68919
|
});
|
|
@@ -68100,25 +68998,18 @@ var waterHeaterCapability = {
|
|
|
68100
68998
|
* Forecast deferred — current conditions only for v1.
|
|
68101
68999
|
*/
|
|
68102
69000
|
var WeatherStatusSchema = object({
|
|
68103
|
-
/** Verbatim
|
|
68104
|
-
* when no condition has been reported yet. */
|
|
69001
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68105
69002
|
condition: string().nullable(),
|
|
68106
|
-
/** Current temperature in
|
|
68107
|
-
temperature: number().nullable(),
|
|
68108
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68109
|
-
temperatureUnit: string().nullable(),
|
|
69003
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
69004
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68110
69005
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68111
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68112
|
-
/** Barometric pressure in
|
|
68113
|
-
pressure: number().nullable(),
|
|
68114
|
-
/**
|
|
68115
|
-
|
|
68116
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68117
|
-
windSpeed: number().nullable(),
|
|
68118
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68119
|
-
windSpeedUnit: string().nullable(),
|
|
69006
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
69007
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
69008
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
69009
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
69010
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68120
69011
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68121
|
-
windBearing: number().nullable(),
|
|
69012
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68122
69013
|
/** Ms epoch when the slice was last updated. */
|
|
68123
69014
|
lastFetchedAt: number()
|
|
68124
69015
|
});
|
|
@@ -68146,12 +69037,12 @@ var weatherCapability = {
|
|
|
68146
69037
|
*/
|
|
68147
69038
|
durability: "session",
|
|
68148
69039
|
/**
|
|
68149
|
-
* History (D850): recorded series.
|
|
69040
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68150
69041
|
*/
|
|
68151
69042
|
history: { fields: {
|
|
68152
69043
|
temperature: {
|
|
68153
69044
|
kind: "gauge",
|
|
68154
|
-
|
|
69045
|
+
unit: "°C",
|
|
68155
69046
|
deadband: .2
|
|
68156
69047
|
},
|
|
68157
69048
|
humidity: {
|
|
@@ -68161,12 +69052,12 @@ var weatherCapability = {
|
|
|
68161
69052
|
},
|
|
68162
69053
|
pressure: {
|
|
68163
69054
|
kind: "gauge",
|
|
68164
|
-
|
|
69055
|
+
unit: "hPa",
|
|
68165
69056
|
deadband: .5
|
|
68166
69057
|
},
|
|
68167
69058
|
windSpeed: {
|
|
68168
69059
|
kind: "gauge",
|
|
68169
|
-
|
|
69060
|
+
unit: "m/s",
|
|
68170
69061
|
deadband: .5
|
|
68171
69062
|
}
|
|
68172
69063
|
} }
|
|
@@ -69067,8 +69958,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
69067
69958
|
kind: "mutation",
|
|
69068
69959
|
auth: "admin"
|
|
69069
69960
|
});
|
|
69961
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
69070
69962
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
69071
|
-
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;
|
|
69963
|
+
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;
|
|
69072
69964
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
69073
69965
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
69074
69966
|
new Set(CAP_NAMES);
|
|
@@ -69397,6 +70289,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69397
70289
|
featureProbe: featureProbeCapability,
|
|
69398
70290
|
flood: floodCapability,
|
|
69399
70291
|
gas: gasCapability,
|
|
70292
|
+
groupActive: groupActiveCapability,
|
|
70293
|
+
groupCommands: groupCommandsCapability,
|
|
70294
|
+
groupStatus: groupStatusCapability,
|
|
69400
70295
|
heatingValve: heatingValveCapability,
|
|
69401
70296
|
humidifier: humidifierCapability,
|
|
69402
70297
|
humiditySensor: humiditySensorCapability,
|
|
@@ -69406,6 +70301,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69406
70301
|
lawnMowerControl: lawnMowerControlCapability,
|
|
69407
70302
|
lockControl: lockControlCapability,
|
|
69408
70303
|
mediaPlayer: mediaPlayerCapability,
|
|
70304
|
+
meter: meterCapability,
|
|
69409
70305
|
motion: motionCapability,
|
|
69410
70306
|
motionTrigger: motionTriggerCapability,
|
|
69411
70307
|
motionZones: motionZonesCapability,
|
|
@@ -70182,7 +71078,7 @@ var DeclaredDevices = class {
|
|
|
70182
71078
|
return removed;
|
|
70183
71079
|
}
|
|
70184
71080
|
};
|
|
70185
|
-
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;
|
|
71081
|
+
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;
|
|
70186
71082
|
new Set(Object.values(DeviceType));
|
|
70187
71083
|
Object.freeze({
|
|
70188
71084
|
"accessories.getStatus": {
|
|
@@ -70290,6 +71186,13 @@ Object.freeze({
|
|
|
70290
71186
|
access: "view",
|
|
70291
71187
|
role: "admin"
|
|
70292
71188
|
},
|
|
71189
|
+
"addons.getPackageDocs": {
|
|
71190
|
+
capName: "addons",
|
|
71191
|
+
capScope: "system",
|
|
71192
|
+
addonId: null,
|
|
71193
|
+
access: "view",
|
|
71194
|
+
role: "admin"
|
|
71195
|
+
},
|
|
70293
71196
|
"addons.getVersions": {
|
|
70294
71197
|
capName: "addons",
|
|
70295
71198
|
capScope: "system",
|
|
@@ -73398,6 +74301,27 @@ Object.freeze({
|
|
|
73398
74301
|
access: "view",
|
|
73399
74302
|
role: "viewer"
|
|
73400
74303
|
},
|
|
74304
|
+
"groupActive.getStatus": {
|
|
74305
|
+
capName: "group-active",
|
|
74306
|
+
capScope: "device",
|
|
74307
|
+
addonId: null,
|
|
74308
|
+
access: "view",
|
|
74309
|
+
role: "viewer"
|
|
74310
|
+
},
|
|
74311
|
+
"groupCommands.getStatus": {
|
|
74312
|
+
capName: "group-commands",
|
|
74313
|
+
capScope: "device",
|
|
74314
|
+
addonId: null,
|
|
74315
|
+
access: "view",
|
|
74316
|
+
role: "viewer"
|
|
74317
|
+
},
|
|
74318
|
+
"groupStatus.getStatus": {
|
|
74319
|
+
capName: "group-status",
|
|
74320
|
+
capScope: "device",
|
|
74321
|
+
addonId: null,
|
|
74322
|
+
access: "view",
|
|
74323
|
+
role: "viewer"
|
|
74324
|
+
},
|
|
73401
74325
|
"heatingValve.getStatus": {
|
|
73402
74326
|
capName: "heating-valve",
|
|
73403
74327
|
capScope: "device",
|
|
@@ -74350,6 +75274,13 @@ Object.freeze({
|
|
|
74350
75274
|
access: "create",
|
|
74351
75275
|
role: "admin"
|
|
74352
75276
|
},
|
|
75277
|
+
"meter.getStatus": {
|
|
75278
|
+
capName: "meter",
|
|
75279
|
+
capScope: "device",
|
|
75280
|
+
addonId: null,
|
|
75281
|
+
access: "view",
|
|
75282
|
+
role: "viewer"
|
|
75283
|
+
},
|
|
74353
75284
|
"metricsProvider.collectSnapshot": {
|
|
74354
75285
|
capName: "metrics-provider",
|
|
74355
75286
|
capScope: "system",
|
|
@@ -82448,7 +83379,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
82448
83379
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
82449
83380
|
icon: "square"
|
|
82450
83381
|
}
|
|
82451
|
-
}
|
|
83382
|
+
},
|
|
83383
|
+
overrides: { byType: {
|
|
83384
|
+
[DeviceType.Washer]: {
|
|
83385
|
+
state: { running: {
|
|
83386
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
83387
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
83388
|
+
} },
|
|
83389
|
+
events: {
|
|
83390
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
83391
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
83392
|
+
}
|
|
83393
|
+
},
|
|
83394
|
+
[DeviceType.Dryer]: {
|
|
83395
|
+
state: { running: {
|
|
83396
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
83397
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
83398
|
+
} },
|
|
83399
|
+
events: {
|
|
83400
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
83401
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
83402
|
+
}
|
|
83403
|
+
},
|
|
83404
|
+
[DeviceType.Dishwasher]: {
|
|
83405
|
+
state: { running: {
|
|
83406
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
83407
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
83408
|
+
} },
|
|
83409
|
+
events: {
|
|
83410
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
83411
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
83412
|
+
}
|
|
83413
|
+
}
|
|
83414
|
+
} }
|
|
82452
83415
|
},
|
|
82453
83416
|
update: {
|
|
82454
83417
|
scope: "device",
|
|
@@ -83220,6 +84183,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83220
84183
|
icon: "flame"
|
|
83221
84184
|
}]
|
|
83222
84185
|
},
|
|
84186
|
+
"group-active": {
|
|
84187
|
+
scope: "device",
|
|
84188
|
+
noun: t("Group state", "Stato del gruppo")
|
|
84189
|
+
},
|
|
84190
|
+
"group-commands": {
|
|
84191
|
+
scope: "device",
|
|
84192
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84193
|
+
},
|
|
84194
|
+
"group-status": {
|
|
84195
|
+
scope: "device",
|
|
84196
|
+
noun: t("Group", "Gruppo"),
|
|
84197
|
+
state: [
|
|
84198
|
+
{
|
|
84199
|
+
kind: "numeric",
|
|
84200
|
+
field: "included",
|
|
84201
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84202
|
+
label: t("Reporting", "Rispondono"),
|
|
84203
|
+
icon: "users"
|
|
84204
|
+
},
|
|
84205
|
+
{
|
|
84206
|
+
kind: "numeric",
|
|
84207
|
+
field: "excluded",
|
|
84208
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84209
|
+
label: t("Excluded", "Esclusi"),
|
|
84210
|
+
icon: "users"
|
|
84211
|
+
},
|
|
84212
|
+
{
|
|
84213
|
+
kind: "numeric",
|
|
84214
|
+
field: "total",
|
|
84215
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84216
|
+
label: t("Members", "Membri"),
|
|
84217
|
+
icon: "sigma"
|
|
84218
|
+
}
|
|
84219
|
+
]
|
|
84220
|
+
},
|
|
83223
84221
|
"humidity-sensor": {
|
|
83224
84222
|
scope: "device",
|
|
83225
84223
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83245,6 +84243,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83245
84243
|
}],
|
|
83246
84244
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
83247
84245
|
},
|
|
84246
|
+
meter: {
|
|
84247
|
+
scope: "device",
|
|
84248
|
+
noun: t("Meter", "Contatore"),
|
|
84249
|
+
state: [{
|
|
84250
|
+
kind: "numeric",
|
|
84251
|
+
field: "value",
|
|
84252
|
+
quantity: t("the total", "il totale"),
|
|
84253
|
+
label: t("Total", "Totale"),
|
|
84254
|
+
icon: "gauge"
|
|
84255
|
+
}]
|
|
84256
|
+
},
|
|
83248
84257
|
"numeric-sensor": {
|
|
83249
84258
|
scope: "device",
|
|
83250
84259
|
noun: t("Sensor", "Sensore"),
|
|
@@ -83253,7 +84262,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83253
84262
|
field: "value",
|
|
83254
84263
|
quantity: t("the reading", "il valore"),
|
|
83255
84264
|
label: t("Reading", "Valore"),
|
|
83256
|
-
unitField: "unit",
|
|
83257
84265
|
icon: "gauge"
|
|
83258
84266
|
}]
|
|
83259
84267
|
},
|
|
@@ -83389,7 +84397,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83389
84397
|
field: "temperature",
|
|
83390
84398
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
83391
84399
|
label: t("Temperature", "Temperatura"),
|
|
83392
|
-
|
|
84400
|
+
unit: "°C",
|
|
83393
84401
|
icon: "thermometer"
|
|
83394
84402
|
},
|
|
83395
84403
|
{
|
|
@@ -83405,7 +84413,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83405
84413
|
field: "windSpeed",
|
|
83406
84414
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
83407
84415
|
label: t("Wind", "Vento"),
|
|
83408
|
-
|
|
84416
|
+
unit: "m/s",
|
|
83409
84417
|
icon: "wind"
|
|
83410
84418
|
},
|
|
83411
84419
|
{
|
|
@@ -83413,7 +84421,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83413
84421
|
field: "pressure",
|
|
83414
84422
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
83415
84423
|
label: t("Pressure", "Pressione"),
|
|
83416
|
-
|
|
84424
|
+
unit: "hPa",
|
|
83417
84425
|
icon: "gauge"
|
|
83418
84426
|
}
|
|
83419
84427
|
]
|
|
@@ -83718,8 +84726,47 @@ function projectAction(cap, action) {
|
|
|
83718
84726
|
};
|
|
83719
84727
|
}
|
|
83720
84728
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
83721
|
-
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;
|
|
84729
|
+
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;
|
|
83722
84730
|
DeviceFeature.BatteryOperated;
|
|
84731
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
84732
|
+
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.";
|
|
84733
|
+
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.";
|
|
84734
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
84735
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
84736
|
+
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.";
|
|
84737
|
+
function withheld(reason) {
|
|
84738
|
+
return {
|
|
84739
|
+
[DeviceType.Washer]: {
|
|
84740
|
+
exported: false,
|
|
84741
|
+
reason
|
|
84742
|
+
},
|
|
84743
|
+
[DeviceType.Dryer]: {
|
|
84744
|
+
exported: false,
|
|
84745
|
+
reason
|
|
84746
|
+
},
|
|
84747
|
+
[DeviceType.Dishwasher]: {
|
|
84748
|
+
exported: false,
|
|
84749
|
+
reason
|
|
84750
|
+
}
|
|
84751
|
+
};
|
|
84752
|
+
}
|
|
84753
|
+
function offered(received) {
|
|
84754
|
+
return {
|
|
84755
|
+
[DeviceType.Washer]: {
|
|
84756
|
+
exported: true,
|
|
84757
|
+
as: received
|
|
84758
|
+
},
|
|
84759
|
+
[DeviceType.Dryer]: {
|
|
84760
|
+
exported: true,
|
|
84761
|
+
as: received
|
|
84762
|
+
},
|
|
84763
|
+
[DeviceType.Dishwasher]: {
|
|
84764
|
+
exported: true,
|
|
84765
|
+
as: received
|
|
84766
|
+
}
|
|
84767
|
+
};
|
|
84768
|
+
}
|
|
84769
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
83723
84770
|
Object.freeze({
|
|
83724
84771
|
"accessories.getStatus": [{
|
|
83725
84772
|
name: "deviceId",
|
|
@@ -84686,6 +85733,21 @@ Object.freeze({
|
|
|
84686
85733
|
form: "single",
|
|
84687
85734
|
optional: false
|
|
84688
85735
|
}],
|
|
85736
|
+
"groupActive.getStatus": [{
|
|
85737
|
+
name: "deviceId",
|
|
85738
|
+
form: "single",
|
|
85739
|
+
optional: false
|
|
85740
|
+
}],
|
|
85741
|
+
"groupCommands.getStatus": [{
|
|
85742
|
+
name: "deviceId",
|
|
85743
|
+
form: "single",
|
|
85744
|
+
optional: false
|
|
85745
|
+
}],
|
|
85746
|
+
"groupStatus.getStatus": [{
|
|
85747
|
+
name: "deviceId",
|
|
85748
|
+
form: "single",
|
|
85749
|
+
optional: false
|
|
85750
|
+
}],
|
|
84689
85751
|
"heatingValve.getStatus": [{
|
|
84690
85752
|
name: "deviceId",
|
|
84691
85753
|
form: "single",
|
|
@@ -84886,6 +85948,11 @@ Object.freeze({
|
|
|
84886
85948
|
form: "single",
|
|
84887
85949
|
optional: false
|
|
84888
85950
|
}],
|
|
85951
|
+
"meter.getStatus": [{
|
|
85952
|
+
name: "deviceId",
|
|
85953
|
+
form: "single",
|
|
85954
|
+
optional: false
|
|
85955
|
+
}],
|
|
84889
85956
|
"motion.getStatus": [{
|
|
84890
85957
|
name: "deviceId",
|
|
84891
85958
|
form: "single",
|
|
@@ -86493,7 +87560,6 @@ Object.freeze({
|
|
|
86493
87560
|
"network-access": "ingress",
|
|
86494
87561
|
"smtp-provider": "email"
|
|
86495
87562
|
});
|
|
86496
|
-
DeviceType.Camera;
|
|
86497
87563
|
/**
|
|
86498
87564
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
86499
87565
|
* `z.infer`, they do not restate the shape.
|
|
@@ -86670,6 +87736,8 @@ new Map(Object.entries({
|
|
|
86670
87736
|
"detection-blind": "device-events",
|
|
86671
87737
|
"motion-noisy": "device-events",
|
|
86672
87738
|
"motion-calm": "device-events",
|
|
87739
|
+
"package-llm-silent": "device-events",
|
|
87740
|
+
"package-llm-answered": "device-events",
|
|
86673
87741
|
"recording-stalled": "device-events",
|
|
86674
87742
|
"recording-healthy": "device-events",
|
|
86675
87743
|
"recording-degraded": "device-events",
|
|
@@ -86753,6 +87821,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
86753
87821
|
label: "Motion without a subject",
|
|
86754
87822
|
kinds: ["motion-noisy", "motion-calm"]
|
|
86755
87823
|
},
|
|
87824
|
+
{
|
|
87825
|
+
id: "package-llm",
|
|
87826
|
+
family: "device-events",
|
|
87827
|
+
label: "Package confirm",
|
|
87828
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
87829
|
+
},
|
|
86756
87830
|
{
|
|
86757
87831
|
id: "recording",
|
|
86758
87832
|
family: "device-events",
|
|
@@ -86934,6 +88008,8 @@ var DEVICE_EVENTS = [
|
|
|
86934
88008
|
"detection-blind",
|
|
86935
88009
|
"motion-noisy",
|
|
86936
88010
|
"motion-calm",
|
|
88011
|
+
"package-llm-silent",
|
|
88012
|
+
"package-llm-answered",
|
|
86937
88013
|
"recording-stalled",
|
|
86938
88014
|
"recording-healthy",
|
|
86939
88015
|
"recording-degraded",
|
|
@@ -87202,6 +88278,15 @@ new Map([
|
|
|
87202
88278
|
snapshotLabel: "Cameras with constant motion now",
|
|
87203
88279
|
snapshotSection: null
|
|
87204
88280
|
},
|
|
88281
|
+
{
|
|
88282
|
+
id: "package-llm-confirm",
|
|
88283
|
+
family: "device-events",
|
|
88284
|
+
label: "Package confirm (not answering / answering again)",
|
|
88285
|
+
bad: ["package-llm-silent"],
|
|
88286
|
+
recovery: ["package-llm-answered"],
|
|
88287
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88288
|
+
snapshotSection: null
|
|
88289
|
+
},
|
|
87205
88290
|
{
|
|
87206
88291
|
id: "recording-health",
|
|
87207
88292
|
family: "device-events",
|