@camstack/addon-provider-reolink 1.2.210 → 1.2.212
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 +57 -0
- package/dist/addon.js +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.js
CHANGED
|
@@ -36,7 +36,7 @@ let node_os = require("node:os");
|
|
|
36
36
|
node_os = require_chunk.__toESM(node_os, 1);
|
|
37
37
|
let node_fs = require("node:fs");
|
|
38
38
|
node_fs = require_chunk.__toESM(node_fs, 1);
|
|
39
|
-
//#region ../types/dist/event-category-
|
|
39
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
40
40
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
41
41
|
EventCategory["SystemBoot"] = "system.boot";
|
|
42
42
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -362,6 +362,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
362
362
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
363
363
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
364
364
|
/**
|
|
365
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
366
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
367
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
368
|
+
*/
|
|
369
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
370
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
371
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
372
|
+
/**
|
|
365
373
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
366
374
|
* (a settings change via `setAgentInferenceDevices` /
|
|
367
375
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5471,7 +5479,7 @@ var ZodIssueCode = {
|
|
|
5471
5479
|
var ZodFirstPartyTypeKind;
|
|
5472
5480
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5473
5481
|
//#endregion
|
|
5474
|
-
//#region ../types/dist/sleep
|
|
5482
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5475
5483
|
/**
|
|
5476
5484
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5477
5485
|
* window to float samples (D455).
|
|
@@ -8029,6 +8037,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
8029
8037
|
}).strict();
|
|
8030
8038
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8031
8039
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8040
|
+
var READING_QUANTITIES = [
|
|
8041
|
+
"temperature",
|
|
8042
|
+
"pressure",
|
|
8043
|
+
"speed",
|
|
8044
|
+
"precipitation",
|
|
8045
|
+
"precipitation-rate",
|
|
8046
|
+
"length",
|
|
8047
|
+
"area",
|
|
8048
|
+
"illuminance",
|
|
8049
|
+
"irradiance",
|
|
8050
|
+
"power",
|
|
8051
|
+
"energy",
|
|
8052
|
+
"voltage",
|
|
8053
|
+
"current",
|
|
8054
|
+
"apparent-power",
|
|
8055
|
+
"humidity",
|
|
8056
|
+
"percentage",
|
|
8057
|
+
"concentration-volume",
|
|
8058
|
+
"concentration-mass",
|
|
8059
|
+
"concentration-ppb",
|
|
8060
|
+
"volume",
|
|
8061
|
+
"duration",
|
|
8062
|
+
"duration-ms",
|
|
8063
|
+
"information",
|
|
8064
|
+
"sound-level",
|
|
8065
|
+
"signal-level",
|
|
8066
|
+
"colour-temperature",
|
|
8067
|
+
"angle",
|
|
8068
|
+
"bitrate",
|
|
8069
|
+
"rate",
|
|
8070
|
+
"mass",
|
|
8071
|
+
"index",
|
|
8072
|
+
"ratio",
|
|
8073
|
+
"count",
|
|
8074
|
+
"none",
|
|
8075
|
+
"device"
|
|
8076
|
+
];
|
|
8077
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8078
|
+
new Set(READING_QUANTITIES);
|
|
8079
|
+
/**
|
|
8080
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8081
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8082
|
+
*/
|
|
8083
|
+
var QUANTITY_BASE = {
|
|
8084
|
+
temperature: "°C",
|
|
8085
|
+
pressure: "hPa",
|
|
8086
|
+
speed: "m/s",
|
|
8087
|
+
precipitation: "mm",
|
|
8088
|
+
"precipitation-rate": "mm/h",
|
|
8089
|
+
length: "m",
|
|
8090
|
+
area: "m²",
|
|
8091
|
+
illuminance: "lx",
|
|
8092
|
+
irradiance: "W/m²",
|
|
8093
|
+
power: "W",
|
|
8094
|
+
energy: "kWh",
|
|
8095
|
+
voltage: "V",
|
|
8096
|
+
current: "A",
|
|
8097
|
+
"apparent-power": "VA",
|
|
8098
|
+
humidity: "%",
|
|
8099
|
+
percentage: "%",
|
|
8100
|
+
"concentration-volume": "ppm",
|
|
8101
|
+
"concentration-mass": "µg/m³",
|
|
8102
|
+
"concentration-ppb": "ppb",
|
|
8103
|
+
volume: "L",
|
|
8104
|
+
duration: "s",
|
|
8105
|
+
"duration-ms": "ms",
|
|
8106
|
+
information: "B",
|
|
8107
|
+
"sound-level": "dBFS",
|
|
8108
|
+
"signal-level": "dBm",
|
|
8109
|
+
"colour-temperature": "mired",
|
|
8110
|
+
angle: "°",
|
|
8111
|
+
bitrate: "kbps",
|
|
8112
|
+
rate: "fps",
|
|
8113
|
+
mass: "kg",
|
|
8114
|
+
index: "none",
|
|
8115
|
+
ratio: "none",
|
|
8116
|
+
count: "none",
|
|
8117
|
+
none: "none",
|
|
8118
|
+
device: "device"
|
|
8119
|
+
};
|
|
8120
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8121
|
+
function baseUnitOf(quantity) {
|
|
8122
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8123
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8124
|
+
return symbol;
|
|
8125
|
+
}
|
|
8126
|
+
function readingMeta(quantity, extras) {
|
|
8127
|
+
return {
|
|
8128
|
+
quantity,
|
|
8129
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8130
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8131
|
+
};
|
|
8132
|
+
}
|
|
8032
8133
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8033
8134
|
var CamProfileSchema = _enum([
|
|
8034
8135
|
"high",
|
|
@@ -8056,8 +8157,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8056
8157
|
"derived"
|
|
8057
8158
|
]);
|
|
8058
8159
|
var CamStreamResolutionSchema = object({
|
|
8059
|
-
width: number().int().positive(),
|
|
8060
|
-
height: number().int().positive()
|
|
8160
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8161
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8061
8162
|
});
|
|
8062
8163
|
var CameraStreamSchema = object({
|
|
8063
8164
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8609,6 +8710,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8609
8710
|
"filesystem-browse",
|
|
8610
8711
|
"flood",
|
|
8611
8712
|
"gas",
|
|
8713
|
+
"group-active",
|
|
8714
|
+
"group-commands",
|
|
8715
|
+
"group-status",
|
|
8612
8716
|
"heating-valve",
|
|
8613
8717
|
"humidifier",
|
|
8614
8718
|
"humidity-sensor",
|
|
@@ -8629,6 +8733,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8629
8733
|
"login-method",
|
|
8630
8734
|
"media-player",
|
|
8631
8735
|
"mesh-network",
|
|
8736
|
+
"meter",
|
|
8632
8737
|
"metrics-provider",
|
|
8633
8738
|
"model-convert",
|
|
8634
8739
|
"model-distributor",
|
|
@@ -8738,14 +8843,6 @@ Object.freeze({
|
|
|
8738
8843
|
{
|
|
8739
8844
|
"path": "aqi",
|
|
8740
8845
|
"valueType": "number"
|
|
8741
|
-
},
|
|
8742
|
-
{
|
|
8743
|
-
"path": "unit",
|
|
8744
|
-
"valueType": "string"
|
|
8745
|
-
},
|
|
8746
|
-
{
|
|
8747
|
-
"path": "precision",
|
|
8748
|
-
"valueType": "number"
|
|
8749
8846
|
}
|
|
8750
8847
|
],
|
|
8751
8848
|
"alarm-panel": [
|
|
@@ -8781,20 +8878,10 @@ Object.freeze({
|
|
|
8781
8878
|
"valueType": "boolean"
|
|
8782
8879
|
}
|
|
8783
8880
|
],
|
|
8784
|
-
"ambient-light-sensor": [
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
},
|
|
8789
|
-
{
|
|
8790
|
-
"path": "unit",
|
|
8791
|
-
"valueType": "string"
|
|
8792
|
-
},
|
|
8793
|
-
{
|
|
8794
|
-
"path": "precision",
|
|
8795
|
-
"valueType": "number"
|
|
8796
|
-
}
|
|
8797
|
-
],
|
|
8881
|
+
"ambient-light-sensor": [{
|
|
8882
|
+
"path": "lux",
|
|
8883
|
+
"valueType": "number"
|
|
8884
|
+
}],
|
|
8798
8885
|
"audio-metrics": [
|
|
8799
8886
|
{
|
|
8800
8887
|
"path": "ts",
|
|
@@ -8874,6 +8961,10 @@ Object.freeze({
|
|
|
8874
8961
|
"path": "lastUpdated",
|
|
8875
8962
|
"valueType": "number"
|
|
8876
8963
|
},
|
|
8964
|
+
{
|
|
8965
|
+
"path": "volts",
|
|
8966
|
+
"valueType": "number"
|
|
8967
|
+
},
|
|
8877
8968
|
{
|
|
8878
8969
|
"path": "lastContactAt",
|
|
8879
8970
|
"valueType": "number"
|
|
@@ -9116,10 +9207,6 @@ Object.freeze({
|
|
|
9116
9207
|
"datetime"
|
|
9117
9208
|
]
|
|
9118
9209
|
},
|
|
9119
|
-
{
|
|
9120
|
-
"path": "unit",
|
|
9121
|
-
"valueType": "string"
|
|
9122
|
-
},
|
|
9123
9210
|
{
|
|
9124
9211
|
"path": "min",
|
|
9125
9212
|
"valueType": "number"
|
|
@@ -9131,19 +9218,6 @@ Object.freeze({
|
|
|
9131
9218
|
{
|
|
9132
9219
|
"path": "step",
|
|
9133
9220
|
"valueType": "number"
|
|
9134
|
-
},
|
|
9135
|
-
{
|
|
9136
|
-
"path": "precision",
|
|
9137
|
-
"valueType": "number"
|
|
9138
|
-
},
|
|
9139
|
-
{
|
|
9140
|
-
"path": "format",
|
|
9141
|
-
"valueType": "enum",
|
|
9142
|
-
"enumValues": [
|
|
9143
|
-
"date",
|
|
9144
|
-
"time",
|
|
9145
|
-
"datetime"
|
|
9146
|
-
]
|
|
9147
9221
|
}
|
|
9148
9222
|
],
|
|
9149
9223
|
"cover": [
|
|
@@ -9384,13 +9458,8 @@ Object.freeze({
|
|
|
9384
9458
|
"path": "value",
|
|
9385
9459
|
"valueType": "string"
|
|
9386
9460
|
}, {
|
|
9387
|
-
"path": "
|
|
9388
|
-
"valueType": "
|
|
9389
|
-
"enumValues": [
|
|
9390
|
-
"date",
|
|
9391
|
-
"time",
|
|
9392
|
-
"datetime"
|
|
9393
|
-
]
|
|
9461
|
+
"path": "timestamp",
|
|
9462
|
+
"valueType": "boolean"
|
|
9394
9463
|
}],
|
|
9395
9464
|
"event-emitter": [
|
|
9396
9465
|
{
|
|
@@ -9463,6 +9532,24 @@ Object.freeze({
|
|
|
9463
9532
|
"path": "detected",
|
|
9464
9533
|
"valueType": "boolean"
|
|
9465
9534
|
}],
|
|
9535
|
+
"group-active": [{
|
|
9536
|
+
"path": "active",
|
|
9537
|
+
"valueType": "boolean"
|
|
9538
|
+
}],
|
|
9539
|
+
"group-status": [
|
|
9540
|
+
{
|
|
9541
|
+
"path": "included",
|
|
9542
|
+
"valueType": "number"
|
|
9543
|
+
},
|
|
9544
|
+
{
|
|
9545
|
+
"path": "excluded",
|
|
9546
|
+
"valueType": "number"
|
|
9547
|
+
},
|
|
9548
|
+
{
|
|
9549
|
+
"path": "total",
|
|
9550
|
+
"valueType": "number"
|
|
9551
|
+
}
|
|
9552
|
+
],
|
|
9466
9553
|
"heating-valve": [{
|
|
9467
9554
|
"path": "position",
|
|
9468
9555
|
"valueType": "number"
|
|
@@ -9497,20 +9584,10 @@ Object.freeze({
|
|
|
9497
9584
|
"valueType": "number"
|
|
9498
9585
|
}
|
|
9499
9586
|
],
|
|
9500
|
-
"humidity-sensor": [
|
|
9501
|
-
|
|
9502
|
-
|
|
9503
|
-
|
|
9504
|
-
},
|
|
9505
|
-
{
|
|
9506
|
-
"path": "unit",
|
|
9507
|
-
"valueType": "string"
|
|
9508
|
-
},
|
|
9509
|
-
{
|
|
9510
|
-
"path": "precision",
|
|
9511
|
-
"valueType": "number"
|
|
9512
|
-
}
|
|
9513
|
-
],
|
|
9587
|
+
"humidity-sensor": [{
|
|
9588
|
+
"path": "percent",
|
|
9589
|
+
"valueType": "number"
|
|
9590
|
+
}],
|
|
9514
9591
|
"image": [{
|
|
9515
9592
|
"path": "url",
|
|
9516
9593
|
"valueType": "string"
|
|
@@ -9718,6 +9795,10 @@ Object.freeze({
|
|
|
9718
9795
|
]
|
|
9719
9796
|
}
|
|
9720
9797
|
],
|
|
9798
|
+
"meter": [{
|
|
9799
|
+
"path": "value",
|
|
9800
|
+
"valueType": "number"
|
|
9801
|
+
}],
|
|
9721
9802
|
"motion": [
|
|
9722
9803
|
{
|
|
9723
9804
|
"path": "detected",
|
|
@@ -9849,20 +9930,10 @@ Object.freeze({
|
|
|
9849
9930
|
"valueType": "boolean"
|
|
9850
9931
|
}
|
|
9851
9932
|
],
|
|
9852
|
-
"numeric-sensor": [
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
},
|
|
9857
|
-
{
|
|
9858
|
-
"path": "unit",
|
|
9859
|
-
"valueType": "string"
|
|
9860
|
-
},
|
|
9861
|
-
{
|
|
9862
|
-
"path": "precision",
|
|
9863
|
-
"valueType": "number"
|
|
9864
|
-
}
|
|
9865
|
-
],
|
|
9933
|
+
"numeric-sensor": [{
|
|
9934
|
+
"path": "value",
|
|
9935
|
+
"valueType": "number"
|
|
9936
|
+
}],
|
|
9866
9937
|
"pet-feeder": [
|
|
9867
9938
|
{
|
|
9868
9939
|
"path": "foodLevel",
|
|
@@ -9954,14 +10025,6 @@ Object.freeze({
|
|
|
9954
10025
|
{
|
|
9955
10026
|
"path": "powerFactor",
|
|
9956
10027
|
"valueType": "number"
|
|
9957
|
-
},
|
|
9958
|
-
{
|
|
9959
|
-
"path": "unit",
|
|
9960
|
-
"valueType": "string"
|
|
9961
|
-
},
|
|
9962
|
-
{
|
|
9963
|
-
"path": "precision",
|
|
9964
|
-
"valueType": "number"
|
|
9965
10028
|
}
|
|
9966
10029
|
],
|
|
9967
10030
|
"presence": [
|
|
@@ -9990,20 +10053,10 @@ Object.freeze({
|
|
|
9990
10053
|
"valueType": "number"
|
|
9991
10054
|
}
|
|
9992
10055
|
],
|
|
9993
|
-
"pressure-sensor": [
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
},
|
|
9998
|
-
{
|
|
9999
|
-
"path": "unit",
|
|
10000
|
-
"valueType": "string"
|
|
10001
|
-
},
|
|
10002
|
-
{
|
|
10003
|
-
"path": "precision",
|
|
10004
|
-
"valueType": "number"
|
|
10005
|
-
}
|
|
10006
|
-
],
|
|
10056
|
+
"pressure-sensor": [{
|
|
10057
|
+
"path": "hpa",
|
|
10058
|
+
"valueType": "number"
|
|
10059
|
+
}],
|
|
10007
10060
|
"privacy-mask": [{
|
|
10008
10061
|
"path": "enabled",
|
|
10009
10062
|
"valueType": "boolean"
|
|
@@ -10314,20 +10367,10 @@ Object.freeze({
|
|
|
10314
10367
|
"path": "tampered",
|
|
10315
10368
|
"valueType": "boolean"
|
|
10316
10369
|
}],
|
|
10317
|
-
"temperature-sensor": [
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
},
|
|
10322
|
-
{
|
|
10323
|
-
"path": "unit",
|
|
10324
|
-
"valueType": "string"
|
|
10325
|
-
},
|
|
10326
|
-
{
|
|
10327
|
-
"path": "precision",
|
|
10328
|
-
"valueType": "number"
|
|
10329
|
-
}
|
|
10330
|
-
],
|
|
10370
|
+
"temperature-sensor": [{
|
|
10371
|
+
"path": "celsius",
|
|
10372
|
+
"valueType": "number"
|
|
10373
|
+
}],
|
|
10331
10374
|
"update": [
|
|
10332
10375
|
{
|
|
10333
10376
|
"path": "currentVersion",
|
|
@@ -10438,10 +10481,6 @@ Object.freeze({
|
|
|
10438
10481
|
"path": "temperature",
|
|
10439
10482
|
"valueType": "number"
|
|
10440
10483
|
},
|
|
10441
|
-
{
|
|
10442
|
-
"path": "temperatureUnit",
|
|
10443
|
-
"valueType": "string"
|
|
10444
|
-
},
|
|
10445
10484
|
{
|
|
10446
10485
|
"path": "humidity",
|
|
10447
10486
|
"valueType": "number"
|
|
@@ -10450,18 +10489,10 @@ Object.freeze({
|
|
|
10450
10489
|
"path": "pressure",
|
|
10451
10490
|
"valueType": "number"
|
|
10452
10491
|
},
|
|
10453
|
-
{
|
|
10454
|
-
"path": "pressureUnit",
|
|
10455
|
-
"valueType": "string"
|
|
10456
|
-
},
|
|
10457
10492
|
{
|
|
10458
10493
|
"path": "windSpeed",
|
|
10459
10494
|
"valueType": "number"
|
|
10460
10495
|
},
|
|
10461
|
-
{
|
|
10462
|
-
"path": "windSpeedUnit",
|
|
10463
|
-
"valueType": "string"
|
|
10464
|
-
},
|
|
10465
10496
|
{
|
|
10466
10497
|
"path": "windBearing",
|
|
10467
10498
|
"valueType": "number"
|
|
@@ -10549,7 +10580,7 @@ function sleep$2(ms) {
|
|
|
10549
10580
|
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
10550
10581
|
}
|
|
10551
10582
|
//#endregion
|
|
10552
|
-
//#region ../types/dist/err-msg-
|
|
10583
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10553
10584
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10554
10585
|
DeviceType["Camera"] = "camera";
|
|
10555
10586
|
DeviceType["Hub"] = "hub";
|
|
@@ -10643,8 +10674,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10643
10674
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10644
10675
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10645
10676
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10646
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10677
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10678
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10647
10679
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10680
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10681
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10682
|
+
DeviceType["Washer"] = "washer";
|
|
10683
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10684
|
+
DeviceType["Dryer"] = "dryer";
|
|
10648
10685
|
return DeviceType;
|
|
10649
10686
|
}({});
|
|
10650
10687
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10892,7 +10929,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
10892
10929
|
return DeviceRole;
|
|
10893
10930
|
}({});
|
|
10894
10931
|
//#endregion
|
|
10895
|
-
//#region ../types/dist/composition-
|
|
10932
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10896
10933
|
/**
|
|
10897
10934
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10898
10935
|
*
|
|
@@ -11207,6 +11244,13 @@ var table$1 = {
|
|
|
11207
11244
|
apply: () => {
|
|
11208
11245
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11209
11246
|
}
|
|
11247
|
+
},
|
|
11248
|
+
schmitt: {
|
|
11249
|
+
minArgs: 3,
|
|
11250
|
+
maxArgs: 5,
|
|
11251
|
+
apply: () => {
|
|
11252
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11253
|
+
}
|
|
11210
11254
|
}
|
|
11211
11255
|
};
|
|
11212
11256
|
Object.freeze(Object.assign(Object.create(null), table$1));
|
|
@@ -11647,15 +11691,232 @@ function validateExpressionSource(src) {
|
|
|
11647
11691
|
}
|
|
11648
11692
|
return null;
|
|
11649
11693
|
}
|
|
11650
|
-
/**
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
|
|
11694
|
+
/**
|
|
11695
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11696
|
+
*
|
|
11697
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11698
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11699
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11700
|
+
*
|
|
11701
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11702
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11703
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11704
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11705
|
+
* can move later without moving the others.
|
|
11706
|
+
*/
|
|
11707
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11708
|
+
var APPLIANCE_KINDS = [
|
|
11709
|
+
"washer",
|
|
11710
|
+
"dryer",
|
|
11711
|
+
"dishwasher"
|
|
11712
|
+
];
|
|
11713
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11714
|
+
/**
|
|
11715
|
+
* Statistics and integrals over a history read (D944).
|
|
11716
|
+
*
|
|
11717
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11718
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11719
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11720
|
+
* as zero. A truncated read is not published.
|
|
11721
|
+
*/
|
|
11722
|
+
var STATISTIC_STATS = [
|
|
11723
|
+
"min",
|
|
11724
|
+
"max",
|
|
11725
|
+
"mean",
|
|
11726
|
+
"sum",
|
|
11727
|
+
"count",
|
|
11728
|
+
"change"
|
|
11729
|
+
];
|
|
11730
|
+
/**
|
|
11731
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11732
|
+
*
|
|
11733
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11734
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11735
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11736
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11737
|
+
*/
|
|
11738
|
+
var MINUTE_MS = 6e4;
|
|
11739
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11740
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11741
|
+
var ROLLING_SPANS = [
|
|
11742
|
+
"1h",
|
|
11743
|
+
"24h",
|
|
11744
|
+
"2d",
|
|
11745
|
+
"7d",
|
|
11746
|
+
"30d",
|
|
11747
|
+
"custom"
|
|
11748
|
+
];
|
|
11749
|
+
var CALENDAR_PERIODS = [
|
|
11750
|
+
"today",
|
|
11751
|
+
"yesterday",
|
|
11752
|
+
"this-week",
|
|
11753
|
+
"this-month"
|
|
11754
|
+
];
|
|
11755
|
+
var RESET_PERIODS = [
|
|
11756
|
+
"never",
|
|
11757
|
+
"daily",
|
|
11758
|
+
"weekly",
|
|
11759
|
+
"monthly"
|
|
11760
|
+
];
|
|
11761
|
+
5 * MINUTE_MS;
|
|
11762
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11763
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11764
|
+
var rollingWindowObject = object({
|
|
11765
|
+
kind: literal("rolling"),
|
|
11766
|
+
span: _enum(ROLLING_SPANS),
|
|
11767
|
+
customMinutes: number().int().min(5).optional()
|
|
11768
|
+
}).check((payload) => {
|
|
11769
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11770
|
+
code: "custom",
|
|
11771
|
+
message: "a custom range needs a duration in minutes",
|
|
11772
|
+
path: ["customMinutes"],
|
|
11773
|
+
input: payload.value
|
|
11774
|
+
});
|
|
11775
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11776
|
+
code: "custom",
|
|
11777
|
+
message: "only a custom range carries a duration",
|
|
11778
|
+
path: ["customMinutes"],
|
|
11779
|
+
input: payload.value
|
|
11780
|
+
});
|
|
11781
|
+
});
|
|
11782
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11783
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11784
|
+
kind: literal("calendar"),
|
|
11785
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11786
|
+
})]);
|
|
11787
|
+
/**
|
|
11788
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11789
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11790
|
+
* `composition.ts` (D659).
|
|
11791
|
+
*/
|
|
11654
11792
|
var CompositionSourceRefSchema = object({
|
|
11655
11793
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11656
11794
|
addonId: string().min(1),
|
|
11657
11795
|
stableId: string().min(1)
|
|
11658
11796
|
});
|
|
11797
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11798
|
+
"temperature",
|
|
11799
|
+
"humidity",
|
|
11800
|
+
"pressure",
|
|
11801
|
+
"illuminance",
|
|
11802
|
+
"power",
|
|
11803
|
+
"energy",
|
|
11804
|
+
"battery",
|
|
11805
|
+
"numeric",
|
|
11806
|
+
"motion",
|
|
11807
|
+
"contact",
|
|
11808
|
+
"leak",
|
|
11809
|
+
"smoke",
|
|
11810
|
+
"occupancy",
|
|
11811
|
+
"binary",
|
|
11812
|
+
"switch",
|
|
11813
|
+
"light",
|
|
11814
|
+
"fan",
|
|
11815
|
+
"cover",
|
|
11816
|
+
"valve",
|
|
11817
|
+
"lock",
|
|
11818
|
+
"media-player",
|
|
11819
|
+
"climate"
|
|
11820
|
+
];
|
|
11821
|
+
var NUMERIC_AGGREGATES = [
|
|
11822
|
+
"mean",
|
|
11823
|
+
"median",
|
|
11824
|
+
"min",
|
|
11825
|
+
"max",
|
|
11826
|
+
"sum"
|
|
11827
|
+
];
|
|
11828
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11829
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11830
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11831
|
+
var AGGREGATE_REDUCERS = [
|
|
11832
|
+
"mean",
|
|
11833
|
+
"median",
|
|
11834
|
+
"min",
|
|
11835
|
+
"max",
|
|
11836
|
+
"sum",
|
|
11837
|
+
"any",
|
|
11838
|
+
"all"
|
|
11839
|
+
];
|
|
11840
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11841
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11842
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11843
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11844
|
+
var HelperMemberSchema = object({
|
|
11845
|
+
source: CompositionSourceRefSchema,
|
|
11846
|
+
cap: string().min(1),
|
|
11847
|
+
fieldPath: string().min(1)
|
|
11848
|
+
});
|
|
11849
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11850
|
+
object({
|
|
11851
|
+
kind: literal("group"),
|
|
11852
|
+
templateId: GroupTemplateIdSchema,
|
|
11853
|
+
aggregate: AggregateReducerSchema,
|
|
11854
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11855
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11856
|
+
active: ActiveCriterionSchema.optional()
|
|
11857
|
+
}),
|
|
11858
|
+
object({
|
|
11859
|
+
kind: literal("appliance"),
|
|
11860
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11861
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11862
|
+
thresholdWatts: number().positive(),
|
|
11863
|
+
startDwellMs: number().int().nonnegative(),
|
|
11864
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11865
|
+
member: HelperMemberSchema
|
|
11866
|
+
}),
|
|
11867
|
+
object({
|
|
11868
|
+
kind: literal("statistic"),
|
|
11869
|
+
stat: _enum(STATISTIC_STATS),
|
|
11870
|
+
window: StatisticWindowSchema,
|
|
11871
|
+
source: HelperMemberSchema
|
|
11872
|
+
}),
|
|
11873
|
+
object({
|
|
11874
|
+
kind: literal("integral"),
|
|
11875
|
+
reset: _enum(RESET_PERIODS),
|
|
11876
|
+
output: _enum(["energy", "meter"]),
|
|
11877
|
+
source: HelperMemberSchema
|
|
11878
|
+
}),
|
|
11879
|
+
object({
|
|
11880
|
+
kind: literal("threshold"),
|
|
11881
|
+
source: HelperMemberSchema,
|
|
11882
|
+
high: number(),
|
|
11883
|
+
low: number(),
|
|
11884
|
+
onForMs: number().int().nonnegative(),
|
|
11885
|
+
offForMs: number().int().nonnegative()
|
|
11886
|
+
}),
|
|
11887
|
+
object({
|
|
11888
|
+
kind: literal("arithmetic"),
|
|
11889
|
+
op: _enum([
|
|
11890
|
+
"sum",
|
|
11891
|
+
"difference",
|
|
11892
|
+
"ratio"
|
|
11893
|
+
]),
|
|
11894
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11895
|
+
}),
|
|
11896
|
+
object({
|
|
11897
|
+
kind: literal("expression"),
|
|
11898
|
+
expr: string().min(1),
|
|
11899
|
+
inputs: array(object({
|
|
11900
|
+
name: string().min(1),
|
|
11901
|
+
member: HelperMemberSchema
|
|
11902
|
+
})).min(1).max(64),
|
|
11903
|
+
output: _enum(["number", "boolean"])
|
|
11904
|
+
}),
|
|
11905
|
+
object({
|
|
11906
|
+
kind: literal("derivative"),
|
|
11907
|
+
window: RollingWindowSchema,
|
|
11908
|
+
per: _enum([
|
|
11909
|
+
"second",
|
|
11910
|
+
"minute",
|
|
11911
|
+
"hour"
|
|
11912
|
+
]),
|
|
11913
|
+
source: HelperMemberSchema
|
|
11914
|
+
})
|
|
11915
|
+
]);
|
|
11916
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11917
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11918
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11919
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11659
11920
|
/** One field of one capability of one source device. */
|
|
11660
11921
|
var CompositionFieldReadSchema = object({
|
|
11661
11922
|
source: CompositionSourceRefSchema,
|
|
@@ -11699,7 +11960,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11699
11960
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11700
11961
|
CompositionFromSourceSchema,
|
|
11701
11962
|
CompositionExpressionSourceSchema,
|
|
11702
|
-
CompositionCodeSourceSchema
|
|
11963
|
+
CompositionCodeSourceSchema,
|
|
11964
|
+
object({
|
|
11965
|
+
kind: literal("aggregate"),
|
|
11966
|
+
reducer: _enum([
|
|
11967
|
+
"mean",
|
|
11968
|
+
"median",
|
|
11969
|
+
"min",
|
|
11970
|
+
"max",
|
|
11971
|
+
"sum",
|
|
11972
|
+
"any",
|
|
11973
|
+
"all"
|
|
11974
|
+
]),
|
|
11975
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11976
|
+
/**
|
|
11977
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11978
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11979
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11980
|
+
*/
|
|
11981
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11982
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11983
|
+
publish: _enum([
|
|
11984
|
+
"value",
|
|
11985
|
+
"included",
|
|
11986
|
+
"excluded",
|
|
11987
|
+
"total"
|
|
11988
|
+
]),
|
|
11989
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11990
|
+
empty: _enum([
|
|
11991
|
+
"null",
|
|
11992
|
+
"omit",
|
|
11993
|
+
"offline"
|
|
11994
|
+
])
|
|
11995
|
+
}),
|
|
11996
|
+
object({
|
|
11997
|
+
kind: literal("series"),
|
|
11998
|
+
read: CompositionFieldReadSchema,
|
|
11999
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12000
|
+
publish: _enum([
|
|
12001
|
+
"value",
|
|
12002
|
+
"included",
|
|
12003
|
+
"excluded",
|
|
12004
|
+
"total"
|
|
12005
|
+
]),
|
|
12006
|
+
/**
|
|
12007
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12008
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12009
|
+
*/
|
|
12010
|
+
empty: _enum([
|
|
12011
|
+
"null",
|
|
12012
|
+
"omit",
|
|
12013
|
+
"offline"
|
|
12014
|
+
])
|
|
12015
|
+
})
|
|
11703
12016
|
]);
|
|
11704
12017
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11705
12018
|
kind: literal("forward"),
|
|
@@ -11745,7 +12058,13 @@ var CompositionSchema = object({
|
|
|
11745
12058
|
kind: literal("existing"),
|
|
11746
12059
|
device: CompositionSourceRefSchema
|
|
11747
12060
|
})]),
|
|
11748
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12061
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12062
|
+
/**
|
|
12063
|
+
* Present when the block is a helper template. Absent on a free
|
|
12064
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12065
|
+
* never the compiled features.
|
|
12066
|
+
*/
|
|
12067
|
+
helper: HelperSpecSchema.optional()
|
|
11749
12068
|
}).superRefine((composition, ctx) => {
|
|
11750
12069
|
const seen = /* @__PURE__ */ new Set();
|
|
11751
12070
|
composition.features.forEach((feature, index) => {
|
|
@@ -17422,7 +17741,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17422
17741
|
*/
|
|
17423
17742
|
interactiveConnectPath: string().min(1).optional(),
|
|
17424
17743
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17425
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17744
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17745
|
+
/**
|
|
17746
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17747
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17748
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17749
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17750
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17751
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17752
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17753
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17754
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17755
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17756
|
+
* offers it as the default path; the fields the session fills are
|
|
17757
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17758
|
+
*/
|
|
17759
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17426
17760
|
}))
|
|
17427
17761
|
});
|
|
17428
17762
|
var ListInputSchema = object({
|
|
@@ -18523,7 +18857,12 @@ var CompositionProblemSchema = object({
|
|
|
18523
18857
|
"item-field-reserved",
|
|
18524
18858
|
"target-missing",
|
|
18525
18859
|
"target-unreadable",
|
|
18526
|
-
"not-replaceable"
|
|
18860
|
+
"not-replaceable",
|
|
18861
|
+
"native-capability-replace",
|
|
18862
|
+
"mixed-quantity",
|
|
18863
|
+
"helper-mismatch",
|
|
18864
|
+
"member-constraint",
|
|
18865
|
+
"retention"
|
|
18527
18866
|
]),
|
|
18528
18867
|
path: string(),
|
|
18529
18868
|
message: string()
|
|
@@ -18544,7 +18883,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18544
18883
|
"null",
|
|
18545
18884
|
"offline",
|
|
18546
18885
|
"unknown",
|
|
18547
|
-
"release"
|
|
18886
|
+
"release",
|
|
18887
|
+
"omit"
|
|
18548
18888
|
]);
|
|
18549
18889
|
/**
|
|
18550
18890
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18581,9 +18921,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18581
18921
|
reads: array(CompositionFieldReadSchema)
|
|
18582
18922
|
});
|
|
18583
18923
|
/**
|
|
18584
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18585
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18586
|
-
*
|
|
18924
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18925
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18926
|
+
* Replacing a capability the device already serves is refused
|
|
18927
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18928
|
+
* wire for a claim the hub already holds.
|
|
18587
18929
|
*/
|
|
18588
18930
|
var CompositionFeatureModeSchema = _enum([
|
|
18589
18931
|
"new",
|
|
@@ -18754,8 +19096,392 @@ Object.freeze({
|
|
|
18754
19096
|
latchedAt: {
|
|
18755
19097
|
kind: "fixed",
|
|
18756
19098
|
result: ["number", "null"]
|
|
19099
|
+
},
|
|
19100
|
+
schmitt: {
|
|
19101
|
+
kind: "fixed",
|
|
19102
|
+
result: ["boolean", "null"]
|
|
18757
19103
|
}
|
|
18758
19104
|
});
|
|
19105
|
+
/**
|
|
19106
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19107
|
+
* Data, not a form default written into the block.
|
|
19108
|
+
*/
|
|
19109
|
+
var NOW$2 = {
|
|
19110
|
+
fieldPath: "lastFetchedAt",
|
|
19111
|
+
expr: "now"
|
|
19112
|
+
};
|
|
19113
|
+
var CHANGED = {
|
|
19114
|
+
fieldPath: "lastChangedAt",
|
|
19115
|
+
expr: "now"
|
|
19116
|
+
};
|
|
19117
|
+
function numeric(input) {
|
|
19118
|
+
return {
|
|
19119
|
+
...input,
|
|
19120
|
+
family: "numeric",
|
|
19121
|
+
deviceType: DeviceType.Sensor,
|
|
19122
|
+
memberDeviceType: DeviceType.Sensor,
|
|
19123
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19124
|
+
activeWhen: void 0,
|
|
19125
|
+
commandCaps: [],
|
|
19126
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
19127
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
19128
|
+
accept: [{
|
|
19129
|
+
cap: input.outputCap,
|
|
19130
|
+
fieldPath: input.outputField
|
|
19131
|
+
}]
|
|
19132
|
+
};
|
|
19133
|
+
}
|
|
19134
|
+
function binary(input) {
|
|
19135
|
+
return {
|
|
19136
|
+
...input,
|
|
19137
|
+
family: "binary",
|
|
19138
|
+
deviceType: DeviceType.Sensor,
|
|
19139
|
+
memberDeviceType: DeviceType.Sensor,
|
|
19140
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19141
|
+
activeWhen: void 0,
|
|
19142
|
+
commandCaps: [],
|
|
19143
|
+
quantity: "none",
|
|
19144
|
+
baseUnit: void 0,
|
|
19145
|
+
aggregates: BINARY_AGGREGATES,
|
|
19146
|
+
empty: "offline"
|
|
19147
|
+
};
|
|
19148
|
+
}
|
|
19149
|
+
var GROUP_TEMPLATES = [
|
|
19150
|
+
numeric({
|
|
19151
|
+
id: "temperature",
|
|
19152
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
19153
|
+
role: DeviceRole.TemperatureSensor,
|
|
19154
|
+
outputCap: "temperature-sensor",
|
|
19155
|
+
outputField: "celsius",
|
|
19156
|
+
quantity: "temperature",
|
|
19157
|
+
defaultAggregate: "mean",
|
|
19158
|
+
empty: "null",
|
|
19159
|
+
companions: [NOW$2]
|
|
19160
|
+
}),
|
|
19161
|
+
numeric({
|
|
19162
|
+
id: "humidity",
|
|
19163
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19164
|
+
role: DeviceRole.HumiditySensor,
|
|
19165
|
+
outputCap: "humidity-sensor",
|
|
19166
|
+
outputField: "percent",
|
|
19167
|
+
quantity: "humidity",
|
|
19168
|
+
defaultAggregate: "mean",
|
|
19169
|
+
empty: "null",
|
|
19170
|
+
companions: [NOW$2]
|
|
19171
|
+
}),
|
|
19172
|
+
numeric({
|
|
19173
|
+
id: "pressure",
|
|
19174
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
19175
|
+
role: DeviceRole.PressureSensor,
|
|
19176
|
+
outputCap: "pressure-sensor",
|
|
19177
|
+
outputField: "hpa",
|
|
19178
|
+
quantity: "pressure",
|
|
19179
|
+
defaultAggregate: "mean",
|
|
19180
|
+
empty: "null",
|
|
19181
|
+
companions: [NOW$2]
|
|
19182
|
+
}),
|
|
19183
|
+
numeric({
|
|
19184
|
+
id: "illuminance",
|
|
19185
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
19186
|
+
role: DeviceRole.AmbientLightSensor,
|
|
19187
|
+
outputCap: "ambient-light-sensor",
|
|
19188
|
+
outputField: "lux",
|
|
19189
|
+
quantity: "illuminance",
|
|
19190
|
+
defaultAggregate: "mean",
|
|
19191
|
+
empty: "null",
|
|
19192
|
+
companions: [NOW$2]
|
|
19193
|
+
}),
|
|
19194
|
+
numeric({
|
|
19195
|
+
id: "power",
|
|
19196
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
19197
|
+
role: DeviceRole.PowerSensor,
|
|
19198
|
+
outputCap: "power-meter",
|
|
19199
|
+
outputField: "watts",
|
|
19200
|
+
quantity: "power",
|
|
19201
|
+
defaultAggregate: "sum",
|
|
19202
|
+
empty: "omit",
|
|
19203
|
+
companions: [NOW$2]
|
|
19204
|
+
}),
|
|
19205
|
+
numeric({
|
|
19206
|
+
id: "energy",
|
|
19207
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
19208
|
+
role: DeviceRole.EnergySensor,
|
|
19209
|
+
outputCap: "power-meter",
|
|
19210
|
+
outputField: "kwhTotal",
|
|
19211
|
+
quantity: "energy",
|
|
19212
|
+
defaultAggregate: "sum",
|
|
19213
|
+
empty: "omit",
|
|
19214
|
+
companions: [NOW$2]
|
|
19215
|
+
}),
|
|
19216
|
+
numeric({
|
|
19217
|
+
id: "battery",
|
|
19218
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19219
|
+
role: DeviceRole.BatterySensor,
|
|
19220
|
+
outputCap: "battery",
|
|
19221
|
+
outputField: "percentage",
|
|
19222
|
+
quantity: "percentage",
|
|
19223
|
+
defaultAggregate: "mean",
|
|
19224
|
+
empty: "null",
|
|
19225
|
+
companions: [
|
|
19226
|
+
{
|
|
19227
|
+
fieldPath: "charging",
|
|
19228
|
+
expr: "\"unknown\""
|
|
19229
|
+
},
|
|
19230
|
+
{
|
|
19231
|
+
fieldPath: "sleeping",
|
|
19232
|
+
expr: "false"
|
|
19233
|
+
},
|
|
19234
|
+
{
|
|
19235
|
+
fieldPath: "lastUpdated",
|
|
19236
|
+
expr: "now"
|
|
19237
|
+
}
|
|
19238
|
+
]
|
|
19239
|
+
}),
|
|
19240
|
+
numeric({
|
|
19241
|
+
id: "numeric",
|
|
19242
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
19243
|
+
role: DeviceRole.NumericSensor,
|
|
19244
|
+
outputCap: "numeric-sensor",
|
|
19245
|
+
outputField: "value",
|
|
19246
|
+
quantity: "device",
|
|
19247
|
+
defaultAggregate: "mean",
|
|
19248
|
+
empty: "null",
|
|
19249
|
+
companions: [NOW$2]
|
|
19250
|
+
}),
|
|
19251
|
+
binary({
|
|
19252
|
+
id: "motion",
|
|
19253
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
19254
|
+
role: DeviceRole.MotionSensor,
|
|
19255
|
+
outputCap: "motion",
|
|
19256
|
+
outputField: "detected",
|
|
19257
|
+
defaultAggregate: "any",
|
|
19258
|
+
accept: [{
|
|
19259
|
+
cap: "motion",
|
|
19260
|
+
fieldPath: "detected"
|
|
19261
|
+
}],
|
|
19262
|
+
companions: [{
|
|
19263
|
+
fieldPath: "lastDetectedAt",
|
|
19264
|
+
expr: "null"
|
|
19265
|
+
}, {
|
|
19266
|
+
fieldPath: "autoClearAfterMs",
|
|
19267
|
+
expr: "null"
|
|
19268
|
+
}]
|
|
19269
|
+
}),
|
|
19270
|
+
binary({
|
|
19271
|
+
id: "contact",
|
|
19272
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
19273
|
+
role: DeviceRole.ContactSensor,
|
|
19274
|
+
outputCap: "contact",
|
|
19275
|
+
outputField: "entryOpen",
|
|
19276
|
+
defaultAggregate: "any",
|
|
19277
|
+
accept: [{
|
|
19278
|
+
cap: "contact",
|
|
19279
|
+
fieldPath: "entryOpen"
|
|
19280
|
+
}],
|
|
19281
|
+
companions: [CHANGED]
|
|
19282
|
+
}),
|
|
19283
|
+
binary({
|
|
19284
|
+
id: "leak",
|
|
19285
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
19286
|
+
role: DeviceRole.LeakSensor,
|
|
19287
|
+
outputCap: "flood",
|
|
19288
|
+
outputField: "flooded",
|
|
19289
|
+
defaultAggregate: "any",
|
|
19290
|
+
accept: [{
|
|
19291
|
+
cap: "flood",
|
|
19292
|
+
fieldPath: "flooded"
|
|
19293
|
+
}],
|
|
19294
|
+
companions: [CHANGED]
|
|
19295
|
+
}),
|
|
19296
|
+
binary({
|
|
19297
|
+
id: "smoke",
|
|
19298
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
19299
|
+
role: DeviceRole.SmokeSensor,
|
|
19300
|
+
outputCap: "smoke",
|
|
19301
|
+
outputField: "detected",
|
|
19302
|
+
defaultAggregate: "any",
|
|
19303
|
+
accept: [{
|
|
19304
|
+
cap: "smoke",
|
|
19305
|
+
fieldPath: "detected"
|
|
19306
|
+
}],
|
|
19307
|
+
companions: [CHANGED]
|
|
19308
|
+
}),
|
|
19309
|
+
binary({
|
|
19310
|
+
id: "occupancy",
|
|
19311
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
19312
|
+
role: DeviceRole.BinarySensor,
|
|
19313
|
+
outputCap: "binary",
|
|
19314
|
+
outputField: "on",
|
|
19315
|
+
defaultAggregate: "any",
|
|
19316
|
+
accept: [{
|
|
19317
|
+
cap: "motion",
|
|
19318
|
+
fieldPath: "detected"
|
|
19319
|
+
}, {
|
|
19320
|
+
cap: "binary",
|
|
19321
|
+
fieldPath: "on"
|
|
19322
|
+
}],
|
|
19323
|
+
companions: [CHANGED]
|
|
19324
|
+
}),
|
|
19325
|
+
binary({
|
|
19326
|
+
id: "binary",
|
|
19327
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
19328
|
+
role: DeviceRole.BinarySensor,
|
|
19329
|
+
outputCap: "binary",
|
|
19330
|
+
outputField: "on",
|
|
19331
|
+
defaultAggregate: "any",
|
|
19332
|
+
accept: [{
|
|
19333
|
+
cap: "binary",
|
|
19334
|
+
fieldPath: "on"
|
|
19335
|
+
}],
|
|
19336
|
+
companions: [CHANGED]
|
|
19337
|
+
}),
|
|
19338
|
+
actuator({
|
|
19339
|
+
id: "switch",
|
|
19340
|
+
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.",
|
|
19341
|
+
deviceType: DeviceType.Switch,
|
|
19342
|
+
outputCap: "switch",
|
|
19343
|
+
outputField: "on",
|
|
19344
|
+
member: {
|
|
19345
|
+
cap: "switch",
|
|
19346
|
+
fieldPath: "on"
|
|
19347
|
+
},
|
|
19348
|
+
commandCaps: ["switch"]
|
|
19349
|
+
}),
|
|
19350
|
+
actuator({
|
|
19351
|
+
id: "light",
|
|
19352
|
+
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.",
|
|
19353
|
+
deviceType: DeviceType.Light,
|
|
19354
|
+
outputCap: "switch",
|
|
19355
|
+
outputField: "on",
|
|
19356
|
+
member: {
|
|
19357
|
+
cap: "switch",
|
|
19358
|
+
fieldPath: "on"
|
|
19359
|
+
},
|
|
19360
|
+
commandCaps: [
|
|
19361
|
+
"switch",
|
|
19362
|
+
"brightness",
|
|
19363
|
+
"color"
|
|
19364
|
+
]
|
|
19365
|
+
}),
|
|
19366
|
+
actuator({
|
|
19367
|
+
id: "fan",
|
|
19368
|
+
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.",
|
|
19369
|
+
deviceType: DeviceType.Fan,
|
|
19370
|
+
outputCap: "switch",
|
|
19371
|
+
outputField: "on",
|
|
19372
|
+
member: {
|
|
19373
|
+
cap: "switch",
|
|
19374
|
+
fieldPath: "on"
|
|
19375
|
+
},
|
|
19376
|
+
commandCaps: ["switch", "fan-control"]
|
|
19377
|
+
}),
|
|
19378
|
+
actuator({
|
|
19379
|
+
id: "cover",
|
|
19380
|
+
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.",
|
|
19381
|
+
deviceType: DeviceType.Cover,
|
|
19382
|
+
outputCap: "group-active",
|
|
19383
|
+
outputField: "active",
|
|
19384
|
+
member: {
|
|
19385
|
+
cap: "cover",
|
|
19386
|
+
fieldPath: "state"
|
|
19387
|
+
},
|
|
19388
|
+
activeWhen: [
|
|
19389
|
+
"open",
|
|
19390
|
+
"opening",
|
|
19391
|
+
"stopped"
|
|
19392
|
+
],
|
|
19393
|
+
commandCaps: ["cover"]
|
|
19394
|
+
}),
|
|
19395
|
+
actuator({
|
|
19396
|
+
id: "valve",
|
|
19397
|
+
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.",
|
|
19398
|
+
deviceType: DeviceType.Valve,
|
|
19399
|
+
outputCap: "group-active",
|
|
19400
|
+
outputField: "active",
|
|
19401
|
+
member: {
|
|
19402
|
+
cap: "valve",
|
|
19403
|
+
fieldPath: "state"
|
|
19404
|
+
},
|
|
19405
|
+
activeWhen: [
|
|
19406
|
+
"open",
|
|
19407
|
+
"opening",
|
|
19408
|
+
"stopped"
|
|
19409
|
+
],
|
|
19410
|
+
commandCaps: ["valve"]
|
|
19411
|
+
}),
|
|
19412
|
+
actuator({
|
|
19413
|
+
id: "lock",
|
|
19414
|
+
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.",
|
|
19415
|
+
deviceType: DeviceType.Lock,
|
|
19416
|
+
outputCap: "group-active",
|
|
19417
|
+
outputField: "active",
|
|
19418
|
+
member: {
|
|
19419
|
+
cap: "lock-control",
|
|
19420
|
+
fieldPath: "state"
|
|
19421
|
+
},
|
|
19422
|
+
activeWhen: ["locked"],
|
|
19423
|
+
commandCaps: ["lock-control"]
|
|
19424
|
+
}),
|
|
19425
|
+
actuator({
|
|
19426
|
+
id: "media-player",
|
|
19427
|
+
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.",
|
|
19428
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19429
|
+
outputCap: "group-active",
|
|
19430
|
+
outputField: "active",
|
|
19431
|
+
member: {
|
|
19432
|
+
cap: "media-player",
|
|
19433
|
+
fieldPath: "state"
|
|
19434
|
+
},
|
|
19435
|
+
activeWhen: ["playing", "buffering"],
|
|
19436
|
+
commandCaps: ["media-player"]
|
|
19437
|
+
}),
|
|
19438
|
+
actuator({
|
|
19439
|
+
id: "climate",
|
|
19440
|
+
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.",
|
|
19441
|
+
deviceType: DeviceType.Thermostat,
|
|
19442
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19443
|
+
outputCap: "group-active",
|
|
19444
|
+
outputField: "active",
|
|
19445
|
+
member: {
|
|
19446
|
+
cap: "climate-control",
|
|
19447
|
+
fieldPath: "mode"
|
|
19448
|
+
},
|
|
19449
|
+
activeWhen: [
|
|
19450
|
+
"heat",
|
|
19451
|
+
"cool",
|
|
19452
|
+
"auto",
|
|
19453
|
+
"heat_cool",
|
|
19454
|
+
"fan_only",
|
|
19455
|
+
"dry"
|
|
19456
|
+
],
|
|
19457
|
+
commandCaps: ["climate-control"]
|
|
19458
|
+
})
|
|
19459
|
+
];
|
|
19460
|
+
function actuator(input) {
|
|
19461
|
+
return {
|
|
19462
|
+
id: input.id,
|
|
19463
|
+
summary: input.summary,
|
|
19464
|
+
deviceType: input.deviceType,
|
|
19465
|
+
outputCap: input.outputCap,
|
|
19466
|
+
outputField: input.outputField,
|
|
19467
|
+
commandCaps: input.commandCaps,
|
|
19468
|
+
family: "actuator",
|
|
19469
|
+
role: void 0,
|
|
19470
|
+
memberDeviceType: input.deviceType,
|
|
19471
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19472
|
+
activeWhen: input.activeWhen,
|
|
19473
|
+
quantity: "none",
|
|
19474
|
+
baseUnit: void 0,
|
|
19475
|
+
aggregates: BINARY_AGGREGATES,
|
|
19476
|
+
defaultAggregate: "any",
|
|
19477
|
+
empty: "offline",
|
|
19478
|
+
accept: [input.member],
|
|
19479
|
+
companions: [CHANGED]
|
|
19480
|
+
};
|
|
19481
|
+
}
|
|
19482
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19483
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19484
|
+
DeviceType.Camera;
|
|
18759
19485
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18760
19486
|
/**
|
|
18761
19487
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20582,12 +21308,12 @@ function buildDeviceAdminUrl(parts) {
|
|
|
20582
21308
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20583
21309
|
* in-place so dispatch keeps working.
|
|
20584
21310
|
*
|
|
20585
|
-
* **
|
|
20586
|
-
*
|
|
20587
|
-
*
|
|
20588
|
-
*
|
|
20589
|
-
* (`ha-domain-mapping`)
|
|
20590
|
-
* stored after that point.
|
|
21311
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
21312
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
21313
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
21314
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
21315
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
21316
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20591
21317
|
*
|
|
20592
21318
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20593
21319
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20601,6 +21327,14 @@ var SourceInfoSchema = object({
|
|
|
20601
21327
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20602
21328
|
* Used to detect rename when `id` changes. */
|
|
20603
21329
|
uniqueId: string().optional(),
|
|
21330
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
21331
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
21332
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
21333
|
+
dateTimeShape: _enum([
|
|
21334
|
+
"date",
|
|
21335
|
+
"time",
|
|
21336
|
+
"datetime"
|
|
21337
|
+
]).optional(),
|
|
20604
21338
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20605
21339
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20606
21340
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41705,7 +42439,8 @@ method(object({
|
|
|
41705
42439
|
"enum"
|
|
41706
42440
|
]),
|
|
41707
42441
|
enumValues: array(string()).optional(),
|
|
41708
|
-
item: boolean().optional()
|
|
42442
|
+
item: boolean().optional(),
|
|
42443
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41709
42444
|
})).readonly(),
|
|
41710
42445
|
itemArray: object({
|
|
41711
42446
|
path: string(),
|
|
@@ -44106,7 +44841,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
44106
44841
|
});
|
|
44107
44842
|
/**
|
|
44108
44843
|
* Optional, richer endpoint shape returned by providers that expose
|
|
44109
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44844
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
44110
44845
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
44111
44846
|
* the originating provider config (mode + sourcePort) so the
|
|
44112
44847
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -45589,8 +46324,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
45589
46324
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
45590
46325
|
var MaskGridShapeSchema = object({
|
|
45591
46326
|
kind: literal("grid"),
|
|
45592
|
-
gridWidth: number(),
|
|
45593
|
-
gridHeight: number(),
|
|
46327
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
46328
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
45594
46329
|
cells: array(boolean())
|
|
45595
46330
|
});
|
|
45596
46331
|
discriminatedUnion("kind", [
|
|
@@ -45702,6 +46437,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45702
46437
|
"detection-blind",
|
|
45703
46438
|
"motion-noisy",
|
|
45704
46439
|
"motion-calm",
|
|
46440
|
+
"package-llm-silent",
|
|
46441
|
+
"package-llm-answered",
|
|
45705
46442
|
"recording-stalled",
|
|
45706
46443
|
"recording-healthy",
|
|
45707
46444
|
"recording-degraded",
|
|
@@ -46791,7 +47528,20 @@ var NcRuleInputSchema = object({
|
|
|
46791
47528
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46792
47529
|
* path does not run Zod defaults.
|
|
46793
47530
|
*/
|
|
46794
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
47531
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
47532
|
+
/**
|
|
47533
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
47534
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
47535
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
47536
|
+
* same mark the Library writes, and records whose notification it was and
|
|
47537
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
47538
|
+
*
|
|
47539
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
47540
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
47541
|
+
* authored before this field meant. An editor turns it off by writing
|
|
47542
|
+
* `false`, so it needs no `clear` key.
|
|
47543
|
+
*/
|
|
47544
|
+
askVerdict: boolean().optional()
|
|
46795
47545
|
});
|
|
46796
47546
|
/**
|
|
46797
47547
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -57315,6 +58065,28 @@ var PackageVersionInfoSchema = object({
|
|
|
57315
58065
|
deprecated: string().optional(),
|
|
57316
58066
|
distTags: array(string()).readonly()
|
|
57317
58067
|
});
|
|
58068
|
+
/**
|
|
58069
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
58070
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
58071
|
+
* tarball failure — never an empty string standing in for either.
|
|
58072
|
+
*/
|
|
58073
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
58074
|
+
object({
|
|
58075
|
+
status: literal("ok"),
|
|
58076
|
+
markdown: string()
|
|
58077
|
+
}),
|
|
58078
|
+
object({ status: literal("missing") }),
|
|
58079
|
+
object({
|
|
58080
|
+
status: literal("error"),
|
|
58081
|
+
message: string()
|
|
58082
|
+
})
|
|
58083
|
+
]);
|
|
58084
|
+
var PackageDocsSchema = object({
|
|
58085
|
+
name: string(),
|
|
58086
|
+
version: string(),
|
|
58087
|
+
readme: PackageDocBodySchema,
|
|
58088
|
+
changelog: PackageDocBodySchema
|
|
58089
|
+
});
|
|
57318
58090
|
var SearchResultSchema = object({
|
|
57319
58091
|
name: string(),
|
|
57320
58092
|
version: string(),
|
|
@@ -57533,7 +58305,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
57533
58305
|
}), object({ success: literal(true) }), {
|
|
57534
58306
|
kind: "mutation",
|
|
57535
58307
|
auth: "admin"
|
|
57536
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
58308
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
58309
|
+
name: string().min(1),
|
|
58310
|
+
version: string().min(1).optional()
|
|
58311
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
57537
58312
|
kind: "mutation",
|
|
57538
58313
|
auth: "admin"
|
|
57539
58314
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -57592,27 +58367,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
57592
58367
|
*/
|
|
57593
58368
|
var AirQualitySensorStatusSchema = object({
|
|
57594
58369
|
/** Carbon dioxide concentration in ppm. */
|
|
57595
|
-
co2Ppm: number().min(0).optional(),
|
|
58370
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
57596
58371
|
/** Total volatile organic compounds in ppb. */
|
|
57597
|
-
vocPpb: number().min(0).optional(),
|
|
58372
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
57598
58373
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
57599
|
-
pm25: number().min(0).optional(),
|
|
58374
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
57600
58375
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
57601
|
-
pm10: number().min(0).optional(),
|
|
58376
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
57602
58377
|
/** Composite AQI value (typically 0..500). */
|
|
57603
|
-
aqi: number().optional(),
|
|
58378
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
57604
58379
|
/** Ms epoch when the slice was last updated. */
|
|
57605
|
-
lastFetchedAt: number()
|
|
57606
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
57607
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
57608
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
57609
|
-
* per slice is unambiguous. */
|
|
57610
|
-
unit: string().optional(),
|
|
57611
|
-
/** Suggested decimal places for numeric display.
|
|
57612
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57613
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57614
|
-
* auto-formatting when absent. */
|
|
57615
|
-
precision: number().int().min(0).max(10).optional()
|
|
58380
|
+
lastFetchedAt: number()
|
|
57616
58381
|
});
|
|
57617
58382
|
var airQualitySensorCapability = {
|
|
57618
58383
|
name: "air-quality-sensor",
|
|
@@ -57649,12 +58414,12 @@ var airQualitySensorCapability = {
|
|
|
57649
58414
|
},
|
|
57650
58415
|
pm25: {
|
|
57651
58416
|
kind: "gauge",
|
|
57652
|
-
unit: "
|
|
58417
|
+
unit: "µg/m³",
|
|
57653
58418
|
deadband: 1
|
|
57654
58419
|
},
|
|
57655
58420
|
pm10: {
|
|
57656
58421
|
kind: "gauge",
|
|
57657
|
-
unit: "
|
|
58422
|
+
unit: "µg/m³",
|
|
57658
58423
|
deadband: 1
|
|
57659
58424
|
},
|
|
57660
58425
|
aqi: {
|
|
@@ -57672,22 +58437,13 @@ var airQualitySensorCapability = {
|
|
|
57672
58437
|
* entries with `device_class: illuminance`.
|
|
57673
58438
|
*/
|
|
57674
58439
|
var AmbientLightSensorStatusSchema = object({
|
|
57675
|
-
/** Current illuminance in lux (lx). */
|
|
57676
|
-
lux: number().min(0).meta({
|
|
57677
|
-
|
|
58440
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
58441
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
58442
|
+
precision: 0,
|
|
57678
58443
|
label: "Illuminance"
|
|
57679
|
-
}),
|
|
58444
|
+
})),
|
|
57680
58445
|
/** Ms epoch when the slice was last updated. */
|
|
57681
|
-
lastFetchedAt: number()
|
|
57682
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
57683
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
57684
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
57685
|
-
unit: string().optional(),
|
|
57686
|
-
/** Suggested decimal places for numeric display.
|
|
57687
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57688
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57689
|
-
* auto-formatting when absent. */
|
|
57690
|
-
precision: number().int().min(0).max(10).optional()
|
|
58446
|
+
lastFetchedAt: number()
|
|
57691
58447
|
});
|
|
57692
58448
|
var ambientLightSensorCapability = {
|
|
57693
58449
|
name: "ambient-light-sensor",
|
|
@@ -57719,12 +58475,7 @@ var ambientLightSensorCapability = {
|
|
|
57719
58475
|
} } },
|
|
57720
58476
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57721
58477
|
* whether persisting is worth a SQLite commit. */
|
|
57722
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
57723
|
-
customize: {
|
|
57724
|
-
version: 1,
|
|
57725
|
-
advanced: "derive",
|
|
57726
|
-
targets: []
|
|
57727
|
-
}
|
|
58478
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
57728
58479
|
};
|
|
57729
58480
|
/**
|
|
57730
58481
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -57951,10 +58702,7 @@ var BatteryStatusSchema = object({
|
|
|
57951
58702
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
57952
58703
|
* declines to band a non-finite reading, which is the correct shape.
|
|
57953
58704
|
*/
|
|
57954
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
57955
|
-
unit: "%",
|
|
57956
|
-
label: "Charge"
|
|
57957
|
-
}),
|
|
58705
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
57958
58706
|
/**
|
|
57959
58707
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
57960
58708
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -57981,7 +58729,14 @@ var BatteryStatusSchema = object({
|
|
|
57981
58729
|
*/
|
|
57982
58730
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
57983
58731
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
57984
|
-
lastUpdated: number(),
|
|
58732
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
58733
|
+
/**
|
|
58734
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
58735
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
58736
|
+
* that only report charge. A second reading on this cap, not a second
|
|
58737
|
+
* `numeric-sensor` on the same device.
|
|
58738
|
+
*/
|
|
58739
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
57985
58740
|
/**
|
|
57986
58741
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
57987
58742
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -58028,12 +58783,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
58028
58783
|
DeviceType.Switch,
|
|
58029
58784
|
DeviceType.PetFeeder,
|
|
58030
58785
|
DeviceType.Container,
|
|
58031
|
-
DeviceType.Thermostat
|
|
58786
|
+
DeviceType.Thermostat,
|
|
58787
|
+
DeviceType.EventEmitter
|
|
58032
58788
|
];
|
|
58033
58789
|
/** Generic Customize target for the percentage reading (D936). */
|
|
58034
58790
|
var batteryCustomize = {
|
|
58035
58791
|
version: 1,
|
|
58036
|
-
advanced: "derive",
|
|
58037
58792
|
targets: [{
|
|
58038
58793
|
id: "percentage",
|
|
58039
58794
|
cardinality: "scalar",
|
|
@@ -58042,7 +58797,7 @@ var batteryCustomize = {
|
|
|
58042
58797
|
stateField: "percentage"
|
|
58043
58798
|
},
|
|
58044
58799
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
58045
|
-
apply: "add
|
|
58800
|
+
apply: "add",
|
|
58046
58801
|
path: "percentage",
|
|
58047
58802
|
sources: [{
|
|
58048
58803
|
kind: "field",
|
|
@@ -58163,10 +58918,16 @@ onStatusChanged: { data: object({
|
|
|
58163
58918
|
/**
|
|
58164
58919
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
58165
58920
|
*/
|
|
58166
|
-
history: { fields: {
|
|
58167
|
-
|
|
58168
|
-
|
|
58169
|
-
|
|
58921
|
+
history: { fields: {
|
|
58922
|
+
percentage: {
|
|
58923
|
+
kind: "gauge",
|
|
58924
|
+
unit: "%"
|
|
58925
|
+
},
|
|
58926
|
+
volts: {
|
|
58927
|
+
kind: "gauge",
|
|
58928
|
+
unit: "V"
|
|
58929
|
+
}
|
|
58930
|
+
} },
|
|
58170
58931
|
customize: batteryCustomize,
|
|
58171
58932
|
/** Clock fields: written, but excluded from the compare that decides
|
|
58172
58933
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -58213,12 +58974,7 @@ var binaryCapability = {
|
|
|
58213
58974
|
history: { fields: { on: { kind: "boolean" } } },
|
|
58214
58975
|
/** Clock fields: written, but excluded from the compare that decides
|
|
58215
58976
|
* whether persisting is worth a SQLite commit. */
|
|
58216
|
-
volatileStateFields: ["lastChangedAt"]
|
|
58217
|
-
customize: {
|
|
58218
|
-
version: 1,
|
|
58219
|
-
advanced: "derive",
|
|
58220
|
-
targets: []
|
|
58221
|
-
}
|
|
58977
|
+
volatileStateFields: ["lastChangedAt"]
|
|
58222
58978
|
};
|
|
58223
58979
|
/**
|
|
58224
58980
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -58234,7 +58990,7 @@ var binaryCapability = {
|
|
|
58234
58990
|
*/
|
|
58235
58991
|
var BrightnessStatusSchema = object({
|
|
58236
58992
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
58237
|
-
percentage: number().min(0).max(100),
|
|
58993
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
58238
58994
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
58239
58995
|
lastChangedAt: number()
|
|
58240
58996
|
});
|
|
@@ -58688,21 +59444,21 @@ var ClimateControlStatusSchema = object({
|
|
|
58688
59444
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
58689
59445
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
58690
59446
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
58691
|
-
target: number().nullable(),
|
|
59447
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
58692
59448
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
58693
59449
|
* in `heat_cool` mode. */
|
|
58694
|
-
targetHigh: number().nullable(),
|
|
59450
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
58695
59451
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
58696
59452
|
* in `heat_cool` mode. */
|
|
58697
|
-
targetLow: number().nullable(),
|
|
59453
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
58698
59454
|
/** Target relative humidity (0..100). Null when the device has no
|
|
58699
59455
|
* humidity control. */
|
|
58700
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59456
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58701
59457
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
58702
59458
|
* the device's internal sensor. */
|
|
58703
|
-
currentTemp: number().nullable(),
|
|
59459
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
58704
59460
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
58705
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59461
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58706
59462
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
58707
59463
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
58708
59464
|
swingVertical: boolean().nullable(),
|
|
@@ -58710,11 +59466,11 @@ var ClimateControlStatusSchema = object({
|
|
|
58710
59466
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
58711
59467
|
swingHorizontal: boolean().nullable(),
|
|
58712
59468
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58713
|
-
minTemp: number().nullable().optional(),
|
|
59469
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58714
59470
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58715
|
-
maxTemp: number().nullable().optional(),
|
|
59471
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58716
59472
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
58717
|
-
tempStep: number().positive().nullable().optional(),
|
|
59473
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
58718
59474
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
58719
59475
|
lastFetchedAt: number()
|
|
58720
59476
|
});
|
|
@@ -58856,17 +59612,17 @@ var climateControlCapability = {
|
|
|
58856
59612
|
* modes to expose in the picker without a slice fetch.
|
|
58857
59613
|
*/
|
|
58858
59614
|
var RgbTripletSchema = object({
|
|
58859
|
-
r: number().int().min(0).max(255),
|
|
58860
|
-
g: number().int().min(0).max(255),
|
|
58861
|
-
b: number().int().min(0).max(255)
|
|
59615
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
59616
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
59617
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
58862
59618
|
});
|
|
58863
59619
|
var HsvTripletSchema = object({
|
|
58864
59620
|
/** Hue in degrees, 0..360. */
|
|
58865
|
-
h: number().min(0).max(360),
|
|
59621
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
58866
59622
|
/** Saturation as 0..100 inclusive. */
|
|
58867
|
-
s: number().min(0).max(100),
|
|
59623
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
58868
59624
|
/** Value/brightness as 0..100 inclusive. */
|
|
58869
|
-
v: number().min(0).max(100)
|
|
59625
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
58870
59626
|
});
|
|
58871
59627
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
58872
59628
|
object({
|
|
@@ -58895,7 +59651,7 @@ var ColorStatusSchema = object({
|
|
|
58895
59651
|
/** Populated when `mode === 'hsv'`. */
|
|
58896
59652
|
hsv: HsvTripletSchema.optional(),
|
|
58897
59653
|
/** Populated when `mode === 'mired'`. */
|
|
58898
|
-
mireds: number().int().optional(),
|
|
59654
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
58899
59655
|
/** Ms epoch of the last operator-driven change. */
|
|
58900
59656
|
lastChangedAt: number()
|
|
58901
59657
|
});
|
|
@@ -59090,18 +59846,12 @@ _enum([
|
|
|
59090
59846
|
"empty",
|
|
59091
59847
|
"full"
|
|
59092
59848
|
]);
|
|
59093
|
-
/**
|
|
59094
|
-
|
|
59095
|
-
|
|
59096
|
-
"days",
|
|
59097
|
-
"hours",
|
|
59098
|
-
"cycles"
|
|
59099
|
-
]);
|
|
59100
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
59101
|
-
* days). `value` null = unknown (D393). */
|
|
59849
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
59850
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
59851
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
59102
59852
|
var ConsumableRemainingSchema = object({
|
|
59103
|
-
value: number().min(0).nullable(),
|
|
59104
|
-
|
|
59853
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
59854
|
+
kind: ConsumableRemainingKindSchema
|
|
59105
59855
|
});
|
|
59106
59856
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
59107
59857
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -59114,7 +59864,7 @@ var ConsumableItemSchema = object({
|
|
|
59114
59864
|
/** Display name. */
|
|
59115
59865
|
label: string().min(1),
|
|
59116
59866
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
59117
|
-
level: number().min(0).max(100).nullable(),
|
|
59867
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59118
59868
|
/** The provider's discrete verdict when known (binary mode). */
|
|
59119
59869
|
status: ConsumableStatusSchema.nullable(),
|
|
59120
59870
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -59196,8 +59946,8 @@ var consumablesCustomize = {
|
|
|
59196
59946
|
transforms: [{ kind: "identity" }]
|
|
59197
59947
|
}],
|
|
59198
59948
|
literals: [{
|
|
59199
|
-
path: "remaining.
|
|
59200
|
-
values: [...
|
|
59949
|
+
path: "remaining.kind",
|
|
59950
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
59201
59951
|
}]
|
|
59202
59952
|
},
|
|
59203
59953
|
{
|
|
@@ -59326,7 +60076,6 @@ reset: method(object({
|
|
|
59326
60076
|
},
|
|
59327
60077
|
"remaining.value": {
|
|
59328
60078
|
kind: "gauge",
|
|
59329
|
-
unitFrom: "remaining.unit",
|
|
59330
60079
|
deadband: 1,
|
|
59331
60080
|
displayName: "Remaining"
|
|
59332
60081
|
}
|
|
@@ -59396,10 +60145,9 @@ var contactCapability = {
|
|
|
59396
60145
|
* (empty array for the other kinds). It lives in the slice because
|
|
59397
60146
|
* HA `select.*` entities may update their options at runtime.
|
|
59398
60147
|
*
|
|
59399
|
-
*
|
|
59400
|
-
*
|
|
59401
|
-
*
|
|
59402
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
60148
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
60149
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
60150
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
59403
60151
|
*/
|
|
59404
60152
|
var ControlStatusSchema = object({
|
|
59405
60153
|
kind: _enum([
|
|
@@ -59411,39 +60159,17 @@ var ControlStatusSchema = object({
|
|
|
59411
60159
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
59412
60160
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
59413
60161
|
* or time-only — HA accepts all three forms). */
|
|
59414
|
-
value: union([number(), string()]),
|
|
60162
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
59415
60163
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
59416
60164
|
options: array(string()),
|
|
59417
60165
|
/** Ms epoch when the slice was last updated. */
|
|
59418
60166
|
lastChangedAt: number(),
|
|
59419
|
-
/**
|
|
59420
|
-
|
|
59421
|
-
|
|
59422
|
-
|
|
59423
|
-
/**
|
|
59424
|
-
|
|
59425
|
-
min: number().optional(),
|
|
59426
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
59427
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
59428
|
-
max: number().optional(),
|
|
59429
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
59430
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
59431
|
-
step: number().optional(),
|
|
59432
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
59433
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
59434
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
59435
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
59436
|
-
precision: number().int().min(0).max(10).optional(),
|
|
59437
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
59438
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
59439
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
59440
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
59441
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
59442
|
-
format: _enum([
|
|
59443
|
-
"date",
|
|
59444
|
-
"time",
|
|
59445
|
-
"datetime"
|
|
59446
|
-
]).optional()
|
|
60167
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
60168
|
+
min: number().optional().meta(readingMeta("device")),
|
|
60169
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
60170
|
+
max: number().optional().meta(readingMeta("device")),
|
|
60171
|
+
/** Step increment, in the device quantity's base unit. */
|
|
60172
|
+
step: number().optional().meta(readingMeta("device"))
|
|
59447
60173
|
});
|
|
59448
60174
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
59449
60175
|
object({
|
|
@@ -59509,9 +60235,9 @@ var CoverStatusSchema = object({
|
|
|
59509
60235
|
]),
|
|
59510
60236
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
59511
60237
|
* no intermediate position surface. */
|
|
59512
|
-
position: number().min(0).max(100).nullable(),
|
|
60238
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59513
60239
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
59514
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
60240
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59515
60241
|
/** Ms epoch when the slice was last updated. */
|
|
59516
60242
|
lastChangedAt: number()
|
|
59517
60243
|
});
|
|
@@ -59614,9 +60340,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
59614
60340
|
var DayNightStatusSchema = object({
|
|
59615
60341
|
mode: DayNightModeSchema,
|
|
59616
60342
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
59617
|
-
sensitivity: number().optional(),
|
|
60343
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
59618
60344
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
59619
|
-
switchDelaySec: number().optional(),
|
|
60345
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
59620
60346
|
lastFetchedAt: number()
|
|
59621
60347
|
});
|
|
59622
60348
|
/**
|
|
@@ -59834,11 +60560,11 @@ var DishwasherStatusSchema = object({
|
|
|
59834
60560
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
59835
60561
|
availablePrograms: array(string()),
|
|
59836
60562
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
59837
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
60563
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59838
60564
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
59839
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
60565
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59840
60566
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
59841
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
60567
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59842
60568
|
/** True when the door is reported open; null when the door state is not known. */
|
|
59843
60569
|
doorOpen: boolean().nullable(),
|
|
59844
60570
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -59862,7 +60588,7 @@ var DishwasherStatusSchema = object({
|
|
|
59862
60588
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
59863
60589
|
machineCareDue: boolean().nullable(),
|
|
59864
60590
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
59865
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
60591
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
59866
60592
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
59867
60593
|
halfLoad: boolean().nullable(),
|
|
59868
60594
|
hygienePlus: boolean().nullable(),
|
|
@@ -59877,7 +60603,7 @@ var DishwasherStatusSchema = object({
|
|
|
59877
60603
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
59878
60604
|
activeEvents: array(string()),
|
|
59879
60605
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
59880
|
-
errorCode: number().nullable(),
|
|
60606
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
59881
60607
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
59882
60608
|
errorLabel: string().nullable(),
|
|
59883
60609
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -60108,7 +60834,7 @@ var DoorbellStatusSchema = object({
|
|
|
60108
60834
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
60109
60835
|
lastPressedAt: number().nullable(),
|
|
60110
60836
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
60111
|
-
pressCountSinceStart: number()
|
|
60837
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
60112
60838
|
});
|
|
60113
60839
|
var DoorbellPressEventSchema = object({
|
|
60114
60840
|
deviceId: number(),
|
|
@@ -60173,17 +60899,7 @@ onPressed: {
|
|
|
60173
60899
|
history: "none",
|
|
60174
60900
|
customize: doorbellCustomize
|
|
60175
60901
|
};
|
|
60176
|
-
|
|
60177
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
60178
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
60179
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
60180
|
-
* The option set is stable across observations; it is persisted in the
|
|
60181
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
60182
|
-
* stored in `sourceInfo`.
|
|
60183
|
-
*/
|
|
60184
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
60185
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
60186
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
60902
|
+
_enum([
|
|
60187
60903
|
"date",
|
|
60188
60904
|
"time",
|
|
60189
60905
|
"datetime"
|
|
@@ -60191,12 +60907,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
60191
60907
|
var EnumSensorStatusSchema = object({
|
|
60192
60908
|
value: string(),
|
|
60193
60909
|
/**
|
|
60194
|
-
* Set
|
|
60195
|
-
* as
|
|
60196
|
-
*
|
|
60197
|
-
* a time-only sensor → `'time'`.
|
|
60910
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
60911
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
60912
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
60198
60913
|
*/
|
|
60199
|
-
|
|
60914
|
+
timestamp: boolean().optional(),
|
|
60200
60915
|
/** Ms epoch when the slice was last updated. */
|
|
60201
60916
|
lastFetchedAt: number()
|
|
60202
60917
|
});
|
|
@@ -60223,11 +60938,11 @@ var enumSensorCapability = {
|
|
|
60223
60938
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
60224
60939
|
* operation state, an HVAC action). The option set is per device, so the
|
|
60225
60940
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
60226
|
-
* `
|
|
60941
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
60227
60942
|
*/
|
|
60228
60943
|
history: { fields: { value: {
|
|
60229
60944
|
kind: "enum",
|
|
60230
|
-
skipWhenSet: "
|
|
60945
|
+
skipWhenSet: "timestamp"
|
|
60231
60946
|
} } },
|
|
60232
60947
|
/** Clock fields: written, but excluded from the compare that decides
|
|
60233
60948
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -60247,13 +60962,13 @@ var EventFireSchema = object({
|
|
|
60247
60962
|
deviceId: number(),
|
|
60248
60963
|
eventType: string(),
|
|
60249
60964
|
data: record(string(), unknown()).nullable(),
|
|
60250
|
-
timestamp: number(),
|
|
60251
|
-
seq: number()
|
|
60965
|
+
timestamp: number().meta(readingMeta("none")),
|
|
60966
|
+
seq: number().meta(readingMeta("count"))
|
|
60252
60967
|
});
|
|
60253
60968
|
var EventEmitterStatusSchema = object({
|
|
60254
60969
|
eventTypes: array(string()),
|
|
60255
60970
|
lastEvent: EventFireSchema.nullable(),
|
|
60256
|
-
eventCountSinceStart: number()
|
|
60971
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
60257
60972
|
});
|
|
60258
60973
|
var eventEmitterCapability = {
|
|
60259
60974
|
name: "event-emitter",
|
|
@@ -60666,10 +61381,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
60666
61381
|
var FanControlStatusSchema = object({
|
|
60667
61382
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
60668
61383
|
* speed surface (single-speed fan). */
|
|
60669
|
-
percentage: number().min(0).max(100).nullable(),
|
|
61384
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60670
61385
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
60671
61386
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
60672
|
-
percentageStep: number().positive().optional(),
|
|
61387
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
60673
61388
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
60674
61389
|
* — empty string when no preset is active or supported. */
|
|
60675
61390
|
preset: string(),
|
|
@@ -60790,7 +61505,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
60790
61505
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
60791
61506
|
model: string().nullable(),
|
|
60792
61507
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
60793
|
-
channelCount: number().nullable(),
|
|
61508
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
60794
61509
|
/**
|
|
60795
61510
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
60796
61511
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -60913,9 +61628,151 @@ var gasCapability = {
|
|
|
60913
61628
|
* whether persisting is worth a SQLite commit. */
|
|
60914
61629
|
volatileStateFields: ["lastChangedAt"]
|
|
60915
61630
|
};
|
|
61631
|
+
var GroupCommandsSchema = object({
|
|
61632
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
61633
|
+
results: array(object({
|
|
61634
|
+
deviceId: number().int().nonnegative(),
|
|
61635
|
+
cap: string().min(1),
|
|
61636
|
+
method: string().min(1),
|
|
61637
|
+
ok: boolean(),
|
|
61638
|
+
error: string().optional(),
|
|
61639
|
+
/** Ms epoch of the attempt. */
|
|
61640
|
+
at: number()
|
|
61641
|
+
})) });
|
|
61642
|
+
var groupCommandsCapability = {
|
|
61643
|
+
name: "group-commands",
|
|
61644
|
+
scope: "device",
|
|
61645
|
+
deviceNative: true,
|
|
61646
|
+
mode: "singleton",
|
|
61647
|
+
deviceTypes: [
|
|
61648
|
+
DeviceType.Switch,
|
|
61649
|
+
DeviceType.Light,
|
|
61650
|
+
DeviceType.Fan,
|
|
61651
|
+
DeviceType.Cover,
|
|
61652
|
+
DeviceType.Valve,
|
|
61653
|
+
DeviceType.Lock,
|
|
61654
|
+
DeviceType.MediaPlayer,
|
|
61655
|
+
DeviceType.Thermostat,
|
|
61656
|
+
DeviceType.Climate
|
|
61657
|
+
],
|
|
61658
|
+
methods: {},
|
|
61659
|
+
status: {
|
|
61660
|
+
schema: GroupCommandsSchema,
|
|
61661
|
+
kind: "push"
|
|
61662
|
+
},
|
|
61663
|
+
runtimeState: GroupCommandsSchema,
|
|
61664
|
+
/**
|
|
61665
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
61666
|
+
* failure would outlive the command that caused it.
|
|
61667
|
+
*
|
|
61668
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61669
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61670
|
+
*/
|
|
61671
|
+
durability: "session",
|
|
61672
|
+
history: "none"
|
|
61673
|
+
};
|
|
61674
|
+
/**
|
|
61675
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
61676
|
+
* included member is, or every included member is. What "active" means is the
|
|
61677
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
61678
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
61679
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
61680
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
61681
|
+
* empty included set takes the device offline, never `active: false`.
|
|
61682
|
+
*/
|
|
61683
|
+
var GroupActiveSchema = object({
|
|
61684
|
+
active: boolean().meta({ label: "Active" }),
|
|
61685
|
+
/** Ms epoch when the slice was last updated. */
|
|
61686
|
+
lastChangedAt: number()
|
|
61687
|
+
});
|
|
61688
|
+
var groupActiveCapability = {
|
|
61689
|
+
name: "group-active",
|
|
61690
|
+
scope: "device",
|
|
61691
|
+
deviceNative: true,
|
|
61692
|
+
mode: "singleton",
|
|
61693
|
+
deviceTypes: [
|
|
61694
|
+
DeviceType.Cover,
|
|
61695
|
+
DeviceType.Valve,
|
|
61696
|
+
DeviceType.Lock,
|
|
61697
|
+
DeviceType.MediaPlayer,
|
|
61698
|
+
DeviceType.Climate,
|
|
61699
|
+
DeviceType.Thermostat
|
|
61700
|
+
],
|
|
61701
|
+
methods: {},
|
|
61702
|
+
status: {
|
|
61703
|
+
schema: GroupActiveSchema,
|
|
61704
|
+
kind: "push"
|
|
61705
|
+
},
|
|
61706
|
+
runtimeState: GroupActiveSchema,
|
|
61707
|
+
/**
|
|
61708
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
61709
|
+
* next source event; a restored value would outlive the members it named.
|
|
61710
|
+
*
|
|
61711
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61712
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61713
|
+
*/
|
|
61714
|
+
durability: "session",
|
|
61715
|
+
history: "none"
|
|
61716
|
+
};
|
|
61717
|
+
/**
|
|
61718
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
61719
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
61720
|
+
* The reading itself stays on the output capability. History is none — the
|
|
61721
|
+
* series that later statistics read is the output cap's own history block.
|
|
61722
|
+
*/
|
|
61723
|
+
var GroupStatusSchema = object({
|
|
61724
|
+
/** Members whose current value entered the aggregate. */
|
|
61725
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
61726
|
+
precision: 0,
|
|
61727
|
+
label: "Reporting"
|
|
61728
|
+
})),
|
|
61729
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
61730
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
61731
|
+
precision: 0,
|
|
61732
|
+
label: "Excluded"
|
|
61733
|
+
})),
|
|
61734
|
+
/** `included` + `excluded`. */
|
|
61735
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
61736
|
+
precision: 0,
|
|
61737
|
+
label: "Members"
|
|
61738
|
+
}))
|
|
61739
|
+
});
|
|
61740
|
+
var groupStatusCapability = {
|
|
61741
|
+
name: "group-status",
|
|
61742
|
+
scope: "device",
|
|
61743
|
+
deviceNative: true,
|
|
61744
|
+
mode: "singleton",
|
|
61745
|
+
deviceTypes: [
|
|
61746
|
+
DeviceType.Sensor,
|
|
61747
|
+
DeviceType.Switch,
|
|
61748
|
+
DeviceType.Light,
|
|
61749
|
+
DeviceType.Fan,
|
|
61750
|
+
DeviceType.Cover,
|
|
61751
|
+
DeviceType.Valve,
|
|
61752
|
+
DeviceType.Lock,
|
|
61753
|
+
DeviceType.MediaPlayer,
|
|
61754
|
+
DeviceType.Thermostat,
|
|
61755
|
+
DeviceType.Climate
|
|
61756
|
+
],
|
|
61757
|
+
methods: {},
|
|
61758
|
+
status: {
|
|
61759
|
+
schema: GroupStatusSchema,
|
|
61760
|
+
kind: "push"
|
|
61761
|
+
},
|
|
61762
|
+
runtimeState: GroupStatusSchema,
|
|
61763
|
+
/**
|
|
61764
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
61765
|
+
* next source event; a restored count would outlive the readings it named.
|
|
61766
|
+
*
|
|
61767
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61768
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61769
|
+
*/
|
|
61770
|
+
durability: "session",
|
|
61771
|
+
history: "none"
|
|
61772
|
+
};
|
|
60916
61773
|
var HeatingValveStatusSchema = object({
|
|
60917
61774
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
60918
|
-
position: number().min(0).max(100).nullable(),
|
|
61775
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60919
61776
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
60920
61777
|
lastFetchedAt: number()
|
|
60921
61778
|
});
|
|
@@ -60958,9 +61815,9 @@ var HumidifierStatusSchema = object({
|
|
|
60958
61815
|
/** Whether the humidifier is currently on. */
|
|
60959
61816
|
on: boolean(),
|
|
60960
61817
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
60961
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
61818
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60962
61819
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
60963
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
61820
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60964
61821
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
60965
61822
|
* device has no mode surface. */
|
|
60966
61823
|
mode: string().nullable(),
|
|
@@ -60970,9 +61827,9 @@ var HumidifierStatusSchema = object({
|
|
|
60970
61827
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
60971
61828
|
action: string().nullable(),
|
|
60972
61829
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
60973
|
-
minHumidity: number().nullable(),
|
|
61830
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60974
61831
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
60975
|
-
maxHumidity: number().nullable(),
|
|
61832
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60976
61833
|
/** Ms epoch when the slice was last updated. */
|
|
60977
61834
|
lastChangedAt: number()
|
|
60978
61835
|
});
|
|
@@ -61042,22 +61899,13 @@ var humidifierCapability = {
|
|
|
61042
61899
|
* `sourceInfo`.
|
|
61043
61900
|
*/
|
|
61044
61901
|
var HumiditySensorStatusSchema = object({
|
|
61045
|
-
/** Current relative humidity, 0..100. */
|
|
61046
|
-
percent: number().min(0).max(100).meta({
|
|
61047
|
-
|
|
61902
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
61903
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
61904
|
+
precision: 0,
|
|
61048
61905
|
label: "Humidity"
|
|
61049
|
-
}),
|
|
61906
|
+
})),
|
|
61050
61907
|
/** Ms epoch when the slice was last updated. */
|
|
61051
|
-
lastFetchedAt: number()
|
|
61052
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61053
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61054
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61055
|
-
unit: string().optional(),
|
|
61056
|
-
/** Suggested decimal places for numeric display.
|
|
61057
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61058
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61059
|
-
* auto-formatting when absent. */
|
|
61060
|
-
precision: number().int().min(0).max(10).optional()
|
|
61908
|
+
lastFetchedAt: number()
|
|
61061
61909
|
});
|
|
61062
61910
|
var humiditySensorCapability = {
|
|
61063
61911
|
name: "humidity-sensor",
|
|
@@ -61088,12 +61936,7 @@ var humiditySensorCapability = {
|
|
|
61088
61936
|
} } },
|
|
61089
61937
|
/** Clock fields: written, but excluded from the compare that decides
|
|
61090
61938
|
* whether persisting is worth a SQLite commit. */
|
|
61091
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
61092
|
-
customize: {
|
|
61093
|
-
version: 1,
|
|
61094
|
-
advanced: "derive",
|
|
61095
|
-
targets: []
|
|
61096
|
-
}
|
|
61939
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
61097
61940
|
};
|
|
61098
61941
|
/**
|
|
61099
61942
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -61114,7 +61957,7 @@ var ImageStatusSchema = object({
|
|
|
61114
61957
|
* entity exposes no `entity_picture` (yet). */
|
|
61115
61958
|
url: string().nullable(),
|
|
61116
61959
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
61117
|
-
lastUpdated: number().nullable()
|
|
61960
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
61118
61961
|
});
|
|
61119
61962
|
var imageCapability = {
|
|
61120
61963
|
name: "image",
|
|
@@ -61202,19 +62045,19 @@ var NormalizedRangeSchema = object({
|
|
|
61202
62045
|
*/
|
|
61203
62046
|
var ImageSettingsStatusSchema = object({
|
|
61204
62047
|
/** Normalized 0–100. */
|
|
61205
|
-
brightness: number().optional(),
|
|
62048
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
61206
62049
|
/** Normalized 0–100. */
|
|
61207
|
-
contrast: number().optional(),
|
|
62050
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
61208
62051
|
/** Normalized 0–100. */
|
|
61209
|
-
saturation: number().optional(),
|
|
62052
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
61210
62053
|
/** Normalized 0–100. */
|
|
61211
|
-
sharpness: number().optional(),
|
|
62054
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
61212
62055
|
mirror: boolean().optional(),
|
|
61213
62056
|
flip: boolean().optional(),
|
|
61214
62057
|
rotate: ImageRotateSchema.optional(),
|
|
61215
62058
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
61216
62059
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
61217
|
-
warmth: number().optional(),
|
|
62060
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
61218
62061
|
exposureMode: ExposureModeSchema.optional(),
|
|
61219
62062
|
backlightMode: BacklightModeSchema.optional(),
|
|
61220
62063
|
lastFetchedAt: number()
|
|
@@ -61493,10 +62336,10 @@ var IntercomAbilitySchema = object({
|
|
|
61493
62336
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
61494
62337
|
codecs: array(string()),
|
|
61495
62338
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
61496
|
-
sampleRate: number(),
|
|
62339
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
61497
62340
|
duplex: _enum(["half", "full"]),
|
|
61498
62341
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
61499
|
-
maxBacklogMs: number()
|
|
62342
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
61500
62343
|
});
|
|
61501
62344
|
var IntercomStatusSchema = object({
|
|
61502
62345
|
/** True while a talk session is open. */
|
|
@@ -61723,13 +62566,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
61723
62566
|
activity: LawnMowerActivitySchema,
|
|
61724
62567
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
61725
62568
|
* reading. */
|
|
61726
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
62569
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61727
62570
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
61728
62571
|
* task is active / progress is unavailable. */
|
|
61729
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
62572
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61730
62573
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
61731
62574
|
* or null when unknown. */
|
|
61732
|
-
currentCode: number().nullable(),
|
|
62575
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
61733
62576
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
61734
62577
|
currentCodeLabel: string().nullable(),
|
|
61735
62578
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -62182,7 +63025,14 @@ var lockControlCapability = {
|
|
|
62182
63025
|
}),
|
|
62183
63026
|
unlock: method(object({
|
|
62184
63027
|
deviceId: number().int().nonnegative(),
|
|
62185
|
-
code: string().min(1).optional()
|
|
63028
|
+
code: string().min(1).optional(),
|
|
63029
|
+
/**
|
|
63030
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
63031
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
63032
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
63033
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
63034
|
+
*/
|
|
63035
|
+
confirm: boolean().optional()
|
|
62186
63036
|
}), _void(), {
|
|
62187
63037
|
kind: "mutation",
|
|
62188
63038
|
auth: "protected"
|
|
@@ -62219,6 +63069,44 @@ var lockControlCapability = {
|
|
|
62219
63069
|
volatileStateFields: ["lastChangedAt"]
|
|
62220
63070
|
};
|
|
62221
63071
|
/**
|
|
63072
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
63073
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
63074
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
63075
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
63076
|
+
*/
|
|
63077
|
+
var MeterStatusSchema = object({
|
|
63078
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
63079
|
+
lastFetchedAt: number()
|
|
63080
|
+
});
|
|
63081
|
+
var meterCapability = {
|
|
63082
|
+
name: "meter",
|
|
63083
|
+
scope: "device",
|
|
63084
|
+
deviceNative: true,
|
|
63085
|
+
mode: "singleton",
|
|
63086
|
+
deviceTypes: [DeviceType.Sensor],
|
|
63087
|
+
methods: {},
|
|
63088
|
+
status: {
|
|
63089
|
+
schema: MeterStatusSchema,
|
|
63090
|
+
kind: "push"
|
|
63091
|
+
},
|
|
63092
|
+
runtimeState: MeterStatusSchema,
|
|
63093
|
+
/**
|
|
63094
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
63095
|
+
* history integral. A restart shows it only until the history pass
|
|
63096
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
63097
|
+
*
|
|
63098
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
63099
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
63100
|
+
*/
|
|
63101
|
+
durability: "restored",
|
|
63102
|
+
history: { fields: { value: {
|
|
63103
|
+
kind: "counter",
|
|
63104
|
+
deadband: .001,
|
|
63105
|
+
minIntervalMs: 6e4
|
|
63106
|
+
} } },
|
|
63107
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
63108
|
+
};
|
|
63109
|
+
/**
|
|
62222
63110
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
62223
63111
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
62224
63112
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -62262,7 +63150,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
62262
63150
|
state: MediaPlayerStateSchema,
|
|
62263
63151
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
62264
63152
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
62265
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
63153
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62266
63154
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
62267
63155
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
62268
63156
|
isMuted: boolean().nullable(),
|
|
@@ -62275,10 +63163,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
62275
63163
|
currentMedia: MediaInfoSchema.nullable(),
|
|
62276
63164
|
/** Current playback position in ms. Null when not seekable or
|
|
62277
63165
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
62278
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
63166
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
62279
63167
|
/** Total duration of the current media in ms. Null when unknown
|
|
62280
63168
|
* (live stream) or nothing is playing. */
|
|
62281
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
63169
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
62282
63170
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
62283
63171
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
62284
63172
|
shuffle: boolean().nullable(),
|
|
@@ -62587,7 +63475,7 @@ var motionCustomize = {
|
|
|
62587
63475
|
eventName: "onMotionChanged"
|
|
62588
63476
|
},
|
|
62589
63477
|
deviceTypes: [DeviceType.Camera],
|
|
62590
|
-
apply: "
|
|
63478
|
+
apply: "add",
|
|
62591
63479
|
applyAuthority: {
|
|
62592
63480
|
kind: "camera-sensors",
|
|
62593
63481
|
timeoutField: "motionCooldownMs"
|
|
@@ -62659,7 +63547,7 @@ var MotionStatusSchema = object({
|
|
|
62659
63547
|
* it, every provider seeded it at boot, and every session left it
|
|
62660
63548
|
* `detected: true` after its detach.
|
|
62661
63549
|
*/
|
|
62662
|
-
autoClearAfterMs: number().nullable()
|
|
63550
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
62663
63551
|
});
|
|
62664
63552
|
/**
|
|
62665
63553
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -62696,12 +63584,18 @@ var motionCapability = {
|
|
|
62696
63584
|
methods: {
|
|
62697
63585
|
/**
|
|
62698
63586
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
62699
|
-
* for consumers that don't need the full status object
|
|
62700
|
-
*
|
|
62701
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
62702
|
-
* consumer.
|
|
63587
|
+
* for consumers that don't need the full status object. A composed
|
|
63588
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
62703
63589
|
*/
|
|
62704
63590
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
63591
|
+
/**
|
|
63592
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
63593
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
63594
|
+
*/
|
|
63595
|
+
composedMethods: { isDetected: {
|
|
63596
|
+
kind: "slice",
|
|
63597
|
+
field: "detected"
|
|
63598
|
+
} },
|
|
62705
63599
|
events: {
|
|
62706
63600
|
/**
|
|
62707
63601
|
* Fires every time the runner transitions a camera between
|
|
@@ -62841,7 +63735,7 @@ var MotionZoneRegionSchema = object({
|
|
|
62841
63735
|
* the grid region(s). */
|
|
62842
63736
|
var MotionZoneStatusSchema = object({
|
|
62843
63737
|
enabled: boolean(),
|
|
62844
|
-
sensitivity: number(),
|
|
63738
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
62845
63739
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
62846
63740
|
regions: array(MotionZoneRegionSchema),
|
|
62847
63741
|
lastFetchedAt: number()
|
|
@@ -63211,7 +64105,7 @@ var NavigationStatusSchema = object({
|
|
|
63211
64105
|
following: boolean(),
|
|
63212
64106
|
flash: boolean(),
|
|
63213
64107
|
lightMode: NavigationLightModeSchema,
|
|
63214
|
-
lightLevel: number().min(40).max(100),
|
|
64108
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
63215
64109
|
/** Ms epoch when the slice was last updated. */
|
|
63216
64110
|
lastChangedAt: number()
|
|
63217
64111
|
});
|
|
@@ -63345,13 +64239,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
63345
64239
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
63346
64240
|
* SKIP a null rather than coerce it.
|
|
63347
64241
|
*/
|
|
63348
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
64242
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63349
64243
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
63350
|
-
rssiDbm: number().optional(),
|
|
64244
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
63351
64245
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
63352
64246
|
ssid: string().optional(),
|
|
63353
64247
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
63354
|
-
lastUpdated: number()
|
|
64248
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
63355
64249
|
});
|
|
63356
64250
|
/** The slice a provider seeds before its first read: nothing is known yet. */
|
|
63357
64251
|
var NETWORK_LINK_UNKNOWN = {
|
|
@@ -63756,7 +64650,7 @@ var NotifierStatusSchema = object({
|
|
|
63756
64650
|
lastError: string().nullable(),
|
|
63757
64651
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
63758
64652
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
63759
|
-
queueDepth: number().int().nonnegative(),
|
|
64653
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
63760
64654
|
/** Per-feature capability matrix — authoritative source for the
|
|
63761
64655
|
* compose-form field gating. */
|
|
63762
64656
|
supports: NotifierSupportsSchema
|
|
@@ -63848,11 +64742,9 @@ onSent: { data: object({
|
|
|
63848
64742
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
63849
64743
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
63850
64744
|
*
|
|
63851
|
-
* The
|
|
63852
|
-
*
|
|
63853
|
-
*
|
|
63854
|
-
* The UI reads them directly from the slice — they are the single source
|
|
63855
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
64745
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
64746
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
64747
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
63856
64748
|
*
|
|
63857
64749
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
63858
64750
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -63861,15 +64753,8 @@ onSent: { data: object({
|
|
|
63861
64753
|
* numeric values land here.
|
|
63862
64754
|
*/
|
|
63863
64755
|
var NumericSensorStatusSchema = object({
|
|
63864
|
-
|
|
63865
|
-
|
|
63866
|
-
* Populated live from the upstream source on each state push.
|
|
63867
|
-
* Absent for unitless sensors. */
|
|
63868
|
-
unit: string().optional(),
|
|
63869
|
-
/** Suggested decimal places for numeric display.
|
|
63870
|
-
* Populated live from the upstream source when provided.
|
|
63871
|
-
* Falls back to auto-formatting when absent. */
|
|
63872
|
-
precision: number().int().min(0).max(10).optional(),
|
|
64756
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
64757
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
63873
64758
|
/** Ms epoch when the slice was last updated. */
|
|
63874
64759
|
lastFetchedAt: number()
|
|
63875
64760
|
});
|
|
@@ -63893,11 +64778,11 @@ var numericSensorCapability = {
|
|
|
63893
64778
|
*/
|
|
63894
64779
|
durability: "restored",
|
|
63895
64780
|
/**
|
|
63896
|
-
* History (D850): recorded series. The unit is
|
|
64781
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
64782
|
+
* resolved when the series is read — the cap has no single unit.
|
|
63897
64783
|
*/
|
|
63898
64784
|
history: { fields: { value: {
|
|
63899
64785
|
kind: "gauge",
|
|
63900
|
-
unitFrom: "unit",
|
|
63901
64786
|
minIntervalMs: 3e4
|
|
63902
64787
|
} } },
|
|
63903
64788
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -64235,23 +65120,26 @@ var PetFeederStatusSchema = object({
|
|
|
64235
65120
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
64236
65121
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
64237
65122
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
64238
|
-
foodLevel: number().nullable(),
|
|
65123
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
64239
65124
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
64240
65125
|
* single-hopper models. */
|
|
64241
|
-
food1: number().nullable(),
|
|
65126
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
64242
65127
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
64243
65128
|
* single-hopper models. */
|
|
64244
|
-
food2: number().nullable(),
|
|
65129
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
64245
65130
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
64246
65131
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
64247
65132
|
* below the feeder's low threshold. */
|
|
64248
65133
|
lowFood: boolean(),
|
|
64249
65134
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
64250
65135
|
* device has no battery reading. */
|
|
64251
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
64252
|
-
/**
|
|
64253
|
-
*
|
|
64254
|
-
|
|
65136
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
65137
|
+
/**
|
|
65138
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
65139
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
65140
|
+
* model has no desiccant sensor.
|
|
65141
|
+
*/
|
|
65142
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
64255
65143
|
/** True while a feed is in progress. */
|
|
64256
65144
|
feeding: boolean(),
|
|
64257
65145
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -64262,7 +65150,7 @@ var PetFeederStatusSchema = object({
|
|
|
64262
65150
|
* with `errorCode` for consumers that want the raw integer. */
|
|
64263
65151
|
error: string().nullable(),
|
|
64264
65152
|
/** Raw device error code (0 / null = no error). */
|
|
64265
|
-
errorCode: number().nullable(),
|
|
65153
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64266
65154
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
64267
65155
|
isDualHopper: boolean(),
|
|
64268
65156
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -64272,7 +65160,7 @@ var PetFeederStatusSchema = object({
|
|
|
64272
65160
|
/** Play a chime when dispensing. */
|
|
64273
65161
|
feedSound: boolean(),
|
|
64274
65162
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
64275
|
-
volume: number(),
|
|
65163
|
+
volume: number().meta(readingMeta("none")),
|
|
64276
65164
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
64277
65165
|
lastFetchedAt: number()
|
|
64278
65166
|
});
|
|
@@ -64391,7 +65279,7 @@ var petFeederCapability = {
|
|
|
64391
65279
|
},
|
|
64392
65280
|
desiccantLeftDays: {
|
|
64393
65281
|
kind: "gauge",
|
|
64394
|
-
unit: "
|
|
65282
|
+
unit: "s"
|
|
64395
65283
|
}
|
|
64396
65284
|
} }
|
|
64397
65285
|
};
|
|
@@ -64792,43 +65680,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
64792
65680
|
*/
|
|
64793
65681
|
var PowerMeterStatusSchema = object({
|
|
64794
65682
|
/** Instantaneous power draw in watts. */
|
|
64795
|
-
watts: number().optional().meta({
|
|
64796
|
-
unit: "W",
|
|
64797
|
-
label: "Power"
|
|
64798
|
-
}),
|
|
65683
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
64799
65684
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
64800
|
-
kwhTotal: number().optional().meta({
|
|
64801
|
-
unit: "kWh",
|
|
64802
|
-
label: "Energy"
|
|
64803
|
-
}),
|
|
65685
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
64804
65686
|
/** Voltage in volts. */
|
|
64805
|
-
volts: number().optional(),
|
|
65687
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
64806
65688
|
/** Current in amperes. */
|
|
64807
|
-
amps: number().optional(),
|
|
64808
|
-
/** Apparent power in volt-amperes
|
|
64809
|
-
va: number().optional(),
|
|
65689
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
65690
|
+
/** Apparent power in volt-amperes. */
|
|
65691
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
64810
65692
|
/** Power factor (0..1) if reported. */
|
|
64811
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
65693
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
64812
65694
|
/** Ms epoch when the slice was last updated. */
|
|
64813
|
-
lastFetchedAt: number()
|
|
64814
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
64815
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
64816
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
64817
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
64818
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
64819
|
-
unit: string().optional(),
|
|
64820
|
-
/** Suggested decimal places for numeric display.
|
|
64821
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64822
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64823
|
-
* auto-formatting when absent. */
|
|
64824
|
-
precision: number().int().min(0).max(10).optional()
|
|
65695
|
+
lastFetchedAt: number()
|
|
64825
65696
|
});
|
|
65697
|
+
/**
|
|
65698
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
65699
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
65700
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
65701
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
65702
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
65703
|
+
*/
|
|
65704
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
65705
|
+
DeviceType.Sensor,
|
|
65706
|
+
DeviceType.Switch,
|
|
65707
|
+
DeviceType.Light,
|
|
65708
|
+
DeviceType.Fan,
|
|
65709
|
+
DeviceType.Climate,
|
|
65710
|
+
DeviceType.Thermostat,
|
|
65711
|
+
DeviceType.Humidifier,
|
|
65712
|
+
DeviceType.WaterHeater,
|
|
65713
|
+
DeviceType.MediaPlayer,
|
|
65714
|
+
DeviceType.Washer,
|
|
65715
|
+
DeviceType.Dryer,
|
|
65716
|
+
DeviceType.Dishwasher,
|
|
65717
|
+
DeviceType.Vacuum,
|
|
65718
|
+
DeviceType.LawnMower,
|
|
65719
|
+
DeviceType.PetFeeder
|
|
65720
|
+
];
|
|
65721
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
65722
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
65723
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
65724
|
+
function powerTarget(id, unit) {
|
|
65725
|
+
return {
|
|
65726
|
+
id,
|
|
65727
|
+
cardinality: "scalar",
|
|
65728
|
+
vocabulary: {
|
|
65729
|
+
cap: "power-meter",
|
|
65730
|
+
stateField: id
|
|
65731
|
+
},
|
|
65732
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
65733
|
+
apply: "add",
|
|
65734
|
+
path: id,
|
|
65735
|
+
sources: [{
|
|
65736
|
+
kind: "numeric",
|
|
65737
|
+
requiredUnit: unit,
|
|
65738
|
+
transforms: [{ kind: "identity" }]
|
|
65739
|
+
}],
|
|
65740
|
+
companions: [{
|
|
65741
|
+
kind: "clock",
|
|
65742
|
+
path: "lastFetchedAt",
|
|
65743
|
+
when: "always"
|
|
65744
|
+
}],
|
|
65745
|
+
sourceReport: { status: "assignment-status" },
|
|
65746
|
+
advancedExpression: true
|
|
65747
|
+
};
|
|
65748
|
+
}
|
|
65749
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
65750
|
+
var powerMeterCustomize = {
|
|
65751
|
+
version: 1,
|
|
65752
|
+
targets: [
|
|
65753
|
+
powerTarget("watts", "W"),
|
|
65754
|
+
powerTarget("kwhTotal", "kWh"),
|
|
65755
|
+
powerTarget("volts", "V"),
|
|
65756
|
+
powerTarget("amps", "A")
|
|
65757
|
+
]
|
|
65758
|
+
};
|
|
64826
65759
|
var powerMeterCapability = {
|
|
64827
65760
|
name: "power-meter",
|
|
64828
65761
|
scope: "device",
|
|
64829
65762
|
deviceNative: true,
|
|
64830
65763
|
mode: "singleton",
|
|
64831
|
-
deviceTypes:
|
|
65764
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
64832
65765
|
methods: {},
|
|
64833
65766
|
status: {
|
|
64834
65767
|
schema: PowerMeterStatusSchema,
|
|
@@ -64886,11 +65819,7 @@ var powerMeterCapability = {
|
|
|
64886
65819
|
/** Clock fields: written, but excluded from the compare that decides
|
|
64887
65820
|
* whether persisting is worth a SQLite commit. */
|
|
64888
65821
|
volatileStateFields: ["lastFetchedAt"],
|
|
64889
|
-
customize:
|
|
64890
|
-
version: 1,
|
|
64891
|
-
advanced: "derive",
|
|
64892
|
-
targets: []
|
|
64893
|
-
}
|
|
65822
|
+
customize: powerMeterCustomize
|
|
64894
65823
|
};
|
|
64895
65824
|
/**
|
|
64896
65825
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -64910,11 +65839,11 @@ var powerMeterCapability = {
|
|
|
64910
65839
|
*/
|
|
64911
65840
|
var GpsLocationSchema = object({
|
|
64912
65841
|
/** Latitude in decimal degrees, -90..90. */
|
|
64913
|
-
latitude: number().min(-90).max(90),
|
|
65842
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
64914
65843
|
/** Longitude in decimal degrees, -180..180. */
|
|
64915
|
-
longitude: number().min(-180).max(180),
|
|
65844
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
64916
65845
|
/** Reported accuracy in meters (lower = better). */
|
|
64917
|
-
accuracyMeters: number().nonnegative()
|
|
65846
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
64918
65847
|
});
|
|
64919
65848
|
var PresenceStatusSchema = object({
|
|
64920
65849
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -64926,7 +65855,7 @@ var PresenceStatusSchema = object({
|
|
|
64926
65855
|
gps: GpsLocationSchema.nullable(),
|
|
64927
65856
|
/** Optional battery level of the tracking device (0..100). Null
|
|
64928
65857
|
* when not reported. */
|
|
64929
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
65858
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64930
65859
|
/** Ms epoch when the slice was last updated. */
|
|
64931
65860
|
lastChangedAt: number()
|
|
64932
65861
|
});
|
|
@@ -64976,19 +65905,10 @@ var presenceCapability = {
|
|
|
64976
65905
|
* `sourceInfo`.
|
|
64977
65906
|
*/
|
|
64978
65907
|
var PressureSensorStatusSchema = object({
|
|
64979
|
-
/** Current pressure in hPa. */
|
|
64980
|
-
hpa: number(),
|
|
65908
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
65909
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
64981
65910
|
/** Ms epoch when the slice was last updated. */
|
|
64982
|
-
lastFetchedAt: number()
|
|
64983
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64984
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64985
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
64986
|
-
unit: string().optional(),
|
|
64987
|
-
/** Suggested decimal places for numeric display.
|
|
64988
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64989
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64990
|
-
* auto-formatting when absent. */
|
|
64991
|
-
precision: number().int().min(0).max(10).optional()
|
|
65911
|
+
lastFetchedAt: number()
|
|
64992
65912
|
});
|
|
64993
65913
|
var pressureSensorCapability = {
|
|
64994
65914
|
name: "pressure-sensor",
|
|
@@ -65514,8 +66434,8 @@ var ptzCapability = {
|
|
|
65514
66434
|
};
|
|
65515
66435
|
var PtzAutotrackSettingsSchema = object({
|
|
65516
66436
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
65517
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
65518
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
66437
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
66438
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
65519
66439
|
});
|
|
65520
66440
|
/**
|
|
65521
66441
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -65669,7 +66589,7 @@ var RunningStateStatusSchema = object({
|
|
|
65669
66589
|
/** null = unknown — never coerced to false (D393). */
|
|
65670
66590
|
running: boolean().nullable(),
|
|
65671
66591
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
65672
|
-
since: number().nullable(),
|
|
66592
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
65673
66593
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
65674
66594
|
phase: string().nullable(),
|
|
65675
66595
|
/** null until a reading has been published (D393). */
|
|
@@ -65684,7 +66604,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
65684
66604
|
/** Generic Customize target for the running boolean (D936). */
|
|
65685
66605
|
var runningCustomize = {
|
|
65686
66606
|
version: 1,
|
|
65687
|
-
advanced: "derive",
|
|
65688
66607
|
targets: [{
|
|
65689
66608
|
id: "running",
|
|
65690
66609
|
cardinality: "scalar",
|
|
@@ -65693,6 +66612,8 @@ var runningCustomize = {
|
|
|
65693
66612
|
stateField: "running"
|
|
65694
66613
|
},
|
|
65695
66614
|
deviceTypes: [
|
|
66615
|
+
DeviceType.Washer,
|
|
66616
|
+
DeviceType.Dryer,
|
|
65696
66617
|
DeviceType.Dishwasher,
|
|
65697
66618
|
DeviceType.Vacuum,
|
|
65698
66619
|
DeviceType.LawnMower,
|
|
@@ -65704,7 +66625,7 @@ var runningCustomize = {
|
|
|
65704
66625
|
DeviceType.Thermostat,
|
|
65705
66626
|
DeviceType.PetFeeder
|
|
65706
66627
|
],
|
|
65707
|
-
apply: "add
|
|
66628
|
+
apply: "add",
|
|
65708
66629
|
path: "running",
|
|
65709
66630
|
sources: [
|
|
65710
66631
|
{
|
|
@@ -66997,9 +67918,9 @@ var RecordTriggerSchema = _enum([
|
|
|
66997
67918
|
*/
|
|
66998
67919
|
var RecordWindowSchema = object({
|
|
66999
67920
|
trigger: RecordTriggerSchema,
|
|
67000
|
-
day: number().int().min(0).max(6),
|
|
67001
|
-
startMinute: number().int().min(0).max(1439),
|
|
67002
|
-
endMinute: number().int().min(1).max(1440)
|
|
67921
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
67922
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
67923
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
67003
67924
|
});
|
|
67004
67925
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
67005
67926
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -67075,10 +67996,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
67075
67996
|
/** Master "record to the card at all" switch. */
|
|
67076
67997
|
enabled: boolean().nullable(),
|
|
67077
67998
|
overwriteWhenFull: boolean().nullable(),
|
|
67078
|
-
preRecordSec: number().nullable(),
|
|
67079
|
-
postRecordSec: number().nullable(),
|
|
67999
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
68000
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
67080
68001
|
/** Length of one recorded file, in minutes. */
|
|
67081
|
-
segmentMinutes: number().nullable(),
|
|
68002
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
67082
68003
|
/** The primary track's weekly windows, flattened. */
|
|
67083
68004
|
windows: array(RecordWindowSchema),
|
|
67084
68005
|
/**
|
|
@@ -67094,7 +68015,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
67094
68015
|
* provider reporting a non-zero count also reports the schedule as not
|
|
67095
68016
|
* writable.
|
|
67096
68017
|
*/
|
|
67097
|
-
unreadableWindows: number(),
|
|
68018
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
67098
68019
|
/**
|
|
67099
68020
|
* The camera is scheduled to record and has NO usable storage.
|
|
67100
68021
|
*
|
|
@@ -68104,7 +69025,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
68104
69025
|
url: string().optional(),
|
|
68105
69026
|
codec: string().optional(),
|
|
68106
69027
|
resolution: CamStreamResolutionSchema.optional(),
|
|
68107
|
-
fps: number().positive().optional(),
|
|
69028
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
68108
69029
|
label: string().optional(),
|
|
68109
69030
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
68110
69031
|
deviceFeatures: array(string()).optional(),
|
|
@@ -68191,18 +69112,18 @@ var StreamProfileSchema = _enum([
|
|
|
68191
69112
|
]);
|
|
68192
69113
|
/** The current encoding config of one stream profile. */
|
|
68193
69114
|
var StreamProfileConfigSchema = object({
|
|
68194
|
-
width: number(),
|
|
68195
|
-
height: number(),
|
|
69115
|
+
width: number().meta(readingMeta("none")),
|
|
69116
|
+
height: number().meta(readingMeta("none")),
|
|
68196
69117
|
codec: _enum(["h264", "h265"]),
|
|
68197
|
-
framerate: number(),
|
|
68198
|
-
bitrate: number(),
|
|
69118
|
+
framerate: number().meta(readingMeta("rate")),
|
|
69119
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
68199
69120
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
68200
69121
|
encoderProfile: _enum([
|
|
68201
69122
|
"high",
|
|
68202
69123
|
"main",
|
|
68203
69124
|
"baseline"
|
|
68204
69125
|
]).optional(),
|
|
68205
|
-
gop: number().optional(),
|
|
69126
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
68206
69127
|
/**
|
|
68207
69128
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
68208
69129
|
*
|
|
@@ -68574,7 +69495,8 @@ var switchCapability = {
|
|
|
68574
69495
|
deviceTypes: [
|
|
68575
69496
|
DeviceType.Switch,
|
|
68576
69497
|
DeviceType.Siren,
|
|
68577
|
-
DeviceType.Light
|
|
69498
|
+
DeviceType.Light,
|
|
69499
|
+
DeviceType.Fan
|
|
68578
69500
|
],
|
|
68579
69501
|
methods: { setState: method(object({
|
|
68580
69502
|
deviceId: number(),
|
|
@@ -68621,12 +69543,7 @@ var switchCapability = {
|
|
|
68621
69543
|
label: "On",
|
|
68622
69544
|
kind: "boolean"
|
|
68623
69545
|
}
|
|
68624
|
-
}] }
|
|
68625
|
-
customize: {
|
|
68626
|
-
version: 1,
|
|
68627
|
-
advanced: "derive",
|
|
68628
|
-
targets: []
|
|
68629
|
-
}
|
|
69546
|
+
}] }
|
|
68630
69547
|
};
|
|
68631
69548
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
68632
69549
|
function hasControlCharacter(value) {
|
|
@@ -69209,35 +70126,21 @@ var tamperCapability = {
|
|
|
69209
70126
|
* entries with `device_class: temperature` and any future native
|
|
69210
70127
|
* thermometer.
|
|
69211
70128
|
*
|
|
69212
|
-
*
|
|
69213
|
-
*
|
|
69214
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
69215
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
69216
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
69217
|
-
* `sourceInfo`.
|
|
70129
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
70130
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
69218
70131
|
*
|
|
69219
70132
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
69220
70133
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
69221
70134
|
* changed" steady state.
|
|
69222
70135
|
*/
|
|
69223
70136
|
var TemperatureSensorStatusSchema = object({
|
|
69224
|
-
/** Current temperature in Celsius. */
|
|
69225
|
-
celsius: number().meta({
|
|
69226
|
-
|
|
70137
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
70138
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
70139
|
+
precision: 1,
|
|
69227
70140
|
label: "Temperature"
|
|
69228
|
-
}),
|
|
70141
|
+
})),
|
|
69229
70142
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
69230
|
-
lastFetchedAt: number()
|
|
69231
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
69232
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
69233
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
69234
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
69235
|
-
unit: string().optional(),
|
|
69236
|
-
/** Suggested decimal places for numeric display.
|
|
69237
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
69238
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
69239
|
-
* auto-formatting when absent. */
|
|
69240
|
-
precision: number().int().min(0).max(10).optional()
|
|
70143
|
+
lastFetchedAt: number()
|
|
69241
70144
|
});
|
|
69242
70145
|
var temperatureSensorCapability = {
|
|
69243
70146
|
name: "temperature-sensor",
|
|
@@ -69268,12 +70171,7 @@ var temperatureSensorCapability = {
|
|
|
69268
70171
|
} } },
|
|
69269
70172
|
/** Clock fields: written, but excluded from the compare that decides
|
|
69270
70173
|
* whether persisting is worth a SQLite commit. */
|
|
69271
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
69272
|
-
customize: {
|
|
69273
|
-
version: 1,
|
|
69274
|
-
advanced: "derive",
|
|
69275
|
-
targets: []
|
|
69276
|
-
}
|
|
70174
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
69277
70175
|
};
|
|
69278
70176
|
/**
|
|
69279
70177
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -69556,16 +70454,16 @@ var VacuumControlStatusSchema = object({
|
|
|
69556
70454
|
]),
|
|
69557
70455
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
69558
70456
|
* reading. */
|
|
69559
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
70457
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
69560
70458
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
69561
70459
|
* the vacuum has no speed control. */
|
|
69562
70460
|
fanSpeed: string().nullable(),
|
|
69563
70461
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
69564
70462
|
availableFanSpeeds: array(string()),
|
|
69565
70463
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
69566
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
70464
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
69567
70465
|
/** Current error code (0 / null = no error). */
|
|
69568
|
-
errorCode: number().nullable(),
|
|
70466
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
69569
70467
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
69570
70468
|
errorLabel: string().nullable(),
|
|
69571
70469
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -69643,7 +70541,7 @@ var ValveStatusSchema = object({
|
|
|
69643
70541
|
]),
|
|
69644
70542
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
69645
70543
|
* intermediate position surface. */
|
|
69646
|
-
position: number().min(0).max(100).nullable(),
|
|
70544
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
69647
70545
|
/** Ms epoch when the slice was last updated. */
|
|
69648
70546
|
lastChangedAt: number()
|
|
69649
70547
|
});
|
|
@@ -69751,9 +70649,9 @@ var vibrationCapability = {
|
|
|
69751
70649
|
*/
|
|
69752
70650
|
var WaterHeaterStatusSchema = object({
|
|
69753
70651
|
/** Current measured temperature. Null when not reported. */
|
|
69754
|
-
currentTemp: number().nullable(),
|
|
70652
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
69755
70653
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
69756
|
-
targetTemp: number().nullable(),
|
|
70654
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
69757
70655
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
69758
70656
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
69759
70657
|
* device reports an unknown state. */
|
|
@@ -69764,9 +70662,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
69764
70662
|
* has no away surface. */
|
|
69765
70663
|
away: boolean().nullable(),
|
|
69766
70664
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
69767
|
-
minTemp: number().nullable(),
|
|
70665
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
69768
70666
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
69769
|
-
maxTemp: number().nullable(),
|
|
70667
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
69770
70668
|
/** Ms epoch when the slice was last updated. */
|
|
69771
70669
|
lastChangedAt: number()
|
|
69772
70670
|
});
|
|
@@ -69851,25 +70749,18 @@ var waterHeaterCapability = {
|
|
|
69851
70749
|
* Forecast deferred — current conditions only for v1.
|
|
69852
70750
|
*/
|
|
69853
70751
|
var WeatherStatusSchema = object({
|
|
69854
|
-
/** Verbatim
|
|
69855
|
-
* when no condition has been reported yet. */
|
|
70752
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
69856
70753
|
condition: string().nullable(),
|
|
69857
|
-
/** Current temperature in
|
|
69858
|
-
temperature: number().nullable(),
|
|
69859
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
69860
|
-
temperatureUnit: string().nullable(),
|
|
70754
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
70755
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
69861
70756
|
/** Relative humidity (0..100). Null when not provided. */
|
|
69862
|
-
humidity: number().min(0).max(100).nullable(),
|
|
69863
|
-
/** Barometric pressure in
|
|
69864
|
-
pressure: number().nullable(),
|
|
69865
|
-
/**
|
|
69866
|
-
|
|
69867
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
69868
|
-
windSpeed: number().nullable(),
|
|
69869
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
69870
|
-
windSpeedUnit: string().nullable(),
|
|
70757
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
70758
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
70759
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
70760
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
70761
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
69871
70762
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
69872
|
-
windBearing: number().nullable(),
|
|
70763
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
69873
70764
|
/** Ms epoch when the slice was last updated. */
|
|
69874
70765
|
lastFetchedAt: number()
|
|
69875
70766
|
});
|
|
@@ -69897,12 +70788,12 @@ var weatherCapability = {
|
|
|
69897
70788
|
*/
|
|
69898
70789
|
durability: "session",
|
|
69899
70790
|
/**
|
|
69900
|
-
* History (D850): recorded series.
|
|
70791
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
69901
70792
|
*/
|
|
69902
70793
|
history: { fields: {
|
|
69903
70794
|
temperature: {
|
|
69904
70795
|
kind: "gauge",
|
|
69905
|
-
|
|
70796
|
+
unit: "°C",
|
|
69906
70797
|
deadband: .2
|
|
69907
70798
|
},
|
|
69908
70799
|
humidity: {
|
|
@@ -69912,12 +70803,12 @@ var weatherCapability = {
|
|
|
69912
70803
|
},
|
|
69913
70804
|
pressure: {
|
|
69914
70805
|
kind: "gauge",
|
|
69915
|
-
|
|
70806
|
+
unit: "hPa",
|
|
69916
70807
|
deadband: .5
|
|
69917
70808
|
},
|
|
69918
70809
|
windSpeed: {
|
|
69919
70810
|
kind: "gauge",
|
|
69920
|
-
|
|
70811
|
+
unit: "m/s",
|
|
69921
70812
|
deadband: .5
|
|
69922
70813
|
}
|
|
69923
70814
|
} }
|
|
@@ -70951,8 +71842,9 @@ function withClipEventLabels(provider, deps) {
|
|
|
70951
71842
|
listClips
|
|
70952
71843
|
};
|
|
70953
71844
|
}
|
|
71845
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
70954
71846
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
70955
|
-
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;
|
|
71847
|
+
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;
|
|
70956
71848
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
70957
71849
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
70958
71850
|
new Set(CAP_NAMES);
|
|
@@ -71296,6 +72188,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
71296
72188
|
featureProbe: featureProbeCapability,
|
|
71297
72189
|
flood: floodCapability,
|
|
71298
72190
|
gas: gasCapability,
|
|
72191
|
+
groupActive: groupActiveCapability,
|
|
72192
|
+
groupCommands: groupCommandsCapability,
|
|
72193
|
+
groupStatus: groupStatusCapability,
|
|
71299
72194
|
heatingValve: heatingValveCapability,
|
|
71300
72195
|
humidifier: humidifierCapability,
|
|
71301
72196
|
humiditySensor: humiditySensorCapability,
|
|
@@ -71305,6 +72200,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
71305
72200
|
lawnMowerControl: lawnMowerControlCapability,
|
|
71306
72201
|
lockControl: lockControlCapability,
|
|
71307
72202
|
mediaPlayer: mediaPlayerCapability,
|
|
72203
|
+
meter: meterCapability,
|
|
71308
72204
|
motion: motionCapability,
|
|
71309
72205
|
motionTrigger: motionTriggerCapability,
|
|
71310
72206
|
motionZones: motionZonesCapability,
|
|
@@ -72564,7 +73460,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
72564
73460
|
return toDeviceSummary(device, this.addonId);
|
|
72565
73461
|
}
|
|
72566
73462
|
};
|
|
72567
|
-
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;
|
|
73463
|
+
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;
|
|
72568
73464
|
new Set(Object.values(DeviceType));
|
|
72569
73465
|
Object.freeze({
|
|
72570
73466
|
"accessories.getStatus": {
|
|
@@ -72672,6 +73568,13 @@ Object.freeze({
|
|
|
72672
73568
|
access: "view",
|
|
72673
73569
|
role: "admin"
|
|
72674
73570
|
},
|
|
73571
|
+
"addons.getPackageDocs": {
|
|
73572
|
+
capName: "addons",
|
|
73573
|
+
capScope: "system",
|
|
73574
|
+
addonId: null,
|
|
73575
|
+
access: "view",
|
|
73576
|
+
role: "admin"
|
|
73577
|
+
},
|
|
72675
73578
|
"addons.getVersions": {
|
|
72676
73579
|
capName: "addons",
|
|
72677
73580
|
capScope: "system",
|
|
@@ -75780,6 +76683,27 @@ Object.freeze({
|
|
|
75780
76683
|
access: "view",
|
|
75781
76684
|
role: "viewer"
|
|
75782
76685
|
},
|
|
76686
|
+
"groupActive.getStatus": {
|
|
76687
|
+
capName: "group-active",
|
|
76688
|
+
capScope: "device",
|
|
76689
|
+
addonId: null,
|
|
76690
|
+
access: "view",
|
|
76691
|
+
role: "viewer"
|
|
76692
|
+
},
|
|
76693
|
+
"groupCommands.getStatus": {
|
|
76694
|
+
capName: "group-commands",
|
|
76695
|
+
capScope: "device",
|
|
76696
|
+
addonId: null,
|
|
76697
|
+
access: "view",
|
|
76698
|
+
role: "viewer"
|
|
76699
|
+
},
|
|
76700
|
+
"groupStatus.getStatus": {
|
|
76701
|
+
capName: "group-status",
|
|
76702
|
+
capScope: "device",
|
|
76703
|
+
addonId: null,
|
|
76704
|
+
access: "view",
|
|
76705
|
+
role: "viewer"
|
|
76706
|
+
},
|
|
75783
76707
|
"heatingValve.getStatus": {
|
|
75784
76708
|
capName: "heating-valve",
|
|
75785
76709
|
capScope: "device",
|
|
@@ -76732,6 +77656,13 @@ Object.freeze({
|
|
|
76732
77656
|
access: "create",
|
|
76733
77657
|
role: "admin"
|
|
76734
77658
|
},
|
|
77659
|
+
"meter.getStatus": {
|
|
77660
|
+
capName: "meter",
|
|
77661
|
+
capScope: "device",
|
|
77662
|
+
addonId: null,
|
|
77663
|
+
access: "view",
|
|
77664
|
+
role: "viewer"
|
|
77665
|
+
},
|
|
76735
77666
|
"metricsProvider.collectSnapshot": {
|
|
76736
77667
|
capName: "metrics-provider",
|
|
76737
77668
|
capScope: "system",
|
|
@@ -84830,7 +85761,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
84830
85761
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
84831
85762
|
icon: "square"
|
|
84832
85763
|
}
|
|
84833
|
-
}
|
|
85764
|
+
},
|
|
85765
|
+
overrides: { byType: {
|
|
85766
|
+
[DeviceType.Washer]: {
|
|
85767
|
+
state: { running: {
|
|
85768
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
85769
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
85770
|
+
} },
|
|
85771
|
+
events: {
|
|
85772
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
85773
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
85774
|
+
}
|
|
85775
|
+
},
|
|
85776
|
+
[DeviceType.Dryer]: {
|
|
85777
|
+
state: { running: {
|
|
85778
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
85779
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
85780
|
+
} },
|
|
85781
|
+
events: {
|
|
85782
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
85783
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
85784
|
+
}
|
|
85785
|
+
},
|
|
85786
|
+
[DeviceType.Dishwasher]: {
|
|
85787
|
+
state: { running: {
|
|
85788
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
85789
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
85790
|
+
} },
|
|
85791
|
+
events: {
|
|
85792
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
85793
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
85794
|
+
}
|
|
85795
|
+
}
|
|
85796
|
+
} }
|
|
84834
85797
|
},
|
|
84835
85798
|
update: {
|
|
84836
85799
|
scope: "device",
|
|
@@ -85602,6 +86565,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85602
86565
|
icon: "flame"
|
|
85603
86566
|
}]
|
|
85604
86567
|
},
|
|
86568
|
+
"group-active": {
|
|
86569
|
+
scope: "device",
|
|
86570
|
+
noun: t("Group state", "Stato del gruppo")
|
|
86571
|
+
},
|
|
86572
|
+
"group-commands": {
|
|
86573
|
+
scope: "device",
|
|
86574
|
+
noun: t("Group command", "Comando di gruppo")
|
|
86575
|
+
},
|
|
86576
|
+
"group-status": {
|
|
86577
|
+
scope: "device",
|
|
86578
|
+
noun: t("Group", "Gruppo"),
|
|
86579
|
+
state: [
|
|
86580
|
+
{
|
|
86581
|
+
kind: "numeric",
|
|
86582
|
+
field: "included",
|
|
86583
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
86584
|
+
label: t("Reporting", "Rispondono"),
|
|
86585
|
+
icon: "users"
|
|
86586
|
+
},
|
|
86587
|
+
{
|
|
86588
|
+
kind: "numeric",
|
|
86589
|
+
field: "excluded",
|
|
86590
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
86591
|
+
label: t("Excluded", "Esclusi"),
|
|
86592
|
+
icon: "users"
|
|
86593
|
+
},
|
|
86594
|
+
{
|
|
86595
|
+
kind: "numeric",
|
|
86596
|
+
field: "total",
|
|
86597
|
+
quantity: t("the member count", "il numero di membri"),
|
|
86598
|
+
label: t("Members", "Membri"),
|
|
86599
|
+
icon: "sigma"
|
|
86600
|
+
}
|
|
86601
|
+
]
|
|
86602
|
+
},
|
|
85605
86603
|
"humidity-sensor": {
|
|
85606
86604
|
scope: "device",
|
|
85607
86605
|
noun: t("Humidity", "Umidità"),
|
|
@@ -85627,6 +86625,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85627
86625
|
}],
|
|
85628
86626
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
85629
86627
|
},
|
|
86628
|
+
meter: {
|
|
86629
|
+
scope: "device",
|
|
86630
|
+
noun: t("Meter", "Contatore"),
|
|
86631
|
+
state: [{
|
|
86632
|
+
kind: "numeric",
|
|
86633
|
+
field: "value",
|
|
86634
|
+
quantity: t("the total", "il totale"),
|
|
86635
|
+
label: t("Total", "Totale"),
|
|
86636
|
+
icon: "gauge"
|
|
86637
|
+
}]
|
|
86638
|
+
},
|
|
85630
86639
|
"numeric-sensor": {
|
|
85631
86640
|
scope: "device",
|
|
85632
86641
|
noun: t("Sensor", "Sensore"),
|
|
@@ -85635,7 +86644,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85635
86644
|
field: "value",
|
|
85636
86645
|
quantity: t("the reading", "il valore"),
|
|
85637
86646
|
label: t("Reading", "Valore"),
|
|
85638
|
-
unitField: "unit",
|
|
85639
86647
|
icon: "gauge"
|
|
85640
86648
|
}]
|
|
85641
86649
|
},
|
|
@@ -85771,7 +86779,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85771
86779
|
field: "temperature",
|
|
85772
86780
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
85773
86781
|
label: t("Temperature", "Temperatura"),
|
|
85774
|
-
|
|
86782
|
+
unit: "°C",
|
|
85775
86783
|
icon: "thermometer"
|
|
85776
86784
|
},
|
|
85777
86785
|
{
|
|
@@ -85787,7 +86795,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85787
86795
|
field: "windSpeed",
|
|
85788
86796
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
85789
86797
|
label: t("Wind", "Vento"),
|
|
85790
|
-
|
|
86798
|
+
unit: "m/s",
|
|
85791
86799
|
icon: "wind"
|
|
85792
86800
|
},
|
|
85793
86801
|
{
|
|
@@ -85795,7 +86803,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85795
86803
|
field: "pressure",
|
|
85796
86804
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
85797
86805
|
label: t("Pressure", "Pressione"),
|
|
85798
|
-
|
|
86806
|
+
unit: "hPa",
|
|
85799
86807
|
icon: "gauge"
|
|
85800
86808
|
}
|
|
85801
86809
|
]
|
|
@@ -86100,8 +87108,47 @@ function projectAction(cap, action) {
|
|
|
86100
87108
|
};
|
|
86101
87109
|
}
|
|
86102
87110
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
86103
|
-
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;
|
|
87111
|
+
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;
|
|
86104
87112
|
DeviceFeature.BatteryOperated;
|
|
87113
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
87114
|
+
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.";
|
|
87115
|
+
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.";
|
|
87116
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
87117
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
87118
|
+
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.";
|
|
87119
|
+
function withheld(reason) {
|
|
87120
|
+
return {
|
|
87121
|
+
[DeviceType.Washer]: {
|
|
87122
|
+
exported: false,
|
|
87123
|
+
reason
|
|
87124
|
+
},
|
|
87125
|
+
[DeviceType.Dryer]: {
|
|
87126
|
+
exported: false,
|
|
87127
|
+
reason
|
|
87128
|
+
},
|
|
87129
|
+
[DeviceType.Dishwasher]: {
|
|
87130
|
+
exported: false,
|
|
87131
|
+
reason
|
|
87132
|
+
}
|
|
87133
|
+
};
|
|
87134
|
+
}
|
|
87135
|
+
function offered(received) {
|
|
87136
|
+
return {
|
|
87137
|
+
[DeviceType.Washer]: {
|
|
87138
|
+
exported: true,
|
|
87139
|
+
as: received
|
|
87140
|
+
},
|
|
87141
|
+
[DeviceType.Dryer]: {
|
|
87142
|
+
exported: true,
|
|
87143
|
+
as: received
|
|
87144
|
+
},
|
|
87145
|
+
[DeviceType.Dishwasher]: {
|
|
87146
|
+
exported: true,
|
|
87147
|
+
as: received
|
|
87148
|
+
}
|
|
87149
|
+
};
|
|
87150
|
+
}
|
|
87151
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
86105
87152
|
var LAST_FETCHED_FIELD = "lastFetchedAt";
|
|
86106
87153
|
/**
|
|
86107
87154
|
* How long a bridge stops re-attempting a refresh that did not land.
|
|
@@ -87220,6 +88267,21 @@ Object.freeze({
|
|
|
87220
88267
|
form: "single",
|
|
87221
88268
|
optional: false
|
|
87222
88269
|
}],
|
|
88270
|
+
"groupActive.getStatus": [{
|
|
88271
|
+
name: "deviceId",
|
|
88272
|
+
form: "single",
|
|
88273
|
+
optional: false
|
|
88274
|
+
}],
|
|
88275
|
+
"groupCommands.getStatus": [{
|
|
88276
|
+
name: "deviceId",
|
|
88277
|
+
form: "single",
|
|
88278
|
+
optional: false
|
|
88279
|
+
}],
|
|
88280
|
+
"groupStatus.getStatus": [{
|
|
88281
|
+
name: "deviceId",
|
|
88282
|
+
form: "single",
|
|
88283
|
+
optional: false
|
|
88284
|
+
}],
|
|
87223
88285
|
"heatingValve.getStatus": [{
|
|
87224
88286
|
name: "deviceId",
|
|
87225
88287
|
form: "single",
|
|
@@ -87420,6 +88482,11 @@ Object.freeze({
|
|
|
87420
88482
|
form: "single",
|
|
87421
88483
|
optional: false
|
|
87422
88484
|
}],
|
|
88485
|
+
"meter.getStatus": [{
|
|
88486
|
+
name: "deviceId",
|
|
88487
|
+
form: "single",
|
|
88488
|
+
optional: false
|
|
88489
|
+
}],
|
|
87423
88490
|
"motion.getStatus": [{
|
|
87424
88491
|
name: "deviceId",
|
|
87425
88492
|
form: "single",
|
|
@@ -89027,7 +90094,6 @@ Object.freeze({
|
|
|
89027
90094
|
"network-access": "ingress",
|
|
89028
90095
|
"smtp-provider": "email"
|
|
89029
90096
|
});
|
|
89030
|
-
DeviceType.Camera;
|
|
89031
90097
|
/**
|
|
89032
90098
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
89033
90099
|
* `z.infer`, they do not restate the shape.
|
|
@@ -89204,6 +90270,8 @@ new Map(Object.entries({
|
|
|
89204
90270
|
"detection-blind": "device-events",
|
|
89205
90271
|
"motion-noisy": "device-events",
|
|
89206
90272
|
"motion-calm": "device-events",
|
|
90273
|
+
"package-llm-silent": "device-events",
|
|
90274
|
+
"package-llm-answered": "device-events",
|
|
89207
90275
|
"recording-stalled": "device-events",
|
|
89208
90276
|
"recording-healthy": "device-events",
|
|
89209
90277
|
"recording-degraded": "device-events",
|
|
@@ -89287,6 +90355,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
89287
90355
|
label: "Motion without a subject",
|
|
89288
90356
|
kinds: ["motion-noisy", "motion-calm"]
|
|
89289
90357
|
},
|
|
90358
|
+
{
|
|
90359
|
+
id: "package-llm",
|
|
90360
|
+
family: "device-events",
|
|
90361
|
+
label: "Package confirm",
|
|
90362
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
90363
|
+
},
|
|
89290
90364
|
{
|
|
89291
90365
|
id: "recording",
|
|
89292
90366
|
family: "device-events",
|
|
@@ -89468,6 +90542,8 @@ var DEVICE_EVENTS = [
|
|
|
89468
90542
|
"detection-blind",
|
|
89469
90543
|
"motion-noisy",
|
|
89470
90544
|
"motion-calm",
|
|
90545
|
+
"package-llm-silent",
|
|
90546
|
+
"package-llm-answered",
|
|
89471
90547
|
"recording-stalled",
|
|
89472
90548
|
"recording-healthy",
|
|
89473
90549
|
"recording-degraded",
|
|
@@ -89736,6 +90812,15 @@ new Map([
|
|
|
89736
90812
|
snapshotLabel: "Cameras with constant motion now",
|
|
89737
90813
|
snapshotSection: null
|
|
89738
90814
|
},
|
|
90815
|
+
{
|
|
90816
|
+
id: "package-llm-confirm",
|
|
90817
|
+
family: "device-events",
|
|
90818
|
+
label: "Package confirm (not answering / answering again)",
|
|
90819
|
+
bad: ["package-llm-silent"],
|
|
90820
|
+
recovery: ["package-llm-answered"],
|
|
90821
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
90822
|
+
snapshotSection: null
|
|
90823
|
+
},
|
|
89739
90824
|
{
|
|
89740
90825
|
id: "recording-health",
|
|
89741
90826
|
family: "device-events",
|