@camstack/addon-provider-wyze 0.2.158 → 0.2.160
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +39 -0
- package/dist/addon.js +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.js
CHANGED
|
@@ -31,7 +31,7 @@ let net = require("net");
|
|
|
31
31
|
net = __toESM(net, 1);
|
|
32
32
|
let node_child_process = require("node:child_process");
|
|
33
33
|
let node_tls = require("node:tls");
|
|
34
|
-
//#region ../types/dist/event-category-
|
|
34
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
35
35
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
36
36
|
EventCategory["SystemBoot"] = "system.boot";
|
|
37
37
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -357,6 +357,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
357
357
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
358
358
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
359
359
|
/**
|
|
360
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
361
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
362
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
363
|
+
*/
|
|
364
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
365
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
366
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
367
|
+
/**
|
|
360
368
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
361
369
|
* (a settings change via `setAgentInferenceDevices` /
|
|
362
370
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5466,7 +5474,7 @@ var ZodIssueCode = {
|
|
|
5466
5474
|
var ZodFirstPartyTypeKind;
|
|
5467
5475
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5468
5476
|
//#endregion
|
|
5469
|
-
//#region ../types/dist/sleep
|
|
5477
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5470
5478
|
/**
|
|
5471
5479
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5472
5480
|
* window to float samples (D455).
|
|
@@ -8020,6 +8028,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
8020
8028
|
}).strict();
|
|
8021
8029
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8022
8030
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8031
|
+
var READING_QUANTITIES = [
|
|
8032
|
+
"temperature",
|
|
8033
|
+
"pressure",
|
|
8034
|
+
"speed",
|
|
8035
|
+
"precipitation",
|
|
8036
|
+
"precipitation-rate",
|
|
8037
|
+
"length",
|
|
8038
|
+
"area",
|
|
8039
|
+
"illuminance",
|
|
8040
|
+
"irradiance",
|
|
8041
|
+
"power",
|
|
8042
|
+
"energy",
|
|
8043
|
+
"voltage",
|
|
8044
|
+
"current",
|
|
8045
|
+
"apparent-power",
|
|
8046
|
+
"humidity",
|
|
8047
|
+
"percentage",
|
|
8048
|
+
"concentration-volume",
|
|
8049
|
+
"concentration-mass",
|
|
8050
|
+
"concentration-ppb",
|
|
8051
|
+
"volume",
|
|
8052
|
+
"duration",
|
|
8053
|
+
"duration-ms",
|
|
8054
|
+
"information",
|
|
8055
|
+
"sound-level",
|
|
8056
|
+
"signal-level",
|
|
8057
|
+
"colour-temperature",
|
|
8058
|
+
"angle",
|
|
8059
|
+
"bitrate",
|
|
8060
|
+
"rate",
|
|
8061
|
+
"mass",
|
|
8062
|
+
"index",
|
|
8063
|
+
"ratio",
|
|
8064
|
+
"count",
|
|
8065
|
+
"none",
|
|
8066
|
+
"device"
|
|
8067
|
+
];
|
|
8068
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8069
|
+
new Set(READING_QUANTITIES);
|
|
8070
|
+
/**
|
|
8071
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8072
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8073
|
+
*/
|
|
8074
|
+
var QUANTITY_BASE = {
|
|
8075
|
+
temperature: "°C",
|
|
8076
|
+
pressure: "hPa",
|
|
8077
|
+
speed: "m/s",
|
|
8078
|
+
precipitation: "mm",
|
|
8079
|
+
"precipitation-rate": "mm/h",
|
|
8080
|
+
length: "m",
|
|
8081
|
+
area: "m²",
|
|
8082
|
+
illuminance: "lx",
|
|
8083
|
+
irradiance: "W/m²",
|
|
8084
|
+
power: "W",
|
|
8085
|
+
energy: "kWh",
|
|
8086
|
+
voltage: "V",
|
|
8087
|
+
current: "A",
|
|
8088
|
+
"apparent-power": "VA",
|
|
8089
|
+
humidity: "%",
|
|
8090
|
+
percentage: "%",
|
|
8091
|
+
"concentration-volume": "ppm",
|
|
8092
|
+
"concentration-mass": "µg/m³",
|
|
8093
|
+
"concentration-ppb": "ppb",
|
|
8094
|
+
volume: "L",
|
|
8095
|
+
duration: "s",
|
|
8096
|
+
"duration-ms": "ms",
|
|
8097
|
+
information: "B",
|
|
8098
|
+
"sound-level": "dBFS",
|
|
8099
|
+
"signal-level": "dBm",
|
|
8100
|
+
"colour-temperature": "mired",
|
|
8101
|
+
angle: "°",
|
|
8102
|
+
bitrate: "kbps",
|
|
8103
|
+
rate: "fps",
|
|
8104
|
+
mass: "kg",
|
|
8105
|
+
index: "none",
|
|
8106
|
+
ratio: "none",
|
|
8107
|
+
count: "none",
|
|
8108
|
+
none: "none",
|
|
8109
|
+
device: "device"
|
|
8110
|
+
};
|
|
8111
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8112
|
+
function baseUnitOf(quantity) {
|
|
8113
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8114
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8115
|
+
return symbol;
|
|
8116
|
+
}
|
|
8117
|
+
function readingMeta(quantity, extras) {
|
|
8118
|
+
return {
|
|
8119
|
+
quantity,
|
|
8120
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8121
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8122
|
+
};
|
|
8123
|
+
}
|
|
8023
8124
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8024
8125
|
var CamProfileSchema = _enum([
|
|
8025
8126
|
"high",
|
|
@@ -8047,8 +8148,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8047
8148
|
"derived"
|
|
8048
8149
|
]);
|
|
8049
8150
|
var CamStreamResolutionSchema = object({
|
|
8050
|
-
width: number().int().positive(),
|
|
8051
|
-
height: number().int().positive()
|
|
8151
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8152
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8052
8153
|
});
|
|
8053
8154
|
var CameraStreamSchema = object({
|
|
8054
8155
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8566,6 +8667,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8566
8667
|
"filesystem-browse",
|
|
8567
8668
|
"flood",
|
|
8568
8669
|
"gas",
|
|
8670
|
+
"group-active",
|
|
8671
|
+
"group-commands",
|
|
8672
|
+
"group-status",
|
|
8569
8673
|
"heating-valve",
|
|
8570
8674
|
"humidifier",
|
|
8571
8675
|
"humidity-sensor",
|
|
@@ -8586,6 +8690,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8586
8690
|
"login-method",
|
|
8587
8691
|
"media-player",
|
|
8588
8692
|
"mesh-network",
|
|
8693
|
+
"meter",
|
|
8589
8694
|
"metrics-provider",
|
|
8590
8695
|
"model-convert",
|
|
8591
8696
|
"model-distributor",
|
|
@@ -8695,14 +8800,6 @@ Object.freeze({
|
|
|
8695
8800
|
{
|
|
8696
8801
|
"path": "aqi",
|
|
8697
8802
|
"valueType": "number"
|
|
8698
|
-
},
|
|
8699
|
-
{
|
|
8700
|
-
"path": "unit",
|
|
8701
|
-
"valueType": "string"
|
|
8702
|
-
},
|
|
8703
|
-
{
|
|
8704
|
-
"path": "precision",
|
|
8705
|
-
"valueType": "number"
|
|
8706
8803
|
}
|
|
8707
8804
|
],
|
|
8708
8805
|
"alarm-panel": [
|
|
@@ -8738,20 +8835,10 @@ Object.freeze({
|
|
|
8738
8835
|
"valueType": "boolean"
|
|
8739
8836
|
}
|
|
8740
8837
|
],
|
|
8741
|
-
"ambient-light-sensor": [
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
8745
|
-
},
|
|
8746
|
-
{
|
|
8747
|
-
"path": "unit",
|
|
8748
|
-
"valueType": "string"
|
|
8749
|
-
},
|
|
8750
|
-
{
|
|
8751
|
-
"path": "precision",
|
|
8752
|
-
"valueType": "number"
|
|
8753
|
-
}
|
|
8754
|
-
],
|
|
8838
|
+
"ambient-light-sensor": [{
|
|
8839
|
+
"path": "lux",
|
|
8840
|
+
"valueType": "number"
|
|
8841
|
+
}],
|
|
8755
8842
|
"audio-metrics": [
|
|
8756
8843
|
{
|
|
8757
8844
|
"path": "ts",
|
|
@@ -8831,6 +8918,10 @@ Object.freeze({
|
|
|
8831
8918
|
"path": "lastUpdated",
|
|
8832
8919
|
"valueType": "number"
|
|
8833
8920
|
},
|
|
8921
|
+
{
|
|
8922
|
+
"path": "volts",
|
|
8923
|
+
"valueType": "number"
|
|
8924
|
+
},
|
|
8834
8925
|
{
|
|
8835
8926
|
"path": "lastContactAt",
|
|
8836
8927
|
"valueType": "number"
|
|
@@ -9073,10 +9164,6 @@ Object.freeze({
|
|
|
9073
9164
|
"datetime"
|
|
9074
9165
|
]
|
|
9075
9166
|
},
|
|
9076
|
-
{
|
|
9077
|
-
"path": "unit",
|
|
9078
|
-
"valueType": "string"
|
|
9079
|
-
},
|
|
9080
9167
|
{
|
|
9081
9168
|
"path": "min",
|
|
9082
9169
|
"valueType": "number"
|
|
@@ -9088,19 +9175,6 @@ Object.freeze({
|
|
|
9088
9175
|
{
|
|
9089
9176
|
"path": "step",
|
|
9090
9177
|
"valueType": "number"
|
|
9091
|
-
},
|
|
9092
|
-
{
|
|
9093
|
-
"path": "precision",
|
|
9094
|
-
"valueType": "number"
|
|
9095
|
-
},
|
|
9096
|
-
{
|
|
9097
|
-
"path": "format",
|
|
9098
|
-
"valueType": "enum",
|
|
9099
|
-
"enumValues": [
|
|
9100
|
-
"date",
|
|
9101
|
-
"time",
|
|
9102
|
-
"datetime"
|
|
9103
|
-
]
|
|
9104
9178
|
}
|
|
9105
9179
|
],
|
|
9106
9180
|
"cover": [
|
|
@@ -9341,13 +9415,8 @@ Object.freeze({
|
|
|
9341
9415
|
"path": "value",
|
|
9342
9416
|
"valueType": "string"
|
|
9343
9417
|
}, {
|
|
9344
|
-
"path": "
|
|
9345
|
-
"valueType": "
|
|
9346
|
-
"enumValues": [
|
|
9347
|
-
"date",
|
|
9348
|
-
"time",
|
|
9349
|
-
"datetime"
|
|
9350
|
-
]
|
|
9418
|
+
"path": "timestamp",
|
|
9419
|
+
"valueType": "boolean"
|
|
9351
9420
|
}],
|
|
9352
9421
|
"event-emitter": [
|
|
9353
9422
|
{
|
|
@@ -9420,6 +9489,24 @@ Object.freeze({
|
|
|
9420
9489
|
"path": "detected",
|
|
9421
9490
|
"valueType": "boolean"
|
|
9422
9491
|
}],
|
|
9492
|
+
"group-active": [{
|
|
9493
|
+
"path": "active",
|
|
9494
|
+
"valueType": "boolean"
|
|
9495
|
+
}],
|
|
9496
|
+
"group-status": [
|
|
9497
|
+
{
|
|
9498
|
+
"path": "included",
|
|
9499
|
+
"valueType": "number"
|
|
9500
|
+
},
|
|
9501
|
+
{
|
|
9502
|
+
"path": "excluded",
|
|
9503
|
+
"valueType": "number"
|
|
9504
|
+
},
|
|
9505
|
+
{
|
|
9506
|
+
"path": "total",
|
|
9507
|
+
"valueType": "number"
|
|
9508
|
+
}
|
|
9509
|
+
],
|
|
9423
9510
|
"heating-valve": [{
|
|
9424
9511
|
"path": "position",
|
|
9425
9512
|
"valueType": "number"
|
|
@@ -9454,20 +9541,10 @@ Object.freeze({
|
|
|
9454
9541
|
"valueType": "number"
|
|
9455
9542
|
}
|
|
9456
9543
|
],
|
|
9457
|
-
"humidity-sensor": [
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
},
|
|
9462
|
-
{
|
|
9463
|
-
"path": "unit",
|
|
9464
|
-
"valueType": "string"
|
|
9465
|
-
},
|
|
9466
|
-
{
|
|
9467
|
-
"path": "precision",
|
|
9468
|
-
"valueType": "number"
|
|
9469
|
-
}
|
|
9470
|
-
],
|
|
9544
|
+
"humidity-sensor": [{
|
|
9545
|
+
"path": "percent",
|
|
9546
|
+
"valueType": "number"
|
|
9547
|
+
}],
|
|
9471
9548
|
"image": [{
|
|
9472
9549
|
"path": "url",
|
|
9473
9550
|
"valueType": "string"
|
|
@@ -9675,6 +9752,10 @@ Object.freeze({
|
|
|
9675
9752
|
]
|
|
9676
9753
|
}
|
|
9677
9754
|
],
|
|
9755
|
+
"meter": [{
|
|
9756
|
+
"path": "value",
|
|
9757
|
+
"valueType": "number"
|
|
9758
|
+
}],
|
|
9678
9759
|
"motion": [
|
|
9679
9760
|
{
|
|
9680
9761
|
"path": "detected",
|
|
@@ -9806,20 +9887,10 @@ Object.freeze({
|
|
|
9806
9887
|
"valueType": "boolean"
|
|
9807
9888
|
}
|
|
9808
9889
|
],
|
|
9809
|
-
"numeric-sensor": [
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
},
|
|
9814
|
-
{
|
|
9815
|
-
"path": "unit",
|
|
9816
|
-
"valueType": "string"
|
|
9817
|
-
},
|
|
9818
|
-
{
|
|
9819
|
-
"path": "precision",
|
|
9820
|
-
"valueType": "number"
|
|
9821
|
-
}
|
|
9822
|
-
],
|
|
9890
|
+
"numeric-sensor": [{
|
|
9891
|
+
"path": "value",
|
|
9892
|
+
"valueType": "number"
|
|
9893
|
+
}],
|
|
9823
9894
|
"pet-feeder": [
|
|
9824
9895
|
{
|
|
9825
9896
|
"path": "foodLevel",
|
|
@@ -9911,14 +9982,6 @@ Object.freeze({
|
|
|
9911
9982
|
{
|
|
9912
9983
|
"path": "powerFactor",
|
|
9913
9984
|
"valueType": "number"
|
|
9914
|
-
},
|
|
9915
|
-
{
|
|
9916
|
-
"path": "unit",
|
|
9917
|
-
"valueType": "string"
|
|
9918
|
-
},
|
|
9919
|
-
{
|
|
9920
|
-
"path": "precision",
|
|
9921
|
-
"valueType": "number"
|
|
9922
9985
|
}
|
|
9923
9986
|
],
|
|
9924
9987
|
"presence": [
|
|
@@ -9947,20 +10010,10 @@ Object.freeze({
|
|
|
9947
10010
|
"valueType": "number"
|
|
9948
10011
|
}
|
|
9949
10012
|
],
|
|
9950
|
-
"pressure-sensor": [
|
|
9951
|
-
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
},
|
|
9955
|
-
{
|
|
9956
|
-
"path": "unit",
|
|
9957
|
-
"valueType": "string"
|
|
9958
|
-
},
|
|
9959
|
-
{
|
|
9960
|
-
"path": "precision",
|
|
9961
|
-
"valueType": "number"
|
|
9962
|
-
}
|
|
9963
|
-
],
|
|
10013
|
+
"pressure-sensor": [{
|
|
10014
|
+
"path": "hpa",
|
|
10015
|
+
"valueType": "number"
|
|
10016
|
+
}],
|
|
9964
10017
|
"privacy-mask": [{
|
|
9965
10018
|
"path": "enabled",
|
|
9966
10019
|
"valueType": "boolean"
|
|
@@ -10271,20 +10324,10 @@ Object.freeze({
|
|
|
10271
10324
|
"path": "tampered",
|
|
10272
10325
|
"valueType": "boolean"
|
|
10273
10326
|
}],
|
|
10274
|
-
"temperature-sensor": [
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
},
|
|
10279
|
-
{
|
|
10280
|
-
"path": "unit",
|
|
10281
|
-
"valueType": "string"
|
|
10282
|
-
},
|
|
10283
|
-
{
|
|
10284
|
-
"path": "precision",
|
|
10285
|
-
"valueType": "number"
|
|
10286
|
-
}
|
|
10287
|
-
],
|
|
10327
|
+
"temperature-sensor": [{
|
|
10328
|
+
"path": "celsius",
|
|
10329
|
+
"valueType": "number"
|
|
10330
|
+
}],
|
|
10288
10331
|
"update": [
|
|
10289
10332
|
{
|
|
10290
10333
|
"path": "currentVersion",
|
|
@@ -10395,10 +10438,6 @@ Object.freeze({
|
|
|
10395
10438
|
"path": "temperature",
|
|
10396
10439
|
"valueType": "number"
|
|
10397
10440
|
},
|
|
10398
|
-
{
|
|
10399
|
-
"path": "temperatureUnit",
|
|
10400
|
-
"valueType": "string"
|
|
10401
|
-
},
|
|
10402
10441
|
{
|
|
10403
10442
|
"path": "humidity",
|
|
10404
10443
|
"valueType": "number"
|
|
@@ -10407,18 +10446,10 @@ Object.freeze({
|
|
|
10407
10446
|
"path": "pressure",
|
|
10408
10447
|
"valueType": "number"
|
|
10409
10448
|
},
|
|
10410
|
-
{
|
|
10411
|
-
"path": "pressureUnit",
|
|
10412
|
-
"valueType": "string"
|
|
10413
|
-
},
|
|
10414
10449
|
{
|
|
10415
10450
|
"path": "windSpeed",
|
|
10416
10451
|
"valueType": "number"
|
|
10417
10452
|
},
|
|
10418
|
-
{
|
|
10419
|
-
"path": "windSpeedUnit",
|
|
10420
|
-
"valueType": "string"
|
|
10421
|
-
},
|
|
10422
10453
|
{
|
|
10423
10454
|
"path": "windBearing",
|
|
10424
10455
|
"valueType": "number"
|
|
@@ -10482,7 +10513,7 @@ function userError(code, params, englishFallback) {
|
|
|
10482
10513
|
return new CamstackError(code, params, englishFallback);
|
|
10483
10514
|
}
|
|
10484
10515
|
//#endregion
|
|
10485
|
-
//#region ../types/dist/err-msg-
|
|
10516
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10486
10517
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10487
10518
|
DeviceType["Camera"] = "camera";
|
|
10488
10519
|
DeviceType["Hub"] = "hub";
|
|
@@ -10576,8 +10607,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10576
10607
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10577
10608
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10578
10609
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10579
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10610
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10611
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10580
10612
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10613
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10614
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10615
|
+
DeviceType["Washer"] = "washer";
|
|
10616
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10617
|
+
DeviceType["Dryer"] = "dryer";
|
|
10581
10618
|
return DeviceType;
|
|
10582
10619
|
}({});
|
|
10583
10620
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10835,7 +10872,7 @@ function errMsg(err) {
|
|
|
10835
10872
|
return String(err);
|
|
10836
10873
|
}
|
|
10837
10874
|
//#endregion
|
|
10838
|
-
//#region ../types/dist/composition-
|
|
10875
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10839
10876
|
/**
|
|
10840
10877
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10841
10878
|
*
|
|
@@ -11150,6 +11187,13 @@ var table = {
|
|
|
11150
11187
|
apply: () => {
|
|
11151
11188
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11152
11189
|
}
|
|
11190
|
+
},
|
|
11191
|
+
schmitt: {
|
|
11192
|
+
minArgs: 3,
|
|
11193
|
+
maxArgs: 5,
|
|
11194
|
+
apply: () => {
|
|
11195
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11196
|
+
}
|
|
11153
11197
|
}
|
|
11154
11198
|
};
|
|
11155
11199
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11590,15 +11634,232 @@ function validateExpressionSource(src) {
|
|
|
11590
11634
|
}
|
|
11591
11635
|
return null;
|
|
11592
11636
|
}
|
|
11593
|
-
/**
|
|
11594
|
-
|
|
11595
|
-
|
|
11596
|
-
|
|
11637
|
+
/**
|
|
11638
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11639
|
+
*
|
|
11640
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11641
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11642
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11643
|
+
*
|
|
11644
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11645
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11646
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11647
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11648
|
+
* can move later without moving the others.
|
|
11649
|
+
*/
|
|
11650
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11651
|
+
var APPLIANCE_KINDS = [
|
|
11652
|
+
"washer",
|
|
11653
|
+
"dryer",
|
|
11654
|
+
"dishwasher"
|
|
11655
|
+
];
|
|
11656
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11657
|
+
/**
|
|
11658
|
+
* Statistics and integrals over a history read (D944).
|
|
11659
|
+
*
|
|
11660
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11661
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11662
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11663
|
+
* as zero. A truncated read is not published.
|
|
11664
|
+
*/
|
|
11665
|
+
var STATISTIC_STATS = [
|
|
11666
|
+
"min",
|
|
11667
|
+
"max",
|
|
11668
|
+
"mean",
|
|
11669
|
+
"sum",
|
|
11670
|
+
"count",
|
|
11671
|
+
"change"
|
|
11672
|
+
];
|
|
11673
|
+
/**
|
|
11674
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11675
|
+
*
|
|
11676
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11677
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11678
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11679
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11680
|
+
*/
|
|
11681
|
+
var MINUTE_MS = 6e4;
|
|
11682
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11683
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11684
|
+
var ROLLING_SPANS = [
|
|
11685
|
+
"1h",
|
|
11686
|
+
"24h",
|
|
11687
|
+
"2d",
|
|
11688
|
+
"7d",
|
|
11689
|
+
"30d",
|
|
11690
|
+
"custom"
|
|
11691
|
+
];
|
|
11692
|
+
var CALENDAR_PERIODS = [
|
|
11693
|
+
"today",
|
|
11694
|
+
"yesterday",
|
|
11695
|
+
"this-week",
|
|
11696
|
+
"this-month"
|
|
11697
|
+
];
|
|
11698
|
+
var RESET_PERIODS = [
|
|
11699
|
+
"never",
|
|
11700
|
+
"daily",
|
|
11701
|
+
"weekly",
|
|
11702
|
+
"monthly"
|
|
11703
|
+
];
|
|
11704
|
+
5 * MINUTE_MS;
|
|
11705
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11706
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11707
|
+
var rollingWindowObject = object({
|
|
11708
|
+
kind: literal("rolling"),
|
|
11709
|
+
span: _enum(ROLLING_SPANS),
|
|
11710
|
+
customMinutes: number().int().min(5).optional()
|
|
11711
|
+
}).check((payload) => {
|
|
11712
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11713
|
+
code: "custom",
|
|
11714
|
+
message: "a custom range needs a duration in minutes",
|
|
11715
|
+
path: ["customMinutes"],
|
|
11716
|
+
input: payload.value
|
|
11717
|
+
});
|
|
11718
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11719
|
+
code: "custom",
|
|
11720
|
+
message: "only a custom range carries a duration",
|
|
11721
|
+
path: ["customMinutes"],
|
|
11722
|
+
input: payload.value
|
|
11723
|
+
});
|
|
11724
|
+
});
|
|
11725
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11726
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11727
|
+
kind: literal("calendar"),
|
|
11728
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11729
|
+
})]);
|
|
11730
|
+
/**
|
|
11731
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11732
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11733
|
+
* `composition.ts` (D659).
|
|
11734
|
+
*/
|
|
11597
11735
|
var CompositionSourceRefSchema = object({
|
|
11598
11736
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11599
11737
|
addonId: string().min(1),
|
|
11600
11738
|
stableId: string().min(1)
|
|
11601
11739
|
});
|
|
11740
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11741
|
+
"temperature",
|
|
11742
|
+
"humidity",
|
|
11743
|
+
"pressure",
|
|
11744
|
+
"illuminance",
|
|
11745
|
+
"power",
|
|
11746
|
+
"energy",
|
|
11747
|
+
"battery",
|
|
11748
|
+
"numeric",
|
|
11749
|
+
"motion",
|
|
11750
|
+
"contact",
|
|
11751
|
+
"leak",
|
|
11752
|
+
"smoke",
|
|
11753
|
+
"occupancy",
|
|
11754
|
+
"binary",
|
|
11755
|
+
"switch",
|
|
11756
|
+
"light",
|
|
11757
|
+
"fan",
|
|
11758
|
+
"cover",
|
|
11759
|
+
"valve",
|
|
11760
|
+
"lock",
|
|
11761
|
+
"media-player",
|
|
11762
|
+
"climate"
|
|
11763
|
+
];
|
|
11764
|
+
var NUMERIC_AGGREGATES = [
|
|
11765
|
+
"mean",
|
|
11766
|
+
"median",
|
|
11767
|
+
"min",
|
|
11768
|
+
"max",
|
|
11769
|
+
"sum"
|
|
11770
|
+
];
|
|
11771
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11772
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11773
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11774
|
+
var AGGREGATE_REDUCERS = [
|
|
11775
|
+
"mean",
|
|
11776
|
+
"median",
|
|
11777
|
+
"min",
|
|
11778
|
+
"max",
|
|
11779
|
+
"sum",
|
|
11780
|
+
"any",
|
|
11781
|
+
"all"
|
|
11782
|
+
];
|
|
11783
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11784
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11785
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11786
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11787
|
+
var HelperMemberSchema = object({
|
|
11788
|
+
source: CompositionSourceRefSchema,
|
|
11789
|
+
cap: string().min(1),
|
|
11790
|
+
fieldPath: string().min(1)
|
|
11791
|
+
});
|
|
11792
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11793
|
+
object({
|
|
11794
|
+
kind: literal("group"),
|
|
11795
|
+
templateId: GroupTemplateIdSchema,
|
|
11796
|
+
aggregate: AggregateReducerSchema,
|
|
11797
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11798
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11799
|
+
active: ActiveCriterionSchema.optional()
|
|
11800
|
+
}),
|
|
11801
|
+
object({
|
|
11802
|
+
kind: literal("appliance"),
|
|
11803
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11804
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11805
|
+
thresholdWatts: number().positive(),
|
|
11806
|
+
startDwellMs: number().int().nonnegative(),
|
|
11807
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11808
|
+
member: HelperMemberSchema
|
|
11809
|
+
}),
|
|
11810
|
+
object({
|
|
11811
|
+
kind: literal("statistic"),
|
|
11812
|
+
stat: _enum(STATISTIC_STATS),
|
|
11813
|
+
window: StatisticWindowSchema,
|
|
11814
|
+
source: HelperMemberSchema
|
|
11815
|
+
}),
|
|
11816
|
+
object({
|
|
11817
|
+
kind: literal("integral"),
|
|
11818
|
+
reset: _enum(RESET_PERIODS),
|
|
11819
|
+
output: _enum(["energy", "meter"]),
|
|
11820
|
+
source: HelperMemberSchema
|
|
11821
|
+
}),
|
|
11822
|
+
object({
|
|
11823
|
+
kind: literal("threshold"),
|
|
11824
|
+
source: HelperMemberSchema,
|
|
11825
|
+
high: number(),
|
|
11826
|
+
low: number(),
|
|
11827
|
+
onForMs: number().int().nonnegative(),
|
|
11828
|
+
offForMs: number().int().nonnegative()
|
|
11829
|
+
}),
|
|
11830
|
+
object({
|
|
11831
|
+
kind: literal("arithmetic"),
|
|
11832
|
+
op: _enum([
|
|
11833
|
+
"sum",
|
|
11834
|
+
"difference",
|
|
11835
|
+
"ratio"
|
|
11836
|
+
]),
|
|
11837
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11838
|
+
}),
|
|
11839
|
+
object({
|
|
11840
|
+
kind: literal("expression"),
|
|
11841
|
+
expr: string().min(1),
|
|
11842
|
+
inputs: array(object({
|
|
11843
|
+
name: string().min(1),
|
|
11844
|
+
member: HelperMemberSchema
|
|
11845
|
+
})).min(1).max(64),
|
|
11846
|
+
output: _enum(["number", "boolean"])
|
|
11847
|
+
}),
|
|
11848
|
+
object({
|
|
11849
|
+
kind: literal("derivative"),
|
|
11850
|
+
window: RollingWindowSchema,
|
|
11851
|
+
per: _enum([
|
|
11852
|
+
"second",
|
|
11853
|
+
"minute",
|
|
11854
|
+
"hour"
|
|
11855
|
+
]),
|
|
11856
|
+
source: HelperMemberSchema
|
|
11857
|
+
})
|
|
11858
|
+
]);
|
|
11859
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11860
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11861
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11862
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11602
11863
|
/** One field of one capability of one source device. */
|
|
11603
11864
|
var CompositionFieldReadSchema = object({
|
|
11604
11865
|
source: CompositionSourceRefSchema,
|
|
@@ -11642,7 +11903,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11642
11903
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11643
11904
|
CompositionFromSourceSchema,
|
|
11644
11905
|
CompositionExpressionSourceSchema,
|
|
11645
|
-
CompositionCodeSourceSchema
|
|
11906
|
+
CompositionCodeSourceSchema,
|
|
11907
|
+
object({
|
|
11908
|
+
kind: literal("aggregate"),
|
|
11909
|
+
reducer: _enum([
|
|
11910
|
+
"mean",
|
|
11911
|
+
"median",
|
|
11912
|
+
"min",
|
|
11913
|
+
"max",
|
|
11914
|
+
"sum",
|
|
11915
|
+
"any",
|
|
11916
|
+
"all"
|
|
11917
|
+
]),
|
|
11918
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11919
|
+
/**
|
|
11920
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11921
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11922
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11923
|
+
*/
|
|
11924
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11925
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11926
|
+
publish: _enum([
|
|
11927
|
+
"value",
|
|
11928
|
+
"included",
|
|
11929
|
+
"excluded",
|
|
11930
|
+
"total"
|
|
11931
|
+
]),
|
|
11932
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11933
|
+
empty: _enum([
|
|
11934
|
+
"null",
|
|
11935
|
+
"omit",
|
|
11936
|
+
"offline"
|
|
11937
|
+
])
|
|
11938
|
+
}),
|
|
11939
|
+
object({
|
|
11940
|
+
kind: literal("series"),
|
|
11941
|
+
read: CompositionFieldReadSchema,
|
|
11942
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11943
|
+
publish: _enum([
|
|
11944
|
+
"value",
|
|
11945
|
+
"included",
|
|
11946
|
+
"excluded",
|
|
11947
|
+
"total"
|
|
11948
|
+
]),
|
|
11949
|
+
/**
|
|
11950
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11951
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11952
|
+
*/
|
|
11953
|
+
empty: _enum([
|
|
11954
|
+
"null",
|
|
11955
|
+
"omit",
|
|
11956
|
+
"offline"
|
|
11957
|
+
])
|
|
11958
|
+
})
|
|
11646
11959
|
]);
|
|
11647
11960
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11648
11961
|
kind: literal("forward"),
|
|
@@ -11688,7 +12001,13 @@ var CompositionSchema = object({
|
|
|
11688
12001
|
kind: literal("existing"),
|
|
11689
12002
|
device: CompositionSourceRefSchema
|
|
11690
12003
|
})]),
|
|
11691
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12004
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12005
|
+
/**
|
|
12006
|
+
* Present when the block is a helper template. Absent on a free
|
|
12007
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12008
|
+
* never the compiled features.
|
|
12009
|
+
*/
|
|
12010
|
+
helper: HelperSpecSchema.optional()
|
|
11692
12011
|
}).superRefine((composition, ctx) => {
|
|
11693
12012
|
const seen = /* @__PURE__ */ new Set();
|
|
11694
12013
|
composition.features.forEach((feature, index) => {
|
|
@@ -16815,7 +17134,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16815
17134
|
*/
|
|
16816
17135
|
interactiveConnectPath: string().min(1).optional(),
|
|
16817
17136
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16818
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17137
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17138
|
+
/**
|
|
17139
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17140
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17141
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17142
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17143
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17144
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17145
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17146
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17147
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17148
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17149
|
+
* offers it as the default path; the fields the session fills are
|
|
17150
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17151
|
+
*/
|
|
17152
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16819
17153
|
}))
|
|
16820
17154
|
});
|
|
16821
17155
|
var ListInputSchema = object({
|
|
@@ -17916,7 +18250,12 @@ var CompositionProblemSchema = object({
|
|
|
17916
18250
|
"item-field-reserved",
|
|
17917
18251
|
"target-missing",
|
|
17918
18252
|
"target-unreadable",
|
|
17919
|
-
"not-replaceable"
|
|
18253
|
+
"not-replaceable",
|
|
18254
|
+
"native-capability-replace",
|
|
18255
|
+
"mixed-quantity",
|
|
18256
|
+
"helper-mismatch",
|
|
18257
|
+
"member-constraint",
|
|
18258
|
+
"retention"
|
|
17920
18259
|
]),
|
|
17921
18260
|
path: string(),
|
|
17922
18261
|
message: string()
|
|
@@ -17937,7 +18276,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17937
18276
|
"null",
|
|
17938
18277
|
"offline",
|
|
17939
18278
|
"unknown",
|
|
17940
|
-
"release"
|
|
18279
|
+
"release",
|
|
18280
|
+
"omit"
|
|
17941
18281
|
]);
|
|
17942
18282
|
/**
|
|
17943
18283
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17974,9 +18314,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17974
18314
|
reads: array(CompositionFieldReadSchema)
|
|
17975
18315
|
});
|
|
17976
18316
|
/**
|
|
17977
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17978
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17979
|
-
*
|
|
18317
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18318
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18319
|
+
* Replacing a capability the device already serves is refused
|
|
18320
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18321
|
+
* wire for a claim the hub already holds.
|
|
17980
18322
|
*/
|
|
17981
18323
|
var CompositionFeatureModeSchema = _enum([
|
|
17982
18324
|
"new",
|
|
@@ -18147,8 +18489,392 @@ Object.freeze({
|
|
|
18147
18489
|
latchedAt: {
|
|
18148
18490
|
kind: "fixed",
|
|
18149
18491
|
result: ["number", "null"]
|
|
18492
|
+
},
|
|
18493
|
+
schmitt: {
|
|
18494
|
+
kind: "fixed",
|
|
18495
|
+
result: ["boolean", "null"]
|
|
18150
18496
|
}
|
|
18151
18497
|
});
|
|
18498
|
+
/**
|
|
18499
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18500
|
+
* Data, not a form default written into the block.
|
|
18501
|
+
*/
|
|
18502
|
+
var NOW$2 = {
|
|
18503
|
+
fieldPath: "lastFetchedAt",
|
|
18504
|
+
expr: "now"
|
|
18505
|
+
};
|
|
18506
|
+
var CHANGED = {
|
|
18507
|
+
fieldPath: "lastChangedAt",
|
|
18508
|
+
expr: "now"
|
|
18509
|
+
};
|
|
18510
|
+
function numeric(input) {
|
|
18511
|
+
return {
|
|
18512
|
+
...input,
|
|
18513
|
+
family: "numeric",
|
|
18514
|
+
deviceType: DeviceType.Sensor,
|
|
18515
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18516
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18517
|
+
activeWhen: void 0,
|
|
18518
|
+
commandCaps: [],
|
|
18519
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18520
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18521
|
+
accept: [{
|
|
18522
|
+
cap: input.outputCap,
|
|
18523
|
+
fieldPath: input.outputField
|
|
18524
|
+
}]
|
|
18525
|
+
};
|
|
18526
|
+
}
|
|
18527
|
+
function binary(input) {
|
|
18528
|
+
return {
|
|
18529
|
+
...input,
|
|
18530
|
+
family: "binary",
|
|
18531
|
+
deviceType: DeviceType.Sensor,
|
|
18532
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18533
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18534
|
+
activeWhen: void 0,
|
|
18535
|
+
commandCaps: [],
|
|
18536
|
+
quantity: "none",
|
|
18537
|
+
baseUnit: void 0,
|
|
18538
|
+
aggregates: BINARY_AGGREGATES,
|
|
18539
|
+
empty: "offline"
|
|
18540
|
+
};
|
|
18541
|
+
}
|
|
18542
|
+
var GROUP_TEMPLATES = [
|
|
18543
|
+
numeric({
|
|
18544
|
+
id: "temperature",
|
|
18545
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18546
|
+
role: DeviceRole.TemperatureSensor,
|
|
18547
|
+
outputCap: "temperature-sensor",
|
|
18548
|
+
outputField: "celsius",
|
|
18549
|
+
quantity: "temperature",
|
|
18550
|
+
defaultAggregate: "mean",
|
|
18551
|
+
empty: "null",
|
|
18552
|
+
companions: [NOW$2]
|
|
18553
|
+
}),
|
|
18554
|
+
numeric({
|
|
18555
|
+
id: "humidity",
|
|
18556
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18557
|
+
role: DeviceRole.HumiditySensor,
|
|
18558
|
+
outputCap: "humidity-sensor",
|
|
18559
|
+
outputField: "percent",
|
|
18560
|
+
quantity: "humidity",
|
|
18561
|
+
defaultAggregate: "mean",
|
|
18562
|
+
empty: "null",
|
|
18563
|
+
companions: [NOW$2]
|
|
18564
|
+
}),
|
|
18565
|
+
numeric({
|
|
18566
|
+
id: "pressure",
|
|
18567
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18568
|
+
role: DeviceRole.PressureSensor,
|
|
18569
|
+
outputCap: "pressure-sensor",
|
|
18570
|
+
outputField: "hpa",
|
|
18571
|
+
quantity: "pressure",
|
|
18572
|
+
defaultAggregate: "mean",
|
|
18573
|
+
empty: "null",
|
|
18574
|
+
companions: [NOW$2]
|
|
18575
|
+
}),
|
|
18576
|
+
numeric({
|
|
18577
|
+
id: "illuminance",
|
|
18578
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18579
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18580
|
+
outputCap: "ambient-light-sensor",
|
|
18581
|
+
outputField: "lux",
|
|
18582
|
+
quantity: "illuminance",
|
|
18583
|
+
defaultAggregate: "mean",
|
|
18584
|
+
empty: "null",
|
|
18585
|
+
companions: [NOW$2]
|
|
18586
|
+
}),
|
|
18587
|
+
numeric({
|
|
18588
|
+
id: "power",
|
|
18589
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18590
|
+
role: DeviceRole.PowerSensor,
|
|
18591
|
+
outputCap: "power-meter",
|
|
18592
|
+
outputField: "watts",
|
|
18593
|
+
quantity: "power",
|
|
18594
|
+
defaultAggregate: "sum",
|
|
18595
|
+
empty: "omit",
|
|
18596
|
+
companions: [NOW$2]
|
|
18597
|
+
}),
|
|
18598
|
+
numeric({
|
|
18599
|
+
id: "energy",
|
|
18600
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18601
|
+
role: DeviceRole.EnergySensor,
|
|
18602
|
+
outputCap: "power-meter",
|
|
18603
|
+
outputField: "kwhTotal",
|
|
18604
|
+
quantity: "energy",
|
|
18605
|
+
defaultAggregate: "sum",
|
|
18606
|
+
empty: "omit",
|
|
18607
|
+
companions: [NOW$2]
|
|
18608
|
+
}),
|
|
18609
|
+
numeric({
|
|
18610
|
+
id: "battery",
|
|
18611
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18612
|
+
role: DeviceRole.BatterySensor,
|
|
18613
|
+
outputCap: "battery",
|
|
18614
|
+
outputField: "percentage",
|
|
18615
|
+
quantity: "percentage",
|
|
18616
|
+
defaultAggregate: "mean",
|
|
18617
|
+
empty: "null",
|
|
18618
|
+
companions: [
|
|
18619
|
+
{
|
|
18620
|
+
fieldPath: "charging",
|
|
18621
|
+
expr: "\"unknown\""
|
|
18622
|
+
},
|
|
18623
|
+
{
|
|
18624
|
+
fieldPath: "sleeping",
|
|
18625
|
+
expr: "false"
|
|
18626
|
+
},
|
|
18627
|
+
{
|
|
18628
|
+
fieldPath: "lastUpdated",
|
|
18629
|
+
expr: "now"
|
|
18630
|
+
}
|
|
18631
|
+
]
|
|
18632
|
+
}),
|
|
18633
|
+
numeric({
|
|
18634
|
+
id: "numeric",
|
|
18635
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18636
|
+
role: DeviceRole.NumericSensor,
|
|
18637
|
+
outputCap: "numeric-sensor",
|
|
18638
|
+
outputField: "value",
|
|
18639
|
+
quantity: "device",
|
|
18640
|
+
defaultAggregate: "mean",
|
|
18641
|
+
empty: "null",
|
|
18642
|
+
companions: [NOW$2]
|
|
18643
|
+
}),
|
|
18644
|
+
binary({
|
|
18645
|
+
id: "motion",
|
|
18646
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18647
|
+
role: DeviceRole.MotionSensor,
|
|
18648
|
+
outputCap: "motion",
|
|
18649
|
+
outputField: "detected",
|
|
18650
|
+
defaultAggregate: "any",
|
|
18651
|
+
accept: [{
|
|
18652
|
+
cap: "motion",
|
|
18653
|
+
fieldPath: "detected"
|
|
18654
|
+
}],
|
|
18655
|
+
companions: [{
|
|
18656
|
+
fieldPath: "lastDetectedAt",
|
|
18657
|
+
expr: "null"
|
|
18658
|
+
}, {
|
|
18659
|
+
fieldPath: "autoClearAfterMs",
|
|
18660
|
+
expr: "null"
|
|
18661
|
+
}]
|
|
18662
|
+
}),
|
|
18663
|
+
binary({
|
|
18664
|
+
id: "contact",
|
|
18665
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18666
|
+
role: DeviceRole.ContactSensor,
|
|
18667
|
+
outputCap: "contact",
|
|
18668
|
+
outputField: "entryOpen",
|
|
18669
|
+
defaultAggregate: "any",
|
|
18670
|
+
accept: [{
|
|
18671
|
+
cap: "contact",
|
|
18672
|
+
fieldPath: "entryOpen"
|
|
18673
|
+
}],
|
|
18674
|
+
companions: [CHANGED]
|
|
18675
|
+
}),
|
|
18676
|
+
binary({
|
|
18677
|
+
id: "leak",
|
|
18678
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18679
|
+
role: DeviceRole.LeakSensor,
|
|
18680
|
+
outputCap: "flood",
|
|
18681
|
+
outputField: "flooded",
|
|
18682
|
+
defaultAggregate: "any",
|
|
18683
|
+
accept: [{
|
|
18684
|
+
cap: "flood",
|
|
18685
|
+
fieldPath: "flooded"
|
|
18686
|
+
}],
|
|
18687
|
+
companions: [CHANGED]
|
|
18688
|
+
}),
|
|
18689
|
+
binary({
|
|
18690
|
+
id: "smoke",
|
|
18691
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18692
|
+
role: DeviceRole.SmokeSensor,
|
|
18693
|
+
outputCap: "smoke",
|
|
18694
|
+
outputField: "detected",
|
|
18695
|
+
defaultAggregate: "any",
|
|
18696
|
+
accept: [{
|
|
18697
|
+
cap: "smoke",
|
|
18698
|
+
fieldPath: "detected"
|
|
18699
|
+
}],
|
|
18700
|
+
companions: [CHANGED]
|
|
18701
|
+
}),
|
|
18702
|
+
binary({
|
|
18703
|
+
id: "occupancy",
|
|
18704
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18705
|
+
role: DeviceRole.BinarySensor,
|
|
18706
|
+
outputCap: "binary",
|
|
18707
|
+
outputField: "on",
|
|
18708
|
+
defaultAggregate: "any",
|
|
18709
|
+
accept: [{
|
|
18710
|
+
cap: "motion",
|
|
18711
|
+
fieldPath: "detected"
|
|
18712
|
+
}, {
|
|
18713
|
+
cap: "binary",
|
|
18714
|
+
fieldPath: "on"
|
|
18715
|
+
}],
|
|
18716
|
+
companions: [CHANGED]
|
|
18717
|
+
}),
|
|
18718
|
+
binary({
|
|
18719
|
+
id: "binary",
|
|
18720
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18721
|
+
role: DeviceRole.BinarySensor,
|
|
18722
|
+
outputCap: "binary",
|
|
18723
|
+
outputField: "on",
|
|
18724
|
+
defaultAggregate: "any",
|
|
18725
|
+
accept: [{
|
|
18726
|
+
cap: "binary",
|
|
18727
|
+
fieldPath: "on"
|
|
18728
|
+
}],
|
|
18729
|
+
companions: [CHANGED]
|
|
18730
|
+
}),
|
|
18731
|
+
actuator({
|
|
18732
|
+
id: "switch",
|
|
18733
|
+
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.",
|
|
18734
|
+
deviceType: DeviceType.Switch,
|
|
18735
|
+
outputCap: "switch",
|
|
18736
|
+
outputField: "on",
|
|
18737
|
+
member: {
|
|
18738
|
+
cap: "switch",
|
|
18739
|
+
fieldPath: "on"
|
|
18740
|
+
},
|
|
18741
|
+
commandCaps: ["switch"]
|
|
18742
|
+
}),
|
|
18743
|
+
actuator({
|
|
18744
|
+
id: "light",
|
|
18745
|
+
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.",
|
|
18746
|
+
deviceType: DeviceType.Light,
|
|
18747
|
+
outputCap: "switch",
|
|
18748
|
+
outputField: "on",
|
|
18749
|
+
member: {
|
|
18750
|
+
cap: "switch",
|
|
18751
|
+
fieldPath: "on"
|
|
18752
|
+
},
|
|
18753
|
+
commandCaps: [
|
|
18754
|
+
"switch",
|
|
18755
|
+
"brightness",
|
|
18756
|
+
"color"
|
|
18757
|
+
]
|
|
18758
|
+
}),
|
|
18759
|
+
actuator({
|
|
18760
|
+
id: "fan",
|
|
18761
|
+
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.",
|
|
18762
|
+
deviceType: DeviceType.Fan,
|
|
18763
|
+
outputCap: "switch",
|
|
18764
|
+
outputField: "on",
|
|
18765
|
+
member: {
|
|
18766
|
+
cap: "switch",
|
|
18767
|
+
fieldPath: "on"
|
|
18768
|
+
},
|
|
18769
|
+
commandCaps: ["switch", "fan-control"]
|
|
18770
|
+
}),
|
|
18771
|
+
actuator({
|
|
18772
|
+
id: "cover",
|
|
18773
|
+
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.",
|
|
18774
|
+
deviceType: DeviceType.Cover,
|
|
18775
|
+
outputCap: "group-active",
|
|
18776
|
+
outputField: "active",
|
|
18777
|
+
member: {
|
|
18778
|
+
cap: "cover",
|
|
18779
|
+
fieldPath: "state"
|
|
18780
|
+
},
|
|
18781
|
+
activeWhen: [
|
|
18782
|
+
"open",
|
|
18783
|
+
"opening",
|
|
18784
|
+
"stopped"
|
|
18785
|
+
],
|
|
18786
|
+
commandCaps: ["cover"]
|
|
18787
|
+
}),
|
|
18788
|
+
actuator({
|
|
18789
|
+
id: "valve",
|
|
18790
|
+
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.",
|
|
18791
|
+
deviceType: DeviceType.Valve,
|
|
18792
|
+
outputCap: "group-active",
|
|
18793
|
+
outputField: "active",
|
|
18794
|
+
member: {
|
|
18795
|
+
cap: "valve",
|
|
18796
|
+
fieldPath: "state"
|
|
18797
|
+
},
|
|
18798
|
+
activeWhen: [
|
|
18799
|
+
"open",
|
|
18800
|
+
"opening",
|
|
18801
|
+
"stopped"
|
|
18802
|
+
],
|
|
18803
|
+
commandCaps: ["valve"]
|
|
18804
|
+
}),
|
|
18805
|
+
actuator({
|
|
18806
|
+
id: "lock",
|
|
18807
|
+
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.",
|
|
18808
|
+
deviceType: DeviceType.Lock,
|
|
18809
|
+
outputCap: "group-active",
|
|
18810
|
+
outputField: "active",
|
|
18811
|
+
member: {
|
|
18812
|
+
cap: "lock-control",
|
|
18813
|
+
fieldPath: "state"
|
|
18814
|
+
},
|
|
18815
|
+
activeWhen: ["locked"],
|
|
18816
|
+
commandCaps: ["lock-control"]
|
|
18817
|
+
}),
|
|
18818
|
+
actuator({
|
|
18819
|
+
id: "media-player",
|
|
18820
|
+
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.",
|
|
18821
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18822
|
+
outputCap: "group-active",
|
|
18823
|
+
outputField: "active",
|
|
18824
|
+
member: {
|
|
18825
|
+
cap: "media-player",
|
|
18826
|
+
fieldPath: "state"
|
|
18827
|
+
},
|
|
18828
|
+
activeWhen: ["playing", "buffering"],
|
|
18829
|
+
commandCaps: ["media-player"]
|
|
18830
|
+
}),
|
|
18831
|
+
actuator({
|
|
18832
|
+
id: "climate",
|
|
18833
|
+
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.",
|
|
18834
|
+
deviceType: DeviceType.Thermostat,
|
|
18835
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18836
|
+
outputCap: "group-active",
|
|
18837
|
+
outputField: "active",
|
|
18838
|
+
member: {
|
|
18839
|
+
cap: "climate-control",
|
|
18840
|
+
fieldPath: "mode"
|
|
18841
|
+
},
|
|
18842
|
+
activeWhen: [
|
|
18843
|
+
"heat",
|
|
18844
|
+
"cool",
|
|
18845
|
+
"auto",
|
|
18846
|
+
"heat_cool",
|
|
18847
|
+
"fan_only",
|
|
18848
|
+
"dry"
|
|
18849
|
+
],
|
|
18850
|
+
commandCaps: ["climate-control"]
|
|
18851
|
+
})
|
|
18852
|
+
];
|
|
18853
|
+
function actuator(input) {
|
|
18854
|
+
return {
|
|
18855
|
+
id: input.id,
|
|
18856
|
+
summary: input.summary,
|
|
18857
|
+
deviceType: input.deviceType,
|
|
18858
|
+
outputCap: input.outputCap,
|
|
18859
|
+
outputField: input.outputField,
|
|
18860
|
+
commandCaps: input.commandCaps,
|
|
18861
|
+
family: "actuator",
|
|
18862
|
+
role: void 0,
|
|
18863
|
+
memberDeviceType: input.deviceType,
|
|
18864
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18865
|
+
activeWhen: input.activeWhen,
|
|
18866
|
+
quantity: "none",
|
|
18867
|
+
baseUnit: void 0,
|
|
18868
|
+
aggregates: BINARY_AGGREGATES,
|
|
18869
|
+
defaultAggregate: "any",
|
|
18870
|
+
empty: "offline",
|
|
18871
|
+
accept: [input.member],
|
|
18872
|
+
companions: [CHANGED]
|
|
18873
|
+
};
|
|
18874
|
+
}
|
|
18875
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18876
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18877
|
+
DeviceType.Camera;
|
|
18152
18878
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18153
18879
|
/**
|
|
18154
18880
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19862,12 +20588,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
19862
20588
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19863
20589
|
* in-place so dispatch keeps working.
|
|
19864
20590
|
*
|
|
19865
|
-
* **
|
|
19866
|
-
*
|
|
19867
|
-
*
|
|
19868
|
-
*
|
|
19869
|
-
* (`ha-domain-mapping`)
|
|
19870
|
-
* stored after that point.
|
|
20591
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20592
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20593
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20594
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20595
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20596
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19871
20597
|
*
|
|
19872
20598
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19873
20599
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19881,6 +20607,14 @@ var SourceInfoSchema = object({
|
|
|
19881
20607
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19882
20608
|
* Used to detect rename when `id` changes. */
|
|
19883
20609
|
uniqueId: string().optional(),
|
|
20610
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20611
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20612
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20613
|
+
dateTimeShape: _enum([
|
|
20614
|
+
"date",
|
|
20615
|
+
"time",
|
|
20616
|
+
"datetime"
|
|
20617
|
+
]).optional(),
|
|
19884
20618
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19885
20619
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19886
20620
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41002,7 +41736,8 @@ method(object({
|
|
|
41002
41736
|
"enum"
|
|
41003
41737
|
]),
|
|
41004
41738
|
enumValues: array(string()).optional(),
|
|
41005
|
-
item: boolean().optional()
|
|
41739
|
+
item: boolean().optional(),
|
|
41740
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41006
41741
|
})).readonly(),
|
|
41007
41742
|
itemArray: object({
|
|
41008
41743
|
path: string(),
|
|
@@ -43363,7 +44098,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43363
44098
|
});
|
|
43364
44099
|
/**
|
|
43365
44100
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43366
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44101
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43367
44102
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43368
44103
|
* the originating provider config (mode + sourcePort) so the
|
|
43369
44104
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44846,8 +45581,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44846
45581
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44847
45582
|
var MaskGridShapeSchema = object({
|
|
44848
45583
|
kind: literal("grid"),
|
|
44849
|
-
gridWidth: number(),
|
|
44850
|
-
gridHeight: number(),
|
|
45584
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45585
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44851
45586
|
cells: array(boolean())
|
|
44852
45587
|
});
|
|
44853
45588
|
discriminatedUnion("kind", [
|
|
@@ -44959,6 +45694,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44959
45694
|
"detection-blind",
|
|
44960
45695
|
"motion-noisy",
|
|
44961
45696
|
"motion-calm",
|
|
45697
|
+
"package-llm-silent",
|
|
45698
|
+
"package-llm-answered",
|
|
44962
45699
|
"recording-stalled",
|
|
44963
45700
|
"recording-healthy",
|
|
44964
45701
|
"recording-degraded",
|
|
@@ -46048,7 +46785,20 @@ var NcRuleInputSchema = object({
|
|
|
46048
46785
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46049
46786
|
* path does not run Zod defaults.
|
|
46050
46787
|
*/
|
|
46051
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46788
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46789
|
+
/**
|
|
46790
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46791
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46792
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46793
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46794
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46795
|
+
*
|
|
46796
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46797
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46798
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46799
|
+
* `false`, so it needs no `clear` key.
|
|
46800
|
+
*/
|
|
46801
|
+
askVerdict: boolean().optional()
|
|
46052
46802
|
});
|
|
46053
46803
|
/**
|
|
46054
46804
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56154,6 +56904,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56154
56904
|
deprecated: string().optional(),
|
|
56155
56905
|
distTags: array(string()).readonly()
|
|
56156
56906
|
});
|
|
56907
|
+
/**
|
|
56908
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56909
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56910
|
+
* tarball failure — never an empty string standing in for either.
|
|
56911
|
+
*/
|
|
56912
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56913
|
+
object({
|
|
56914
|
+
status: literal("ok"),
|
|
56915
|
+
markdown: string()
|
|
56916
|
+
}),
|
|
56917
|
+
object({ status: literal("missing") }),
|
|
56918
|
+
object({
|
|
56919
|
+
status: literal("error"),
|
|
56920
|
+
message: string()
|
|
56921
|
+
})
|
|
56922
|
+
]);
|
|
56923
|
+
var PackageDocsSchema = object({
|
|
56924
|
+
name: string(),
|
|
56925
|
+
version: string(),
|
|
56926
|
+
readme: PackageDocBodySchema,
|
|
56927
|
+
changelog: PackageDocBodySchema
|
|
56928
|
+
});
|
|
56157
56929
|
var SearchResultSchema = object({
|
|
56158
56930
|
name: string(),
|
|
56159
56931
|
version: string(),
|
|
@@ -56372,7 +57144,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56372
57144
|
}), object({ success: literal(true) }), {
|
|
56373
57145
|
kind: "mutation",
|
|
56374
57146
|
auth: "admin"
|
|
56375
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57147
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57148
|
+
name: string().min(1),
|
|
57149
|
+
version: string().min(1).optional()
|
|
57150
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56376
57151
|
kind: "mutation",
|
|
56377
57152
|
auth: "admin"
|
|
56378
57153
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56431,27 +57206,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56431
57206
|
*/
|
|
56432
57207
|
var AirQualitySensorStatusSchema = object({
|
|
56433
57208
|
/** Carbon dioxide concentration in ppm. */
|
|
56434
|
-
co2Ppm: number().min(0).optional(),
|
|
57209
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56435
57210
|
/** Total volatile organic compounds in ppb. */
|
|
56436
|
-
vocPpb: number().min(0).optional(),
|
|
57211
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56437
57212
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56438
|
-
pm25: number().min(0).optional(),
|
|
57213
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56439
57214
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56440
|
-
pm10: number().min(0).optional(),
|
|
57215
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56441
57216
|
/** Composite AQI value (typically 0..500). */
|
|
56442
|
-
aqi: number().optional(),
|
|
57217
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56443
57218
|
/** Ms epoch when the slice was last updated. */
|
|
56444
|
-
lastFetchedAt: number()
|
|
56445
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56446
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56447
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56448
|
-
* per slice is unambiguous. */
|
|
56449
|
-
unit: string().optional(),
|
|
56450
|
-
/** Suggested decimal places for numeric display.
|
|
56451
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56452
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56453
|
-
* auto-formatting when absent. */
|
|
56454
|
-
precision: number().int().min(0).max(10).optional()
|
|
57219
|
+
lastFetchedAt: number()
|
|
56455
57220
|
});
|
|
56456
57221
|
var airQualitySensorCapability = {
|
|
56457
57222
|
name: "air-quality-sensor",
|
|
@@ -56488,12 +57253,12 @@ var airQualitySensorCapability = {
|
|
|
56488
57253
|
},
|
|
56489
57254
|
pm25: {
|
|
56490
57255
|
kind: "gauge",
|
|
56491
|
-
unit: "
|
|
57256
|
+
unit: "µg/m³",
|
|
56492
57257
|
deadband: 1
|
|
56493
57258
|
},
|
|
56494
57259
|
pm10: {
|
|
56495
57260
|
kind: "gauge",
|
|
56496
|
-
unit: "
|
|
57261
|
+
unit: "µg/m³",
|
|
56497
57262
|
deadband: 1
|
|
56498
57263
|
},
|
|
56499
57264
|
aqi: {
|
|
@@ -56511,22 +57276,13 @@ var airQualitySensorCapability = {
|
|
|
56511
57276
|
* entries with `device_class: illuminance`.
|
|
56512
57277
|
*/
|
|
56513
57278
|
var AmbientLightSensorStatusSchema = object({
|
|
56514
|
-
/** Current illuminance in lux (lx). */
|
|
56515
|
-
lux: number().min(0).meta({
|
|
56516
|
-
|
|
57279
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57280
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57281
|
+
precision: 0,
|
|
56517
57282
|
label: "Illuminance"
|
|
56518
|
-
}),
|
|
57283
|
+
})),
|
|
56519
57284
|
/** Ms epoch when the slice was last updated. */
|
|
56520
|
-
lastFetchedAt: number()
|
|
56521
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56522
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56523
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56524
|
-
unit: string().optional(),
|
|
56525
|
-
/** Suggested decimal places for numeric display.
|
|
56526
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56527
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56528
|
-
* auto-formatting when absent. */
|
|
56529
|
-
precision: number().int().min(0).max(10).optional()
|
|
57285
|
+
lastFetchedAt: number()
|
|
56530
57286
|
});
|
|
56531
57287
|
var ambientLightSensorCapability = {
|
|
56532
57288
|
name: "ambient-light-sensor",
|
|
@@ -56558,12 +57314,7 @@ var ambientLightSensorCapability = {
|
|
|
56558
57314
|
} } },
|
|
56559
57315
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56560
57316
|
* whether persisting is worth a SQLite commit. */
|
|
56561
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56562
|
-
customize: {
|
|
56563
|
-
version: 1,
|
|
56564
|
-
advanced: "derive",
|
|
56565
|
-
targets: []
|
|
56566
|
-
}
|
|
57317
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56567
57318
|
};
|
|
56568
57319
|
/**
|
|
56569
57320
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56790,10 +57541,7 @@ var BatteryStatusSchema = object({
|
|
|
56790
57541
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56791
57542
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56792
57543
|
*/
|
|
56793
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56794
|
-
unit: "%",
|
|
56795
|
-
label: "Charge"
|
|
56796
|
-
}),
|
|
57544
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56797
57545
|
/**
|
|
56798
57546
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56799
57547
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56820,7 +57568,14 @@ var BatteryStatusSchema = object({
|
|
|
56820
57568
|
*/
|
|
56821
57569
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56822
57570
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56823
|
-
lastUpdated: number(),
|
|
57571
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57572
|
+
/**
|
|
57573
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57574
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57575
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57576
|
+
* `numeric-sensor` on the same device.
|
|
57577
|
+
*/
|
|
57578
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56824
57579
|
/**
|
|
56825
57580
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56826
57581
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56867,12 +57622,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56867
57622
|
DeviceType.Switch,
|
|
56868
57623
|
DeviceType.PetFeeder,
|
|
56869
57624
|
DeviceType.Container,
|
|
56870
|
-
DeviceType.Thermostat
|
|
57625
|
+
DeviceType.Thermostat,
|
|
57626
|
+
DeviceType.EventEmitter
|
|
56871
57627
|
];
|
|
56872
57628
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56873
57629
|
var batteryCustomize = {
|
|
56874
57630
|
version: 1,
|
|
56875
|
-
advanced: "derive",
|
|
56876
57631
|
targets: [{
|
|
56877
57632
|
id: "percentage",
|
|
56878
57633
|
cardinality: "scalar",
|
|
@@ -56881,7 +57636,7 @@ var batteryCustomize = {
|
|
|
56881
57636
|
stateField: "percentage"
|
|
56882
57637
|
},
|
|
56883
57638
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56884
|
-
apply: "add
|
|
57639
|
+
apply: "add",
|
|
56885
57640
|
path: "percentage",
|
|
56886
57641
|
sources: [{
|
|
56887
57642
|
kind: "field",
|
|
@@ -57002,10 +57757,16 @@ onStatusChanged: { data: object({
|
|
|
57002
57757
|
/**
|
|
57003
57758
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
57004
57759
|
*/
|
|
57005
|
-
history: { fields: {
|
|
57006
|
-
|
|
57007
|
-
|
|
57008
|
-
|
|
57760
|
+
history: { fields: {
|
|
57761
|
+
percentage: {
|
|
57762
|
+
kind: "gauge",
|
|
57763
|
+
unit: "%"
|
|
57764
|
+
},
|
|
57765
|
+
volts: {
|
|
57766
|
+
kind: "gauge",
|
|
57767
|
+
unit: "V"
|
|
57768
|
+
}
|
|
57769
|
+
} },
|
|
57009
57770
|
customize: batteryCustomize,
|
|
57010
57771
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57011
57772
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57052,12 +57813,7 @@ var binaryCapability = {
|
|
|
57052
57813
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57053
57814
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57054
57815
|
* whether persisting is worth a SQLite commit. */
|
|
57055
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57056
|
-
customize: {
|
|
57057
|
-
version: 1,
|
|
57058
|
-
advanced: "derive",
|
|
57059
|
-
targets: []
|
|
57060
|
-
}
|
|
57816
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57061
57817
|
};
|
|
57062
57818
|
/**
|
|
57063
57819
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57073,7 +57829,7 @@ var binaryCapability = {
|
|
|
57073
57829
|
*/
|
|
57074
57830
|
var BrightnessStatusSchema = object({
|
|
57075
57831
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57076
|
-
percentage: number().min(0).max(100),
|
|
57832
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57077
57833
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57078
57834
|
lastChangedAt: number()
|
|
57079
57835
|
});
|
|
@@ -57527,21 +58283,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57527
58283
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57528
58284
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57529
58285
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57530
|
-
target: number().nullable(),
|
|
58286
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57531
58287
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57532
58288
|
* in `heat_cool` mode. */
|
|
57533
|
-
targetHigh: number().nullable(),
|
|
58289
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57534
58290
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57535
58291
|
* in `heat_cool` mode. */
|
|
57536
|
-
targetLow: number().nullable(),
|
|
58292
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57537
58293
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57538
58294
|
* humidity control. */
|
|
57539
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58295
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57540
58296
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57541
58297
|
* the device's internal sensor. */
|
|
57542
|
-
currentTemp: number().nullable(),
|
|
58298
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57543
58299
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57544
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58300
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57545
58301
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57546
58302
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57547
58303
|
swingVertical: boolean().nullable(),
|
|
@@ -57549,11 +58305,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57549
58305
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57550
58306
|
swingHorizontal: boolean().nullable(),
|
|
57551
58307
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57552
|
-
minTemp: number().nullable().optional(),
|
|
58308
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57553
58309
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57554
|
-
maxTemp: number().nullable().optional(),
|
|
58310
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57555
58311
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57556
|
-
tempStep: number().positive().nullable().optional(),
|
|
58312
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57557
58313
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57558
58314
|
lastFetchedAt: number()
|
|
57559
58315
|
});
|
|
@@ -57695,17 +58451,17 @@ var climateControlCapability = {
|
|
|
57695
58451
|
* modes to expose in the picker without a slice fetch.
|
|
57696
58452
|
*/
|
|
57697
58453
|
var RgbTripletSchema = object({
|
|
57698
|
-
r: number().int().min(0).max(255),
|
|
57699
|
-
g: number().int().min(0).max(255),
|
|
57700
|
-
b: number().int().min(0).max(255)
|
|
58454
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58455
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58456
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57701
58457
|
});
|
|
57702
58458
|
var HsvTripletSchema = object({
|
|
57703
58459
|
/** Hue in degrees, 0..360. */
|
|
57704
|
-
h: number().min(0).max(360),
|
|
58460
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57705
58461
|
/** Saturation as 0..100 inclusive. */
|
|
57706
|
-
s: number().min(0).max(100),
|
|
58462
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57707
58463
|
/** Value/brightness as 0..100 inclusive. */
|
|
57708
|
-
v: number().min(0).max(100)
|
|
58464
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57709
58465
|
});
|
|
57710
58466
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57711
58467
|
object({
|
|
@@ -57734,7 +58490,7 @@ var ColorStatusSchema = object({
|
|
|
57734
58490
|
/** Populated when `mode === 'hsv'`. */
|
|
57735
58491
|
hsv: HsvTripletSchema.optional(),
|
|
57736
58492
|
/** Populated when `mode === 'mired'`. */
|
|
57737
|
-
mireds: number().int().optional(),
|
|
58493
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57738
58494
|
/** Ms epoch of the last operator-driven change. */
|
|
57739
58495
|
lastChangedAt: number()
|
|
57740
58496
|
});
|
|
@@ -57937,18 +58693,12 @@ _enum([
|
|
|
57937
58693
|
"empty",
|
|
57938
58694
|
"full"
|
|
57939
58695
|
]);
|
|
57940
|
-
/**
|
|
57941
|
-
|
|
57942
|
-
|
|
57943
|
-
"days",
|
|
57944
|
-
"hours",
|
|
57945
|
-
"cycles"
|
|
57946
|
-
]);
|
|
57947
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57948
|
-
* days). `value` null = unknown (D393). */
|
|
58696
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58697
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58698
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57949
58699
|
var ConsumableRemainingSchema = object({
|
|
57950
|
-
value: number().min(0).nullable(),
|
|
57951
|
-
|
|
58700
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58701
|
+
kind: ConsumableRemainingKindSchema
|
|
57952
58702
|
});
|
|
57953
58703
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
57954
58704
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -57961,7 +58711,7 @@ var ConsumableItemSchema = object({
|
|
|
57961
58711
|
/** Display name. */
|
|
57962
58712
|
label: string().min(1),
|
|
57963
58713
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57964
|
-
level: number().min(0).max(100).nullable(),
|
|
58714
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57965
58715
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57966
58716
|
status: ConsumableStatusSchema.nullable(),
|
|
57967
58717
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58043,8 +58793,8 @@ var consumablesCustomize = {
|
|
|
58043
58793
|
transforms: [{ kind: "identity" }]
|
|
58044
58794
|
}],
|
|
58045
58795
|
literals: [{
|
|
58046
|
-
path: "remaining.
|
|
58047
|
-
values: [...
|
|
58796
|
+
path: "remaining.kind",
|
|
58797
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58048
58798
|
}]
|
|
58049
58799
|
},
|
|
58050
58800
|
{
|
|
@@ -58173,7 +58923,6 @@ reset: method(object({
|
|
|
58173
58923
|
},
|
|
58174
58924
|
"remaining.value": {
|
|
58175
58925
|
kind: "gauge",
|
|
58176
|
-
unitFrom: "remaining.unit",
|
|
58177
58926
|
deadband: 1,
|
|
58178
58927
|
displayName: "Remaining"
|
|
58179
58928
|
}
|
|
@@ -58243,10 +58992,9 @@ var contactCapability = {
|
|
|
58243
58992
|
* (empty array for the other kinds). It lives in the slice because
|
|
58244
58993
|
* HA `select.*` entities may update their options at runtime.
|
|
58245
58994
|
*
|
|
58246
|
-
*
|
|
58247
|
-
*
|
|
58248
|
-
*
|
|
58249
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
58995
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
58996
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
58997
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58250
58998
|
*/
|
|
58251
58999
|
var ControlStatusSchema = object({
|
|
58252
59000
|
kind: _enum([
|
|
@@ -58258,39 +59006,17 @@ var ControlStatusSchema = object({
|
|
|
58258
59006
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58259
59007
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58260
59008
|
* or time-only — HA accepts all three forms). */
|
|
58261
|
-
value: union([number(), string()]),
|
|
59009
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58262
59010
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58263
59011
|
options: array(string()),
|
|
58264
59012
|
/** Ms epoch when the slice was last updated. */
|
|
58265
59013
|
lastChangedAt: number(),
|
|
58266
|
-
/**
|
|
58267
|
-
|
|
58268
|
-
|
|
58269
|
-
|
|
58270
|
-
/**
|
|
58271
|
-
|
|
58272
|
-
min: number().optional(),
|
|
58273
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58274
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58275
|
-
max: number().optional(),
|
|
58276
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58277
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58278
|
-
step: number().optional(),
|
|
58279
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58280
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58281
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58282
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58283
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58284
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58285
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58286
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58287
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58288
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58289
|
-
format: _enum([
|
|
58290
|
-
"date",
|
|
58291
|
-
"time",
|
|
58292
|
-
"datetime"
|
|
58293
|
-
]).optional()
|
|
59014
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
59015
|
+
min: number().optional().meta(readingMeta("device")),
|
|
59016
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
59017
|
+
max: number().optional().meta(readingMeta("device")),
|
|
59018
|
+
/** Step increment, in the device quantity's base unit. */
|
|
59019
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58294
59020
|
});
|
|
58295
59021
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58296
59022
|
object({
|
|
@@ -58356,9 +59082,9 @@ var CoverStatusSchema = object({
|
|
|
58356
59082
|
]),
|
|
58357
59083
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58358
59084
|
* no intermediate position surface. */
|
|
58359
|
-
position: number().min(0).max(100).nullable(),
|
|
59085
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58360
59086
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58361
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59087
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58362
59088
|
/** Ms epoch when the slice was last updated. */
|
|
58363
59089
|
lastChangedAt: number()
|
|
58364
59090
|
});
|
|
@@ -58461,9 +59187,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58461
59187
|
var DayNightStatusSchema = object({
|
|
58462
59188
|
mode: DayNightModeSchema,
|
|
58463
59189
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58464
|
-
sensitivity: number().optional(),
|
|
59190
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58465
59191
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58466
|
-
switchDelaySec: number().optional(),
|
|
59192
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58467
59193
|
lastFetchedAt: number()
|
|
58468
59194
|
});
|
|
58469
59195
|
/**
|
|
@@ -58681,11 +59407,11 @@ var DishwasherStatusSchema = object({
|
|
|
58681
59407
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58682
59408
|
availablePrograms: array(string()),
|
|
58683
59409
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58684
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59410
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58685
59411
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58686
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59412
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58687
59413
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58688
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59414
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58689
59415
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58690
59416
|
doorOpen: boolean().nullable(),
|
|
58691
59417
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58709,7 +59435,7 @@ var DishwasherStatusSchema = object({
|
|
|
58709
59435
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58710
59436
|
machineCareDue: boolean().nullable(),
|
|
58711
59437
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58712
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59438
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58713
59439
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58714
59440
|
halfLoad: boolean().nullable(),
|
|
58715
59441
|
hygienePlus: boolean().nullable(),
|
|
@@ -58724,7 +59450,7 @@ var DishwasherStatusSchema = object({
|
|
|
58724
59450
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58725
59451
|
activeEvents: array(string()),
|
|
58726
59452
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58727
|
-
errorCode: number().nullable(),
|
|
59453
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58728
59454
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58729
59455
|
errorLabel: string().nullable(),
|
|
58730
59456
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58955,7 +59681,7 @@ var DoorbellStatusSchema = object({
|
|
|
58955
59681
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58956
59682
|
lastPressedAt: number().nullable(),
|
|
58957
59683
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58958
|
-
pressCountSinceStart: number()
|
|
59684
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58959
59685
|
});
|
|
58960
59686
|
var DoorbellPressEventSchema = object({
|
|
58961
59687
|
deviceId: number(),
|
|
@@ -59020,17 +59746,7 @@ onPressed: {
|
|
|
59020
59746
|
history: "none",
|
|
59021
59747
|
customize: doorbellCustomize
|
|
59022
59748
|
};
|
|
59023
|
-
|
|
59024
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
59025
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
59026
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
59027
|
-
* The option set is stable across observations; it is persisted in the
|
|
59028
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
59029
|
-
* stored in `sourceInfo`.
|
|
59030
|
-
*/
|
|
59031
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
59032
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
59033
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
59749
|
+
_enum([
|
|
59034
59750
|
"date",
|
|
59035
59751
|
"time",
|
|
59036
59752
|
"datetime"
|
|
@@ -59038,12 +59754,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59038
59754
|
var EnumSensorStatusSchema = object({
|
|
59039
59755
|
value: string(),
|
|
59040
59756
|
/**
|
|
59041
|
-
* Set
|
|
59042
|
-
* as
|
|
59043
|
-
*
|
|
59044
|
-
* a time-only sensor → `'time'`.
|
|
59757
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
59758
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
59759
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59045
59760
|
*/
|
|
59046
|
-
|
|
59761
|
+
timestamp: boolean().optional(),
|
|
59047
59762
|
/** Ms epoch when the slice was last updated. */
|
|
59048
59763
|
lastFetchedAt: number()
|
|
59049
59764
|
});
|
|
@@ -59070,11 +59785,11 @@ var enumSensorCapability = {
|
|
|
59070
59785
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59071
59786
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59072
59787
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59073
|
-
* `
|
|
59788
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59074
59789
|
*/
|
|
59075
59790
|
history: { fields: { value: {
|
|
59076
59791
|
kind: "enum",
|
|
59077
|
-
skipWhenSet: "
|
|
59792
|
+
skipWhenSet: "timestamp"
|
|
59078
59793
|
} } },
|
|
59079
59794
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59080
59795
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59094,13 +59809,13 @@ var EventFireSchema = object({
|
|
|
59094
59809
|
deviceId: number(),
|
|
59095
59810
|
eventType: string(),
|
|
59096
59811
|
data: record(string(), unknown()).nullable(),
|
|
59097
|
-
timestamp: number(),
|
|
59098
|
-
seq: number()
|
|
59812
|
+
timestamp: number().meta(readingMeta("none")),
|
|
59813
|
+
seq: number().meta(readingMeta("count"))
|
|
59099
59814
|
});
|
|
59100
59815
|
var EventEmitterStatusSchema = object({
|
|
59101
59816
|
eventTypes: array(string()),
|
|
59102
59817
|
lastEvent: EventFireSchema.nullable(),
|
|
59103
|
-
eventCountSinceStart: number()
|
|
59818
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59104
59819
|
});
|
|
59105
59820
|
var eventEmitterCapability = {
|
|
59106
59821
|
name: "event-emitter",
|
|
@@ -59513,10 +60228,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59513
60228
|
var FanControlStatusSchema = object({
|
|
59514
60229
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59515
60230
|
* speed surface (single-speed fan). */
|
|
59516
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60231
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59517
60232
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59518
60233
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59519
|
-
percentageStep: number().positive().optional(),
|
|
60234
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59520
60235
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59521
60236
|
* — empty string when no preset is active or supported. */
|
|
59522
60237
|
preset: string(),
|
|
@@ -59637,7 +60352,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59637
60352
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59638
60353
|
model: string().nullable(),
|
|
59639
60354
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59640
|
-
channelCount: number().nullable(),
|
|
60355
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59641
60356
|
/**
|
|
59642
60357
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59643
60358
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59760,9 +60475,151 @@ var gasCapability = {
|
|
|
59760
60475
|
* whether persisting is worth a SQLite commit. */
|
|
59761
60476
|
volatileStateFields: ["lastChangedAt"]
|
|
59762
60477
|
};
|
|
60478
|
+
var GroupCommandsSchema = object({
|
|
60479
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60480
|
+
results: array(object({
|
|
60481
|
+
deviceId: number().int().nonnegative(),
|
|
60482
|
+
cap: string().min(1),
|
|
60483
|
+
method: string().min(1),
|
|
60484
|
+
ok: boolean(),
|
|
60485
|
+
error: string().optional(),
|
|
60486
|
+
/** Ms epoch of the attempt. */
|
|
60487
|
+
at: number()
|
|
60488
|
+
})) });
|
|
60489
|
+
var groupCommandsCapability = {
|
|
60490
|
+
name: "group-commands",
|
|
60491
|
+
scope: "device",
|
|
60492
|
+
deviceNative: true,
|
|
60493
|
+
mode: "singleton",
|
|
60494
|
+
deviceTypes: [
|
|
60495
|
+
DeviceType.Switch,
|
|
60496
|
+
DeviceType.Light,
|
|
60497
|
+
DeviceType.Fan,
|
|
60498
|
+
DeviceType.Cover,
|
|
60499
|
+
DeviceType.Valve,
|
|
60500
|
+
DeviceType.Lock,
|
|
60501
|
+
DeviceType.MediaPlayer,
|
|
60502
|
+
DeviceType.Thermostat,
|
|
60503
|
+
DeviceType.Climate
|
|
60504
|
+
],
|
|
60505
|
+
methods: {},
|
|
60506
|
+
status: {
|
|
60507
|
+
schema: GroupCommandsSchema,
|
|
60508
|
+
kind: "push"
|
|
60509
|
+
},
|
|
60510
|
+
runtimeState: GroupCommandsSchema,
|
|
60511
|
+
/**
|
|
60512
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
60513
|
+
* failure would outlive the command that caused it.
|
|
60514
|
+
*
|
|
60515
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60516
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60517
|
+
*/
|
|
60518
|
+
durability: "session",
|
|
60519
|
+
history: "none"
|
|
60520
|
+
};
|
|
60521
|
+
/**
|
|
60522
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
60523
|
+
* included member is, or every included member is. What "active" means is the
|
|
60524
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
60525
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
60526
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
60527
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
60528
|
+
* empty included set takes the device offline, never `active: false`.
|
|
60529
|
+
*/
|
|
60530
|
+
var GroupActiveSchema = object({
|
|
60531
|
+
active: boolean().meta({ label: "Active" }),
|
|
60532
|
+
/** Ms epoch when the slice was last updated. */
|
|
60533
|
+
lastChangedAt: number()
|
|
60534
|
+
});
|
|
60535
|
+
var groupActiveCapability = {
|
|
60536
|
+
name: "group-active",
|
|
60537
|
+
scope: "device",
|
|
60538
|
+
deviceNative: true,
|
|
60539
|
+
mode: "singleton",
|
|
60540
|
+
deviceTypes: [
|
|
60541
|
+
DeviceType.Cover,
|
|
60542
|
+
DeviceType.Valve,
|
|
60543
|
+
DeviceType.Lock,
|
|
60544
|
+
DeviceType.MediaPlayer,
|
|
60545
|
+
DeviceType.Climate,
|
|
60546
|
+
DeviceType.Thermostat
|
|
60547
|
+
],
|
|
60548
|
+
methods: {},
|
|
60549
|
+
status: {
|
|
60550
|
+
schema: GroupActiveSchema,
|
|
60551
|
+
kind: "push"
|
|
60552
|
+
},
|
|
60553
|
+
runtimeState: GroupActiveSchema,
|
|
60554
|
+
/**
|
|
60555
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
60556
|
+
* next source event; a restored value would outlive the members it named.
|
|
60557
|
+
*
|
|
60558
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60559
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60560
|
+
*/
|
|
60561
|
+
durability: "session",
|
|
60562
|
+
history: "none"
|
|
60563
|
+
};
|
|
60564
|
+
/**
|
|
60565
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60566
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60567
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60568
|
+
* series that later statistics read is the output cap's own history block.
|
|
60569
|
+
*/
|
|
60570
|
+
var GroupStatusSchema = object({
|
|
60571
|
+
/** Members whose current value entered the aggregate. */
|
|
60572
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60573
|
+
precision: 0,
|
|
60574
|
+
label: "Reporting"
|
|
60575
|
+
})),
|
|
60576
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60577
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60578
|
+
precision: 0,
|
|
60579
|
+
label: "Excluded"
|
|
60580
|
+
})),
|
|
60581
|
+
/** `included` + `excluded`. */
|
|
60582
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60583
|
+
precision: 0,
|
|
60584
|
+
label: "Members"
|
|
60585
|
+
}))
|
|
60586
|
+
});
|
|
60587
|
+
var groupStatusCapability = {
|
|
60588
|
+
name: "group-status",
|
|
60589
|
+
scope: "device",
|
|
60590
|
+
deviceNative: true,
|
|
60591
|
+
mode: "singleton",
|
|
60592
|
+
deviceTypes: [
|
|
60593
|
+
DeviceType.Sensor,
|
|
60594
|
+
DeviceType.Switch,
|
|
60595
|
+
DeviceType.Light,
|
|
60596
|
+
DeviceType.Fan,
|
|
60597
|
+
DeviceType.Cover,
|
|
60598
|
+
DeviceType.Valve,
|
|
60599
|
+
DeviceType.Lock,
|
|
60600
|
+
DeviceType.MediaPlayer,
|
|
60601
|
+
DeviceType.Thermostat,
|
|
60602
|
+
DeviceType.Climate
|
|
60603
|
+
],
|
|
60604
|
+
methods: {},
|
|
60605
|
+
status: {
|
|
60606
|
+
schema: GroupStatusSchema,
|
|
60607
|
+
kind: "push"
|
|
60608
|
+
},
|
|
60609
|
+
runtimeState: GroupStatusSchema,
|
|
60610
|
+
/**
|
|
60611
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60612
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60613
|
+
*
|
|
60614
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60615
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60616
|
+
*/
|
|
60617
|
+
durability: "session",
|
|
60618
|
+
history: "none"
|
|
60619
|
+
};
|
|
59763
60620
|
var HeatingValveStatusSchema = object({
|
|
59764
60621
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59765
|
-
position: number().min(0).max(100).nullable(),
|
|
60622
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59766
60623
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59767
60624
|
lastFetchedAt: number()
|
|
59768
60625
|
});
|
|
@@ -59805,9 +60662,9 @@ var HumidifierStatusSchema = object({
|
|
|
59805
60662
|
/** Whether the humidifier is currently on. */
|
|
59806
60663
|
on: boolean(),
|
|
59807
60664
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59808
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60665
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59809
60666
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59810
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60667
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59811
60668
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59812
60669
|
* device has no mode surface. */
|
|
59813
60670
|
mode: string().nullable(),
|
|
@@ -59817,9 +60674,9 @@ var HumidifierStatusSchema = object({
|
|
|
59817
60674
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59818
60675
|
action: string().nullable(),
|
|
59819
60676
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59820
|
-
minHumidity: number().nullable(),
|
|
60677
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59821
60678
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59822
|
-
maxHumidity: number().nullable(),
|
|
60679
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59823
60680
|
/** Ms epoch when the slice was last updated. */
|
|
59824
60681
|
lastChangedAt: number()
|
|
59825
60682
|
});
|
|
@@ -59889,22 +60746,13 @@ var humidifierCapability = {
|
|
|
59889
60746
|
* `sourceInfo`.
|
|
59890
60747
|
*/
|
|
59891
60748
|
var HumiditySensorStatusSchema = object({
|
|
59892
|
-
/** Current relative humidity, 0..100. */
|
|
59893
|
-
percent: number().min(0).max(100).meta({
|
|
59894
|
-
|
|
60749
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60750
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60751
|
+
precision: 0,
|
|
59895
60752
|
label: "Humidity"
|
|
59896
|
-
}),
|
|
60753
|
+
})),
|
|
59897
60754
|
/** Ms epoch when the slice was last updated. */
|
|
59898
|
-
lastFetchedAt: number()
|
|
59899
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59900
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59901
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59902
|
-
unit: string().optional(),
|
|
59903
|
-
/** Suggested decimal places for numeric display.
|
|
59904
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59905
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59906
|
-
* auto-formatting when absent. */
|
|
59907
|
-
precision: number().int().min(0).max(10).optional()
|
|
60755
|
+
lastFetchedAt: number()
|
|
59908
60756
|
});
|
|
59909
60757
|
var humiditySensorCapability = {
|
|
59910
60758
|
name: "humidity-sensor",
|
|
@@ -59935,12 +60783,7 @@ var humiditySensorCapability = {
|
|
|
59935
60783
|
} } },
|
|
59936
60784
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59937
60785
|
* whether persisting is worth a SQLite commit. */
|
|
59938
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
59939
|
-
customize: {
|
|
59940
|
-
version: 1,
|
|
59941
|
-
advanced: "derive",
|
|
59942
|
-
targets: []
|
|
59943
|
-
}
|
|
60786
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
59944
60787
|
};
|
|
59945
60788
|
/**
|
|
59946
60789
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -59961,7 +60804,7 @@ var ImageStatusSchema = object({
|
|
|
59961
60804
|
* entity exposes no `entity_picture` (yet). */
|
|
59962
60805
|
url: string().nullable(),
|
|
59963
60806
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
59964
|
-
lastUpdated: number().nullable()
|
|
60807
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
59965
60808
|
});
|
|
59966
60809
|
var imageCapability = {
|
|
59967
60810
|
name: "image",
|
|
@@ -60049,19 +60892,19 @@ var NormalizedRangeSchema = object({
|
|
|
60049
60892
|
*/
|
|
60050
60893
|
var ImageSettingsStatusSchema = object({
|
|
60051
60894
|
/** Normalized 0–100. */
|
|
60052
|
-
brightness: number().optional(),
|
|
60895
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60053
60896
|
/** Normalized 0–100. */
|
|
60054
|
-
contrast: number().optional(),
|
|
60897
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60055
60898
|
/** Normalized 0–100. */
|
|
60056
|
-
saturation: number().optional(),
|
|
60899
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60057
60900
|
/** Normalized 0–100. */
|
|
60058
|
-
sharpness: number().optional(),
|
|
60901
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60059
60902
|
mirror: boolean().optional(),
|
|
60060
60903
|
flip: boolean().optional(),
|
|
60061
60904
|
rotate: ImageRotateSchema.optional(),
|
|
60062
60905
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60063
60906
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60064
|
-
warmth: number().optional(),
|
|
60907
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60065
60908
|
exposureMode: ExposureModeSchema.optional(),
|
|
60066
60909
|
backlightMode: BacklightModeSchema.optional(),
|
|
60067
60910
|
lastFetchedAt: number()
|
|
@@ -60340,10 +61183,10 @@ var IntercomAbilitySchema = object({
|
|
|
60340
61183
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60341
61184
|
codecs: array(string()),
|
|
60342
61185
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60343
|
-
sampleRate: number(),
|
|
61186
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60344
61187
|
duplex: _enum(["half", "full"]),
|
|
60345
61188
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60346
|
-
maxBacklogMs: number()
|
|
61189
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60347
61190
|
});
|
|
60348
61191
|
var IntercomStatusSchema = object({
|
|
60349
61192
|
/** True while a talk session is open. */
|
|
@@ -60570,13 +61413,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60570
61413
|
activity: LawnMowerActivitySchema,
|
|
60571
61414
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60572
61415
|
* reading. */
|
|
60573
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61416
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60574
61417
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60575
61418
|
* task is active / progress is unavailable. */
|
|
60576
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61419
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60577
61420
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60578
61421
|
* or null when unknown. */
|
|
60579
|
-
currentCode: number().nullable(),
|
|
61422
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60580
61423
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60581
61424
|
currentCodeLabel: string().nullable(),
|
|
60582
61425
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61029,7 +61872,14 @@ var lockControlCapability = {
|
|
|
61029
61872
|
}),
|
|
61030
61873
|
unlock: method(object({
|
|
61031
61874
|
deviceId: number().int().nonnegative(),
|
|
61032
|
-
code: string().min(1).optional()
|
|
61875
|
+
code: string().min(1).optional(),
|
|
61876
|
+
/**
|
|
61877
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
61878
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
61879
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
61880
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
61881
|
+
*/
|
|
61882
|
+
confirm: boolean().optional()
|
|
61033
61883
|
}), _void(), {
|
|
61034
61884
|
kind: "mutation",
|
|
61035
61885
|
auth: "protected"
|
|
@@ -61066,6 +61916,44 @@ var lockControlCapability = {
|
|
|
61066
61916
|
volatileStateFields: ["lastChangedAt"]
|
|
61067
61917
|
};
|
|
61068
61918
|
/**
|
|
61919
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
61920
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
61921
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
61922
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
61923
|
+
*/
|
|
61924
|
+
var MeterStatusSchema = object({
|
|
61925
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
61926
|
+
lastFetchedAt: number()
|
|
61927
|
+
});
|
|
61928
|
+
var meterCapability = {
|
|
61929
|
+
name: "meter",
|
|
61930
|
+
scope: "device",
|
|
61931
|
+
deviceNative: true,
|
|
61932
|
+
mode: "singleton",
|
|
61933
|
+
deviceTypes: [DeviceType.Sensor],
|
|
61934
|
+
methods: {},
|
|
61935
|
+
status: {
|
|
61936
|
+
schema: MeterStatusSchema,
|
|
61937
|
+
kind: "push"
|
|
61938
|
+
},
|
|
61939
|
+
runtimeState: MeterStatusSchema,
|
|
61940
|
+
/**
|
|
61941
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
61942
|
+
* history integral. A restart shows it only until the history pass
|
|
61943
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
61944
|
+
*
|
|
61945
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61946
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61947
|
+
*/
|
|
61948
|
+
durability: "restored",
|
|
61949
|
+
history: { fields: { value: {
|
|
61950
|
+
kind: "counter",
|
|
61951
|
+
deadband: .001,
|
|
61952
|
+
minIntervalMs: 6e4
|
|
61953
|
+
} } },
|
|
61954
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
61955
|
+
};
|
|
61956
|
+
/**
|
|
61069
61957
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61070
61958
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61071
61959
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -61109,7 +61997,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61109
61997
|
state: MediaPlayerStateSchema,
|
|
61110
61998
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61111
61999
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61112
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
62000
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61113
62001
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61114
62002
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61115
62003
|
isMuted: boolean().nullable(),
|
|
@@ -61122,10 +62010,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61122
62010
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61123
62011
|
/** Current playback position in ms. Null when not seekable or
|
|
61124
62012
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61125
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
62013
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61126
62014
|
/** Total duration of the current media in ms. Null when unknown
|
|
61127
62015
|
* (live stream) or nothing is playing. */
|
|
61128
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
62016
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61129
62017
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61130
62018
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61131
62019
|
shuffle: boolean().nullable(),
|
|
@@ -61434,7 +62322,7 @@ var motionCustomize = {
|
|
|
61434
62322
|
eventName: "onMotionChanged"
|
|
61435
62323
|
},
|
|
61436
62324
|
deviceTypes: [DeviceType.Camera],
|
|
61437
|
-
apply: "
|
|
62325
|
+
apply: "add",
|
|
61438
62326
|
applyAuthority: {
|
|
61439
62327
|
kind: "camera-sensors",
|
|
61440
62328
|
timeoutField: "motionCooldownMs"
|
|
@@ -61506,7 +62394,7 @@ var MotionStatusSchema = object({
|
|
|
61506
62394
|
* it, every provider seeded it at boot, and every session left it
|
|
61507
62395
|
* `detected: true` after its detach.
|
|
61508
62396
|
*/
|
|
61509
|
-
autoClearAfterMs: number().nullable()
|
|
62397
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61510
62398
|
});
|
|
61511
62399
|
/**
|
|
61512
62400
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61543,12 +62431,18 @@ var motionCapability = {
|
|
|
61543
62431
|
methods: {
|
|
61544
62432
|
/**
|
|
61545
62433
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
61546
|
-
* for consumers that don't need the full status object
|
|
61547
|
-
*
|
|
61548
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
61549
|
-
* consumer.
|
|
62434
|
+
* for consumers that don't need the full status object. A composed
|
|
62435
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
61550
62436
|
*/
|
|
61551
62437
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62438
|
+
/**
|
|
62439
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62440
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62441
|
+
*/
|
|
62442
|
+
composedMethods: { isDetected: {
|
|
62443
|
+
kind: "slice",
|
|
62444
|
+
field: "detected"
|
|
62445
|
+
} },
|
|
61552
62446
|
events: {
|
|
61553
62447
|
/**
|
|
61554
62448
|
* Fires every time the runner transitions a camera between
|
|
@@ -61688,7 +62582,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61688
62582
|
* the grid region(s). */
|
|
61689
62583
|
var MotionZoneStatusSchema = object({
|
|
61690
62584
|
enabled: boolean(),
|
|
61691
|
-
sensitivity: number(),
|
|
62585
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61692
62586
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61693
62587
|
regions: array(MotionZoneRegionSchema),
|
|
61694
62588
|
lastFetchedAt: number()
|
|
@@ -62058,7 +62952,7 @@ var NavigationStatusSchema = object({
|
|
|
62058
62952
|
following: boolean(),
|
|
62059
62953
|
flash: boolean(),
|
|
62060
62954
|
lightMode: NavigationLightModeSchema,
|
|
62061
|
-
lightLevel: number().min(40).max(100),
|
|
62955
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62062
62956
|
/** Ms epoch when the slice was last updated. */
|
|
62063
62957
|
lastChangedAt: number()
|
|
62064
62958
|
});
|
|
@@ -62192,13 +63086,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62192
63086
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62193
63087
|
* SKIP a null rather than coerce it.
|
|
62194
63088
|
*/
|
|
62195
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63089
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62196
63090
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62197
|
-
rssiDbm: number().optional(),
|
|
63091
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62198
63092
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62199
63093
|
ssid: string().optional(),
|
|
62200
63094
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62201
|
-
lastUpdated: number()
|
|
63095
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62202
63096
|
});
|
|
62203
63097
|
var networkLinkCapability = {
|
|
62204
63098
|
name: "network-link",
|
|
@@ -62583,7 +63477,7 @@ var NotifierStatusSchema = object({
|
|
|
62583
63477
|
lastError: string().nullable(),
|
|
62584
63478
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62585
63479
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62586
|
-
queueDepth: number().int().nonnegative(),
|
|
63480
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62587
63481
|
/** Per-feature capability matrix — authoritative source for the
|
|
62588
63482
|
* compose-form field gating. */
|
|
62589
63483
|
supports: NotifierSupportsSchema
|
|
@@ -62675,11 +63569,9 @@ onSent: { data: object({
|
|
|
62675
63569
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62676
63570
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62677
63571
|
*
|
|
62678
|
-
* The
|
|
62679
|
-
*
|
|
62680
|
-
*
|
|
62681
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62682
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63572
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63573
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63574
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62683
63575
|
*
|
|
62684
63576
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62685
63577
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62688,15 +63580,8 @@ onSent: { data: object({
|
|
|
62688
63580
|
* numeric values land here.
|
|
62689
63581
|
*/
|
|
62690
63582
|
var NumericSensorStatusSchema = object({
|
|
62691
|
-
|
|
62692
|
-
|
|
62693
|
-
* Populated live from the upstream source on each state push.
|
|
62694
|
-
* Absent for unitless sensors. */
|
|
62695
|
-
unit: string().optional(),
|
|
62696
|
-
/** Suggested decimal places for numeric display.
|
|
62697
|
-
* Populated live from the upstream source when provided.
|
|
62698
|
-
* Falls back to auto-formatting when absent. */
|
|
62699
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63583
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63584
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62700
63585
|
/** Ms epoch when the slice was last updated. */
|
|
62701
63586
|
lastFetchedAt: number()
|
|
62702
63587
|
});
|
|
@@ -62720,11 +63605,11 @@ var numericSensorCapability = {
|
|
|
62720
63605
|
*/
|
|
62721
63606
|
durability: "restored",
|
|
62722
63607
|
/**
|
|
62723
|
-
* History (D850): recorded series. The unit is
|
|
63608
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63609
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62724
63610
|
*/
|
|
62725
63611
|
history: { fields: { value: {
|
|
62726
63612
|
kind: "gauge",
|
|
62727
|
-
unitFrom: "unit",
|
|
62728
63613
|
minIntervalMs: 3e4
|
|
62729
63614
|
} } },
|
|
62730
63615
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -63016,23 +63901,26 @@ var PetFeederStatusSchema = object({
|
|
|
63016
63901
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
63017
63902
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
63018
63903
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
63019
|
-
foodLevel: number().nullable(),
|
|
63904
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
63020
63905
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63021
63906
|
* single-hopper models. */
|
|
63022
|
-
food1: number().nullable(),
|
|
63907
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63023
63908
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63024
63909
|
* single-hopper models. */
|
|
63025
|
-
food2: number().nullable(),
|
|
63910
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63026
63911
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63027
63912
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63028
63913
|
* below the feeder's low threshold. */
|
|
63029
63914
|
lowFood: boolean(),
|
|
63030
63915
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63031
63916
|
* device has no battery reading. */
|
|
63032
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63033
|
-
/**
|
|
63034
|
-
*
|
|
63035
|
-
|
|
63917
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63918
|
+
/**
|
|
63919
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
63920
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
63921
|
+
* model has no desiccant sensor.
|
|
63922
|
+
*/
|
|
63923
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63036
63924
|
/** True while a feed is in progress. */
|
|
63037
63925
|
feeding: boolean(),
|
|
63038
63926
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63043,7 +63931,7 @@ var PetFeederStatusSchema = object({
|
|
|
63043
63931
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63044
63932
|
error: string().nullable(),
|
|
63045
63933
|
/** Raw device error code (0 / null = no error). */
|
|
63046
|
-
errorCode: number().nullable(),
|
|
63934
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63047
63935
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63048
63936
|
isDualHopper: boolean(),
|
|
63049
63937
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63053,7 +63941,7 @@ var PetFeederStatusSchema = object({
|
|
|
63053
63941
|
/** Play a chime when dispensing. */
|
|
63054
63942
|
feedSound: boolean(),
|
|
63055
63943
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63056
|
-
volume: number(),
|
|
63944
|
+
volume: number().meta(readingMeta("none")),
|
|
63057
63945
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63058
63946
|
lastFetchedAt: number()
|
|
63059
63947
|
});
|
|
@@ -63172,7 +64060,7 @@ var petFeederCapability = {
|
|
|
63172
64060
|
},
|
|
63173
64061
|
desiccantLeftDays: {
|
|
63174
64062
|
kind: "gauge",
|
|
63175
|
-
unit: "
|
|
64063
|
+
unit: "s"
|
|
63176
64064
|
}
|
|
63177
64065
|
} }
|
|
63178
64066
|
};
|
|
@@ -63573,43 +64461,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63573
64461
|
*/
|
|
63574
64462
|
var PowerMeterStatusSchema = object({
|
|
63575
64463
|
/** Instantaneous power draw in watts. */
|
|
63576
|
-
watts: number().optional().meta({
|
|
63577
|
-
unit: "W",
|
|
63578
|
-
label: "Power"
|
|
63579
|
-
}),
|
|
64464
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63580
64465
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63581
|
-
kwhTotal: number().optional().meta({
|
|
63582
|
-
unit: "kWh",
|
|
63583
|
-
label: "Energy"
|
|
63584
|
-
}),
|
|
64466
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63585
64467
|
/** Voltage in volts. */
|
|
63586
|
-
volts: number().optional(),
|
|
64468
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
63587
64469
|
/** Current in amperes. */
|
|
63588
|
-
amps: number().optional(),
|
|
63589
|
-
/** Apparent power in volt-amperes
|
|
63590
|
-
va: number().optional(),
|
|
64470
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
64471
|
+
/** Apparent power in volt-amperes. */
|
|
64472
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63591
64473
|
/** Power factor (0..1) if reported. */
|
|
63592
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
64474
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63593
64475
|
/** Ms epoch when the slice was last updated. */
|
|
63594
|
-
lastFetchedAt: number()
|
|
63595
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63596
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63597
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63598
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63599
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63600
|
-
unit: string().optional(),
|
|
63601
|
-
/** Suggested decimal places for numeric display.
|
|
63602
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63603
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63604
|
-
* auto-formatting when absent. */
|
|
63605
|
-
precision: number().int().min(0).max(10).optional()
|
|
64476
|
+
lastFetchedAt: number()
|
|
63606
64477
|
});
|
|
64478
|
+
/**
|
|
64479
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
64480
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
64481
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
64482
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
64483
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
64484
|
+
*/
|
|
64485
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
64486
|
+
DeviceType.Sensor,
|
|
64487
|
+
DeviceType.Switch,
|
|
64488
|
+
DeviceType.Light,
|
|
64489
|
+
DeviceType.Fan,
|
|
64490
|
+
DeviceType.Climate,
|
|
64491
|
+
DeviceType.Thermostat,
|
|
64492
|
+
DeviceType.Humidifier,
|
|
64493
|
+
DeviceType.WaterHeater,
|
|
64494
|
+
DeviceType.MediaPlayer,
|
|
64495
|
+
DeviceType.Washer,
|
|
64496
|
+
DeviceType.Dryer,
|
|
64497
|
+
DeviceType.Dishwasher,
|
|
64498
|
+
DeviceType.Vacuum,
|
|
64499
|
+
DeviceType.LawnMower,
|
|
64500
|
+
DeviceType.PetFeeder
|
|
64501
|
+
];
|
|
64502
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
64503
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
64504
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
64505
|
+
function powerTarget(id, unit) {
|
|
64506
|
+
return {
|
|
64507
|
+
id,
|
|
64508
|
+
cardinality: "scalar",
|
|
64509
|
+
vocabulary: {
|
|
64510
|
+
cap: "power-meter",
|
|
64511
|
+
stateField: id
|
|
64512
|
+
},
|
|
64513
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
64514
|
+
apply: "add",
|
|
64515
|
+
path: id,
|
|
64516
|
+
sources: [{
|
|
64517
|
+
kind: "numeric",
|
|
64518
|
+
requiredUnit: unit,
|
|
64519
|
+
transforms: [{ kind: "identity" }]
|
|
64520
|
+
}],
|
|
64521
|
+
companions: [{
|
|
64522
|
+
kind: "clock",
|
|
64523
|
+
path: "lastFetchedAt",
|
|
64524
|
+
when: "always"
|
|
64525
|
+
}],
|
|
64526
|
+
sourceReport: { status: "assignment-status" },
|
|
64527
|
+
advancedExpression: true
|
|
64528
|
+
};
|
|
64529
|
+
}
|
|
64530
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
64531
|
+
var powerMeterCustomize = {
|
|
64532
|
+
version: 1,
|
|
64533
|
+
targets: [
|
|
64534
|
+
powerTarget("watts", "W"),
|
|
64535
|
+
powerTarget("kwhTotal", "kWh"),
|
|
64536
|
+
powerTarget("volts", "V"),
|
|
64537
|
+
powerTarget("amps", "A")
|
|
64538
|
+
]
|
|
64539
|
+
};
|
|
63607
64540
|
var powerMeterCapability = {
|
|
63608
64541
|
name: "power-meter",
|
|
63609
64542
|
scope: "device",
|
|
63610
64543
|
deviceNative: true,
|
|
63611
64544
|
mode: "singleton",
|
|
63612
|
-
deviceTypes:
|
|
64545
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
63613
64546
|
methods: {},
|
|
63614
64547
|
status: {
|
|
63615
64548
|
schema: PowerMeterStatusSchema,
|
|
@@ -63667,11 +64600,7 @@ var powerMeterCapability = {
|
|
|
63667
64600
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63668
64601
|
* whether persisting is worth a SQLite commit. */
|
|
63669
64602
|
volatileStateFields: ["lastFetchedAt"],
|
|
63670
|
-
customize:
|
|
63671
|
-
version: 1,
|
|
63672
|
-
advanced: "derive",
|
|
63673
|
-
targets: []
|
|
63674
|
-
}
|
|
64603
|
+
customize: powerMeterCustomize
|
|
63675
64604
|
};
|
|
63676
64605
|
/**
|
|
63677
64606
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63691,11 +64620,11 @@ var powerMeterCapability = {
|
|
|
63691
64620
|
*/
|
|
63692
64621
|
var GpsLocationSchema = object({
|
|
63693
64622
|
/** Latitude in decimal degrees, -90..90. */
|
|
63694
|
-
latitude: number().min(-90).max(90),
|
|
64623
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63695
64624
|
/** Longitude in decimal degrees, -180..180. */
|
|
63696
|
-
longitude: number().min(-180).max(180),
|
|
64625
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63697
64626
|
/** Reported accuracy in meters (lower = better). */
|
|
63698
|
-
accuracyMeters: number().nonnegative()
|
|
64627
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63699
64628
|
});
|
|
63700
64629
|
var PresenceStatusSchema = object({
|
|
63701
64630
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63707,7 +64636,7 @@ var PresenceStatusSchema = object({
|
|
|
63707
64636
|
gps: GpsLocationSchema.nullable(),
|
|
63708
64637
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63709
64638
|
* when not reported. */
|
|
63710
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64639
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63711
64640
|
/** Ms epoch when the slice was last updated. */
|
|
63712
64641
|
lastChangedAt: number()
|
|
63713
64642
|
});
|
|
@@ -63757,19 +64686,10 @@ var presenceCapability = {
|
|
|
63757
64686
|
* `sourceInfo`.
|
|
63758
64687
|
*/
|
|
63759
64688
|
var PressureSensorStatusSchema = object({
|
|
63760
|
-
/** Current pressure in hPa. */
|
|
63761
|
-
hpa: number(),
|
|
64689
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64690
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63762
64691
|
/** Ms epoch when the slice was last updated. */
|
|
63763
|
-
lastFetchedAt: number()
|
|
63764
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63765
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63766
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63767
|
-
unit: string().optional(),
|
|
63768
|
-
/** Suggested decimal places for numeric display.
|
|
63769
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63770
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63771
|
-
* auto-formatting when absent. */
|
|
63772
|
-
precision: number().int().min(0).max(10).optional()
|
|
64692
|
+
lastFetchedAt: number()
|
|
63773
64693
|
});
|
|
63774
64694
|
var pressureSensorCapability = {
|
|
63775
64695
|
name: "pressure-sensor",
|
|
@@ -64183,8 +65103,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64183
65103
|
}), _void(), { kind: "mutation" });
|
|
64184
65104
|
var PtzAutotrackSettingsSchema = object({
|
|
64185
65105
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64186
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64187
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65106
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65107
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64188
65108
|
});
|
|
64189
65109
|
/**
|
|
64190
65110
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64338,7 +65258,7 @@ var RunningStateStatusSchema = object({
|
|
|
64338
65258
|
/** null = unknown — never coerced to false (D393). */
|
|
64339
65259
|
running: boolean().nullable(),
|
|
64340
65260
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64341
|
-
since: number().nullable(),
|
|
65261
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64342
65262
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64343
65263
|
phase: string().nullable(),
|
|
64344
65264
|
/** null until a reading has been published (D393). */
|
|
@@ -64353,7 +65273,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64353
65273
|
/** Generic Customize target for the running boolean (D936). */
|
|
64354
65274
|
var runningCustomize = {
|
|
64355
65275
|
version: 1,
|
|
64356
|
-
advanced: "derive",
|
|
64357
65276
|
targets: [{
|
|
64358
65277
|
id: "running",
|
|
64359
65278
|
cardinality: "scalar",
|
|
@@ -64362,6 +65281,8 @@ var runningCustomize = {
|
|
|
64362
65281
|
stateField: "running"
|
|
64363
65282
|
},
|
|
64364
65283
|
deviceTypes: [
|
|
65284
|
+
DeviceType.Washer,
|
|
65285
|
+
DeviceType.Dryer,
|
|
64365
65286
|
DeviceType.Dishwasher,
|
|
64366
65287
|
DeviceType.Vacuum,
|
|
64367
65288
|
DeviceType.LawnMower,
|
|
@@ -64373,7 +65294,7 @@ var runningCustomize = {
|
|
|
64373
65294
|
DeviceType.Thermostat,
|
|
64374
65295
|
DeviceType.PetFeeder
|
|
64375
65296
|
],
|
|
64376
|
-
apply: "add
|
|
65297
|
+
apply: "add",
|
|
64377
65298
|
path: "running",
|
|
64378
65299
|
sources: [
|
|
64379
65300
|
{
|
|
@@ -65637,9 +66558,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65637
66558
|
*/
|
|
65638
66559
|
var RecordWindowSchema = object({
|
|
65639
66560
|
trigger: RecordTriggerSchema,
|
|
65640
|
-
day: number().int().min(0).max(6),
|
|
65641
|
-
startMinute: number().int().min(0).max(1439),
|
|
65642
|
-
endMinute: number().int().min(1).max(1440)
|
|
66561
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
66562
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
66563
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65643
66564
|
});
|
|
65644
66565
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65645
66566
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65715,10 +66636,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65715
66636
|
/** Master "record to the card at all" switch. */
|
|
65716
66637
|
enabled: boolean().nullable(),
|
|
65717
66638
|
overwriteWhenFull: boolean().nullable(),
|
|
65718
|
-
preRecordSec: number().nullable(),
|
|
65719
|
-
postRecordSec: number().nullable(),
|
|
66639
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66640
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65720
66641
|
/** Length of one recorded file, in minutes. */
|
|
65721
|
-
segmentMinutes: number().nullable(),
|
|
66642
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65722
66643
|
/** The primary track's weekly windows, flattened. */
|
|
65723
66644
|
windows: array(RecordWindowSchema),
|
|
65724
66645
|
/**
|
|
@@ -65734,7 +66655,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65734
66655
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65735
66656
|
* writable.
|
|
65736
66657
|
*/
|
|
65737
|
-
unreadableWindows: number(),
|
|
66658
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65738
66659
|
/**
|
|
65739
66660
|
* The camera is scheduled to record and has NO usable storage.
|
|
65740
66661
|
*
|
|
@@ -66579,7 +67500,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66579
67500
|
url: string().optional(),
|
|
66580
67501
|
codec: string().optional(),
|
|
66581
67502
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66582
|
-
fps: number().positive().optional(),
|
|
67503
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66583
67504
|
label: string().optional(),
|
|
66584
67505
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66585
67506
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66666,18 +67587,18 @@ var StreamProfileSchema = _enum([
|
|
|
66666
67587
|
]);
|
|
66667
67588
|
/** The current encoding config of one stream profile. */
|
|
66668
67589
|
var StreamProfileConfigSchema = object({
|
|
66669
|
-
width: number(),
|
|
66670
|
-
height: number(),
|
|
67590
|
+
width: number().meta(readingMeta("none")),
|
|
67591
|
+
height: number().meta(readingMeta("none")),
|
|
66671
67592
|
codec: _enum(["h264", "h265"]),
|
|
66672
|
-
framerate: number(),
|
|
66673
|
-
bitrate: number(),
|
|
67593
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67594
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66674
67595
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66675
67596
|
encoderProfile: _enum([
|
|
66676
67597
|
"high",
|
|
66677
67598
|
"main",
|
|
66678
67599
|
"baseline"
|
|
66679
67600
|
]).optional(),
|
|
66680
|
-
gop: number().optional(),
|
|
67601
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66681
67602
|
/**
|
|
66682
67603
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66683
67604
|
*
|
|
@@ -66851,7 +67772,8 @@ var switchCapability = {
|
|
|
66851
67772
|
deviceTypes: [
|
|
66852
67773
|
DeviceType.Switch,
|
|
66853
67774
|
DeviceType.Siren,
|
|
66854
|
-
DeviceType.Light
|
|
67775
|
+
DeviceType.Light,
|
|
67776
|
+
DeviceType.Fan
|
|
66855
67777
|
],
|
|
66856
67778
|
methods: { setState: method(object({
|
|
66857
67779
|
deviceId: number(),
|
|
@@ -66898,12 +67820,7 @@ var switchCapability = {
|
|
|
66898
67820
|
label: "On",
|
|
66899
67821
|
kind: "boolean"
|
|
66900
67822
|
}
|
|
66901
|
-
}] }
|
|
66902
|
-
customize: {
|
|
66903
|
-
version: 1,
|
|
66904
|
-
advanced: "derive",
|
|
66905
|
-
targets: []
|
|
66906
|
-
}
|
|
67823
|
+
}] }
|
|
66907
67824
|
};
|
|
66908
67825
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66909
67826
|
function hasControlCharacter(value) {
|
|
@@ -67486,35 +68403,21 @@ var tamperCapability = {
|
|
|
67486
68403
|
* entries with `device_class: temperature` and any future native
|
|
67487
68404
|
* thermometer.
|
|
67488
68405
|
*
|
|
67489
|
-
*
|
|
67490
|
-
*
|
|
67491
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67492
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67493
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67494
|
-
* `sourceInfo`.
|
|
68406
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
68407
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67495
68408
|
*
|
|
67496
68409
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67497
68410
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67498
68411
|
* changed" steady state.
|
|
67499
68412
|
*/
|
|
67500
68413
|
var TemperatureSensorStatusSchema = object({
|
|
67501
|
-
/** Current temperature in Celsius. */
|
|
67502
|
-
celsius: number().meta({
|
|
67503
|
-
|
|
68414
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68415
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
68416
|
+
precision: 1,
|
|
67504
68417
|
label: "Temperature"
|
|
67505
|
-
}),
|
|
68418
|
+
})),
|
|
67506
68419
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67507
|
-
lastFetchedAt: number()
|
|
67508
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67509
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67510
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67511
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67512
|
-
unit: string().optional(),
|
|
67513
|
-
/** Suggested decimal places for numeric display.
|
|
67514
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67515
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67516
|
-
* auto-formatting when absent. */
|
|
67517
|
-
precision: number().int().min(0).max(10).optional()
|
|
68420
|
+
lastFetchedAt: number()
|
|
67518
68421
|
});
|
|
67519
68422
|
var temperatureSensorCapability = {
|
|
67520
68423
|
name: "temperature-sensor",
|
|
@@ -67545,12 +68448,7 @@ var temperatureSensorCapability = {
|
|
|
67545
68448
|
} } },
|
|
67546
68449
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67547
68450
|
* whether persisting is worth a SQLite commit. */
|
|
67548
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67549
|
-
customize: {
|
|
67550
|
-
version: 1,
|
|
67551
|
-
advanced: "derive",
|
|
67552
|
-
targets: []
|
|
67553
|
-
}
|
|
68451
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67554
68452
|
};
|
|
67555
68453
|
/**
|
|
67556
68454
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67833,16 +68731,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67833
68731
|
]),
|
|
67834
68732
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67835
68733
|
* reading. */
|
|
67836
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68734
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67837
68735
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67838
68736
|
* the vacuum has no speed control. */
|
|
67839
68737
|
fanSpeed: string().nullable(),
|
|
67840
68738
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67841
68739
|
availableFanSpeeds: array(string()),
|
|
67842
68740
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67843
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68741
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67844
68742
|
/** Current error code (0 / null = no error). */
|
|
67845
|
-
errorCode: number().nullable(),
|
|
68743
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67846
68744
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67847
68745
|
errorLabel: string().nullable(),
|
|
67848
68746
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67920,7 +68818,7 @@ var ValveStatusSchema = object({
|
|
|
67920
68818
|
]),
|
|
67921
68819
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
67922
68820
|
* intermediate position surface. */
|
|
67923
|
-
position: number().min(0).max(100).nullable(),
|
|
68821
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67924
68822
|
/** Ms epoch when the slice was last updated. */
|
|
67925
68823
|
lastChangedAt: number()
|
|
67926
68824
|
});
|
|
@@ -68028,9 +68926,9 @@ var vibrationCapability = {
|
|
|
68028
68926
|
*/
|
|
68029
68927
|
var WaterHeaterStatusSchema = object({
|
|
68030
68928
|
/** Current measured temperature. Null when not reported. */
|
|
68031
|
-
currentTemp: number().nullable(),
|
|
68929
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68032
68930
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68033
|
-
targetTemp: number().nullable(),
|
|
68931
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68034
68932
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68035
68933
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68036
68934
|
* device reports an unknown state. */
|
|
@@ -68041,9 +68939,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68041
68939
|
* has no away surface. */
|
|
68042
68940
|
away: boolean().nullable(),
|
|
68043
68941
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68044
|
-
minTemp: number().nullable(),
|
|
68942
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68045
68943
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68046
|
-
maxTemp: number().nullable(),
|
|
68944
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68047
68945
|
/** Ms epoch when the slice was last updated. */
|
|
68048
68946
|
lastChangedAt: number()
|
|
68049
68947
|
});
|
|
@@ -68128,25 +69026,18 @@ var waterHeaterCapability = {
|
|
|
68128
69026
|
* Forecast deferred — current conditions only for v1.
|
|
68129
69027
|
*/
|
|
68130
69028
|
var WeatherStatusSchema = object({
|
|
68131
|
-
/** Verbatim
|
|
68132
|
-
* when no condition has been reported yet. */
|
|
69029
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68133
69030
|
condition: string().nullable(),
|
|
68134
|
-
/** Current temperature in
|
|
68135
|
-
temperature: number().nullable(),
|
|
68136
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68137
|
-
temperatureUnit: string().nullable(),
|
|
69031
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
69032
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68138
69033
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68139
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68140
|
-
/** Barometric pressure in
|
|
68141
|
-
pressure: number().nullable(),
|
|
68142
|
-
/**
|
|
68143
|
-
|
|
68144
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68145
|
-
windSpeed: number().nullable(),
|
|
68146
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68147
|
-
windSpeedUnit: string().nullable(),
|
|
69034
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
69035
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
69036
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
69037
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
69038
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68148
69039
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68149
|
-
windBearing: number().nullable(),
|
|
69040
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68150
69041
|
/** Ms epoch when the slice was last updated. */
|
|
68151
69042
|
lastFetchedAt: number()
|
|
68152
69043
|
});
|
|
@@ -68174,12 +69065,12 @@ var weatherCapability = {
|
|
|
68174
69065
|
*/
|
|
68175
69066
|
durability: "session",
|
|
68176
69067
|
/**
|
|
68177
|
-
* History (D850): recorded series.
|
|
69068
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68178
69069
|
*/
|
|
68179
69070
|
history: { fields: {
|
|
68180
69071
|
temperature: {
|
|
68181
69072
|
kind: "gauge",
|
|
68182
|
-
|
|
69073
|
+
unit: "°C",
|
|
68183
69074
|
deadband: .2
|
|
68184
69075
|
},
|
|
68185
69076
|
humidity: {
|
|
@@ -68189,12 +69080,12 @@ var weatherCapability = {
|
|
|
68189
69080
|
},
|
|
68190
69081
|
pressure: {
|
|
68191
69082
|
kind: "gauge",
|
|
68192
|
-
|
|
69083
|
+
unit: "hPa",
|
|
68193
69084
|
deadband: .5
|
|
68194
69085
|
},
|
|
68195
69086
|
windSpeed: {
|
|
68196
69087
|
kind: "gauge",
|
|
68197
|
-
|
|
69088
|
+
unit: "m/s",
|
|
68198
69089
|
deadband: .5
|
|
68199
69090
|
}
|
|
68200
69091
|
} }
|
|
@@ -69095,8 +69986,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
69095
69986
|
kind: "mutation",
|
|
69096
69987
|
auth: "admin"
|
|
69097
69988
|
});
|
|
69989
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
69098
69990
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
69099
|
-
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;
|
|
69991
|
+
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;
|
|
69100
69992
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
69101
69993
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
69102
69994
|
new Set(CAP_NAMES);
|
|
@@ -69425,6 +70317,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69425
70317
|
featureProbe: featureProbeCapability,
|
|
69426
70318
|
flood: floodCapability,
|
|
69427
70319
|
gas: gasCapability,
|
|
70320
|
+
groupActive: groupActiveCapability,
|
|
70321
|
+
groupCommands: groupCommandsCapability,
|
|
70322
|
+
groupStatus: groupStatusCapability,
|
|
69428
70323
|
heatingValve: heatingValveCapability,
|
|
69429
70324
|
humidifier: humidifierCapability,
|
|
69430
70325
|
humiditySensor: humiditySensorCapability,
|
|
@@ -69434,6 +70329,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69434
70329
|
lawnMowerControl: lawnMowerControlCapability,
|
|
69435
70330
|
lockControl: lockControlCapability,
|
|
69436
70331
|
mediaPlayer: mediaPlayerCapability,
|
|
70332
|
+
meter: meterCapability,
|
|
69437
70333
|
motion: motionCapability,
|
|
69438
70334
|
motionTrigger: motionTriggerCapability,
|
|
69439
70335
|
motionZones: motionZonesCapability,
|
|
@@ -70693,7 +71589,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
70693
71589
|
return toDeviceSummary(device, this.addonId);
|
|
70694
71590
|
}
|
|
70695
71591
|
};
|
|
70696
|
-
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;
|
|
71592
|
+
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;
|
|
70697
71593
|
new Set(Object.values(DeviceType));
|
|
70698
71594
|
Object.freeze({
|
|
70699
71595
|
"accessories.getStatus": {
|
|
@@ -70801,6 +71697,13 @@ Object.freeze({
|
|
|
70801
71697
|
access: "view",
|
|
70802
71698
|
role: "admin"
|
|
70803
71699
|
},
|
|
71700
|
+
"addons.getPackageDocs": {
|
|
71701
|
+
capName: "addons",
|
|
71702
|
+
capScope: "system",
|
|
71703
|
+
addonId: null,
|
|
71704
|
+
access: "view",
|
|
71705
|
+
role: "admin"
|
|
71706
|
+
},
|
|
70804
71707
|
"addons.getVersions": {
|
|
70805
71708
|
capName: "addons",
|
|
70806
71709
|
capScope: "system",
|
|
@@ -73909,6 +74812,27 @@ Object.freeze({
|
|
|
73909
74812
|
access: "view",
|
|
73910
74813
|
role: "viewer"
|
|
73911
74814
|
},
|
|
74815
|
+
"groupActive.getStatus": {
|
|
74816
|
+
capName: "group-active",
|
|
74817
|
+
capScope: "device",
|
|
74818
|
+
addonId: null,
|
|
74819
|
+
access: "view",
|
|
74820
|
+
role: "viewer"
|
|
74821
|
+
},
|
|
74822
|
+
"groupCommands.getStatus": {
|
|
74823
|
+
capName: "group-commands",
|
|
74824
|
+
capScope: "device",
|
|
74825
|
+
addonId: null,
|
|
74826
|
+
access: "view",
|
|
74827
|
+
role: "viewer"
|
|
74828
|
+
},
|
|
74829
|
+
"groupStatus.getStatus": {
|
|
74830
|
+
capName: "group-status",
|
|
74831
|
+
capScope: "device",
|
|
74832
|
+
addonId: null,
|
|
74833
|
+
access: "view",
|
|
74834
|
+
role: "viewer"
|
|
74835
|
+
},
|
|
73912
74836
|
"heatingValve.getStatus": {
|
|
73913
74837
|
capName: "heating-valve",
|
|
73914
74838
|
capScope: "device",
|
|
@@ -74861,6 +75785,13 @@ Object.freeze({
|
|
|
74861
75785
|
access: "create",
|
|
74862
75786
|
role: "admin"
|
|
74863
75787
|
},
|
|
75788
|
+
"meter.getStatus": {
|
|
75789
|
+
capName: "meter",
|
|
75790
|
+
capScope: "device",
|
|
75791
|
+
addonId: null,
|
|
75792
|
+
access: "view",
|
|
75793
|
+
role: "viewer"
|
|
75794
|
+
},
|
|
74864
75795
|
"metricsProvider.collectSnapshot": {
|
|
74865
75796
|
capName: "metrics-provider",
|
|
74866
75797
|
capScope: "system",
|
|
@@ -82959,7 +83890,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
82959
83890
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
82960
83891
|
icon: "square"
|
|
82961
83892
|
}
|
|
82962
|
-
}
|
|
83893
|
+
},
|
|
83894
|
+
overrides: { byType: {
|
|
83895
|
+
[DeviceType.Washer]: {
|
|
83896
|
+
state: { running: {
|
|
83897
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
83898
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
83899
|
+
} },
|
|
83900
|
+
events: {
|
|
83901
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
83902
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
83903
|
+
}
|
|
83904
|
+
},
|
|
83905
|
+
[DeviceType.Dryer]: {
|
|
83906
|
+
state: { running: {
|
|
83907
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
83908
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
83909
|
+
} },
|
|
83910
|
+
events: {
|
|
83911
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
83912
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
83913
|
+
}
|
|
83914
|
+
},
|
|
83915
|
+
[DeviceType.Dishwasher]: {
|
|
83916
|
+
state: { running: {
|
|
83917
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
83918
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
83919
|
+
} },
|
|
83920
|
+
events: {
|
|
83921
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
83922
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
83923
|
+
}
|
|
83924
|
+
}
|
|
83925
|
+
} }
|
|
82963
83926
|
},
|
|
82964
83927
|
update: {
|
|
82965
83928
|
scope: "device",
|
|
@@ -83731,6 +84694,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83731
84694
|
icon: "flame"
|
|
83732
84695
|
}]
|
|
83733
84696
|
},
|
|
84697
|
+
"group-active": {
|
|
84698
|
+
scope: "device",
|
|
84699
|
+
noun: t("Group state", "Stato del gruppo")
|
|
84700
|
+
},
|
|
84701
|
+
"group-commands": {
|
|
84702
|
+
scope: "device",
|
|
84703
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84704
|
+
},
|
|
84705
|
+
"group-status": {
|
|
84706
|
+
scope: "device",
|
|
84707
|
+
noun: t("Group", "Gruppo"),
|
|
84708
|
+
state: [
|
|
84709
|
+
{
|
|
84710
|
+
kind: "numeric",
|
|
84711
|
+
field: "included",
|
|
84712
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84713
|
+
label: t("Reporting", "Rispondono"),
|
|
84714
|
+
icon: "users"
|
|
84715
|
+
},
|
|
84716
|
+
{
|
|
84717
|
+
kind: "numeric",
|
|
84718
|
+
field: "excluded",
|
|
84719
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84720
|
+
label: t("Excluded", "Esclusi"),
|
|
84721
|
+
icon: "users"
|
|
84722
|
+
},
|
|
84723
|
+
{
|
|
84724
|
+
kind: "numeric",
|
|
84725
|
+
field: "total",
|
|
84726
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84727
|
+
label: t("Members", "Membri"),
|
|
84728
|
+
icon: "sigma"
|
|
84729
|
+
}
|
|
84730
|
+
]
|
|
84731
|
+
},
|
|
83734
84732
|
"humidity-sensor": {
|
|
83735
84733
|
scope: "device",
|
|
83736
84734
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83756,6 +84754,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83756
84754
|
}],
|
|
83757
84755
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
83758
84756
|
},
|
|
84757
|
+
meter: {
|
|
84758
|
+
scope: "device",
|
|
84759
|
+
noun: t("Meter", "Contatore"),
|
|
84760
|
+
state: [{
|
|
84761
|
+
kind: "numeric",
|
|
84762
|
+
field: "value",
|
|
84763
|
+
quantity: t("the total", "il totale"),
|
|
84764
|
+
label: t("Total", "Totale"),
|
|
84765
|
+
icon: "gauge"
|
|
84766
|
+
}]
|
|
84767
|
+
},
|
|
83759
84768
|
"numeric-sensor": {
|
|
83760
84769
|
scope: "device",
|
|
83761
84770
|
noun: t("Sensor", "Sensore"),
|
|
@@ -83764,7 +84773,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83764
84773
|
field: "value",
|
|
83765
84774
|
quantity: t("the reading", "il valore"),
|
|
83766
84775
|
label: t("Reading", "Valore"),
|
|
83767
|
-
unitField: "unit",
|
|
83768
84776
|
icon: "gauge"
|
|
83769
84777
|
}]
|
|
83770
84778
|
},
|
|
@@ -83900,7 +84908,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83900
84908
|
field: "temperature",
|
|
83901
84909
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
83902
84910
|
label: t("Temperature", "Temperatura"),
|
|
83903
|
-
|
|
84911
|
+
unit: "°C",
|
|
83904
84912
|
icon: "thermometer"
|
|
83905
84913
|
},
|
|
83906
84914
|
{
|
|
@@ -83916,7 +84924,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83916
84924
|
field: "windSpeed",
|
|
83917
84925
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
83918
84926
|
label: t("Wind", "Vento"),
|
|
83919
|
-
|
|
84927
|
+
unit: "m/s",
|
|
83920
84928
|
icon: "wind"
|
|
83921
84929
|
},
|
|
83922
84930
|
{
|
|
@@ -83924,7 +84932,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83924
84932
|
field: "pressure",
|
|
83925
84933
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
83926
84934
|
label: t("Pressure", "Pressione"),
|
|
83927
|
-
|
|
84935
|
+
unit: "hPa",
|
|
83928
84936
|
icon: "gauge"
|
|
83929
84937
|
}
|
|
83930
84938
|
]
|
|
@@ -84229,8 +85237,47 @@ function projectAction(cap, action) {
|
|
|
84229
85237
|
};
|
|
84230
85238
|
}
|
|
84231
85239
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
84232
|
-
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;
|
|
85240
|
+
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;
|
|
84233
85241
|
DeviceFeature.BatteryOperated;
|
|
85242
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
85243
|
+
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.";
|
|
85244
|
+
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.";
|
|
85245
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
85246
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
85247
|
+
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.";
|
|
85248
|
+
function withheld(reason) {
|
|
85249
|
+
return {
|
|
85250
|
+
[DeviceType.Washer]: {
|
|
85251
|
+
exported: false,
|
|
85252
|
+
reason
|
|
85253
|
+
},
|
|
85254
|
+
[DeviceType.Dryer]: {
|
|
85255
|
+
exported: false,
|
|
85256
|
+
reason
|
|
85257
|
+
},
|
|
85258
|
+
[DeviceType.Dishwasher]: {
|
|
85259
|
+
exported: false,
|
|
85260
|
+
reason
|
|
85261
|
+
}
|
|
85262
|
+
};
|
|
85263
|
+
}
|
|
85264
|
+
function offered(received) {
|
|
85265
|
+
return {
|
|
85266
|
+
[DeviceType.Washer]: {
|
|
85267
|
+
exported: true,
|
|
85268
|
+
as: received
|
|
85269
|
+
},
|
|
85270
|
+
[DeviceType.Dryer]: {
|
|
85271
|
+
exported: true,
|
|
85272
|
+
as: received
|
|
85273
|
+
},
|
|
85274
|
+
[DeviceType.Dishwasher]: {
|
|
85275
|
+
exported: true,
|
|
85276
|
+
as: received
|
|
85277
|
+
}
|
|
85278
|
+
};
|
|
85279
|
+
}
|
|
85280
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
84234
85281
|
Object.freeze({
|
|
84235
85282
|
"accessories.getStatus": [{
|
|
84236
85283
|
name: "deviceId",
|
|
@@ -85197,6 +86244,21 @@ Object.freeze({
|
|
|
85197
86244
|
form: "single",
|
|
85198
86245
|
optional: false
|
|
85199
86246
|
}],
|
|
86247
|
+
"groupActive.getStatus": [{
|
|
86248
|
+
name: "deviceId",
|
|
86249
|
+
form: "single",
|
|
86250
|
+
optional: false
|
|
86251
|
+
}],
|
|
86252
|
+
"groupCommands.getStatus": [{
|
|
86253
|
+
name: "deviceId",
|
|
86254
|
+
form: "single",
|
|
86255
|
+
optional: false
|
|
86256
|
+
}],
|
|
86257
|
+
"groupStatus.getStatus": [{
|
|
86258
|
+
name: "deviceId",
|
|
86259
|
+
form: "single",
|
|
86260
|
+
optional: false
|
|
86261
|
+
}],
|
|
85200
86262
|
"heatingValve.getStatus": [{
|
|
85201
86263
|
name: "deviceId",
|
|
85202
86264
|
form: "single",
|
|
@@ -85397,6 +86459,11 @@ Object.freeze({
|
|
|
85397
86459
|
form: "single",
|
|
85398
86460
|
optional: false
|
|
85399
86461
|
}],
|
|
86462
|
+
"meter.getStatus": [{
|
|
86463
|
+
name: "deviceId",
|
|
86464
|
+
form: "single",
|
|
86465
|
+
optional: false
|
|
86466
|
+
}],
|
|
85400
86467
|
"motion.getStatus": [{
|
|
85401
86468
|
name: "deviceId",
|
|
85402
86469
|
form: "single",
|
|
@@ -87004,7 +88071,6 @@ Object.freeze({
|
|
|
87004
88071
|
"network-access": "ingress",
|
|
87005
88072
|
"smtp-provider": "email"
|
|
87006
88073
|
});
|
|
87007
|
-
DeviceType.Camera;
|
|
87008
88074
|
/**
|
|
87009
88075
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
87010
88076
|
* `z.infer`, they do not restate the shape.
|
|
@@ -87181,6 +88247,8 @@ new Map(Object.entries({
|
|
|
87181
88247
|
"detection-blind": "device-events",
|
|
87182
88248
|
"motion-noisy": "device-events",
|
|
87183
88249
|
"motion-calm": "device-events",
|
|
88250
|
+
"package-llm-silent": "device-events",
|
|
88251
|
+
"package-llm-answered": "device-events",
|
|
87184
88252
|
"recording-stalled": "device-events",
|
|
87185
88253
|
"recording-healthy": "device-events",
|
|
87186
88254
|
"recording-degraded": "device-events",
|
|
@@ -87264,6 +88332,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
87264
88332
|
label: "Motion without a subject",
|
|
87265
88333
|
kinds: ["motion-noisy", "motion-calm"]
|
|
87266
88334
|
},
|
|
88335
|
+
{
|
|
88336
|
+
id: "package-llm",
|
|
88337
|
+
family: "device-events",
|
|
88338
|
+
label: "Package confirm",
|
|
88339
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
88340
|
+
},
|
|
87267
88341
|
{
|
|
87268
88342
|
id: "recording",
|
|
87269
88343
|
family: "device-events",
|
|
@@ -87445,6 +88519,8 @@ var DEVICE_EVENTS = [
|
|
|
87445
88519
|
"detection-blind",
|
|
87446
88520
|
"motion-noisy",
|
|
87447
88521
|
"motion-calm",
|
|
88522
|
+
"package-llm-silent",
|
|
88523
|
+
"package-llm-answered",
|
|
87448
88524
|
"recording-stalled",
|
|
87449
88525
|
"recording-healthy",
|
|
87450
88526
|
"recording-degraded",
|
|
@@ -87713,6 +88789,15 @@ new Map([
|
|
|
87713
88789
|
snapshotLabel: "Cameras with constant motion now",
|
|
87714
88790
|
snapshotSection: null
|
|
87715
88791
|
},
|
|
88792
|
+
{
|
|
88793
|
+
id: "package-llm-confirm",
|
|
88794
|
+
family: "device-events",
|
|
88795
|
+
label: "Package confirm (not answering / answering again)",
|
|
88796
|
+
bad: ["package-llm-silent"],
|
|
88797
|
+
recovery: ["package-llm-answered"],
|
|
88798
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88799
|
+
snapshotSection: null
|
|
88800
|
+
},
|
|
87716
88801
|
{
|
|
87717
88802
|
id: "recording-health",
|
|
87718
88803
|
family: "device-events",
|