@camstack/addon-provider-rtsp 1.2.146 → 1.2.148
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +42 -0
- package/dist/addon.js +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.js
CHANGED
|
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
//#endregion
|
|
24
24
|
let node_net = require("node:net");
|
|
25
25
|
node_net = __toESM(node_net);
|
|
26
|
-
//#region ../types/dist/event-category-
|
|
26
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
27
27
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
28
28
|
EventCategory["SystemBoot"] = "system.boot";
|
|
29
29
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -349,6 +349,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
349
349
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
350
350
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
351
351
|
/**
|
|
352
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
353
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
354
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
355
|
+
*/
|
|
356
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
357
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
358
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
359
|
+
/**
|
|
352
360
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
353
361
|
* (a settings change via `setAgentInferenceDevices` /
|
|
354
362
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5458,7 +5466,7 @@ var ZodIssueCode = {
|
|
|
5458
5466
|
var ZodFirstPartyTypeKind;
|
|
5459
5467
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5460
5468
|
//#endregion
|
|
5461
|
-
//#region ../types/dist/sleep
|
|
5469
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5462
5470
|
/**
|
|
5463
5471
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5464
5472
|
* window to float samples (D455).
|
|
@@ -8012,6 +8020,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
8012
8020
|
}).strict();
|
|
8013
8021
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8014
8022
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8023
|
+
var READING_QUANTITIES = [
|
|
8024
|
+
"temperature",
|
|
8025
|
+
"pressure",
|
|
8026
|
+
"speed",
|
|
8027
|
+
"precipitation",
|
|
8028
|
+
"precipitation-rate",
|
|
8029
|
+
"length",
|
|
8030
|
+
"area",
|
|
8031
|
+
"illuminance",
|
|
8032
|
+
"irradiance",
|
|
8033
|
+
"power",
|
|
8034
|
+
"energy",
|
|
8035
|
+
"voltage",
|
|
8036
|
+
"current",
|
|
8037
|
+
"apparent-power",
|
|
8038
|
+
"humidity",
|
|
8039
|
+
"percentage",
|
|
8040
|
+
"concentration-volume",
|
|
8041
|
+
"concentration-mass",
|
|
8042
|
+
"concentration-ppb",
|
|
8043
|
+
"volume",
|
|
8044
|
+
"duration",
|
|
8045
|
+
"duration-ms",
|
|
8046
|
+
"information",
|
|
8047
|
+
"sound-level",
|
|
8048
|
+
"signal-level",
|
|
8049
|
+
"colour-temperature",
|
|
8050
|
+
"angle",
|
|
8051
|
+
"bitrate",
|
|
8052
|
+
"rate",
|
|
8053
|
+
"mass",
|
|
8054
|
+
"index",
|
|
8055
|
+
"ratio",
|
|
8056
|
+
"count",
|
|
8057
|
+
"none",
|
|
8058
|
+
"device"
|
|
8059
|
+
];
|
|
8060
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8061
|
+
new Set(READING_QUANTITIES);
|
|
8062
|
+
/**
|
|
8063
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8064
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8065
|
+
*/
|
|
8066
|
+
var QUANTITY_BASE = {
|
|
8067
|
+
temperature: "°C",
|
|
8068
|
+
pressure: "hPa",
|
|
8069
|
+
speed: "m/s",
|
|
8070
|
+
precipitation: "mm",
|
|
8071
|
+
"precipitation-rate": "mm/h",
|
|
8072
|
+
length: "m",
|
|
8073
|
+
area: "m²",
|
|
8074
|
+
illuminance: "lx",
|
|
8075
|
+
irradiance: "W/m²",
|
|
8076
|
+
power: "W",
|
|
8077
|
+
energy: "kWh",
|
|
8078
|
+
voltage: "V",
|
|
8079
|
+
current: "A",
|
|
8080
|
+
"apparent-power": "VA",
|
|
8081
|
+
humidity: "%",
|
|
8082
|
+
percentage: "%",
|
|
8083
|
+
"concentration-volume": "ppm",
|
|
8084
|
+
"concentration-mass": "µg/m³",
|
|
8085
|
+
"concentration-ppb": "ppb",
|
|
8086
|
+
volume: "L",
|
|
8087
|
+
duration: "s",
|
|
8088
|
+
"duration-ms": "ms",
|
|
8089
|
+
information: "B",
|
|
8090
|
+
"sound-level": "dBFS",
|
|
8091
|
+
"signal-level": "dBm",
|
|
8092
|
+
"colour-temperature": "mired",
|
|
8093
|
+
angle: "°",
|
|
8094
|
+
bitrate: "kbps",
|
|
8095
|
+
rate: "fps",
|
|
8096
|
+
mass: "kg",
|
|
8097
|
+
index: "none",
|
|
8098
|
+
ratio: "none",
|
|
8099
|
+
count: "none",
|
|
8100
|
+
none: "none",
|
|
8101
|
+
device: "device"
|
|
8102
|
+
};
|
|
8103
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8104
|
+
function baseUnitOf(quantity) {
|
|
8105
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8106
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8107
|
+
return symbol;
|
|
8108
|
+
}
|
|
8109
|
+
function readingMeta(quantity, extras) {
|
|
8110
|
+
return {
|
|
8111
|
+
quantity,
|
|
8112
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8113
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8114
|
+
};
|
|
8115
|
+
}
|
|
8015
8116
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8016
8117
|
var CamProfileSchema = _enum([
|
|
8017
8118
|
"high",
|
|
@@ -8039,8 +8140,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8039
8140
|
"derived"
|
|
8040
8141
|
]);
|
|
8041
8142
|
var CamStreamResolutionSchema = object({
|
|
8042
|
-
width: number().int().positive(),
|
|
8043
|
-
height: number().int().positive()
|
|
8143
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8144
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8044
8145
|
});
|
|
8045
8146
|
var CameraStreamSchema = object({
|
|
8046
8147
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8558,6 +8659,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8558
8659
|
"filesystem-browse",
|
|
8559
8660
|
"flood",
|
|
8560
8661
|
"gas",
|
|
8662
|
+
"group-active",
|
|
8663
|
+
"group-commands",
|
|
8664
|
+
"group-status",
|
|
8561
8665
|
"heating-valve",
|
|
8562
8666
|
"humidifier",
|
|
8563
8667
|
"humidity-sensor",
|
|
@@ -8578,6 +8682,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8578
8682
|
"login-method",
|
|
8579
8683
|
"media-player",
|
|
8580
8684
|
"mesh-network",
|
|
8685
|
+
"meter",
|
|
8581
8686
|
"metrics-provider",
|
|
8582
8687
|
"model-convert",
|
|
8583
8688
|
"model-distributor",
|
|
@@ -8687,14 +8792,6 @@ Object.freeze({
|
|
|
8687
8792
|
{
|
|
8688
8793
|
"path": "aqi",
|
|
8689
8794
|
"valueType": "number"
|
|
8690
|
-
},
|
|
8691
|
-
{
|
|
8692
|
-
"path": "unit",
|
|
8693
|
-
"valueType": "string"
|
|
8694
|
-
},
|
|
8695
|
-
{
|
|
8696
|
-
"path": "precision",
|
|
8697
|
-
"valueType": "number"
|
|
8698
8795
|
}
|
|
8699
8796
|
],
|
|
8700
8797
|
"alarm-panel": [
|
|
@@ -8730,20 +8827,10 @@ Object.freeze({
|
|
|
8730
8827
|
"valueType": "boolean"
|
|
8731
8828
|
}
|
|
8732
8829
|
],
|
|
8733
|
-
"ambient-light-sensor": [
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
},
|
|
8738
|
-
{
|
|
8739
|
-
"path": "unit",
|
|
8740
|
-
"valueType": "string"
|
|
8741
|
-
},
|
|
8742
|
-
{
|
|
8743
|
-
"path": "precision",
|
|
8744
|
-
"valueType": "number"
|
|
8745
|
-
}
|
|
8746
|
-
],
|
|
8830
|
+
"ambient-light-sensor": [{
|
|
8831
|
+
"path": "lux",
|
|
8832
|
+
"valueType": "number"
|
|
8833
|
+
}],
|
|
8747
8834
|
"audio-metrics": [
|
|
8748
8835
|
{
|
|
8749
8836
|
"path": "ts",
|
|
@@ -8823,6 +8910,10 @@ Object.freeze({
|
|
|
8823
8910
|
"path": "lastUpdated",
|
|
8824
8911
|
"valueType": "number"
|
|
8825
8912
|
},
|
|
8913
|
+
{
|
|
8914
|
+
"path": "volts",
|
|
8915
|
+
"valueType": "number"
|
|
8916
|
+
},
|
|
8826
8917
|
{
|
|
8827
8918
|
"path": "lastContactAt",
|
|
8828
8919
|
"valueType": "number"
|
|
@@ -9065,10 +9156,6 @@ Object.freeze({
|
|
|
9065
9156
|
"datetime"
|
|
9066
9157
|
]
|
|
9067
9158
|
},
|
|
9068
|
-
{
|
|
9069
|
-
"path": "unit",
|
|
9070
|
-
"valueType": "string"
|
|
9071
|
-
},
|
|
9072
9159
|
{
|
|
9073
9160
|
"path": "min",
|
|
9074
9161
|
"valueType": "number"
|
|
@@ -9080,19 +9167,6 @@ Object.freeze({
|
|
|
9080
9167
|
{
|
|
9081
9168
|
"path": "step",
|
|
9082
9169
|
"valueType": "number"
|
|
9083
|
-
},
|
|
9084
|
-
{
|
|
9085
|
-
"path": "precision",
|
|
9086
|
-
"valueType": "number"
|
|
9087
|
-
},
|
|
9088
|
-
{
|
|
9089
|
-
"path": "format",
|
|
9090
|
-
"valueType": "enum",
|
|
9091
|
-
"enumValues": [
|
|
9092
|
-
"date",
|
|
9093
|
-
"time",
|
|
9094
|
-
"datetime"
|
|
9095
|
-
]
|
|
9096
9170
|
}
|
|
9097
9171
|
],
|
|
9098
9172
|
"cover": [
|
|
@@ -9333,13 +9407,8 @@ Object.freeze({
|
|
|
9333
9407
|
"path": "value",
|
|
9334
9408
|
"valueType": "string"
|
|
9335
9409
|
}, {
|
|
9336
|
-
"path": "
|
|
9337
|
-
"valueType": "
|
|
9338
|
-
"enumValues": [
|
|
9339
|
-
"date",
|
|
9340
|
-
"time",
|
|
9341
|
-
"datetime"
|
|
9342
|
-
]
|
|
9410
|
+
"path": "timestamp",
|
|
9411
|
+
"valueType": "boolean"
|
|
9343
9412
|
}],
|
|
9344
9413
|
"event-emitter": [
|
|
9345
9414
|
{
|
|
@@ -9412,6 +9481,24 @@ Object.freeze({
|
|
|
9412
9481
|
"path": "detected",
|
|
9413
9482
|
"valueType": "boolean"
|
|
9414
9483
|
}],
|
|
9484
|
+
"group-active": [{
|
|
9485
|
+
"path": "active",
|
|
9486
|
+
"valueType": "boolean"
|
|
9487
|
+
}],
|
|
9488
|
+
"group-status": [
|
|
9489
|
+
{
|
|
9490
|
+
"path": "included",
|
|
9491
|
+
"valueType": "number"
|
|
9492
|
+
},
|
|
9493
|
+
{
|
|
9494
|
+
"path": "excluded",
|
|
9495
|
+
"valueType": "number"
|
|
9496
|
+
},
|
|
9497
|
+
{
|
|
9498
|
+
"path": "total",
|
|
9499
|
+
"valueType": "number"
|
|
9500
|
+
}
|
|
9501
|
+
],
|
|
9415
9502
|
"heating-valve": [{
|
|
9416
9503
|
"path": "position",
|
|
9417
9504
|
"valueType": "number"
|
|
@@ -9446,20 +9533,10 @@ Object.freeze({
|
|
|
9446
9533
|
"valueType": "number"
|
|
9447
9534
|
}
|
|
9448
9535
|
],
|
|
9449
|
-
"humidity-sensor": [
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
},
|
|
9454
|
-
{
|
|
9455
|
-
"path": "unit",
|
|
9456
|
-
"valueType": "string"
|
|
9457
|
-
},
|
|
9458
|
-
{
|
|
9459
|
-
"path": "precision",
|
|
9460
|
-
"valueType": "number"
|
|
9461
|
-
}
|
|
9462
|
-
],
|
|
9536
|
+
"humidity-sensor": [{
|
|
9537
|
+
"path": "percent",
|
|
9538
|
+
"valueType": "number"
|
|
9539
|
+
}],
|
|
9463
9540
|
"image": [{
|
|
9464
9541
|
"path": "url",
|
|
9465
9542
|
"valueType": "string"
|
|
@@ -9667,6 +9744,10 @@ Object.freeze({
|
|
|
9667
9744
|
]
|
|
9668
9745
|
}
|
|
9669
9746
|
],
|
|
9747
|
+
"meter": [{
|
|
9748
|
+
"path": "value",
|
|
9749
|
+
"valueType": "number"
|
|
9750
|
+
}],
|
|
9670
9751
|
"motion": [
|
|
9671
9752
|
{
|
|
9672
9753
|
"path": "detected",
|
|
@@ -9798,20 +9879,10 @@ Object.freeze({
|
|
|
9798
9879
|
"valueType": "boolean"
|
|
9799
9880
|
}
|
|
9800
9881
|
],
|
|
9801
|
-
"numeric-sensor": [
|
|
9802
|
-
|
|
9803
|
-
|
|
9804
|
-
|
|
9805
|
-
},
|
|
9806
|
-
{
|
|
9807
|
-
"path": "unit",
|
|
9808
|
-
"valueType": "string"
|
|
9809
|
-
},
|
|
9810
|
-
{
|
|
9811
|
-
"path": "precision",
|
|
9812
|
-
"valueType": "number"
|
|
9813
|
-
}
|
|
9814
|
-
],
|
|
9882
|
+
"numeric-sensor": [{
|
|
9883
|
+
"path": "value",
|
|
9884
|
+
"valueType": "number"
|
|
9885
|
+
}],
|
|
9815
9886
|
"pet-feeder": [
|
|
9816
9887
|
{
|
|
9817
9888
|
"path": "foodLevel",
|
|
@@ -9903,14 +9974,6 @@ Object.freeze({
|
|
|
9903
9974
|
{
|
|
9904
9975
|
"path": "powerFactor",
|
|
9905
9976
|
"valueType": "number"
|
|
9906
|
-
},
|
|
9907
|
-
{
|
|
9908
|
-
"path": "unit",
|
|
9909
|
-
"valueType": "string"
|
|
9910
|
-
},
|
|
9911
|
-
{
|
|
9912
|
-
"path": "precision",
|
|
9913
|
-
"valueType": "number"
|
|
9914
9977
|
}
|
|
9915
9978
|
],
|
|
9916
9979
|
"presence": [
|
|
@@ -9939,20 +10002,10 @@ Object.freeze({
|
|
|
9939
10002
|
"valueType": "number"
|
|
9940
10003
|
}
|
|
9941
10004
|
],
|
|
9942
|
-
"pressure-sensor": [
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
},
|
|
9947
|
-
{
|
|
9948
|
-
"path": "unit",
|
|
9949
|
-
"valueType": "string"
|
|
9950
|
-
},
|
|
9951
|
-
{
|
|
9952
|
-
"path": "precision",
|
|
9953
|
-
"valueType": "number"
|
|
9954
|
-
}
|
|
9955
|
-
],
|
|
10005
|
+
"pressure-sensor": [{
|
|
10006
|
+
"path": "hpa",
|
|
10007
|
+
"valueType": "number"
|
|
10008
|
+
}],
|
|
9956
10009
|
"privacy-mask": [{
|
|
9957
10010
|
"path": "enabled",
|
|
9958
10011
|
"valueType": "boolean"
|
|
@@ -10263,20 +10316,10 @@ Object.freeze({
|
|
|
10263
10316
|
"path": "tampered",
|
|
10264
10317
|
"valueType": "boolean"
|
|
10265
10318
|
}],
|
|
10266
|
-
"temperature-sensor": [
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
},
|
|
10271
|
-
{
|
|
10272
|
-
"path": "unit",
|
|
10273
|
-
"valueType": "string"
|
|
10274
|
-
},
|
|
10275
|
-
{
|
|
10276
|
-
"path": "precision",
|
|
10277
|
-
"valueType": "number"
|
|
10278
|
-
}
|
|
10279
|
-
],
|
|
10319
|
+
"temperature-sensor": [{
|
|
10320
|
+
"path": "celsius",
|
|
10321
|
+
"valueType": "number"
|
|
10322
|
+
}],
|
|
10280
10323
|
"update": [
|
|
10281
10324
|
{
|
|
10282
10325
|
"path": "currentVersion",
|
|
@@ -10387,10 +10430,6 @@ Object.freeze({
|
|
|
10387
10430
|
"path": "temperature",
|
|
10388
10431
|
"valueType": "number"
|
|
10389
10432
|
},
|
|
10390
|
-
{
|
|
10391
|
-
"path": "temperatureUnit",
|
|
10392
|
-
"valueType": "string"
|
|
10393
|
-
},
|
|
10394
10433
|
{
|
|
10395
10434
|
"path": "humidity",
|
|
10396
10435
|
"valueType": "number"
|
|
@@ -10399,18 +10438,10 @@ Object.freeze({
|
|
|
10399
10438
|
"path": "pressure",
|
|
10400
10439
|
"valueType": "number"
|
|
10401
10440
|
},
|
|
10402
|
-
{
|
|
10403
|
-
"path": "pressureUnit",
|
|
10404
|
-
"valueType": "string"
|
|
10405
|
-
},
|
|
10406
10441
|
{
|
|
10407
10442
|
"path": "windSpeed",
|
|
10408
10443
|
"valueType": "number"
|
|
10409
10444
|
},
|
|
10410
|
-
{
|
|
10411
|
-
"path": "windSpeedUnit",
|
|
10412
|
-
"valueType": "string"
|
|
10413
|
-
},
|
|
10414
10445
|
{
|
|
10415
10446
|
"path": "windBearing",
|
|
10416
10447
|
"valueType": "number"
|
|
@@ -10549,7 +10580,7 @@ function maskUrlCredentials(rawUrl) {
|
|
|
10549
10580
|
}
|
|
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) {
|
|
@@ -10902,7 +10939,7 @@ function errMsg(err) {
|
|
|
10902
10939
|
return String(err);
|
|
10903
10940
|
}
|
|
10904
10941
|
//#endregion
|
|
10905
|
-
//#region ../types/dist/composition-
|
|
10942
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10906
10943
|
/**
|
|
10907
10944
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10908
10945
|
*
|
|
@@ -11217,6 +11254,13 @@ var table = {
|
|
|
11217
11254
|
apply: () => {
|
|
11218
11255
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11219
11256
|
}
|
|
11257
|
+
},
|
|
11258
|
+
schmitt: {
|
|
11259
|
+
minArgs: 3,
|
|
11260
|
+
maxArgs: 5,
|
|
11261
|
+
apply: () => {
|
|
11262
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11263
|
+
}
|
|
11220
11264
|
}
|
|
11221
11265
|
};
|
|
11222
11266
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11657,15 +11701,232 @@ function validateExpressionSource(src) {
|
|
|
11657
11701
|
}
|
|
11658
11702
|
return null;
|
|
11659
11703
|
}
|
|
11660
|
-
/**
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11704
|
+
/**
|
|
11705
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11706
|
+
*
|
|
11707
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11708
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11709
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11710
|
+
*
|
|
11711
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11712
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11713
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11714
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11715
|
+
* can move later without moving the others.
|
|
11716
|
+
*/
|
|
11717
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11718
|
+
var APPLIANCE_KINDS = [
|
|
11719
|
+
"washer",
|
|
11720
|
+
"dryer",
|
|
11721
|
+
"dishwasher"
|
|
11722
|
+
];
|
|
11723
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11724
|
+
/**
|
|
11725
|
+
* Statistics and integrals over a history read (D944).
|
|
11726
|
+
*
|
|
11727
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11728
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11729
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11730
|
+
* as zero. A truncated read is not published.
|
|
11731
|
+
*/
|
|
11732
|
+
var STATISTIC_STATS = [
|
|
11733
|
+
"min",
|
|
11734
|
+
"max",
|
|
11735
|
+
"mean",
|
|
11736
|
+
"sum",
|
|
11737
|
+
"count",
|
|
11738
|
+
"change"
|
|
11739
|
+
];
|
|
11740
|
+
/**
|
|
11741
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11742
|
+
*
|
|
11743
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11744
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11745
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11746
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11747
|
+
*/
|
|
11748
|
+
var MINUTE_MS = 6e4;
|
|
11749
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11750
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11751
|
+
var ROLLING_SPANS = [
|
|
11752
|
+
"1h",
|
|
11753
|
+
"24h",
|
|
11754
|
+
"2d",
|
|
11755
|
+
"7d",
|
|
11756
|
+
"30d",
|
|
11757
|
+
"custom"
|
|
11758
|
+
];
|
|
11759
|
+
var CALENDAR_PERIODS = [
|
|
11760
|
+
"today",
|
|
11761
|
+
"yesterday",
|
|
11762
|
+
"this-week",
|
|
11763
|
+
"this-month"
|
|
11764
|
+
];
|
|
11765
|
+
var RESET_PERIODS = [
|
|
11766
|
+
"never",
|
|
11767
|
+
"daily",
|
|
11768
|
+
"weekly",
|
|
11769
|
+
"monthly"
|
|
11770
|
+
];
|
|
11771
|
+
5 * MINUTE_MS;
|
|
11772
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11773
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11774
|
+
var rollingWindowObject = object({
|
|
11775
|
+
kind: literal("rolling"),
|
|
11776
|
+
span: _enum(ROLLING_SPANS),
|
|
11777
|
+
customMinutes: number().int().min(5).optional()
|
|
11778
|
+
}).check((payload) => {
|
|
11779
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11780
|
+
code: "custom",
|
|
11781
|
+
message: "a custom range needs a duration in minutes",
|
|
11782
|
+
path: ["customMinutes"],
|
|
11783
|
+
input: payload.value
|
|
11784
|
+
});
|
|
11785
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11786
|
+
code: "custom",
|
|
11787
|
+
message: "only a custom range carries a duration",
|
|
11788
|
+
path: ["customMinutes"],
|
|
11789
|
+
input: payload.value
|
|
11790
|
+
});
|
|
11791
|
+
});
|
|
11792
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11793
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11794
|
+
kind: literal("calendar"),
|
|
11795
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11796
|
+
})]);
|
|
11797
|
+
/**
|
|
11798
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11799
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11800
|
+
* `composition.ts` (D659).
|
|
11801
|
+
*/
|
|
11664
11802
|
var CompositionSourceRefSchema = object({
|
|
11665
11803
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11666
11804
|
addonId: string().min(1),
|
|
11667
11805
|
stableId: string().min(1)
|
|
11668
11806
|
});
|
|
11807
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11808
|
+
"temperature",
|
|
11809
|
+
"humidity",
|
|
11810
|
+
"pressure",
|
|
11811
|
+
"illuminance",
|
|
11812
|
+
"power",
|
|
11813
|
+
"energy",
|
|
11814
|
+
"battery",
|
|
11815
|
+
"numeric",
|
|
11816
|
+
"motion",
|
|
11817
|
+
"contact",
|
|
11818
|
+
"leak",
|
|
11819
|
+
"smoke",
|
|
11820
|
+
"occupancy",
|
|
11821
|
+
"binary",
|
|
11822
|
+
"switch",
|
|
11823
|
+
"light",
|
|
11824
|
+
"fan",
|
|
11825
|
+
"cover",
|
|
11826
|
+
"valve",
|
|
11827
|
+
"lock",
|
|
11828
|
+
"media-player",
|
|
11829
|
+
"climate"
|
|
11830
|
+
];
|
|
11831
|
+
var NUMERIC_AGGREGATES = [
|
|
11832
|
+
"mean",
|
|
11833
|
+
"median",
|
|
11834
|
+
"min",
|
|
11835
|
+
"max",
|
|
11836
|
+
"sum"
|
|
11837
|
+
];
|
|
11838
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11839
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11840
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11841
|
+
var AGGREGATE_REDUCERS = [
|
|
11842
|
+
"mean",
|
|
11843
|
+
"median",
|
|
11844
|
+
"min",
|
|
11845
|
+
"max",
|
|
11846
|
+
"sum",
|
|
11847
|
+
"any",
|
|
11848
|
+
"all"
|
|
11849
|
+
];
|
|
11850
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11851
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11852
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11853
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11854
|
+
var HelperMemberSchema = object({
|
|
11855
|
+
source: CompositionSourceRefSchema,
|
|
11856
|
+
cap: string().min(1),
|
|
11857
|
+
fieldPath: string().min(1)
|
|
11858
|
+
});
|
|
11859
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11860
|
+
object({
|
|
11861
|
+
kind: literal("group"),
|
|
11862
|
+
templateId: GroupTemplateIdSchema,
|
|
11863
|
+
aggregate: AggregateReducerSchema,
|
|
11864
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11865
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11866
|
+
active: ActiveCriterionSchema.optional()
|
|
11867
|
+
}),
|
|
11868
|
+
object({
|
|
11869
|
+
kind: literal("appliance"),
|
|
11870
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11871
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11872
|
+
thresholdWatts: number().positive(),
|
|
11873
|
+
startDwellMs: number().int().nonnegative(),
|
|
11874
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11875
|
+
member: HelperMemberSchema
|
|
11876
|
+
}),
|
|
11877
|
+
object({
|
|
11878
|
+
kind: literal("statistic"),
|
|
11879
|
+
stat: _enum(STATISTIC_STATS),
|
|
11880
|
+
window: StatisticWindowSchema,
|
|
11881
|
+
source: HelperMemberSchema
|
|
11882
|
+
}),
|
|
11883
|
+
object({
|
|
11884
|
+
kind: literal("integral"),
|
|
11885
|
+
reset: _enum(RESET_PERIODS),
|
|
11886
|
+
output: _enum(["energy", "meter"]),
|
|
11887
|
+
source: HelperMemberSchema
|
|
11888
|
+
}),
|
|
11889
|
+
object({
|
|
11890
|
+
kind: literal("threshold"),
|
|
11891
|
+
source: HelperMemberSchema,
|
|
11892
|
+
high: number(),
|
|
11893
|
+
low: number(),
|
|
11894
|
+
onForMs: number().int().nonnegative(),
|
|
11895
|
+
offForMs: number().int().nonnegative()
|
|
11896
|
+
}),
|
|
11897
|
+
object({
|
|
11898
|
+
kind: literal("arithmetic"),
|
|
11899
|
+
op: _enum([
|
|
11900
|
+
"sum",
|
|
11901
|
+
"difference",
|
|
11902
|
+
"ratio"
|
|
11903
|
+
]),
|
|
11904
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11905
|
+
}),
|
|
11906
|
+
object({
|
|
11907
|
+
kind: literal("expression"),
|
|
11908
|
+
expr: string().min(1),
|
|
11909
|
+
inputs: array(object({
|
|
11910
|
+
name: string().min(1),
|
|
11911
|
+
member: HelperMemberSchema
|
|
11912
|
+
})).min(1).max(64),
|
|
11913
|
+
output: _enum(["number", "boolean"])
|
|
11914
|
+
}),
|
|
11915
|
+
object({
|
|
11916
|
+
kind: literal("derivative"),
|
|
11917
|
+
window: RollingWindowSchema,
|
|
11918
|
+
per: _enum([
|
|
11919
|
+
"second",
|
|
11920
|
+
"minute",
|
|
11921
|
+
"hour"
|
|
11922
|
+
]),
|
|
11923
|
+
source: HelperMemberSchema
|
|
11924
|
+
})
|
|
11925
|
+
]);
|
|
11926
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11927
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11928
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11929
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11669
11930
|
/** One field of one capability of one source device. */
|
|
11670
11931
|
var CompositionFieldReadSchema = object({
|
|
11671
11932
|
source: CompositionSourceRefSchema,
|
|
@@ -11709,7 +11970,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11709
11970
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11710
11971
|
CompositionFromSourceSchema,
|
|
11711
11972
|
CompositionExpressionSourceSchema,
|
|
11712
|
-
CompositionCodeSourceSchema
|
|
11973
|
+
CompositionCodeSourceSchema,
|
|
11974
|
+
object({
|
|
11975
|
+
kind: literal("aggregate"),
|
|
11976
|
+
reducer: _enum([
|
|
11977
|
+
"mean",
|
|
11978
|
+
"median",
|
|
11979
|
+
"min",
|
|
11980
|
+
"max",
|
|
11981
|
+
"sum",
|
|
11982
|
+
"any",
|
|
11983
|
+
"all"
|
|
11984
|
+
]),
|
|
11985
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11986
|
+
/**
|
|
11987
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11988
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11989
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11990
|
+
*/
|
|
11991
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11992
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11993
|
+
publish: _enum([
|
|
11994
|
+
"value",
|
|
11995
|
+
"included",
|
|
11996
|
+
"excluded",
|
|
11997
|
+
"total"
|
|
11998
|
+
]),
|
|
11999
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12000
|
+
empty: _enum([
|
|
12001
|
+
"null",
|
|
12002
|
+
"omit",
|
|
12003
|
+
"offline"
|
|
12004
|
+
])
|
|
12005
|
+
}),
|
|
12006
|
+
object({
|
|
12007
|
+
kind: literal("series"),
|
|
12008
|
+
read: CompositionFieldReadSchema,
|
|
12009
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12010
|
+
publish: _enum([
|
|
12011
|
+
"value",
|
|
12012
|
+
"included",
|
|
12013
|
+
"excluded",
|
|
12014
|
+
"total"
|
|
12015
|
+
]),
|
|
12016
|
+
/**
|
|
12017
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12018
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12019
|
+
*/
|
|
12020
|
+
empty: _enum([
|
|
12021
|
+
"null",
|
|
12022
|
+
"omit",
|
|
12023
|
+
"offline"
|
|
12024
|
+
])
|
|
12025
|
+
})
|
|
11713
12026
|
]);
|
|
11714
12027
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11715
12028
|
kind: literal("forward"),
|
|
@@ -11755,7 +12068,13 @@ var CompositionSchema = object({
|
|
|
11755
12068
|
kind: literal("existing"),
|
|
11756
12069
|
device: CompositionSourceRefSchema
|
|
11757
12070
|
})]),
|
|
11758
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12071
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12072
|
+
/**
|
|
12073
|
+
* Present when the block is a helper template. Absent on a free
|
|
12074
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12075
|
+
* never the compiled features.
|
|
12076
|
+
*/
|
|
12077
|
+
helper: HelperSpecSchema.optional()
|
|
11759
12078
|
}).superRefine((composition, ctx) => {
|
|
11760
12079
|
const seen = /* @__PURE__ */ new Set();
|
|
11761
12080
|
composition.features.forEach((feature, index) => {
|
|
@@ -16894,7 +17213,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16894
17213
|
*/
|
|
16895
17214
|
interactiveConnectPath: string().min(1).optional(),
|
|
16896
17215
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16897
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17216
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17217
|
+
/**
|
|
17218
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17219
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17220
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17221
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17222
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17223
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17224
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17225
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17226
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17227
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17228
|
+
* offers it as the default path; the fields the session fills are
|
|
17229
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17230
|
+
*/
|
|
17231
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16898
17232
|
}))
|
|
16899
17233
|
});
|
|
16900
17234
|
var ListInputSchema = object({
|
|
@@ -17995,7 +18329,12 @@ var CompositionProblemSchema = object({
|
|
|
17995
18329
|
"item-field-reserved",
|
|
17996
18330
|
"target-missing",
|
|
17997
18331
|
"target-unreadable",
|
|
17998
|
-
"not-replaceable"
|
|
18332
|
+
"not-replaceable",
|
|
18333
|
+
"native-capability-replace",
|
|
18334
|
+
"mixed-quantity",
|
|
18335
|
+
"helper-mismatch",
|
|
18336
|
+
"member-constraint",
|
|
18337
|
+
"retention"
|
|
17999
18338
|
]),
|
|
18000
18339
|
path: string(),
|
|
18001
18340
|
message: string()
|
|
@@ -18016,7 +18355,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18016
18355
|
"null",
|
|
18017
18356
|
"offline",
|
|
18018
18357
|
"unknown",
|
|
18019
|
-
"release"
|
|
18358
|
+
"release",
|
|
18359
|
+
"omit"
|
|
18020
18360
|
]);
|
|
18021
18361
|
/**
|
|
18022
18362
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18053,9 +18393,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18053
18393
|
reads: array(CompositionFieldReadSchema)
|
|
18054
18394
|
});
|
|
18055
18395
|
/**
|
|
18056
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18057
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18058
|
-
*
|
|
18396
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18397
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18398
|
+
* Replacing a capability the device already serves is refused
|
|
18399
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18400
|
+
* wire for a claim the hub already holds.
|
|
18059
18401
|
*/
|
|
18060
18402
|
var CompositionFeatureModeSchema = _enum([
|
|
18061
18403
|
"new",
|
|
@@ -18226,8 +18568,392 @@ Object.freeze({
|
|
|
18226
18568
|
latchedAt: {
|
|
18227
18569
|
kind: "fixed",
|
|
18228
18570
|
result: ["number", "null"]
|
|
18571
|
+
},
|
|
18572
|
+
schmitt: {
|
|
18573
|
+
kind: "fixed",
|
|
18574
|
+
result: ["boolean", "null"]
|
|
18229
18575
|
}
|
|
18230
18576
|
});
|
|
18577
|
+
/**
|
|
18578
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18579
|
+
* Data, not a form default written into the block.
|
|
18580
|
+
*/
|
|
18581
|
+
var NOW$2 = {
|
|
18582
|
+
fieldPath: "lastFetchedAt",
|
|
18583
|
+
expr: "now"
|
|
18584
|
+
};
|
|
18585
|
+
var CHANGED = {
|
|
18586
|
+
fieldPath: "lastChangedAt",
|
|
18587
|
+
expr: "now"
|
|
18588
|
+
};
|
|
18589
|
+
function numeric(input) {
|
|
18590
|
+
return {
|
|
18591
|
+
...input,
|
|
18592
|
+
family: "numeric",
|
|
18593
|
+
deviceType: DeviceType.Sensor,
|
|
18594
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18595
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18596
|
+
activeWhen: void 0,
|
|
18597
|
+
commandCaps: [],
|
|
18598
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18599
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18600
|
+
accept: [{
|
|
18601
|
+
cap: input.outputCap,
|
|
18602
|
+
fieldPath: input.outputField
|
|
18603
|
+
}]
|
|
18604
|
+
};
|
|
18605
|
+
}
|
|
18606
|
+
function binary(input) {
|
|
18607
|
+
return {
|
|
18608
|
+
...input,
|
|
18609
|
+
family: "binary",
|
|
18610
|
+
deviceType: DeviceType.Sensor,
|
|
18611
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18612
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18613
|
+
activeWhen: void 0,
|
|
18614
|
+
commandCaps: [],
|
|
18615
|
+
quantity: "none",
|
|
18616
|
+
baseUnit: void 0,
|
|
18617
|
+
aggregates: BINARY_AGGREGATES,
|
|
18618
|
+
empty: "offline"
|
|
18619
|
+
};
|
|
18620
|
+
}
|
|
18621
|
+
var GROUP_TEMPLATES = [
|
|
18622
|
+
numeric({
|
|
18623
|
+
id: "temperature",
|
|
18624
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18625
|
+
role: DeviceRole.TemperatureSensor,
|
|
18626
|
+
outputCap: "temperature-sensor",
|
|
18627
|
+
outputField: "celsius",
|
|
18628
|
+
quantity: "temperature",
|
|
18629
|
+
defaultAggregate: "mean",
|
|
18630
|
+
empty: "null",
|
|
18631
|
+
companions: [NOW$2]
|
|
18632
|
+
}),
|
|
18633
|
+
numeric({
|
|
18634
|
+
id: "humidity",
|
|
18635
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18636
|
+
role: DeviceRole.HumiditySensor,
|
|
18637
|
+
outputCap: "humidity-sensor",
|
|
18638
|
+
outputField: "percent",
|
|
18639
|
+
quantity: "humidity",
|
|
18640
|
+
defaultAggregate: "mean",
|
|
18641
|
+
empty: "null",
|
|
18642
|
+
companions: [NOW$2]
|
|
18643
|
+
}),
|
|
18644
|
+
numeric({
|
|
18645
|
+
id: "pressure",
|
|
18646
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18647
|
+
role: DeviceRole.PressureSensor,
|
|
18648
|
+
outputCap: "pressure-sensor",
|
|
18649
|
+
outputField: "hpa",
|
|
18650
|
+
quantity: "pressure",
|
|
18651
|
+
defaultAggregate: "mean",
|
|
18652
|
+
empty: "null",
|
|
18653
|
+
companions: [NOW$2]
|
|
18654
|
+
}),
|
|
18655
|
+
numeric({
|
|
18656
|
+
id: "illuminance",
|
|
18657
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18658
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18659
|
+
outputCap: "ambient-light-sensor",
|
|
18660
|
+
outputField: "lux",
|
|
18661
|
+
quantity: "illuminance",
|
|
18662
|
+
defaultAggregate: "mean",
|
|
18663
|
+
empty: "null",
|
|
18664
|
+
companions: [NOW$2]
|
|
18665
|
+
}),
|
|
18666
|
+
numeric({
|
|
18667
|
+
id: "power",
|
|
18668
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18669
|
+
role: DeviceRole.PowerSensor,
|
|
18670
|
+
outputCap: "power-meter",
|
|
18671
|
+
outputField: "watts",
|
|
18672
|
+
quantity: "power",
|
|
18673
|
+
defaultAggregate: "sum",
|
|
18674
|
+
empty: "omit",
|
|
18675
|
+
companions: [NOW$2]
|
|
18676
|
+
}),
|
|
18677
|
+
numeric({
|
|
18678
|
+
id: "energy",
|
|
18679
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18680
|
+
role: DeviceRole.EnergySensor,
|
|
18681
|
+
outputCap: "power-meter",
|
|
18682
|
+
outputField: "kwhTotal",
|
|
18683
|
+
quantity: "energy",
|
|
18684
|
+
defaultAggregate: "sum",
|
|
18685
|
+
empty: "omit",
|
|
18686
|
+
companions: [NOW$2]
|
|
18687
|
+
}),
|
|
18688
|
+
numeric({
|
|
18689
|
+
id: "battery",
|
|
18690
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18691
|
+
role: DeviceRole.BatterySensor,
|
|
18692
|
+
outputCap: "battery",
|
|
18693
|
+
outputField: "percentage",
|
|
18694
|
+
quantity: "percentage",
|
|
18695
|
+
defaultAggregate: "mean",
|
|
18696
|
+
empty: "null",
|
|
18697
|
+
companions: [
|
|
18698
|
+
{
|
|
18699
|
+
fieldPath: "charging",
|
|
18700
|
+
expr: "\"unknown\""
|
|
18701
|
+
},
|
|
18702
|
+
{
|
|
18703
|
+
fieldPath: "sleeping",
|
|
18704
|
+
expr: "false"
|
|
18705
|
+
},
|
|
18706
|
+
{
|
|
18707
|
+
fieldPath: "lastUpdated",
|
|
18708
|
+
expr: "now"
|
|
18709
|
+
}
|
|
18710
|
+
]
|
|
18711
|
+
}),
|
|
18712
|
+
numeric({
|
|
18713
|
+
id: "numeric",
|
|
18714
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18715
|
+
role: DeviceRole.NumericSensor,
|
|
18716
|
+
outputCap: "numeric-sensor",
|
|
18717
|
+
outputField: "value",
|
|
18718
|
+
quantity: "device",
|
|
18719
|
+
defaultAggregate: "mean",
|
|
18720
|
+
empty: "null",
|
|
18721
|
+
companions: [NOW$2]
|
|
18722
|
+
}),
|
|
18723
|
+
binary({
|
|
18724
|
+
id: "motion",
|
|
18725
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18726
|
+
role: DeviceRole.MotionSensor,
|
|
18727
|
+
outputCap: "motion",
|
|
18728
|
+
outputField: "detected",
|
|
18729
|
+
defaultAggregate: "any",
|
|
18730
|
+
accept: [{
|
|
18731
|
+
cap: "motion",
|
|
18732
|
+
fieldPath: "detected"
|
|
18733
|
+
}],
|
|
18734
|
+
companions: [{
|
|
18735
|
+
fieldPath: "lastDetectedAt",
|
|
18736
|
+
expr: "null"
|
|
18737
|
+
}, {
|
|
18738
|
+
fieldPath: "autoClearAfterMs",
|
|
18739
|
+
expr: "null"
|
|
18740
|
+
}]
|
|
18741
|
+
}),
|
|
18742
|
+
binary({
|
|
18743
|
+
id: "contact",
|
|
18744
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18745
|
+
role: DeviceRole.ContactSensor,
|
|
18746
|
+
outputCap: "contact",
|
|
18747
|
+
outputField: "entryOpen",
|
|
18748
|
+
defaultAggregate: "any",
|
|
18749
|
+
accept: [{
|
|
18750
|
+
cap: "contact",
|
|
18751
|
+
fieldPath: "entryOpen"
|
|
18752
|
+
}],
|
|
18753
|
+
companions: [CHANGED]
|
|
18754
|
+
}),
|
|
18755
|
+
binary({
|
|
18756
|
+
id: "leak",
|
|
18757
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18758
|
+
role: DeviceRole.LeakSensor,
|
|
18759
|
+
outputCap: "flood",
|
|
18760
|
+
outputField: "flooded",
|
|
18761
|
+
defaultAggregate: "any",
|
|
18762
|
+
accept: [{
|
|
18763
|
+
cap: "flood",
|
|
18764
|
+
fieldPath: "flooded"
|
|
18765
|
+
}],
|
|
18766
|
+
companions: [CHANGED]
|
|
18767
|
+
}),
|
|
18768
|
+
binary({
|
|
18769
|
+
id: "smoke",
|
|
18770
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18771
|
+
role: DeviceRole.SmokeSensor,
|
|
18772
|
+
outputCap: "smoke",
|
|
18773
|
+
outputField: "detected",
|
|
18774
|
+
defaultAggregate: "any",
|
|
18775
|
+
accept: [{
|
|
18776
|
+
cap: "smoke",
|
|
18777
|
+
fieldPath: "detected"
|
|
18778
|
+
}],
|
|
18779
|
+
companions: [CHANGED]
|
|
18780
|
+
}),
|
|
18781
|
+
binary({
|
|
18782
|
+
id: "occupancy",
|
|
18783
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18784
|
+
role: DeviceRole.BinarySensor,
|
|
18785
|
+
outputCap: "binary",
|
|
18786
|
+
outputField: "on",
|
|
18787
|
+
defaultAggregate: "any",
|
|
18788
|
+
accept: [{
|
|
18789
|
+
cap: "motion",
|
|
18790
|
+
fieldPath: "detected"
|
|
18791
|
+
}, {
|
|
18792
|
+
cap: "binary",
|
|
18793
|
+
fieldPath: "on"
|
|
18794
|
+
}],
|
|
18795
|
+
companions: [CHANGED]
|
|
18796
|
+
}),
|
|
18797
|
+
binary({
|
|
18798
|
+
id: "binary",
|
|
18799
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18800
|
+
role: DeviceRole.BinarySensor,
|
|
18801
|
+
outputCap: "binary",
|
|
18802
|
+
outputField: "on",
|
|
18803
|
+
defaultAggregate: "any",
|
|
18804
|
+
accept: [{
|
|
18805
|
+
cap: "binary",
|
|
18806
|
+
fieldPath: "on"
|
|
18807
|
+
}],
|
|
18808
|
+
companions: [CHANGED]
|
|
18809
|
+
}),
|
|
18810
|
+
actuator({
|
|
18811
|
+
id: "switch",
|
|
18812
|
+
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.",
|
|
18813
|
+
deviceType: DeviceType.Switch,
|
|
18814
|
+
outputCap: "switch",
|
|
18815
|
+
outputField: "on",
|
|
18816
|
+
member: {
|
|
18817
|
+
cap: "switch",
|
|
18818
|
+
fieldPath: "on"
|
|
18819
|
+
},
|
|
18820
|
+
commandCaps: ["switch"]
|
|
18821
|
+
}),
|
|
18822
|
+
actuator({
|
|
18823
|
+
id: "light",
|
|
18824
|
+
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.",
|
|
18825
|
+
deviceType: DeviceType.Light,
|
|
18826
|
+
outputCap: "switch",
|
|
18827
|
+
outputField: "on",
|
|
18828
|
+
member: {
|
|
18829
|
+
cap: "switch",
|
|
18830
|
+
fieldPath: "on"
|
|
18831
|
+
},
|
|
18832
|
+
commandCaps: [
|
|
18833
|
+
"switch",
|
|
18834
|
+
"brightness",
|
|
18835
|
+
"color"
|
|
18836
|
+
]
|
|
18837
|
+
}),
|
|
18838
|
+
actuator({
|
|
18839
|
+
id: "fan",
|
|
18840
|
+
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.",
|
|
18841
|
+
deviceType: DeviceType.Fan,
|
|
18842
|
+
outputCap: "switch",
|
|
18843
|
+
outputField: "on",
|
|
18844
|
+
member: {
|
|
18845
|
+
cap: "switch",
|
|
18846
|
+
fieldPath: "on"
|
|
18847
|
+
},
|
|
18848
|
+
commandCaps: ["switch", "fan-control"]
|
|
18849
|
+
}),
|
|
18850
|
+
actuator({
|
|
18851
|
+
id: "cover",
|
|
18852
|
+
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.",
|
|
18853
|
+
deviceType: DeviceType.Cover,
|
|
18854
|
+
outputCap: "group-active",
|
|
18855
|
+
outputField: "active",
|
|
18856
|
+
member: {
|
|
18857
|
+
cap: "cover",
|
|
18858
|
+
fieldPath: "state"
|
|
18859
|
+
},
|
|
18860
|
+
activeWhen: [
|
|
18861
|
+
"open",
|
|
18862
|
+
"opening",
|
|
18863
|
+
"stopped"
|
|
18864
|
+
],
|
|
18865
|
+
commandCaps: ["cover"]
|
|
18866
|
+
}),
|
|
18867
|
+
actuator({
|
|
18868
|
+
id: "valve",
|
|
18869
|
+
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.",
|
|
18870
|
+
deviceType: DeviceType.Valve,
|
|
18871
|
+
outputCap: "group-active",
|
|
18872
|
+
outputField: "active",
|
|
18873
|
+
member: {
|
|
18874
|
+
cap: "valve",
|
|
18875
|
+
fieldPath: "state"
|
|
18876
|
+
},
|
|
18877
|
+
activeWhen: [
|
|
18878
|
+
"open",
|
|
18879
|
+
"opening",
|
|
18880
|
+
"stopped"
|
|
18881
|
+
],
|
|
18882
|
+
commandCaps: ["valve"]
|
|
18883
|
+
}),
|
|
18884
|
+
actuator({
|
|
18885
|
+
id: "lock",
|
|
18886
|
+
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.",
|
|
18887
|
+
deviceType: DeviceType.Lock,
|
|
18888
|
+
outputCap: "group-active",
|
|
18889
|
+
outputField: "active",
|
|
18890
|
+
member: {
|
|
18891
|
+
cap: "lock-control",
|
|
18892
|
+
fieldPath: "state"
|
|
18893
|
+
},
|
|
18894
|
+
activeWhen: ["locked"],
|
|
18895
|
+
commandCaps: ["lock-control"]
|
|
18896
|
+
}),
|
|
18897
|
+
actuator({
|
|
18898
|
+
id: "media-player",
|
|
18899
|
+
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.",
|
|
18900
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18901
|
+
outputCap: "group-active",
|
|
18902
|
+
outputField: "active",
|
|
18903
|
+
member: {
|
|
18904
|
+
cap: "media-player",
|
|
18905
|
+
fieldPath: "state"
|
|
18906
|
+
},
|
|
18907
|
+
activeWhen: ["playing", "buffering"],
|
|
18908
|
+
commandCaps: ["media-player"]
|
|
18909
|
+
}),
|
|
18910
|
+
actuator({
|
|
18911
|
+
id: "climate",
|
|
18912
|
+
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.",
|
|
18913
|
+
deviceType: DeviceType.Thermostat,
|
|
18914
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18915
|
+
outputCap: "group-active",
|
|
18916
|
+
outputField: "active",
|
|
18917
|
+
member: {
|
|
18918
|
+
cap: "climate-control",
|
|
18919
|
+
fieldPath: "mode"
|
|
18920
|
+
},
|
|
18921
|
+
activeWhen: [
|
|
18922
|
+
"heat",
|
|
18923
|
+
"cool",
|
|
18924
|
+
"auto",
|
|
18925
|
+
"heat_cool",
|
|
18926
|
+
"fan_only",
|
|
18927
|
+
"dry"
|
|
18928
|
+
],
|
|
18929
|
+
commandCaps: ["climate-control"]
|
|
18930
|
+
})
|
|
18931
|
+
];
|
|
18932
|
+
function actuator(input) {
|
|
18933
|
+
return {
|
|
18934
|
+
id: input.id,
|
|
18935
|
+
summary: input.summary,
|
|
18936
|
+
deviceType: input.deviceType,
|
|
18937
|
+
outputCap: input.outputCap,
|
|
18938
|
+
outputField: input.outputField,
|
|
18939
|
+
commandCaps: input.commandCaps,
|
|
18940
|
+
family: "actuator",
|
|
18941
|
+
role: void 0,
|
|
18942
|
+
memberDeviceType: input.deviceType,
|
|
18943
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18944
|
+
activeWhen: input.activeWhen,
|
|
18945
|
+
quantity: "none",
|
|
18946
|
+
baseUnit: void 0,
|
|
18947
|
+
aggregates: BINARY_AGGREGATES,
|
|
18948
|
+
defaultAggregate: "any",
|
|
18949
|
+
empty: "offline",
|
|
18950
|
+
accept: [input.member],
|
|
18951
|
+
companions: [CHANGED]
|
|
18952
|
+
};
|
|
18953
|
+
}
|
|
18954
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18955
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18956
|
+
DeviceType.Camera;
|
|
18231
18957
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18232
18958
|
/**
|
|
18233
18959
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19941,12 +20667,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
19941
20667
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19942
20668
|
* in-place so dispatch keeps working.
|
|
19943
20669
|
*
|
|
19944
|
-
* **
|
|
19945
|
-
*
|
|
19946
|
-
*
|
|
19947
|
-
*
|
|
19948
|
-
* (`ha-domain-mapping`)
|
|
19949
|
-
* stored after that point.
|
|
20670
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20671
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20672
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20673
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20674
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20675
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19950
20676
|
*
|
|
19951
20677
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19952
20678
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19960,6 +20686,14 @@ var SourceInfoSchema = object({
|
|
|
19960
20686
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19961
20687
|
* Used to detect rename when `id` changes. */
|
|
19962
20688
|
uniqueId: string().optional(),
|
|
20689
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20690
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20691
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20692
|
+
dateTimeShape: _enum([
|
|
20693
|
+
"date",
|
|
20694
|
+
"time",
|
|
20695
|
+
"datetime"
|
|
20696
|
+
]).optional(),
|
|
19963
20697
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19964
20698
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19965
20699
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41064,7 +41798,8 @@ method(object({
|
|
|
41064
41798
|
"enum"
|
|
41065
41799
|
]),
|
|
41066
41800
|
enumValues: array(string()).optional(),
|
|
41067
|
-
item: boolean().optional()
|
|
41801
|
+
item: boolean().optional(),
|
|
41802
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41068
41803
|
})).readonly(),
|
|
41069
41804
|
itemArray: object({
|
|
41070
41805
|
path: string(),
|
|
@@ -43425,7 +44160,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43425
44160
|
});
|
|
43426
44161
|
/**
|
|
43427
44162
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43428
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44163
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43429
44164
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43430
44165
|
* the originating provider config (mode + sourcePort) so the
|
|
43431
44166
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44908,8 +45643,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44908
45643
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44909
45644
|
var MaskGridShapeSchema = object({
|
|
44910
45645
|
kind: literal("grid"),
|
|
44911
|
-
gridWidth: number(),
|
|
44912
|
-
gridHeight: number(),
|
|
45646
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45647
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44913
45648
|
cells: array(boolean())
|
|
44914
45649
|
});
|
|
44915
45650
|
discriminatedUnion("kind", [
|
|
@@ -45021,6 +45756,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45021
45756
|
"detection-blind",
|
|
45022
45757
|
"motion-noisy",
|
|
45023
45758
|
"motion-calm",
|
|
45759
|
+
"package-llm-silent",
|
|
45760
|
+
"package-llm-answered",
|
|
45024
45761
|
"recording-stalled",
|
|
45025
45762
|
"recording-healthy",
|
|
45026
45763
|
"recording-degraded",
|
|
@@ -46110,7 +46847,20 @@ var NcRuleInputSchema = object({
|
|
|
46110
46847
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46111
46848
|
* path does not run Zod defaults.
|
|
46112
46849
|
*/
|
|
46113
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46850
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46851
|
+
/**
|
|
46852
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46853
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46854
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46855
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46856
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46857
|
+
*
|
|
46858
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46859
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46860
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46861
|
+
* `false`, so it needs no `clear` key.
|
|
46862
|
+
*/
|
|
46863
|
+
askVerdict: boolean().optional()
|
|
46114
46864
|
});
|
|
46115
46865
|
/**
|
|
46116
46866
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56216,6 +56966,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56216
56966
|
deprecated: string().optional(),
|
|
56217
56967
|
distTags: array(string()).readonly()
|
|
56218
56968
|
});
|
|
56969
|
+
/**
|
|
56970
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56971
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56972
|
+
* tarball failure — never an empty string standing in for either.
|
|
56973
|
+
*/
|
|
56974
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56975
|
+
object({
|
|
56976
|
+
status: literal("ok"),
|
|
56977
|
+
markdown: string()
|
|
56978
|
+
}),
|
|
56979
|
+
object({ status: literal("missing") }),
|
|
56980
|
+
object({
|
|
56981
|
+
status: literal("error"),
|
|
56982
|
+
message: string()
|
|
56983
|
+
})
|
|
56984
|
+
]);
|
|
56985
|
+
var PackageDocsSchema = object({
|
|
56986
|
+
name: string(),
|
|
56987
|
+
version: string(),
|
|
56988
|
+
readme: PackageDocBodySchema,
|
|
56989
|
+
changelog: PackageDocBodySchema
|
|
56990
|
+
});
|
|
56219
56991
|
var SearchResultSchema = object({
|
|
56220
56992
|
name: string(),
|
|
56221
56993
|
version: string(),
|
|
@@ -56434,7 +57206,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56434
57206
|
}), object({ success: literal(true) }), {
|
|
56435
57207
|
kind: "mutation",
|
|
56436
57208
|
auth: "admin"
|
|
56437
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57209
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57210
|
+
name: string().min(1),
|
|
57211
|
+
version: string().min(1).optional()
|
|
57212
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56438
57213
|
kind: "mutation",
|
|
56439
57214
|
auth: "admin"
|
|
56440
57215
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56493,27 +57268,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56493
57268
|
*/
|
|
56494
57269
|
var AirQualitySensorStatusSchema = object({
|
|
56495
57270
|
/** Carbon dioxide concentration in ppm. */
|
|
56496
|
-
co2Ppm: number().min(0).optional(),
|
|
57271
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56497
57272
|
/** Total volatile organic compounds in ppb. */
|
|
56498
|
-
vocPpb: number().min(0).optional(),
|
|
57273
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56499
57274
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56500
|
-
pm25: number().min(0).optional(),
|
|
57275
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56501
57276
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56502
|
-
pm10: number().min(0).optional(),
|
|
57277
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56503
57278
|
/** Composite AQI value (typically 0..500). */
|
|
56504
|
-
aqi: number().optional(),
|
|
57279
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56505
57280
|
/** Ms epoch when the slice was last updated. */
|
|
56506
|
-
lastFetchedAt: number()
|
|
56507
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56508
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56509
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56510
|
-
* per slice is unambiguous. */
|
|
56511
|
-
unit: string().optional(),
|
|
56512
|
-
/** Suggested decimal places for numeric display.
|
|
56513
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56514
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56515
|
-
* auto-formatting when absent. */
|
|
56516
|
-
precision: number().int().min(0).max(10).optional()
|
|
57281
|
+
lastFetchedAt: number()
|
|
56517
57282
|
});
|
|
56518
57283
|
var airQualitySensorCapability = {
|
|
56519
57284
|
name: "air-quality-sensor",
|
|
@@ -56550,12 +57315,12 @@ var airQualitySensorCapability = {
|
|
|
56550
57315
|
},
|
|
56551
57316
|
pm25: {
|
|
56552
57317
|
kind: "gauge",
|
|
56553
|
-
unit: "
|
|
57318
|
+
unit: "µg/m³",
|
|
56554
57319
|
deadband: 1
|
|
56555
57320
|
},
|
|
56556
57321
|
pm10: {
|
|
56557
57322
|
kind: "gauge",
|
|
56558
|
-
unit: "
|
|
57323
|
+
unit: "µg/m³",
|
|
56559
57324
|
deadband: 1
|
|
56560
57325
|
},
|
|
56561
57326
|
aqi: {
|
|
@@ -56573,22 +57338,13 @@ var airQualitySensorCapability = {
|
|
|
56573
57338
|
* entries with `device_class: illuminance`.
|
|
56574
57339
|
*/
|
|
56575
57340
|
var AmbientLightSensorStatusSchema = object({
|
|
56576
|
-
/** Current illuminance in lux (lx). */
|
|
56577
|
-
lux: number().min(0).meta({
|
|
56578
|
-
|
|
57341
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57342
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57343
|
+
precision: 0,
|
|
56579
57344
|
label: "Illuminance"
|
|
56580
|
-
}),
|
|
57345
|
+
})),
|
|
56581
57346
|
/** Ms epoch when the slice was last updated. */
|
|
56582
|
-
lastFetchedAt: number()
|
|
56583
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56584
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56585
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56586
|
-
unit: string().optional(),
|
|
56587
|
-
/** Suggested decimal places for numeric display.
|
|
56588
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56589
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56590
|
-
* auto-formatting when absent. */
|
|
56591
|
-
precision: number().int().min(0).max(10).optional()
|
|
57347
|
+
lastFetchedAt: number()
|
|
56592
57348
|
});
|
|
56593
57349
|
var ambientLightSensorCapability = {
|
|
56594
57350
|
name: "ambient-light-sensor",
|
|
@@ -56620,12 +57376,7 @@ var ambientLightSensorCapability = {
|
|
|
56620
57376
|
} } },
|
|
56621
57377
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56622
57378
|
* whether persisting is worth a SQLite commit. */
|
|
56623
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56624
|
-
customize: {
|
|
56625
|
-
version: 1,
|
|
56626
|
-
advanced: "derive",
|
|
56627
|
-
targets: []
|
|
56628
|
-
}
|
|
57379
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56629
57380
|
};
|
|
56630
57381
|
/**
|
|
56631
57382
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56852,10 +57603,7 @@ var BatteryStatusSchema = object({
|
|
|
56852
57603
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56853
57604
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56854
57605
|
*/
|
|
56855
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56856
|
-
unit: "%",
|
|
56857
|
-
label: "Charge"
|
|
56858
|
-
}),
|
|
57606
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56859
57607
|
/**
|
|
56860
57608
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56861
57609
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56882,7 +57630,14 @@ var BatteryStatusSchema = object({
|
|
|
56882
57630
|
*/
|
|
56883
57631
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56884
57632
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56885
|
-
lastUpdated: number(),
|
|
57633
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57634
|
+
/**
|
|
57635
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57636
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57637
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57638
|
+
* `numeric-sensor` on the same device.
|
|
57639
|
+
*/
|
|
57640
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56886
57641
|
/**
|
|
56887
57642
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56888
57643
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56929,12 +57684,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56929
57684
|
DeviceType.Switch,
|
|
56930
57685
|
DeviceType.PetFeeder,
|
|
56931
57686
|
DeviceType.Container,
|
|
56932
|
-
DeviceType.Thermostat
|
|
57687
|
+
DeviceType.Thermostat,
|
|
57688
|
+
DeviceType.EventEmitter
|
|
56933
57689
|
];
|
|
56934
57690
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56935
57691
|
var batteryCustomize = {
|
|
56936
57692
|
version: 1,
|
|
56937
|
-
advanced: "derive",
|
|
56938
57693
|
targets: [{
|
|
56939
57694
|
id: "percentage",
|
|
56940
57695
|
cardinality: "scalar",
|
|
@@ -56943,7 +57698,7 @@ var batteryCustomize = {
|
|
|
56943
57698
|
stateField: "percentage"
|
|
56944
57699
|
},
|
|
56945
57700
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56946
|
-
apply: "add
|
|
57701
|
+
apply: "add",
|
|
56947
57702
|
path: "percentage",
|
|
56948
57703
|
sources: [{
|
|
56949
57704
|
kind: "field",
|
|
@@ -57064,10 +57819,16 @@ onStatusChanged: { data: object({
|
|
|
57064
57819
|
/**
|
|
57065
57820
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
57066
57821
|
*/
|
|
57067
|
-
history: { fields: {
|
|
57068
|
-
|
|
57069
|
-
|
|
57070
|
-
|
|
57822
|
+
history: { fields: {
|
|
57823
|
+
percentage: {
|
|
57824
|
+
kind: "gauge",
|
|
57825
|
+
unit: "%"
|
|
57826
|
+
},
|
|
57827
|
+
volts: {
|
|
57828
|
+
kind: "gauge",
|
|
57829
|
+
unit: "V"
|
|
57830
|
+
}
|
|
57831
|
+
} },
|
|
57071
57832
|
customize: batteryCustomize,
|
|
57072
57833
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57073
57834
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57114,12 +57875,7 @@ var binaryCapability = {
|
|
|
57114
57875
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57115
57876
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57116
57877
|
* whether persisting is worth a SQLite commit. */
|
|
57117
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57118
|
-
customize: {
|
|
57119
|
-
version: 1,
|
|
57120
|
-
advanced: "derive",
|
|
57121
|
-
targets: []
|
|
57122
|
-
}
|
|
57878
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57123
57879
|
};
|
|
57124
57880
|
/**
|
|
57125
57881
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57135,7 +57891,7 @@ var binaryCapability = {
|
|
|
57135
57891
|
*/
|
|
57136
57892
|
var BrightnessStatusSchema = object({
|
|
57137
57893
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57138
|
-
percentage: number().min(0).max(100),
|
|
57894
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57139
57895
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57140
57896
|
lastChangedAt: number()
|
|
57141
57897
|
});
|
|
@@ -57589,21 +58345,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57589
58345
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57590
58346
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57591
58347
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57592
|
-
target: number().nullable(),
|
|
58348
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57593
58349
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57594
58350
|
* in `heat_cool` mode. */
|
|
57595
|
-
targetHigh: number().nullable(),
|
|
58351
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57596
58352
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57597
58353
|
* in `heat_cool` mode. */
|
|
57598
|
-
targetLow: number().nullable(),
|
|
58354
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57599
58355
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57600
58356
|
* humidity control. */
|
|
57601
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58357
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57602
58358
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57603
58359
|
* the device's internal sensor. */
|
|
57604
|
-
currentTemp: number().nullable(),
|
|
58360
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57605
58361
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57606
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58362
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57607
58363
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57608
58364
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57609
58365
|
swingVertical: boolean().nullable(),
|
|
@@ -57611,11 +58367,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57611
58367
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57612
58368
|
swingHorizontal: boolean().nullable(),
|
|
57613
58369
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57614
|
-
minTemp: number().nullable().optional(),
|
|
58370
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57615
58371
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57616
|
-
maxTemp: number().nullable().optional(),
|
|
58372
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57617
58373
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57618
|
-
tempStep: number().positive().nullable().optional(),
|
|
58374
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57619
58375
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57620
58376
|
lastFetchedAt: number()
|
|
57621
58377
|
});
|
|
@@ -57757,17 +58513,17 @@ var climateControlCapability = {
|
|
|
57757
58513
|
* modes to expose in the picker without a slice fetch.
|
|
57758
58514
|
*/
|
|
57759
58515
|
var RgbTripletSchema = object({
|
|
57760
|
-
r: number().int().min(0).max(255),
|
|
57761
|
-
g: number().int().min(0).max(255),
|
|
57762
|
-
b: number().int().min(0).max(255)
|
|
58516
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58517
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58518
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57763
58519
|
});
|
|
57764
58520
|
var HsvTripletSchema = object({
|
|
57765
58521
|
/** Hue in degrees, 0..360. */
|
|
57766
|
-
h: number().min(0).max(360),
|
|
58522
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57767
58523
|
/** Saturation as 0..100 inclusive. */
|
|
57768
|
-
s: number().min(0).max(100),
|
|
58524
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57769
58525
|
/** Value/brightness as 0..100 inclusive. */
|
|
57770
|
-
v: number().min(0).max(100)
|
|
58526
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57771
58527
|
});
|
|
57772
58528
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57773
58529
|
object({
|
|
@@ -57796,7 +58552,7 @@ var ColorStatusSchema = object({
|
|
|
57796
58552
|
/** Populated when `mode === 'hsv'`. */
|
|
57797
58553
|
hsv: HsvTripletSchema.optional(),
|
|
57798
58554
|
/** Populated when `mode === 'mired'`. */
|
|
57799
|
-
mireds: number().int().optional(),
|
|
58555
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57800
58556
|
/** Ms epoch of the last operator-driven change. */
|
|
57801
58557
|
lastChangedAt: number()
|
|
57802
58558
|
});
|
|
@@ -57999,18 +58755,12 @@ _enum([
|
|
|
57999
58755
|
"empty",
|
|
58000
58756
|
"full"
|
|
58001
58757
|
]);
|
|
58002
|
-
/**
|
|
58003
|
-
|
|
58004
|
-
|
|
58005
|
-
"days",
|
|
58006
|
-
"hours",
|
|
58007
|
-
"cycles"
|
|
58008
|
-
]);
|
|
58009
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
58010
|
-
* days). `value` null = unknown (D393). */
|
|
58758
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58759
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58760
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
58011
58761
|
var ConsumableRemainingSchema = object({
|
|
58012
|
-
value: number().min(0).nullable(),
|
|
58013
|
-
|
|
58762
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58763
|
+
kind: ConsumableRemainingKindSchema
|
|
58014
58764
|
});
|
|
58015
58765
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
58016
58766
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -58023,7 +58773,7 @@ var ConsumableItemSchema = object({
|
|
|
58023
58773
|
/** Display name. */
|
|
58024
58774
|
label: string().min(1),
|
|
58025
58775
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
58026
|
-
level: number().min(0).max(100).nullable(),
|
|
58776
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58027
58777
|
/** The provider's discrete verdict when known (binary mode). */
|
|
58028
58778
|
status: ConsumableStatusSchema.nullable(),
|
|
58029
58779
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58105,8 +58855,8 @@ var consumablesCustomize = {
|
|
|
58105
58855
|
transforms: [{ kind: "identity" }]
|
|
58106
58856
|
}],
|
|
58107
58857
|
literals: [{
|
|
58108
|
-
path: "remaining.
|
|
58109
|
-
values: [...
|
|
58858
|
+
path: "remaining.kind",
|
|
58859
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58110
58860
|
}]
|
|
58111
58861
|
},
|
|
58112
58862
|
{
|
|
@@ -58235,7 +58985,6 @@ reset: method(object({
|
|
|
58235
58985
|
},
|
|
58236
58986
|
"remaining.value": {
|
|
58237
58987
|
kind: "gauge",
|
|
58238
|
-
unitFrom: "remaining.unit",
|
|
58239
58988
|
deadband: 1,
|
|
58240
58989
|
displayName: "Remaining"
|
|
58241
58990
|
}
|
|
@@ -58305,10 +59054,9 @@ var contactCapability = {
|
|
|
58305
59054
|
* (empty array for the other kinds). It lives in the slice because
|
|
58306
59055
|
* HA `select.*` entities may update their options at runtime.
|
|
58307
59056
|
*
|
|
58308
|
-
*
|
|
58309
|
-
*
|
|
58310
|
-
*
|
|
58311
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
59057
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
59058
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
59059
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58312
59060
|
*/
|
|
58313
59061
|
var ControlStatusSchema = object({
|
|
58314
59062
|
kind: _enum([
|
|
@@ -58320,39 +59068,17 @@ var ControlStatusSchema = object({
|
|
|
58320
59068
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58321
59069
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58322
59070
|
* or time-only — HA accepts all three forms). */
|
|
58323
|
-
value: union([number(), string()]),
|
|
59071
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58324
59072
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58325
59073
|
options: array(string()),
|
|
58326
59074
|
/** Ms epoch when the slice was last updated. */
|
|
58327
59075
|
lastChangedAt: number(),
|
|
58328
|
-
/**
|
|
58329
|
-
|
|
58330
|
-
|
|
58331
|
-
|
|
58332
|
-
/**
|
|
58333
|
-
|
|
58334
|
-
min: number().optional(),
|
|
58335
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58336
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58337
|
-
max: number().optional(),
|
|
58338
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58339
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58340
|
-
step: number().optional(),
|
|
58341
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58342
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58343
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58344
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58345
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58346
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58347
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58348
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58349
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58350
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58351
|
-
format: _enum([
|
|
58352
|
-
"date",
|
|
58353
|
-
"time",
|
|
58354
|
-
"datetime"
|
|
58355
|
-
]).optional()
|
|
59076
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
59077
|
+
min: number().optional().meta(readingMeta("device")),
|
|
59078
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
59079
|
+
max: number().optional().meta(readingMeta("device")),
|
|
59080
|
+
/** Step increment, in the device quantity's base unit. */
|
|
59081
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58356
59082
|
});
|
|
58357
59083
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58358
59084
|
object({
|
|
@@ -58418,9 +59144,9 @@ var CoverStatusSchema = object({
|
|
|
58418
59144
|
]),
|
|
58419
59145
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58420
59146
|
* no intermediate position surface. */
|
|
58421
|
-
position: number().min(0).max(100).nullable(),
|
|
59147
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58422
59148
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58423
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59149
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58424
59150
|
/** Ms epoch when the slice was last updated. */
|
|
58425
59151
|
lastChangedAt: number()
|
|
58426
59152
|
});
|
|
@@ -58523,9 +59249,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58523
59249
|
var DayNightStatusSchema = object({
|
|
58524
59250
|
mode: DayNightModeSchema,
|
|
58525
59251
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58526
|
-
sensitivity: number().optional(),
|
|
59252
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58527
59253
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58528
|
-
switchDelaySec: number().optional(),
|
|
59254
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58529
59255
|
lastFetchedAt: number()
|
|
58530
59256
|
});
|
|
58531
59257
|
/**
|
|
@@ -58743,11 +59469,11 @@ var DishwasherStatusSchema = object({
|
|
|
58743
59469
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58744
59470
|
availablePrograms: array(string()),
|
|
58745
59471
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58746
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59472
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58747
59473
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58748
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59474
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58749
59475
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58750
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59476
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58751
59477
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58752
59478
|
doorOpen: boolean().nullable(),
|
|
58753
59479
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58771,7 +59497,7 @@ var DishwasherStatusSchema = object({
|
|
|
58771
59497
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58772
59498
|
machineCareDue: boolean().nullable(),
|
|
58773
59499
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58774
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59500
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58775
59501
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58776
59502
|
halfLoad: boolean().nullable(),
|
|
58777
59503
|
hygienePlus: boolean().nullable(),
|
|
@@ -58786,7 +59512,7 @@ var DishwasherStatusSchema = object({
|
|
|
58786
59512
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58787
59513
|
activeEvents: array(string()),
|
|
58788
59514
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58789
|
-
errorCode: number().nullable(),
|
|
59515
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58790
59516
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58791
59517
|
errorLabel: string().nullable(),
|
|
58792
59518
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -59017,7 +59743,7 @@ var DoorbellStatusSchema = object({
|
|
|
59017
59743
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
59018
59744
|
lastPressedAt: number().nullable(),
|
|
59019
59745
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
59020
|
-
pressCountSinceStart: number()
|
|
59746
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
59021
59747
|
});
|
|
59022
59748
|
var DoorbellPressEventSchema = object({
|
|
59023
59749
|
deviceId: number(),
|
|
@@ -59082,17 +59808,7 @@ onPressed: {
|
|
|
59082
59808
|
history: "none",
|
|
59083
59809
|
customize: doorbellCustomize
|
|
59084
59810
|
};
|
|
59085
|
-
|
|
59086
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
59087
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
59088
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
59089
|
-
* The option set is stable across observations; it is persisted in the
|
|
59090
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
59091
|
-
* stored in `sourceInfo`.
|
|
59092
|
-
*/
|
|
59093
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
59094
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
59095
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
59811
|
+
_enum([
|
|
59096
59812
|
"date",
|
|
59097
59813
|
"time",
|
|
59098
59814
|
"datetime"
|
|
@@ -59100,12 +59816,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59100
59816
|
var EnumSensorStatusSchema = object({
|
|
59101
59817
|
value: string(),
|
|
59102
59818
|
/**
|
|
59103
|
-
* Set
|
|
59104
|
-
* as
|
|
59105
|
-
*
|
|
59106
|
-
* a time-only sensor → `'time'`.
|
|
59819
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
59820
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
59821
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59107
59822
|
*/
|
|
59108
|
-
|
|
59823
|
+
timestamp: boolean().optional(),
|
|
59109
59824
|
/** Ms epoch when the slice was last updated. */
|
|
59110
59825
|
lastFetchedAt: number()
|
|
59111
59826
|
});
|
|
@@ -59132,11 +59847,11 @@ var enumSensorCapability = {
|
|
|
59132
59847
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59133
59848
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59134
59849
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59135
|
-
* `
|
|
59850
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59136
59851
|
*/
|
|
59137
59852
|
history: { fields: { value: {
|
|
59138
59853
|
kind: "enum",
|
|
59139
|
-
skipWhenSet: "
|
|
59854
|
+
skipWhenSet: "timestamp"
|
|
59140
59855
|
} } },
|
|
59141
59856
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59142
59857
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59156,13 +59871,13 @@ var EventFireSchema = object({
|
|
|
59156
59871
|
deviceId: number(),
|
|
59157
59872
|
eventType: string(),
|
|
59158
59873
|
data: record(string(), unknown()).nullable(),
|
|
59159
|
-
timestamp: number(),
|
|
59160
|
-
seq: number()
|
|
59874
|
+
timestamp: number().meta(readingMeta("none")),
|
|
59875
|
+
seq: number().meta(readingMeta("count"))
|
|
59161
59876
|
});
|
|
59162
59877
|
var EventEmitterStatusSchema = object({
|
|
59163
59878
|
eventTypes: array(string()),
|
|
59164
59879
|
lastEvent: EventFireSchema.nullable(),
|
|
59165
|
-
eventCountSinceStart: number()
|
|
59880
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59166
59881
|
});
|
|
59167
59882
|
var eventEmitterCapability = {
|
|
59168
59883
|
name: "event-emitter",
|
|
@@ -59575,10 +60290,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59575
60290
|
var FanControlStatusSchema = object({
|
|
59576
60291
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59577
60292
|
* speed surface (single-speed fan). */
|
|
59578
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60293
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59579
60294
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59580
60295
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59581
|
-
percentageStep: number().positive().optional(),
|
|
60296
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59582
60297
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59583
60298
|
* — empty string when no preset is active or supported. */
|
|
59584
60299
|
preset: string(),
|
|
@@ -59699,7 +60414,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59699
60414
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59700
60415
|
model: string().nullable(),
|
|
59701
60416
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59702
|
-
channelCount: number().nullable(),
|
|
60417
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59703
60418
|
/**
|
|
59704
60419
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59705
60420
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59822,9 +60537,151 @@ var gasCapability = {
|
|
|
59822
60537
|
* whether persisting is worth a SQLite commit. */
|
|
59823
60538
|
volatileStateFields: ["lastChangedAt"]
|
|
59824
60539
|
};
|
|
60540
|
+
var GroupCommandsSchema = object({
|
|
60541
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60542
|
+
results: array(object({
|
|
60543
|
+
deviceId: number().int().nonnegative(),
|
|
60544
|
+
cap: string().min(1),
|
|
60545
|
+
method: string().min(1),
|
|
60546
|
+
ok: boolean(),
|
|
60547
|
+
error: string().optional(),
|
|
60548
|
+
/** Ms epoch of the attempt. */
|
|
60549
|
+
at: number()
|
|
60550
|
+
})) });
|
|
60551
|
+
var groupCommandsCapability = {
|
|
60552
|
+
name: "group-commands",
|
|
60553
|
+
scope: "device",
|
|
60554
|
+
deviceNative: true,
|
|
60555
|
+
mode: "singleton",
|
|
60556
|
+
deviceTypes: [
|
|
60557
|
+
DeviceType.Switch,
|
|
60558
|
+
DeviceType.Light,
|
|
60559
|
+
DeviceType.Fan,
|
|
60560
|
+
DeviceType.Cover,
|
|
60561
|
+
DeviceType.Valve,
|
|
60562
|
+
DeviceType.Lock,
|
|
60563
|
+
DeviceType.MediaPlayer,
|
|
60564
|
+
DeviceType.Thermostat,
|
|
60565
|
+
DeviceType.Climate
|
|
60566
|
+
],
|
|
60567
|
+
methods: {},
|
|
60568
|
+
status: {
|
|
60569
|
+
schema: GroupCommandsSchema,
|
|
60570
|
+
kind: "push"
|
|
60571
|
+
},
|
|
60572
|
+
runtimeState: GroupCommandsSchema,
|
|
60573
|
+
/**
|
|
60574
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
60575
|
+
* failure would outlive the command that caused it.
|
|
60576
|
+
*
|
|
60577
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60578
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60579
|
+
*/
|
|
60580
|
+
durability: "session",
|
|
60581
|
+
history: "none"
|
|
60582
|
+
};
|
|
60583
|
+
/**
|
|
60584
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
60585
|
+
* included member is, or every included member is. What "active" means is the
|
|
60586
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
60587
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
60588
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
60589
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
60590
|
+
* empty included set takes the device offline, never `active: false`.
|
|
60591
|
+
*/
|
|
60592
|
+
var GroupActiveSchema = object({
|
|
60593
|
+
active: boolean().meta({ label: "Active" }),
|
|
60594
|
+
/** Ms epoch when the slice was last updated. */
|
|
60595
|
+
lastChangedAt: number()
|
|
60596
|
+
});
|
|
60597
|
+
var groupActiveCapability = {
|
|
60598
|
+
name: "group-active",
|
|
60599
|
+
scope: "device",
|
|
60600
|
+
deviceNative: true,
|
|
60601
|
+
mode: "singleton",
|
|
60602
|
+
deviceTypes: [
|
|
60603
|
+
DeviceType.Cover,
|
|
60604
|
+
DeviceType.Valve,
|
|
60605
|
+
DeviceType.Lock,
|
|
60606
|
+
DeviceType.MediaPlayer,
|
|
60607
|
+
DeviceType.Climate,
|
|
60608
|
+
DeviceType.Thermostat
|
|
60609
|
+
],
|
|
60610
|
+
methods: {},
|
|
60611
|
+
status: {
|
|
60612
|
+
schema: GroupActiveSchema,
|
|
60613
|
+
kind: "push"
|
|
60614
|
+
},
|
|
60615
|
+
runtimeState: GroupActiveSchema,
|
|
60616
|
+
/**
|
|
60617
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
60618
|
+
* next source event; a restored value would outlive the members it named.
|
|
60619
|
+
*
|
|
60620
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60621
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60622
|
+
*/
|
|
60623
|
+
durability: "session",
|
|
60624
|
+
history: "none"
|
|
60625
|
+
};
|
|
60626
|
+
/**
|
|
60627
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60628
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60629
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60630
|
+
* series that later statistics read is the output cap's own history block.
|
|
60631
|
+
*/
|
|
60632
|
+
var GroupStatusSchema = object({
|
|
60633
|
+
/** Members whose current value entered the aggregate. */
|
|
60634
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60635
|
+
precision: 0,
|
|
60636
|
+
label: "Reporting"
|
|
60637
|
+
})),
|
|
60638
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60639
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60640
|
+
precision: 0,
|
|
60641
|
+
label: "Excluded"
|
|
60642
|
+
})),
|
|
60643
|
+
/** `included` + `excluded`. */
|
|
60644
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60645
|
+
precision: 0,
|
|
60646
|
+
label: "Members"
|
|
60647
|
+
}))
|
|
60648
|
+
});
|
|
60649
|
+
var groupStatusCapability = {
|
|
60650
|
+
name: "group-status",
|
|
60651
|
+
scope: "device",
|
|
60652
|
+
deviceNative: true,
|
|
60653
|
+
mode: "singleton",
|
|
60654
|
+
deviceTypes: [
|
|
60655
|
+
DeviceType.Sensor,
|
|
60656
|
+
DeviceType.Switch,
|
|
60657
|
+
DeviceType.Light,
|
|
60658
|
+
DeviceType.Fan,
|
|
60659
|
+
DeviceType.Cover,
|
|
60660
|
+
DeviceType.Valve,
|
|
60661
|
+
DeviceType.Lock,
|
|
60662
|
+
DeviceType.MediaPlayer,
|
|
60663
|
+
DeviceType.Thermostat,
|
|
60664
|
+
DeviceType.Climate
|
|
60665
|
+
],
|
|
60666
|
+
methods: {},
|
|
60667
|
+
status: {
|
|
60668
|
+
schema: GroupStatusSchema,
|
|
60669
|
+
kind: "push"
|
|
60670
|
+
},
|
|
60671
|
+
runtimeState: GroupStatusSchema,
|
|
60672
|
+
/**
|
|
60673
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60674
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60675
|
+
*
|
|
60676
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60677
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60678
|
+
*/
|
|
60679
|
+
durability: "session",
|
|
60680
|
+
history: "none"
|
|
60681
|
+
};
|
|
59825
60682
|
var HeatingValveStatusSchema = object({
|
|
59826
60683
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59827
|
-
position: number().min(0).max(100).nullable(),
|
|
60684
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59828
60685
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59829
60686
|
lastFetchedAt: number()
|
|
59830
60687
|
});
|
|
@@ -59867,9 +60724,9 @@ var HumidifierStatusSchema = object({
|
|
|
59867
60724
|
/** Whether the humidifier is currently on. */
|
|
59868
60725
|
on: boolean(),
|
|
59869
60726
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59870
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60727
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59871
60728
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59872
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60729
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59873
60730
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59874
60731
|
* device has no mode surface. */
|
|
59875
60732
|
mode: string().nullable(),
|
|
@@ -59879,9 +60736,9 @@ var HumidifierStatusSchema = object({
|
|
|
59879
60736
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59880
60737
|
action: string().nullable(),
|
|
59881
60738
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59882
|
-
minHumidity: number().nullable(),
|
|
60739
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59883
60740
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59884
|
-
maxHumidity: number().nullable(),
|
|
60741
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59885
60742
|
/** Ms epoch when the slice was last updated. */
|
|
59886
60743
|
lastChangedAt: number()
|
|
59887
60744
|
});
|
|
@@ -59951,22 +60808,13 @@ var humidifierCapability = {
|
|
|
59951
60808
|
* `sourceInfo`.
|
|
59952
60809
|
*/
|
|
59953
60810
|
var HumiditySensorStatusSchema = object({
|
|
59954
|
-
/** Current relative humidity, 0..100. */
|
|
59955
|
-
percent: number().min(0).max(100).meta({
|
|
59956
|
-
|
|
60811
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60812
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60813
|
+
precision: 0,
|
|
59957
60814
|
label: "Humidity"
|
|
59958
|
-
}),
|
|
60815
|
+
})),
|
|
59959
60816
|
/** Ms epoch when the slice was last updated. */
|
|
59960
|
-
lastFetchedAt: number()
|
|
59961
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59962
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59963
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59964
|
-
unit: string().optional(),
|
|
59965
|
-
/** Suggested decimal places for numeric display.
|
|
59966
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59967
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59968
|
-
* auto-formatting when absent. */
|
|
59969
|
-
precision: number().int().min(0).max(10).optional()
|
|
60817
|
+
lastFetchedAt: number()
|
|
59970
60818
|
});
|
|
59971
60819
|
var humiditySensorCapability = {
|
|
59972
60820
|
name: "humidity-sensor",
|
|
@@ -59997,12 +60845,7 @@ var humiditySensorCapability = {
|
|
|
59997
60845
|
} } },
|
|
59998
60846
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59999
60847
|
* whether persisting is worth a SQLite commit. */
|
|
60000
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
60001
|
-
customize: {
|
|
60002
|
-
version: 1,
|
|
60003
|
-
advanced: "derive",
|
|
60004
|
-
targets: []
|
|
60005
|
-
}
|
|
60848
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
60006
60849
|
};
|
|
60007
60850
|
/**
|
|
60008
60851
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -60023,7 +60866,7 @@ var ImageStatusSchema = object({
|
|
|
60023
60866
|
* entity exposes no `entity_picture` (yet). */
|
|
60024
60867
|
url: string().nullable(),
|
|
60025
60868
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
60026
|
-
lastUpdated: number().nullable()
|
|
60869
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
60027
60870
|
});
|
|
60028
60871
|
var imageCapability = {
|
|
60029
60872
|
name: "image",
|
|
@@ -60111,19 +60954,19 @@ var NormalizedRangeSchema = object({
|
|
|
60111
60954
|
*/
|
|
60112
60955
|
var ImageSettingsStatusSchema = object({
|
|
60113
60956
|
/** Normalized 0–100. */
|
|
60114
|
-
brightness: number().optional(),
|
|
60957
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60115
60958
|
/** Normalized 0–100. */
|
|
60116
|
-
contrast: number().optional(),
|
|
60959
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60117
60960
|
/** Normalized 0–100. */
|
|
60118
|
-
saturation: number().optional(),
|
|
60961
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60119
60962
|
/** Normalized 0–100. */
|
|
60120
|
-
sharpness: number().optional(),
|
|
60963
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60121
60964
|
mirror: boolean().optional(),
|
|
60122
60965
|
flip: boolean().optional(),
|
|
60123
60966
|
rotate: ImageRotateSchema.optional(),
|
|
60124
60967
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60125
60968
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60126
|
-
warmth: number().optional(),
|
|
60969
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60127
60970
|
exposureMode: ExposureModeSchema.optional(),
|
|
60128
60971
|
backlightMode: BacklightModeSchema.optional(),
|
|
60129
60972
|
lastFetchedAt: number()
|
|
@@ -60402,10 +61245,10 @@ var IntercomAbilitySchema = object({
|
|
|
60402
61245
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60403
61246
|
codecs: array(string()),
|
|
60404
61247
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60405
|
-
sampleRate: number(),
|
|
61248
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60406
61249
|
duplex: _enum(["half", "full"]),
|
|
60407
61250
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60408
|
-
maxBacklogMs: number()
|
|
61251
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60409
61252
|
});
|
|
60410
61253
|
var IntercomStatusSchema = object({
|
|
60411
61254
|
/** True while a talk session is open. */
|
|
@@ -60632,13 +61475,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60632
61475
|
activity: LawnMowerActivitySchema,
|
|
60633
61476
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60634
61477
|
* reading. */
|
|
60635
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61478
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60636
61479
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60637
61480
|
* task is active / progress is unavailable. */
|
|
60638
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61481
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60639
61482
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60640
61483
|
* or null when unknown. */
|
|
60641
|
-
currentCode: number().nullable(),
|
|
61484
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60642
61485
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60643
61486
|
currentCodeLabel: string().nullable(),
|
|
60644
61487
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61091,7 +61934,14 @@ var lockControlCapability = {
|
|
|
61091
61934
|
}),
|
|
61092
61935
|
unlock: method(object({
|
|
61093
61936
|
deviceId: number().int().nonnegative(),
|
|
61094
|
-
code: string().min(1).optional()
|
|
61937
|
+
code: string().min(1).optional(),
|
|
61938
|
+
/**
|
|
61939
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
61940
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
61941
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
61942
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
61943
|
+
*/
|
|
61944
|
+
confirm: boolean().optional()
|
|
61095
61945
|
}), _void(), {
|
|
61096
61946
|
kind: "mutation",
|
|
61097
61947
|
auth: "protected"
|
|
@@ -61128,6 +61978,44 @@ var lockControlCapability = {
|
|
|
61128
61978
|
volatileStateFields: ["lastChangedAt"]
|
|
61129
61979
|
};
|
|
61130
61980
|
/**
|
|
61981
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
61982
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
61983
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
61984
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
61985
|
+
*/
|
|
61986
|
+
var MeterStatusSchema = object({
|
|
61987
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
61988
|
+
lastFetchedAt: number()
|
|
61989
|
+
});
|
|
61990
|
+
var meterCapability = {
|
|
61991
|
+
name: "meter",
|
|
61992
|
+
scope: "device",
|
|
61993
|
+
deviceNative: true,
|
|
61994
|
+
mode: "singleton",
|
|
61995
|
+
deviceTypes: [DeviceType.Sensor],
|
|
61996
|
+
methods: {},
|
|
61997
|
+
status: {
|
|
61998
|
+
schema: MeterStatusSchema,
|
|
61999
|
+
kind: "push"
|
|
62000
|
+
},
|
|
62001
|
+
runtimeState: MeterStatusSchema,
|
|
62002
|
+
/**
|
|
62003
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
62004
|
+
* history integral. A restart shows it only until the history pass
|
|
62005
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
62006
|
+
*
|
|
62007
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
62008
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
62009
|
+
*/
|
|
62010
|
+
durability: "restored",
|
|
62011
|
+
history: { fields: { value: {
|
|
62012
|
+
kind: "counter",
|
|
62013
|
+
deadband: .001,
|
|
62014
|
+
minIntervalMs: 6e4
|
|
62015
|
+
} } },
|
|
62016
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
62017
|
+
};
|
|
62018
|
+
/**
|
|
61131
62019
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61132
62020
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61133
62021
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -61171,7 +62059,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61171
62059
|
state: MediaPlayerStateSchema,
|
|
61172
62060
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61173
62061
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61174
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
62062
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61175
62063
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61176
62064
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61177
62065
|
isMuted: boolean().nullable(),
|
|
@@ -61184,10 +62072,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61184
62072
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61185
62073
|
/** Current playback position in ms. Null when not seekable or
|
|
61186
62074
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61187
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
62075
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61188
62076
|
/** Total duration of the current media in ms. Null when unknown
|
|
61189
62077
|
* (live stream) or nothing is playing. */
|
|
61190
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
62078
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61191
62079
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61192
62080
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61193
62081
|
shuffle: boolean().nullable(),
|
|
@@ -61496,7 +62384,7 @@ var motionCustomize = {
|
|
|
61496
62384
|
eventName: "onMotionChanged"
|
|
61497
62385
|
},
|
|
61498
62386
|
deviceTypes: [DeviceType.Camera],
|
|
61499
|
-
apply: "
|
|
62387
|
+
apply: "add",
|
|
61500
62388
|
applyAuthority: {
|
|
61501
62389
|
kind: "camera-sensors",
|
|
61502
62390
|
timeoutField: "motionCooldownMs"
|
|
@@ -61568,7 +62456,7 @@ var MotionStatusSchema = object({
|
|
|
61568
62456
|
* it, every provider seeded it at boot, and every session left it
|
|
61569
62457
|
* `detected: true` after its detach.
|
|
61570
62458
|
*/
|
|
61571
|
-
autoClearAfterMs: number().nullable()
|
|
62459
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61572
62460
|
});
|
|
61573
62461
|
/**
|
|
61574
62462
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61605,12 +62493,18 @@ var motionCapability = {
|
|
|
61605
62493
|
methods: {
|
|
61606
62494
|
/**
|
|
61607
62495
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
61608
|
-
* for consumers that don't need the full status object
|
|
61609
|
-
*
|
|
61610
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
61611
|
-
* consumer.
|
|
62496
|
+
* for consumers that don't need the full status object. A composed
|
|
62497
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
61612
62498
|
*/
|
|
61613
62499
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62500
|
+
/**
|
|
62501
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62502
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62503
|
+
*/
|
|
62504
|
+
composedMethods: { isDetected: {
|
|
62505
|
+
kind: "slice",
|
|
62506
|
+
field: "detected"
|
|
62507
|
+
} },
|
|
61614
62508
|
events: {
|
|
61615
62509
|
/**
|
|
61616
62510
|
* Fires every time the runner transitions a camera between
|
|
@@ -61750,7 +62644,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61750
62644
|
* the grid region(s). */
|
|
61751
62645
|
var MotionZoneStatusSchema = object({
|
|
61752
62646
|
enabled: boolean(),
|
|
61753
|
-
sensitivity: number(),
|
|
62647
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61754
62648
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61755
62649
|
regions: array(MotionZoneRegionSchema),
|
|
61756
62650
|
lastFetchedAt: number()
|
|
@@ -62120,7 +63014,7 @@ var NavigationStatusSchema = object({
|
|
|
62120
63014
|
following: boolean(),
|
|
62121
63015
|
flash: boolean(),
|
|
62122
63016
|
lightMode: NavigationLightModeSchema,
|
|
62123
|
-
lightLevel: number().min(40).max(100),
|
|
63017
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62124
63018
|
/** Ms epoch when the slice was last updated. */
|
|
62125
63019
|
lastChangedAt: number()
|
|
62126
63020
|
});
|
|
@@ -62254,13 +63148,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62254
63148
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62255
63149
|
* SKIP a null rather than coerce it.
|
|
62256
63150
|
*/
|
|
62257
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63151
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62258
63152
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62259
|
-
rssiDbm: number().optional(),
|
|
63153
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62260
63154
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62261
63155
|
ssid: string().optional(),
|
|
62262
63156
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62263
|
-
lastUpdated: number()
|
|
63157
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62264
63158
|
});
|
|
62265
63159
|
var networkLinkCapability = {
|
|
62266
63160
|
name: "network-link",
|
|
@@ -62645,7 +63539,7 @@ var NotifierStatusSchema = object({
|
|
|
62645
63539
|
lastError: string().nullable(),
|
|
62646
63540
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62647
63541
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62648
|
-
queueDepth: number().int().nonnegative(),
|
|
63542
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62649
63543
|
/** Per-feature capability matrix — authoritative source for the
|
|
62650
63544
|
* compose-form field gating. */
|
|
62651
63545
|
supports: NotifierSupportsSchema
|
|
@@ -62737,11 +63631,9 @@ onSent: { data: object({
|
|
|
62737
63631
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62738
63632
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62739
63633
|
*
|
|
62740
|
-
* The
|
|
62741
|
-
*
|
|
62742
|
-
*
|
|
62743
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62744
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63634
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63635
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63636
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62745
63637
|
*
|
|
62746
63638
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62747
63639
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62750,15 +63642,8 @@ onSent: { data: object({
|
|
|
62750
63642
|
* numeric values land here.
|
|
62751
63643
|
*/
|
|
62752
63644
|
var NumericSensorStatusSchema = object({
|
|
62753
|
-
|
|
62754
|
-
|
|
62755
|
-
* Populated live from the upstream source on each state push.
|
|
62756
|
-
* Absent for unitless sensors. */
|
|
62757
|
-
unit: string().optional(),
|
|
62758
|
-
/** Suggested decimal places for numeric display.
|
|
62759
|
-
* Populated live from the upstream source when provided.
|
|
62760
|
-
* Falls back to auto-formatting when absent. */
|
|
62761
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63645
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63646
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62762
63647
|
/** Ms epoch when the slice was last updated. */
|
|
62763
63648
|
lastFetchedAt: number()
|
|
62764
63649
|
});
|
|
@@ -62782,11 +63667,11 @@ var numericSensorCapability = {
|
|
|
62782
63667
|
*/
|
|
62783
63668
|
durability: "restored",
|
|
62784
63669
|
/**
|
|
62785
|
-
* History (D850): recorded series. The unit is
|
|
63670
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63671
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62786
63672
|
*/
|
|
62787
63673
|
history: { fields: { value: {
|
|
62788
63674
|
kind: "gauge",
|
|
62789
|
-
unitFrom: "unit",
|
|
62790
63675
|
minIntervalMs: 3e4
|
|
62791
63676
|
} } },
|
|
62792
63677
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -63078,23 +63963,26 @@ var PetFeederStatusSchema = object({
|
|
|
63078
63963
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
63079
63964
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
63080
63965
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
63081
|
-
foodLevel: number().nullable(),
|
|
63966
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
63082
63967
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63083
63968
|
* single-hopper models. */
|
|
63084
|
-
food1: number().nullable(),
|
|
63969
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63085
63970
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63086
63971
|
* single-hopper models. */
|
|
63087
|
-
food2: number().nullable(),
|
|
63972
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63088
63973
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63089
63974
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63090
63975
|
* below the feeder's low threshold. */
|
|
63091
63976
|
lowFood: boolean(),
|
|
63092
63977
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63093
63978
|
* device has no battery reading. */
|
|
63094
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63095
|
-
/**
|
|
63096
|
-
*
|
|
63097
|
-
|
|
63979
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63980
|
+
/**
|
|
63981
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
63982
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
63983
|
+
* model has no desiccant sensor.
|
|
63984
|
+
*/
|
|
63985
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63098
63986
|
/** True while a feed is in progress. */
|
|
63099
63987
|
feeding: boolean(),
|
|
63100
63988
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63105,7 +63993,7 @@ var PetFeederStatusSchema = object({
|
|
|
63105
63993
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63106
63994
|
error: string().nullable(),
|
|
63107
63995
|
/** Raw device error code (0 / null = no error). */
|
|
63108
|
-
errorCode: number().nullable(),
|
|
63996
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63109
63997
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63110
63998
|
isDualHopper: boolean(),
|
|
63111
63999
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63115,7 +64003,7 @@ var PetFeederStatusSchema = object({
|
|
|
63115
64003
|
/** Play a chime when dispensing. */
|
|
63116
64004
|
feedSound: boolean(),
|
|
63117
64005
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63118
|
-
volume: number(),
|
|
64006
|
+
volume: number().meta(readingMeta("none")),
|
|
63119
64007
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63120
64008
|
lastFetchedAt: number()
|
|
63121
64009
|
});
|
|
@@ -63234,7 +64122,7 @@ var petFeederCapability = {
|
|
|
63234
64122
|
},
|
|
63235
64123
|
desiccantLeftDays: {
|
|
63236
64124
|
kind: "gauge",
|
|
63237
|
-
unit: "
|
|
64125
|
+
unit: "s"
|
|
63238
64126
|
}
|
|
63239
64127
|
} }
|
|
63240
64128
|
};
|
|
@@ -63635,43 +64523,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63635
64523
|
*/
|
|
63636
64524
|
var PowerMeterStatusSchema = object({
|
|
63637
64525
|
/** Instantaneous power draw in watts. */
|
|
63638
|
-
watts: number().optional().meta({
|
|
63639
|
-
unit: "W",
|
|
63640
|
-
label: "Power"
|
|
63641
|
-
}),
|
|
64526
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63642
64527
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63643
|
-
kwhTotal: number().optional().meta({
|
|
63644
|
-
unit: "kWh",
|
|
63645
|
-
label: "Energy"
|
|
63646
|
-
}),
|
|
64528
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63647
64529
|
/** Voltage in volts. */
|
|
63648
|
-
volts: number().optional(),
|
|
64530
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
63649
64531
|
/** Current in amperes. */
|
|
63650
|
-
amps: number().optional(),
|
|
63651
|
-
/** Apparent power in volt-amperes
|
|
63652
|
-
va: number().optional(),
|
|
64532
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
64533
|
+
/** Apparent power in volt-amperes. */
|
|
64534
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63653
64535
|
/** Power factor (0..1) if reported. */
|
|
63654
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
64536
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63655
64537
|
/** Ms epoch when the slice was last updated. */
|
|
63656
|
-
lastFetchedAt: number()
|
|
63657
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63658
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63659
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63660
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63661
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63662
|
-
unit: string().optional(),
|
|
63663
|
-
/** Suggested decimal places for numeric display.
|
|
63664
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63665
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63666
|
-
* auto-formatting when absent. */
|
|
63667
|
-
precision: number().int().min(0).max(10).optional()
|
|
64538
|
+
lastFetchedAt: number()
|
|
63668
64539
|
});
|
|
64540
|
+
/**
|
|
64541
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
64542
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
64543
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
64544
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
64545
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
64546
|
+
*/
|
|
64547
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
64548
|
+
DeviceType.Sensor,
|
|
64549
|
+
DeviceType.Switch,
|
|
64550
|
+
DeviceType.Light,
|
|
64551
|
+
DeviceType.Fan,
|
|
64552
|
+
DeviceType.Climate,
|
|
64553
|
+
DeviceType.Thermostat,
|
|
64554
|
+
DeviceType.Humidifier,
|
|
64555
|
+
DeviceType.WaterHeater,
|
|
64556
|
+
DeviceType.MediaPlayer,
|
|
64557
|
+
DeviceType.Washer,
|
|
64558
|
+
DeviceType.Dryer,
|
|
64559
|
+
DeviceType.Dishwasher,
|
|
64560
|
+
DeviceType.Vacuum,
|
|
64561
|
+
DeviceType.LawnMower,
|
|
64562
|
+
DeviceType.PetFeeder
|
|
64563
|
+
];
|
|
64564
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
64565
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
64566
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
64567
|
+
function powerTarget(id, unit) {
|
|
64568
|
+
return {
|
|
64569
|
+
id,
|
|
64570
|
+
cardinality: "scalar",
|
|
64571
|
+
vocabulary: {
|
|
64572
|
+
cap: "power-meter",
|
|
64573
|
+
stateField: id
|
|
64574
|
+
},
|
|
64575
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
64576
|
+
apply: "add",
|
|
64577
|
+
path: id,
|
|
64578
|
+
sources: [{
|
|
64579
|
+
kind: "numeric",
|
|
64580
|
+
requiredUnit: unit,
|
|
64581
|
+
transforms: [{ kind: "identity" }]
|
|
64582
|
+
}],
|
|
64583
|
+
companions: [{
|
|
64584
|
+
kind: "clock",
|
|
64585
|
+
path: "lastFetchedAt",
|
|
64586
|
+
when: "always"
|
|
64587
|
+
}],
|
|
64588
|
+
sourceReport: { status: "assignment-status" },
|
|
64589
|
+
advancedExpression: true
|
|
64590
|
+
};
|
|
64591
|
+
}
|
|
64592
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
64593
|
+
var powerMeterCustomize = {
|
|
64594
|
+
version: 1,
|
|
64595
|
+
targets: [
|
|
64596
|
+
powerTarget("watts", "W"),
|
|
64597
|
+
powerTarget("kwhTotal", "kWh"),
|
|
64598
|
+
powerTarget("volts", "V"),
|
|
64599
|
+
powerTarget("amps", "A")
|
|
64600
|
+
]
|
|
64601
|
+
};
|
|
63669
64602
|
var powerMeterCapability = {
|
|
63670
64603
|
name: "power-meter",
|
|
63671
64604
|
scope: "device",
|
|
63672
64605
|
deviceNative: true,
|
|
63673
64606
|
mode: "singleton",
|
|
63674
|
-
deviceTypes:
|
|
64607
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
63675
64608
|
methods: {},
|
|
63676
64609
|
status: {
|
|
63677
64610
|
schema: PowerMeterStatusSchema,
|
|
@@ -63729,11 +64662,7 @@ var powerMeterCapability = {
|
|
|
63729
64662
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63730
64663
|
* whether persisting is worth a SQLite commit. */
|
|
63731
64664
|
volatileStateFields: ["lastFetchedAt"],
|
|
63732
|
-
customize:
|
|
63733
|
-
version: 1,
|
|
63734
|
-
advanced: "derive",
|
|
63735
|
-
targets: []
|
|
63736
|
-
}
|
|
64665
|
+
customize: powerMeterCustomize
|
|
63737
64666
|
};
|
|
63738
64667
|
/**
|
|
63739
64668
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63753,11 +64682,11 @@ var powerMeterCapability = {
|
|
|
63753
64682
|
*/
|
|
63754
64683
|
var GpsLocationSchema = object({
|
|
63755
64684
|
/** Latitude in decimal degrees, -90..90. */
|
|
63756
|
-
latitude: number().min(-90).max(90),
|
|
64685
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63757
64686
|
/** Longitude in decimal degrees, -180..180. */
|
|
63758
|
-
longitude: number().min(-180).max(180),
|
|
64687
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63759
64688
|
/** Reported accuracy in meters (lower = better). */
|
|
63760
|
-
accuracyMeters: number().nonnegative()
|
|
64689
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63761
64690
|
});
|
|
63762
64691
|
var PresenceStatusSchema = object({
|
|
63763
64692
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63769,7 +64698,7 @@ var PresenceStatusSchema = object({
|
|
|
63769
64698
|
gps: GpsLocationSchema.nullable(),
|
|
63770
64699
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63771
64700
|
* when not reported. */
|
|
63772
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64701
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63773
64702
|
/** Ms epoch when the slice was last updated. */
|
|
63774
64703
|
lastChangedAt: number()
|
|
63775
64704
|
});
|
|
@@ -63819,19 +64748,10 @@ var presenceCapability = {
|
|
|
63819
64748
|
* `sourceInfo`.
|
|
63820
64749
|
*/
|
|
63821
64750
|
var PressureSensorStatusSchema = object({
|
|
63822
|
-
/** Current pressure in hPa. */
|
|
63823
|
-
hpa: number(),
|
|
64751
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64752
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63824
64753
|
/** Ms epoch when the slice was last updated. */
|
|
63825
|
-
lastFetchedAt: number()
|
|
63826
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63827
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63828
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63829
|
-
unit: string().optional(),
|
|
63830
|
-
/** Suggested decimal places for numeric display.
|
|
63831
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63832
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63833
|
-
* auto-formatting when absent. */
|
|
63834
|
-
precision: number().int().min(0).max(10).optional()
|
|
64754
|
+
lastFetchedAt: number()
|
|
63835
64755
|
});
|
|
63836
64756
|
var pressureSensorCapability = {
|
|
63837
64757
|
name: "pressure-sensor",
|
|
@@ -64245,8 +65165,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64245
65165
|
}), _void(), { kind: "mutation" });
|
|
64246
65166
|
var PtzAutotrackSettingsSchema = object({
|
|
64247
65167
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64248
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64249
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65168
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65169
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64250
65170
|
});
|
|
64251
65171
|
/**
|
|
64252
65172
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64400,7 +65320,7 @@ var RunningStateStatusSchema = object({
|
|
|
64400
65320
|
/** null = unknown — never coerced to false (D393). */
|
|
64401
65321
|
running: boolean().nullable(),
|
|
64402
65322
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64403
|
-
since: number().nullable(),
|
|
65323
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64404
65324
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64405
65325
|
phase: string().nullable(),
|
|
64406
65326
|
/** null until a reading has been published (D393). */
|
|
@@ -64415,7 +65335,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64415
65335
|
/** Generic Customize target for the running boolean (D936). */
|
|
64416
65336
|
var runningCustomize = {
|
|
64417
65337
|
version: 1,
|
|
64418
|
-
advanced: "derive",
|
|
64419
65338
|
targets: [{
|
|
64420
65339
|
id: "running",
|
|
64421
65340
|
cardinality: "scalar",
|
|
@@ -64424,6 +65343,8 @@ var runningCustomize = {
|
|
|
64424
65343
|
stateField: "running"
|
|
64425
65344
|
},
|
|
64426
65345
|
deviceTypes: [
|
|
65346
|
+
DeviceType.Washer,
|
|
65347
|
+
DeviceType.Dryer,
|
|
64427
65348
|
DeviceType.Dishwasher,
|
|
64428
65349
|
DeviceType.Vacuum,
|
|
64429
65350
|
DeviceType.LawnMower,
|
|
@@ -64435,7 +65356,7 @@ var runningCustomize = {
|
|
|
64435
65356
|
DeviceType.Thermostat,
|
|
64436
65357
|
DeviceType.PetFeeder
|
|
64437
65358
|
],
|
|
64438
|
-
apply: "add
|
|
65359
|
+
apply: "add",
|
|
64439
65360
|
path: "running",
|
|
64440
65361
|
sources: [
|
|
64441
65362
|
{
|
|
@@ -65699,9 +66620,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65699
66620
|
*/
|
|
65700
66621
|
var RecordWindowSchema = object({
|
|
65701
66622
|
trigger: RecordTriggerSchema,
|
|
65702
|
-
day: number().int().min(0).max(6),
|
|
65703
|
-
startMinute: number().int().min(0).max(1439),
|
|
65704
|
-
endMinute: number().int().min(1).max(1440)
|
|
66623
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
66624
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
66625
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65705
66626
|
});
|
|
65706
66627
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65707
66628
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65777,10 +66698,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65777
66698
|
/** Master "record to the card at all" switch. */
|
|
65778
66699
|
enabled: boolean().nullable(),
|
|
65779
66700
|
overwriteWhenFull: boolean().nullable(),
|
|
65780
|
-
preRecordSec: number().nullable(),
|
|
65781
|
-
postRecordSec: number().nullable(),
|
|
66701
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66702
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65782
66703
|
/** Length of one recorded file, in minutes. */
|
|
65783
|
-
segmentMinutes: number().nullable(),
|
|
66704
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65784
66705
|
/** The primary track's weekly windows, flattened. */
|
|
65785
66706
|
windows: array(RecordWindowSchema),
|
|
65786
66707
|
/**
|
|
@@ -65796,7 +66717,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65796
66717
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65797
66718
|
* writable.
|
|
65798
66719
|
*/
|
|
65799
|
-
unreadableWindows: number(),
|
|
66720
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65800
66721
|
/**
|
|
65801
66722
|
* The camera is scheduled to record and has NO usable storage.
|
|
65802
66723
|
*
|
|
@@ -66641,7 +67562,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66641
67562
|
url: string().optional(),
|
|
66642
67563
|
codec: string().optional(),
|
|
66643
67564
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66644
|
-
fps: number().positive().optional(),
|
|
67565
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66645
67566
|
label: string().optional(),
|
|
66646
67567
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66647
67568
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66728,18 +67649,18 @@ var StreamProfileSchema = _enum([
|
|
|
66728
67649
|
]);
|
|
66729
67650
|
/** The current encoding config of one stream profile. */
|
|
66730
67651
|
var StreamProfileConfigSchema = object({
|
|
66731
|
-
width: number(),
|
|
66732
|
-
height: number(),
|
|
67652
|
+
width: number().meta(readingMeta("none")),
|
|
67653
|
+
height: number().meta(readingMeta("none")),
|
|
66733
67654
|
codec: _enum(["h264", "h265"]),
|
|
66734
|
-
framerate: number(),
|
|
66735
|
-
bitrate: number(),
|
|
67655
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67656
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66736
67657
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66737
67658
|
encoderProfile: _enum([
|
|
66738
67659
|
"high",
|
|
66739
67660
|
"main",
|
|
66740
67661
|
"baseline"
|
|
66741
67662
|
]).optional(),
|
|
66742
|
-
gop: number().optional(),
|
|
67663
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66743
67664
|
/**
|
|
66744
67665
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66745
67666
|
*
|
|
@@ -66913,7 +67834,8 @@ var switchCapability = {
|
|
|
66913
67834
|
deviceTypes: [
|
|
66914
67835
|
DeviceType.Switch,
|
|
66915
67836
|
DeviceType.Siren,
|
|
66916
|
-
DeviceType.Light
|
|
67837
|
+
DeviceType.Light,
|
|
67838
|
+
DeviceType.Fan
|
|
66917
67839
|
],
|
|
66918
67840
|
methods: { setState: method(object({
|
|
66919
67841
|
deviceId: number(),
|
|
@@ -66960,12 +67882,7 @@ var switchCapability = {
|
|
|
66960
67882
|
label: "On",
|
|
66961
67883
|
kind: "boolean"
|
|
66962
67884
|
}
|
|
66963
|
-
}] }
|
|
66964
|
-
customize: {
|
|
66965
|
-
version: 1,
|
|
66966
|
-
advanced: "derive",
|
|
66967
|
-
targets: []
|
|
66968
|
-
}
|
|
67885
|
+
}] }
|
|
66969
67886
|
};
|
|
66970
67887
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66971
67888
|
function hasControlCharacter(value) {
|
|
@@ -67548,35 +68465,21 @@ var tamperCapability = {
|
|
|
67548
68465
|
* entries with `device_class: temperature` and any future native
|
|
67549
68466
|
* thermometer.
|
|
67550
68467
|
*
|
|
67551
|
-
*
|
|
67552
|
-
*
|
|
67553
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67554
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67555
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67556
|
-
* `sourceInfo`.
|
|
68468
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
68469
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67557
68470
|
*
|
|
67558
68471
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67559
68472
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67560
68473
|
* changed" steady state.
|
|
67561
68474
|
*/
|
|
67562
68475
|
var TemperatureSensorStatusSchema = object({
|
|
67563
|
-
/** Current temperature in Celsius. */
|
|
67564
|
-
celsius: number().meta({
|
|
67565
|
-
|
|
68476
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68477
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
68478
|
+
precision: 1,
|
|
67566
68479
|
label: "Temperature"
|
|
67567
|
-
}),
|
|
68480
|
+
})),
|
|
67568
68481
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67569
|
-
lastFetchedAt: number()
|
|
67570
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67571
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67572
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67573
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67574
|
-
unit: string().optional(),
|
|
67575
|
-
/** Suggested decimal places for numeric display.
|
|
67576
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67577
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67578
|
-
* auto-formatting when absent. */
|
|
67579
|
-
precision: number().int().min(0).max(10).optional()
|
|
68482
|
+
lastFetchedAt: number()
|
|
67580
68483
|
});
|
|
67581
68484
|
var temperatureSensorCapability = {
|
|
67582
68485
|
name: "temperature-sensor",
|
|
@@ -67607,12 +68510,7 @@ var temperatureSensorCapability = {
|
|
|
67607
68510
|
} } },
|
|
67608
68511
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67609
68512
|
* whether persisting is worth a SQLite commit. */
|
|
67610
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67611
|
-
customize: {
|
|
67612
|
-
version: 1,
|
|
67613
|
-
advanced: "derive",
|
|
67614
|
-
targets: []
|
|
67615
|
-
}
|
|
68513
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67616
68514
|
};
|
|
67617
68515
|
/**
|
|
67618
68516
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67895,16 +68793,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67895
68793
|
]),
|
|
67896
68794
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67897
68795
|
* reading. */
|
|
67898
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68796
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67899
68797
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67900
68798
|
* the vacuum has no speed control. */
|
|
67901
68799
|
fanSpeed: string().nullable(),
|
|
67902
68800
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67903
68801
|
availableFanSpeeds: array(string()),
|
|
67904
68802
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67905
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68803
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67906
68804
|
/** Current error code (0 / null = no error). */
|
|
67907
|
-
errorCode: number().nullable(),
|
|
68805
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67908
68806
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67909
68807
|
errorLabel: string().nullable(),
|
|
67910
68808
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67982,7 +68880,7 @@ var ValveStatusSchema = object({
|
|
|
67982
68880
|
]),
|
|
67983
68881
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
67984
68882
|
* intermediate position surface. */
|
|
67985
|
-
position: number().min(0).max(100).nullable(),
|
|
68883
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67986
68884
|
/** Ms epoch when the slice was last updated. */
|
|
67987
68885
|
lastChangedAt: number()
|
|
67988
68886
|
});
|
|
@@ -68090,9 +68988,9 @@ var vibrationCapability = {
|
|
|
68090
68988
|
*/
|
|
68091
68989
|
var WaterHeaterStatusSchema = object({
|
|
68092
68990
|
/** Current measured temperature. Null when not reported. */
|
|
68093
|
-
currentTemp: number().nullable(),
|
|
68991
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68094
68992
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68095
|
-
targetTemp: number().nullable(),
|
|
68993
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68096
68994
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68097
68995
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68098
68996
|
* device reports an unknown state. */
|
|
@@ -68103,9 +69001,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68103
69001
|
* has no away surface. */
|
|
68104
69002
|
away: boolean().nullable(),
|
|
68105
69003
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68106
|
-
minTemp: number().nullable(),
|
|
69004
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68107
69005
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68108
|
-
maxTemp: number().nullable(),
|
|
69006
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68109
69007
|
/** Ms epoch when the slice was last updated. */
|
|
68110
69008
|
lastChangedAt: number()
|
|
68111
69009
|
});
|
|
@@ -68190,25 +69088,18 @@ var waterHeaterCapability = {
|
|
|
68190
69088
|
* Forecast deferred — current conditions only for v1.
|
|
68191
69089
|
*/
|
|
68192
69090
|
var WeatherStatusSchema = object({
|
|
68193
|
-
/** Verbatim
|
|
68194
|
-
* when no condition has been reported yet. */
|
|
69091
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68195
69092
|
condition: string().nullable(),
|
|
68196
|
-
/** Current temperature in
|
|
68197
|
-
temperature: number().nullable(),
|
|
68198
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68199
|
-
temperatureUnit: string().nullable(),
|
|
69093
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
69094
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68200
69095
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68201
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68202
|
-
/** Barometric pressure in
|
|
68203
|
-
pressure: number().nullable(),
|
|
68204
|
-
/**
|
|
68205
|
-
|
|
68206
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68207
|
-
windSpeed: number().nullable(),
|
|
68208
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68209
|
-
windSpeedUnit: string().nullable(),
|
|
69096
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
69097
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
69098
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
69099
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
69100
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68210
69101
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68211
|
-
windBearing: number().nullable(),
|
|
69102
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68212
69103
|
/** Ms epoch when the slice was last updated. */
|
|
68213
69104
|
lastFetchedAt: number()
|
|
68214
69105
|
});
|
|
@@ -68236,12 +69127,12 @@ var weatherCapability = {
|
|
|
68236
69127
|
*/
|
|
68237
69128
|
durability: "session",
|
|
68238
69129
|
/**
|
|
68239
|
-
* History (D850): recorded series.
|
|
69130
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68240
69131
|
*/
|
|
68241
69132
|
history: { fields: {
|
|
68242
69133
|
temperature: {
|
|
68243
69134
|
kind: "gauge",
|
|
68244
|
-
|
|
69135
|
+
unit: "°C",
|
|
68245
69136
|
deadband: .2
|
|
68246
69137
|
},
|
|
68247
69138
|
humidity: {
|
|
@@ -68251,12 +69142,12 @@ var weatherCapability = {
|
|
|
68251
69142
|
},
|
|
68252
69143
|
pressure: {
|
|
68253
69144
|
kind: "gauge",
|
|
68254
|
-
|
|
69145
|
+
unit: "hPa",
|
|
68255
69146
|
deadband: .5
|
|
68256
69147
|
},
|
|
68257
69148
|
windSpeed: {
|
|
68258
69149
|
kind: "gauge",
|
|
68259
|
-
|
|
69150
|
+
unit: "m/s",
|
|
68260
69151
|
deadband: .5
|
|
68261
69152
|
}
|
|
68262
69153
|
} }
|
|
@@ -69157,8 +70048,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
69157
70048
|
kind: "mutation",
|
|
69158
70049
|
auth: "admin"
|
|
69159
70050
|
});
|
|
70051
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
69160
70052
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
69161
|
-
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;
|
|
70053
|
+
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;
|
|
69162
70054
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
69163
70055
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
69164
70056
|
new Set(CAP_NAMES);
|
|
@@ -69487,6 +70379,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69487
70379
|
featureProbe: featureProbeCapability,
|
|
69488
70380
|
flood: floodCapability,
|
|
69489
70381
|
gas: gasCapability,
|
|
70382
|
+
groupActive: groupActiveCapability,
|
|
70383
|
+
groupCommands: groupCommandsCapability,
|
|
70384
|
+
groupStatus: groupStatusCapability,
|
|
69490
70385
|
heatingValve: heatingValveCapability,
|
|
69491
70386
|
humidifier: humidifierCapability,
|
|
69492
70387
|
humiditySensor: humiditySensorCapability,
|
|
@@ -69496,6 +70391,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69496
70391
|
lawnMowerControl: lawnMowerControlCapability,
|
|
69497
70392
|
lockControl: lockControlCapability,
|
|
69498
70393
|
mediaPlayer: mediaPlayerCapability,
|
|
70394
|
+
meter: meterCapability,
|
|
69499
70395
|
motion: motionCapability,
|
|
69500
70396
|
motionTrigger: motionTriggerCapability,
|
|
69501
70397
|
motionZones: motionZonesCapability,
|
|
@@ -70755,7 +71651,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
70755
71651
|
return toDeviceSummary(device, this.addonId);
|
|
70756
71652
|
}
|
|
70757
71653
|
};
|
|
70758
|
-
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;
|
|
71654
|
+
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;
|
|
70759
71655
|
new Set(Object.values(DeviceType));
|
|
70760
71656
|
Object.freeze({
|
|
70761
71657
|
"accessories.getStatus": {
|
|
@@ -70863,6 +71759,13 @@ Object.freeze({
|
|
|
70863
71759
|
access: "view",
|
|
70864
71760
|
role: "admin"
|
|
70865
71761
|
},
|
|
71762
|
+
"addons.getPackageDocs": {
|
|
71763
|
+
capName: "addons",
|
|
71764
|
+
capScope: "system",
|
|
71765
|
+
addonId: null,
|
|
71766
|
+
access: "view",
|
|
71767
|
+
role: "admin"
|
|
71768
|
+
},
|
|
70866
71769
|
"addons.getVersions": {
|
|
70867
71770
|
capName: "addons",
|
|
70868
71771
|
capScope: "system",
|
|
@@ -73971,6 +74874,27 @@ Object.freeze({
|
|
|
73971
74874
|
access: "view",
|
|
73972
74875
|
role: "viewer"
|
|
73973
74876
|
},
|
|
74877
|
+
"groupActive.getStatus": {
|
|
74878
|
+
capName: "group-active",
|
|
74879
|
+
capScope: "device",
|
|
74880
|
+
addonId: null,
|
|
74881
|
+
access: "view",
|
|
74882
|
+
role: "viewer"
|
|
74883
|
+
},
|
|
74884
|
+
"groupCommands.getStatus": {
|
|
74885
|
+
capName: "group-commands",
|
|
74886
|
+
capScope: "device",
|
|
74887
|
+
addonId: null,
|
|
74888
|
+
access: "view",
|
|
74889
|
+
role: "viewer"
|
|
74890
|
+
},
|
|
74891
|
+
"groupStatus.getStatus": {
|
|
74892
|
+
capName: "group-status",
|
|
74893
|
+
capScope: "device",
|
|
74894
|
+
addonId: null,
|
|
74895
|
+
access: "view",
|
|
74896
|
+
role: "viewer"
|
|
74897
|
+
},
|
|
73974
74898
|
"heatingValve.getStatus": {
|
|
73975
74899
|
capName: "heating-valve",
|
|
73976
74900
|
capScope: "device",
|
|
@@ -74923,6 +75847,13 @@ Object.freeze({
|
|
|
74923
75847
|
access: "create",
|
|
74924
75848
|
role: "admin"
|
|
74925
75849
|
},
|
|
75850
|
+
"meter.getStatus": {
|
|
75851
|
+
capName: "meter",
|
|
75852
|
+
capScope: "device",
|
|
75853
|
+
addonId: null,
|
|
75854
|
+
access: "view",
|
|
75855
|
+
role: "viewer"
|
|
75856
|
+
},
|
|
74926
75857
|
"metricsProvider.collectSnapshot": {
|
|
74927
75858
|
capName: "metrics-provider",
|
|
74928
75859
|
capScope: "system",
|
|
@@ -83021,7 +83952,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
83021
83952
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
83022
83953
|
icon: "square"
|
|
83023
83954
|
}
|
|
83024
|
-
}
|
|
83955
|
+
},
|
|
83956
|
+
overrides: { byType: {
|
|
83957
|
+
[DeviceType.Washer]: {
|
|
83958
|
+
state: { running: {
|
|
83959
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
83960
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
83961
|
+
} },
|
|
83962
|
+
events: {
|
|
83963
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
83964
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
83965
|
+
}
|
|
83966
|
+
},
|
|
83967
|
+
[DeviceType.Dryer]: {
|
|
83968
|
+
state: { running: {
|
|
83969
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
83970
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
83971
|
+
} },
|
|
83972
|
+
events: {
|
|
83973
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
83974
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
83975
|
+
}
|
|
83976
|
+
},
|
|
83977
|
+
[DeviceType.Dishwasher]: {
|
|
83978
|
+
state: { running: {
|
|
83979
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
83980
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
83981
|
+
} },
|
|
83982
|
+
events: {
|
|
83983
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
83984
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
83985
|
+
}
|
|
83986
|
+
}
|
|
83987
|
+
} }
|
|
83025
83988
|
},
|
|
83026
83989
|
update: {
|
|
83027
83990
|
scope: "device",
|
|
@@ -83793,6 +84756,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83793
84756
|
icon: "flame"
|
|
83794
84757
|
}]
|
|
83795
84758
|
},
|
|
84759
|
+
"group-active": {
|
|
84760
|
+
scope: "device",
|
|
84761
|
+
noun: t("Group state", "Stato del gruppo")
|
|
84762
|
+
},
|
|
84763
|
+
"group-commands": {
|
|
84764
|
+
scope: "device",
|
|
84765
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84766
|
+
},
|
|
84767
|
+
"group-status": {
|
|
84768
|
+
scope: "device",
|
|
84769
|
+
noun: t("Group", "Gruppo"),
|
|
84770
|
+
state: [
|
|
84771
|
+
{
|
|
84772
|
+
kind: "numeric",
|
|
84773
|
+
field: "included",
|
|
84774
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84775
|
+
label: t("Reporting", "Rispondono"),
|
|
84776
|
+
icon: "users"
|
|
84777
|
+
},
|
|
84778
|
+
{
|
|
84779
|
+
kind: "numeric",
|
|
84780
|
+
field: "excluded",
|
|
84781
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84782
|
+
label: t("Excluded", "Esclusi"),
|
|
84783
|
+
icon: "users"
|
|
84784
|
+
},
|
|
84785
|
+
{
|
|
84786
|
+
kind: "numeric",
|
|
84787
|
+
field: "total",
|
|
84788
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84789
|
+
label: t("Members", "Membri"),
|
|
84790
|
+
icon: "sigma"
|
|
84791
|
+
}
|
|
84792
|
+
]
|
|
84793
|
+
},
|
|
83796
84794
|
"humidity-sensor": {
|
|
83797
84795
|
scope: "device",
|
|
83798
84796
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83818,6 +84816,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83818
84816
|
}],
|
|
83819
84817
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
83820
84818
|
},
|
|
84819
|
+
meter: {
|
|
84820
|
+
scope: "device",
|
|
84821
|
+
noun: t("Meter", "Contatore"),
|
|
84822
|
+
state: [{
|
|
84823
|
+
kind: "numeric",
|
|
84824
|
+
field: "value",
|
|
84825
|
+
quantity: t("the total", "il totale"),
|
|
84826
|
+
label: t("Total", "Totale"),
|
|
84827
|
+
icon: "gauge"
|
|
84828
|
+
}]
|
|
84829
|
+
},
|
|
83821
84830
|
"numeric-sensor": {
|
|
83822
84831
|
scope: "device",
|
|
83823
84832
|
noun: t("Sensor", "Sensore"),
|
|
@@ -83826,7 +84835,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83826
84835
|
field: "value",
|
|
83827
84836
|
quantity: t("the reading", "il valore"),
|
|
83828
84837
|
label: t("Reading", "Valore"),
|
|
83829
|
-
unitField: "unit",
|
|
83830
84838
|
icon: "gauge"
|
|
83831
84839
|
}]
|
|
83832
84840
|
},
|
|
@@ -83962,7 +84970,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83962
84970
|
field: "temperature",
|
|
83963
84971
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
83964
84972
|
label: t("Temperature", "Temperatura"),
|
|
83965
|
-
|
|
84973
|
+
unit: "°C",
|
|
83966
84974
|
icon: "thermometer"
|
|
83967
84975
|
},
|
|
83968
84976
|
{
|
|
@@ -83978,7 +84986,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83978
84986
|
field: "windSpeed",
|
|
83979
84987
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
83980
84988
|
label: t("Wind", "Vento"),
|
|
83981
|
-
|
|
84989
|
+
unit: "m/s",
|
|
83982
84990
|
icon: "wind"
|
|
83983
84991
|
},
|
|
83984
84992
|
{
|
|
@@ -83986,7 +84994,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83986
84994
|
field: "pressure",
|
|
83987
84995
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
83988
84996
|
label: t("Pressure", "Pressione"),
|
|
83989
|
-
|
|
84997
|
+
unit: "hPa",
|
|
83990
84998
|
icon: "gauge"
|
|
83991
84999
|
}
|
|
83992
85000
|
]
|
|
@@ -84291,8 +85299,47 @@ function projectAction(cap, action) {
|
|
|
84291
85299
|
};
|
|
84292
85300
|
}
|
|
84293
85301
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
84294
|
-
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;
|
|
85302
|
+
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;
|
|
84295
85303
|
DeviceFeature.BatteryOperated;
|
|
85304
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
85305
|
+
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.";
|
|
85306
|
+
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.";
|
|
85307
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
85308
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
85309
|
+
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.";
|
|
85310
|
+
function withheld(reason) {
|
|
85311
|
+
return {
|
|
85312
|
+
[DeviceType.Washer]: {
|
|
85313
|
+
exported: false,
|
|
85314
|
+
reason
|
|
85315
|
+
},
|
|
85316
|
+
[DeviceType.Dryer]: {
|
|
85317
|
+
exported: false,
|
|
85318
|
+
reason
|
|
85319
|
+
},
|
|
85320
|
+
[DeviceType.Dishwasher]: {
|
|
85321
|
+
exported: false,
|
|
85322
|
+
reason
|
|
85323
|
+
}
|
|
85324
|
+
};
|
|
85325
|
+
}
|
|
85326
|
+
function offered(received) {
|
|
85327
|
+
return {
|
|
85328
|
+
[DeviceType.Washer]: {
|
|
85329
|
+
exported: true,
|
|
85330
|
+
as: received
|
|
85331
|
+
},
|
|
85332
|
+
[DeviceType.Dryer]: {
|
|
85333
|
+
exported: true,
|
|
85334
|
+
as: received
|
|
85335
|
+
},
|
|
85336
|
+
[DeviceType.Dishwasher]: {
|
|
85337
|
+
exported: true,
|
|
85338
|
+
as: received
|
|
85339
|
+
}
|
|
85340
|
+
};
|
|
85341
|
+
}
|
|
85342
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
84296
85343
|
/** Reject after `ms`; always clears its own timer. */
|
|
84297
85344
|
async function withTimeout$1(promise, ms, label) {
|
|
84298
85345
|
let timer;
|
|
@@ -85325,6 +86372,21 @@ Object.freeze({
|
|
|
85325
86372
|
form: "single",
|
|
85326
86373
|
optional: false
|
|
85327
86374
|
}],
|
|
86375
|
+
"groupActive.getStatus": [{
|
|
86376
|
+
name: "deviceId",
|
|
86377
|
+
form: "single",
|
|
86378
|
+
optional: false
|
|
86379
|
+
}],
|
|
86380
|
+
"groupCommands.getStatus": [{
|
|
86381
|
+
name: "deviceId",
|
|
86382
|
+
form: "single",
|
|
86383
|
+
optional: false
|
|
86384
|
+
}],
|
|
86385
|
+
"groupStatus.getStatus": [{
|
|
86386
|
+
name: "deviceId",
|
|
86387
|
+
form: "single",
|
|
86388
|
+
optional: false
|
|
86389
|
+
}],
|
|
85328
86390
|
"heatingValve.getStatus": [{
|
|
85329
86391
|
name: "deviceId",
|
|
85330
86392
|
form: "single",
|
|
@@ -85525,6 +86587,11 @@ Object.freeze({
|
|
|
85525
86587
|
form: "single",
|
|
85526
86588
|
optional: false
|
|
85527
86589
|
}],
|
|
86590
|
+
"meter.getStatus": [{
|
|
86591
|
+
name: "deviceId",
|
|
86592
|
+
form: "single",
|
|
86593
|
+
optional: false
|
|
86594
|
+
}],
|
|
85528
86595
|
"motion.getStatus": [{
|
|
85529
86596
|
name: "deviceId",
|
|
85530
86597
|
form: "single",
|
|
@@ -87132,7 +88199,6 @@ Object.freeze({
|
|
|
87132
88199
|
"network-access": "ingress",
|
|
87133
88200
|
"smtp-provider": "email"
|
|
87134
88201
|
});
|
|
87135
|
-
DeviceType.Camera;
|
|
87136
88202
|
/**
|
|
87137
88203
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
87138
88204
|
* `z.infer`, they do not restate the shape.
|
|
@@ -87309,6 +88375,8 @@ new Map(Object.entries({
|
|
|
87309
88375
|
"detection-blind": "device-events",
|
|
87310
88376
|
"motion-noisy": "device-events",
|
|
87311
88377
|
"motion-calm": "device-events",
|
|
88378
|
+
"package-llm-silent": "device-events",
|
|
88379
|
+
"package-llm-answered": "device-events",
|
|
87312
88380
|
"recording-stalled": "device-events",
|
|
87313
88381
|
"recording-healthy": "device-events",
|
|
87314
88382
|
"recording-degraded": "device-events",
|
|
@@ -87392,6 +88460,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
87392
88460
|
label: "Motion without a subject",
|
|
87393
88461
|
kinds: ["motion-noisy", "motion-calm"]
|
|
87394
88462
|
},
|
|
88463
|
+
{
|
|
88464
|
+
id: "package-llm",
|
|
88465
|
+
family: "device-events",
|
|
88466
|
+
label: "Package confirm",
|
|
88467
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
88468
|
+
},
|
|
87395
88469
|
{
|
|
87396
88470
|
id: "recording",
|
|
87397
88471
|
family: "device-events",
|
|
@@ -87573,6 +88647,8 @@ var DEVICE_EVENTS = [
|
|
|
87573
88647
|
"detection-blind",
|
|
87574
88648
|
"motion-noisy",
|
|
87575
88649
|
"motion-calm",
|
|
88650
|
+
"package-llm-silent",
|
|
88651
|
+
"package-llm-answered",
|
|
87576
88652
|
"recording-stalled",
|
|
87577
88653
|
"recording-healthy",
|
|
87578
88654
|
"recording-degraded",
|
|
@@ -87841,6 +88917,15 @@ new Map([
|
|
|
87841
88917
|
snapshotLabel: "Cameras with constant motion now",
|
|
87842
88918
|
snapshotSection: null
|
|
87843
88919
|
},
|
|
88920
|
+
{
|
|
88921
|
+
id: "package-llm-confirm",
|
|
88922
|
+
family: "device-events",
|
|
88923
|
+
label: "Package confirm (not answering / answering again)",
|
|
88924
|
+
bad: ["package-llm-silent"],
|
|
88925
|
+
recovery: ["package-llm-answered"],
|
|
88926
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88927
|
+
snapshotSection: null
|
|
88928
|
+
},
|
|
87844
88929
|
{
|
|
87845
88930
|
id: "recording-health",
|
|
87846
88931
|
family: "device-events",
|