@camstack/addon-provider-amcrest 0.2.160 → 0.2.162
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +40 -0
- package/dist/addon.js +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.js
CHANGED
|
@@ -35,7 +35,7 @@ let node_stream_promises = require("node:stream/promises");
|
|
|
35
35
|
let node_child_process = require("node:child_process");
|
|
36
36
|
require("node:zlib");
|
|
37
37
|
let node_os = require("node:os");
|
|
38
|
-
//#region ../types/dist/event-category-
|
|
38
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
39
39
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
40
40
|
EventCategory["SystemBoot"] = "system.boot";
|
|
41
41
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -361,6 +361,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
361
361
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
362
362
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
363
363
|
/**
|
|
364
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
365
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
366
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
367
|
+
*/
|
|
368
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
369
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
370
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
371
|
+
/**
|
|
364
372
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
365
373
|
* (a settings change via `setAgentInferenceDevices` /
|
|
366
374
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5470,7 +5478,7 @@ var ZodIssueCode = {
|
|
|
5470
5478
|
var ZodFirstPartyTypeKind;
|
|
5471
5479
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5472
5480
|
//#endregion
|
|
5473
|
-
//#region ../types/dist/sleep
|
|
5481
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5474
5482
|
/**
|
|
5475
5483
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5476
5484
|
* window to float samples (D455).
|
|
@@ -8024,6 +8032,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
8024
8032
|
}).strict();
|
|
8025
8033
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8026
8034
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8035
|
+
var READING_QUANTITIES = [
|
|
8036
|
+
"temperature",
|
|
8037
|
+
"pressure",
|
|
8038
|
+
"speed",
|
|
8039
|
+
"precipitation",
|
|
8040
|
+
"precipitation-rate",
|
|
8041
|
+
"length",
|
|
8042
|
+
"area",
|
|
8043
|
+
"illuminance",
|
|
8044
|
+
"irradiance",
|
|
8045
|
+
"power",
|
|
8046
|
+
"energy",
|
|
8047
|
+
"voltage",
|
|
8048
|
+
"current",
|
|
8049
|
+
"apparent-power",
|
|
8050
|
+
"humidity",
|
|
8051
|
+
"percentage",
|
|
8052
|
+
"concentration-volume",
|
|
8053
|
+
"concentration-mass",
|
|
8054
|
+
"concentration-ppb",
|
|
8055
|
+
"volume",
|
|
8056
|
+
"duration",
|
|
8057
|
+
"duration-ms",
|
|
8058
|
+
"information",
|
|
8059
|
+
"sound-level",
|
|
8060
|
+
"signal-level",
|
|
8061
|
+
"colour-temperature",
|
|
8062
|
+
"angle",
|
|
8063
|
+
"bitrate",
|
|
8064
|
+
"rate",
|
|
8065
|
+
"mass",
|
|
8066
|
+
"index",
|
|
8067
|
+
"ratio",
|
|
8068
|
+
"count",
|
|
8069
|
+
"none",
|
|
8070
|
+
"device"
|
|
8071
|
+
];
|
|
8072
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8073
|
+
new Set(READING_QUANTITIES);
|
|
8074
|
+
/**
|
|
8075
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8076
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8077
|
+
*/
|
|
8078
|
+
var QUANTITY_BASE = {
|
|
8079
|
+
temperature: "°C",
|
|
8080
|
+
pressure: "hPa",
|
|
8081
|
+
speed: "m/s",
|
|
8082
|
+
precipitation: "mm",
|
|
8083
|
+
"precipitation-rate": "mm/h",
|
|
8084
|
+
length: "m",
|
|
8085
|
+
area: "m²",
|
|
8086
|
+
illuminance: "lx",
|
|
8087
|
+
irradiance: "W/m²",
|
|
8088
|
+
power: "W",
|
|
8089
|
+
energy: "kWh",
|
|
8090
|
+
voltage: "V",
|
|
8091
|
+
current: "A",
|
|
8092
|
+
"apparent-power": "VA",
|
|
8093
|
+
humidity: "%",
|
|
8094
|
+
percentage: "%",
|
|
8095
|
+
"concentration-volume": "ppm",
|
|
8096
|
+
"concentration-mass": "µg/m³",
|
|
8097
|
+
"concentration-ppb": "ppb",
|
|
8098
|
+
volume: "L",
|
|
8099
|
+
duration: "s",
|
|
8100
|
+
"duration-ms": "ms",
|
|
8101
|
+
information: "B",
|
|
8102
|
+
"sound-level": "dBFS",
|
|
8103
|
+
"signal-level": "dBm",
|
|
8104
|
+
"colour-temperature": "mired",
|
|
8105
|
+
angle: "°",
|
|
8106
|
+
bitrate: "kbps",
|
|
8107
|
+
rate: "fps",
|
|
8108
|
+
mass: "kg",
|
|
8109
|
+
index: "none",
|
|
8110
|
+
ratio: "none",
|
|
8111
|
+
count: "none",
|
|
8112
|
+
none: "none",
|
|
8113
|
+
device: "device"
|
|
8114
|
+
};
|
|
8115
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8116
|
+
function baseUnitOf(quantity) {
|
|
8117
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8118
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8119
|
+
return symbol;
|
|
8120
|
+
}
|
|
8121
|
+
function readingMeta(quantity, extras) {
|
|
8122
|
+
return {
|
|
8123
|
+
quantity,
|
|
8124
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8125
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8126
|
+
};
|
|
8127
|
+
}
|
|
8027
8128
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8028
8129
|
var CamProfileSchema = _enum([
|
|
8029
8130
|
"high",
|
|
@@ -8051,8 +8152,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8051
8152
|
"derived"
|
|
8052
8153
|
]);
|
|
8053
8154
|
var CamStreamResolutionSchema = object({
|
|
8054
|
-
width: number().int().positive(),
|
|
8055
|
-
height: number().int().positive()
|
|
8155
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8156
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8056
8157
|
});
|
|
8057
8158
|
var CameraStreamSchema = object({
|
|
8058
8159
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8570,6 +8671,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8570
8671
|
"filesystem-browse",
|
|
8571
8672
|
"flood",
|
|
8572
8673
|
"gas",
|
|
8674
|
+
"group-active",
|
|
8675
|
+
"group-commands",
|
|
8676
|
+
"group-status",
|
|
8573
8677
|
"heating-valve",
|
|
8574
8678
|
"humidifier",
|
|
8575
8679
|
"humidity-sensor",
|
|
@@ -8590,6 +8694,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8590
8694
|
"login-method",
|
|
8591
8695
|
"media-player",
|
|
8592
8696
|
"mesh-network",
|
|
8697
|
+
"meter",
|
|
8593
8698
|
"metrics-provider",
|
|
8594
8699
|
"model-convert",
|
|
8595
8700
|
"model-distributor",
|
|
@@ -8699,14 +8804,6 @@ Object.freeze({
|
|
|
8699
8804
|
{
|
|
8700
8805
|
"path": "aqi",
|
|
8701
8806
|
"valueType": "number"
|
|
8702
|
-
},
|
|
8703
|
-
{
|
|
8704
|
-
"path": "unit",
|
|
8705
|
-
"valueType": "string"
|
|
8706
|
-
},
|
|
8707
|
-
{
|
|
8708
|
-
"path": "precision",
|
|
8709
|
-
"valueType": "number"
|
|
8710
8807
|
}
|
|
8711
8808
|
],
|
|
8712
8809
|
"alarm-panel": [
|
|
@@ -8742,20 +8839,10 @@ Object.freeze({
|
|
|
8742
8839
|
"valueType": "boolean"
|
|
8743
8840
|
}
|
|
8744
8841
|
],
|
|
8745
|
-
"ambient-light-sensor": [
|
|
8746
|
-
|
|
8747
|
-
|
|
8748
|
-
|
|
8749
|
-
},
|
|
8750
|
-
{
|
|
8751
|
-
"path": "unit",
|
|
8752
|
-
"valueType": "string"
|
|
8753
|
-
},
|
|
8754
|
-
{
|
|
8755
|
-
"path": "precision",
|
|
8756
|
-
"valueType": "number"
|
|
8757
|
-
}
|
|
8758
|
-
],
|
|
8842
|
+
"ambient-light-sensor": [{
|
|
8843
|
+
"path": "lux",
|
|
8844
|
+
"valueType": "number"
|
|
8845
|
+
}],
|
|
8759
8846
|
"audio-metrics": [
|
|
8760
8847
|
{
|
|
8761
8848
|
"path": "ts",
|
|
@@ -8835,6 +8922,10 @@ Object.freeze({
|
|
|
8835
8922
|
"path": "lastUpdated",
|
|
8836
8923
|
"valueType": "number"
|
|
8837
8924
|
},
|
|
8925
|
+
{
|
|
8926
|
+
"path": "volts",
|
|
8927
|
+
"valueType": "number"
|
|
8928
|
+
},
|
|
8838
8929
|
{
|
|
8839
8930
|
"path": "lastContactAt",
|
|
8840
8931
|
"valueType": "number"
|
|
@@ -9077,10 +9168,6 @@ Object.freeze({
|
|
|
9077
9168
|
"datetime"
|
|
9078
9169
|
]
|
|
9079
9170
|
},
|
|
9080
|
-
{
|
|
9081
|
-
"path": "unit",
|
|
9082
|
-
"valueType": "string"
|
|
9083
|
-
},
|
|
9084
9171
|
{
|
|
9085
9172
|
"path": "min",
|
|
9086
9173
|
"valueType": "number"
|
|
@@ -9092,19 +9179,6 @@ Object.freeze({
|
|
|
9092
9179
|
{
|
|
9093
9180
|
"path": "step",
|
|
9094
9181
|
"valueType": "number"
|
|
9095
|
-
},
|
|
9096
|
-
{
|
|
9097
|
-
"path": "precision",
|
|
9098
|
-
"valueType": "number"
|
|
9099
|
-
},
|
|
9100
|
-
{
|
|
9101
|
-
"path": "format",
|
|
9102
|
-
"valueType": "enum",
|
|
9103
|
-
"enumValues": [
|
|
9104
|
-
"date",
|
|
9105
|
-
"time",
|
|
9106
|
-
"datetime"
|
|
9107
|
-
]
|
|
9108
9182
|
}
|
|
9109
9183
|
],
|
|
9110
9184
|
"cover": [
|
|
@@ -9345,13 +9419,8 @@ Object.freeze({
|
|
|
9345
9419
|
"path": "value",
|
|
9346
9420
|
"valueType": "string"
|
|
9347
9421
|
}, {
|
|
9348
|
-
"path": "
|
|
9349
|
-
"valueType": "
|
|
9350
|
-
"enumValues": [
|
|
9351
|
-
"date",
|
|
9352
|
-
"time",
|
|
9353
|
-
"datetime"
|
|
9354
|
-
]
|
|
9422
|
+
"path": "timestamp",
|
|
9423
|
+
"valueType": "boolean"
|
|
9355
9424
|
}],
|
|
9356
9425
|
"event-emitter": [
|
|
9357
9426
|
{
|
|
@@ -9424,6 +9493,24 @@ Object.freeze({
|
|
|
9424
9493
|
"path": "detected",
|
|
9425
9494
|
"valueType": "boolean"
|
|
9426
9495
|
}],
|
|
9496
|
+
"group-active": [{
|
|
9497
|
+
"path": "active",
|
|
9498
|
+
"valueType": "boolean"
|
|
9499
|
+
}],
|
|
9500
|
+
"group-status": [
|
|
9501
|
+
{
|
|
9502
|
+
"path": "included",
|
|
9503
|
+
"valueType": "number"
|
|
9504
|
+
},
|
|
9505
|
+
{
|
|
9506
|
+
"path": "excluded",
|
|
9507
|
+
"valueType": "number"
|
|
9508
|
+
},
|
|
9509
|
+
{
|
|
9510
|
+
"path": "total",
|
|
9511
|
+
"valueType": "number"
|
|
9512
|
+
}
|
|
9513
|
+
],
|
|
9427
9514
|
"heating-valve": [{
|
|
9428
9515
|
"path": "position",
|
|
9429
9516
|
"valueType": "number"
|
|
@@ -9458,20 +9545,10 @@ Object.freeze({
|
|
|
9458
9545
|
"valueType": "number"
|
|
9459
9546
|
}
|
|
9460
9547
|
],
|
|
9461
|
-
"humidity-sensor": [
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
},
|
|
9466
|
-
{
|
|
9467
|
-
"path": "unit",
|
|
9468
|
-
"valueType": "string"
|
|
9469
|
-
},
|
|
9470
|
-
{
|
|
9471
|
-
"path": "precision",
|
|
9472
|
-
"valueType": "number"
|
|
9473
|
-
}
|
|
9474
|
-
],
|
|
9548
|
+
"humidity-sensor": [{
|
|
9549
|
+
"path": "percent",
|
|
9550
|
+
"valueType": "number"
|
|
9551
|
+
}],
|
|
9475
9552
|
"image": [{
|
|
9476
9553
|
"path": "url",
|
|
9477
9554
|
"valueType": "string"
|
|
@@ -9679,6 +9756,10 @@ Object.freeze({
|
|
|
9679
9756
|
]
|
|
9680
9757
|
}
|
|
9681
9758
|
],
|
|
9759
|
+
"meter": [{
|
|
9760
|
+
"path": "value",
|
|
9761
|
+
"valueType": "number"
|
|
9762
|
+
}],
|
|
9682
9763
|
"motion": [
|
|
9683
9764
|
{
|
|
9684
9765
|
"path": "detected",
|
|
@@ -9810,20 +9891,10 @@ Object.freeze({
|
|
|
9810
9891
|
"valueType": "boolean"
|
|
9811
9892
|
}
|
|
9812
9893
|
],
|
|
9813
|
-
"numeric-sensor": [
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
},
|
|
9818
|
-
{
|
|
9819
|
-
"path": "unit",
|
|
9820
|
-
"valueType": "string"
|
|
9821
|
-
},
|
|
9822
|
-
{
|
|
9823
|
-
"path": "precision",
|
|
9824
|
-
"valueType": "number"
|
|
9825
|
-
}
|
|
9826
|
-
],
|
|
9894
|
+
"numeric-sensor": [{
|
|
9895
|
+
"path": "value",
|
|
9896
|
+
"valueType": "number"
|
|
9897
|
+
}],
|
|
9827
9898
|
"pet-feeder": [
|
|
9828
9899
|
{
|
|
9829
9900
|
"path": "foodLevel",
|
|
@@ -9915,14 +9986,6 @@ Object.freeze({
|
|
|
9915
9986
|
{
|
|
9916
9987
|
"path": "powerFactor",
|
|
9917
9988
|
"valueType": "number"
|
|
9918
|
-
},
|
|
9919
|
-
{
|
|
9920
|
-
"path": "unit",
|
|
9921
|
-
"valueType": "string"
|
|
9922
|
-
},
|
|
9923
|
-
{
|
|
9924
|
-
"path": "precision",
|
|
9925
|
-
"valueType": "number"
|
|
9926
9989
|
}
|
|
9927
9990
|
],
|
|
9928
9991
|
"presence": [
|
|
@@ -9951,20 +10014,10 @@ Object.freeze({
|
|
|
9951
10014
|
"valueType": "number"
|
|
9952
10015
|
}
|
|
9953
10016
|
],
|
|
9954
|
-
"pressure-sensor": [
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
},
|
|
9959
|
-
{
|
|
9960
|
-
"path": "unit",
|
|
9961
|
-
"valueType": "string"
|
|
9962
|
-
},
|
|
9963
|
-
{
|
|
9964
|
-
"path": "precision",
|
|
9965
|
-
"valueType": "number"
|
|
9966
|
-
}
|
|
9967
|
-
],
|
|
10017
|
+
"pressure-sensor": [{
|
|
10018
|
+
"path": "hpa",
|
|
10019
|
+
"valueType": "number"
|
|
10020
|
+
}],
|
|
9968
10021
|
"privacy-mask": [{
|
|
9969
10022
|
"path": "enabled",
|
|
9970
10023
|
"valueType": "boolean"
|
|
@@ -10275,20 +10328,10 @@ Object.freeze({
|
|
|
10275
10328
|
"path": "tampered",
|
|
10276
10329
|
"valueType": "boolean"
|
|
10277
10330
|
}],
|
|
10278
|
-
"temperature-sensor": [
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
},
|
|
10283
|
-
{
|
|
10284
|
-
"path": "unit",
|
|
10285
|
-
"valueType": "string"
|
|
10286
|
-
},
|
|
10287
|
-
{
|
|
10288
|
-
"path": "precision",
|
|
10289
|
-
"valueType": "number"
|
|
10290
|
-
}
|
|
10291
|
-
],
|
|
10331
|
+
"temperature-sensor": [{
|
|
10332
|
+
"path": "celsius",
|
|
10333
|
+
"valueType": "number"
|
|
10334
|
+
}],
|
|
10292
10335
|
"update": [
|
|
10293
10336
|
{
|
|
10294
10337
|
"path": "currentVersion",
|
|
@@ -10399,10 +10442,6 @@ Object.freeze({
|
|
|
10399
10442
|
"path": "temperature",
|
|
10400
10443
|
"valueType": "number"
|
|
10401
10444
|
},
|
|
10402
|
-
{
|
|
10403
|
-
"path": "temperatureUnit",
|
|
10404
|
-
"valueType": "string"
|
|
10405
|
-
},
|
|
10406
10445
|
{
|
|
10407
10446
|
"path": "humidity",
|
|
10408
10447
|
"valueType": "number"
|
|
@@ -10411,18 +10450,10 @@ Object.freeze({
|
|
|
10411
10450
|
"path": "pressure",
|
|
10412
10451
|
"valueType": "number"
|
|
10413
10452
|
},
|
|
10414
|
-
{
|
|
10415
|
-
"path": "pressureUnit",
|
|
10416
|
-
"valueType": "string"
|
|
10417
|
-
},
|
|
10418
10453
|
{
|
|
10419
10454
|
"path": "windSpeed",
|
|
10420
10455
|
"valueType": "number"
|
|
10421
10456
|
},
|
|
10422
|
-
{
|
|
10423
|
-
"path": "windSpeedUnit",
|
|
10424
|
-
"valueType": "string"
|
|
10425
|
-
},
|
|
10426
10457
|
{
|
|
10427
10458
|
"path": "windBearing",
|
|
10428
10459
|
"valueType": "number"
|
|
@@ -10486,7 +10517,7 @@ function userError(code, params, englishFallback) {
|
|
|
10486
10517
|
return new CamstackError(code, params, englishFallback);
|
|
10487
10518
|
}
|
|
10488
10519
|
//#endregion
|
|
10489
|
-
//#region ../types/dist/err-msg-
|
|
10520
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10490
10521
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10491
10522
|
DeviceType["Camera"] = "camera";
|
|
10492
10523
|
DeviceType["Hub"] = "hub";
|
|
@@ -10580,8 +10611,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10580
10611
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10581
10612
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10582
10613
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10583
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10614
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10615
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10584
10616
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10617
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10618
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10619
|
+
DeviceType["Washer"] = "washer";
|
|
10620
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10621
|
+
DeviceType["Dryer"] = "dryer";
|
|
10585
10622
|
return DeviceType;
|
|
10586
10623
|
}({});
|
|
10587
10624
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10829,7 +10866,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
10829
10866
|
return DeviceRole;
|
|
10830
10867
|
}({});
|
|
10831
10868
|
//#endregion
|
|
10832
|
-
//#region ../types/dist/composition-
|
|
10869
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10833
10870
|
/**
|
|
10834
10871
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10835
10872
|
*
|
|
@@ -11144,6 +11181,13 @@ var table = {
|
|
|
11144
11181
|
apply: () => {
|
|
11145
11182
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11146
11183
|
}
|
|
11184
|
+
},
|
|
11185
|
+
schmitt: {
|
|
11186
|
+
minArgs: 3,
|
|
11187
|
+
maxArgs: 5,
|
|
11188
|
+
apply: () => {
|
|
11189
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11190
|
+
}
|
|
11147
11191
|
}
|
|
11148
11192
|
};
|
|
11149
11193
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11584,15 +11628,232 @@ function validateExpressionSource(src) {
|
|
|
11584
11628
|
}
|
|
11585
11629
|
return null;
|
|
11586
11630
|
}
|
|
11587
|
-
/**
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11631
|
+
/**
|
|
11632
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11633
|
+
*
|
|
11634
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11635
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11636
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11637
|
+
*
|
|
11638
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11639
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11640
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11641
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11642
|
+
* can move later without moving the others.
|
|
11643
|
+
*/
|
|
11644
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11645
|
+
var APPLIANCE_KINDS = [
|
|
11646
|
+
"washer",
|
|
11647
|
+
"dryer",
|
|
11648
|
+
"dishwasher"
|
|
11649
|
+
];
|
|
11650
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11651
|
+
/**
|
|
11652
|
+
* Statistics and integrals over a history read (D944).
|
|
11653
|
+
*
|
|
11654
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11655
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11656
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11657
|
+
* as zero. A truncated read is not published.
|
|
11658
|
+
*/
|
|
11659
|
+
var STATISTIC_STATS = [
|
|
11660
|
+
"min",
|
|
11661
|
+
"max",
|
|
11662
|
+
"mean",
|
|
11663
|
+
"sum",
|
|
11664
|
+
"count",
|
|
11665
|
+
"change"
|
|
11666
|
+
];
|
|
11667
|
+
/**
|
|
11668
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11669
|
+
*
|
|
11670
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11671
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11672
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11673
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11674
|
+
*/
|
|
11675
|
+
var MINUTE_MS = 6e4;
|
|
11676
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11677
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11678
|
+
var ROLLING_SPANS = [
|
|
11679
|
+
"1h",
|
|
11680
|
+
"24h",
|
|
11681
|
+
"2d",
|
|
11682
|
+
"7d",
|
|
11683
|
+
"30d",
|
|
11684
|
+
"custom"
|
|
11685
|
+
];
|
|
11686
|
+
var CALENDAR_PERIODS = [
|
|
11687
|
+
"today",
|
|
11688
|
+
"yesterday",
|
|
11689
|
+
"this-week",
|
|
11690
|
+
"this-month"
|
|
11691
|
+
];
|
|
11692
|
+
var RESET_PERIODS = [
|
|
11693
|
+
"never",
|
|
11694
|
+
"daily",
|
|
11695
|
+
"weekly",
|
|
11696
|
+
"monthly"
|
|
11697
|
+
];
|
|
11698
|
+
5 * MINUTE_MS;
|
|
11699
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11700
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11701
|
+
var rollingWindowObject = object({
|
|
11702
|
+
kind: literal("rolling"),
|
|
11703
|
+
span: _enum(ROLLING_SPANS),
|
|
11704
|
+
customMinutes: number().int().min(5).optional()
|
|
11705
|
+
}).check((payload) => {
|
|
11706
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11707
|
+
code: "custom",
|
|
11708
|
+
message: "a custom range needs a duration in minutes",
|
|
11709
|
+
path: ["customMinutes"],
|
|
11710
|
+
input: payload.value
|
|
11711
|
+
});
|
|
11712
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11713
|
+
code: "custom",
|
|
11714
|
+
message: "only a custom range carries a duration",
|
|
11715
|
+
path: ["customMinutes"],
|
|
11716
|
+
input: payload.value
|
|
11717
|
+
});
|
|
11718
|
+
});
|
|
11719
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11720
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11721
|
+
kind: literal("calendar"),
|
|
11722
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11723
|
+
})]);
|
|
11724
|
+
/**
|
|
11725
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11726
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11727
|
+
* `composition.ts` (D659).
|
|
11728
|
+
*/
|
|
11591
11729
|
var CompositionSourceRefSchema = object({
|
|
11592
11730
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11593
11731
|
addonId: string().min(1),
|
|
11594
11732
|
stableId: string().min(1)
|
|
11595
11733
|
});
|
|
11734
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11735
|
+
"temperature",
|
|
11736
|
+
"humidity",
|
|
11737
|
+
"pressure",
|
|
11738
|
+
"illuminance",
|
|
11739
|
+
"power",
|
|
11740
|
+
"energy",
|
|
11741
|
+
"battery",
|
|
11742
|
+
"numeric",
|
|
11743
|
+
"motion",
|
|
11744
|
+
"contact",
|
|
11745
|
+
"leak",
|
|
11746
|
+
"smoke",
|
|
11747
|
+
"occupancy",
|
|
11748
|
+
"binary",
|
|
11749
|
+
"switch",
|
|
11750
|
+
"light",
|
|
11751
|
+
"fan",
|
|
11752
|
+
"cover",
|
|
11753
|
+
"valve",
|
|
11754
|
+
"lock",
|
|
11755
|
+
"media-player",
|
|
11756
|
+
"climate"
|
|
11757
|
+
];
|
|
11758
|
+
var NUMERIC_AGGREGATES = [
|
|
11759
|
+
"mean",
|
|
11760
|
+
"median",
|
|
11761
|
+
"min",
|
|
11762
|
+
"max",
|
|
11763
|
+
"sum"
|
|
11764
|
+
];
|
|
11765
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11766
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11767
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11768
|
+
var AGGREGATE_REDUCERS = [
|
|
11769
|
+
"mean",
|
|
11770
|
+
"median",
|
|
11771
|
+
"min",
|
|
11772
|
+
"max",
|
|
11773
|
+
"sum",
|
|
11774
|
+
"any",
|
|
11775
|
+
"all"
|
|
11776
|
+
];
|
|
11777
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11778
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11779
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11780
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11781
|
+
var HelperMemberSchema = object({
|
|
11782
|
+
source: CompositionSourceRefSchema,
|
|
11783
|
+
cap: string().min(1),
|
|
11784
|
+
fieldPath: string().min(1)
|
|
11785
|
+
});
|
|
11786
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11787
|
+
object({
|
|
11788
|
+
kind: literal("group"),
|
|
11789
|
+
templateId: GroupTemplateIdSchema,
|
|
11790
|
+
aggregate: AggregateReducerSchema,
|
|
11791
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11792
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11793
|
+
active: ActiveCriterionSchema.optional()
|
|
11794
|
+
}),
|
|
11795
|
+
object({
|
|
11796
|
+
kind: literal("appliance"),
|
|
11797
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11798
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11799
|
+
thresholdWatts: number().positive(),
|
|
11800
|
+
startDwellMs: number().int().nonnegative(),
|
|
11801
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11802
|
+
member: HelperMemberSchema
|
|
11803
|
+
}),
|
|
11804
|
+
object({
|
|
11805
|
+
kind: literal("statistic"),
|
|
11806
|
+
stat: _enum(STATISTIC_STATS),
|
|
11807
|
+
window: StatisticWindowSchema,
|
|
11808
|
+
source: HelperMemberSchema
|
|
11809
|
+
}),
|
|
11810
|
+
object({
|
|
11811
|
+
kind: literal("integral"),
|
|
11812
|
+
reset: _enum(RESET_PERIODS),
|
|
11813
|
+
output: _enum(["energy", "meter"]),
|
|
11814
|
+
source: HelperMemberSchema
|
|
11815
|
+
}),
|
|
11816
|
+
object({
|
|
11817
|
+
kind: literal("threshold"),
|
|
11818
|
+
source: HelperMemberSchema,
|
|
11819
|
+
high: number(),
|
|
11820
|
+
low: number(),
|
|
11821
|
+
onForMs: number().int().nonnegative(),
|
|
11822
|
+
offForMs: number().int().nonnegative()
|
|
11823
|
+
}),
|
|
11824
|
+
object({
|
|
11825
|
+
kind: literal("arithmetic"),
|
|
11826
|
+
op: _enum([
|
|
11827
|
+
"sum",
|
|
11828
|
+
"difference",
|
|
11829
|
+
"ratio"
|
|
11830
|
+
]),
|
|
11831
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11832
|
+
}),
|
|
11833
|
+
object({
|
|
11834
|
+
kind: literal("expression"),
|
|
11835
|
+
expr: string().min(1),
|
|
11836
|
+
inputs: array(object({
|
|
11837
|
+
name: string().min(1),
|
|
11838
|
+
member: HelperMemberSchema
|
|
11839
|
+
})).min(1).max(64),
|
|
11840
|
+
output: _enum(["number", "boolean"])
|
|
11841
|
+
}),
|
|
11842
|
+
object({
|
|
11843
|
+
kind: literal("derivative"),
|
|
11844
|
+
window: RollingWindowSchema,
|
|
11845
|
+
per: _enum([
|
|
11846
|
+
"second",
|
|
11847
|
+
"minute",
|
|
11848
|
+
"hour"
|
|
11849
|
+
]),
|
|
11850
|
+
source: HelperMemberSchema
|
|
11851
|
+
})
|
|
11852
|
+
]);
|
|
11853
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11854
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11855
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11856
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11596
11857
|
/** One field of one capability of one source device. */
|
|
11597
11858
|
var CompositionFieldReadSchema = object({
|
|
11598
11859
|
source: CompositionSourceRefSchema,
|
|
@@ -11636,7 +11897,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11636
11897
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11637
11898
|
CompositionFromSourceSchema,
|
|
11638
11899
|
CompositionExpressionSourceSchema,
|
|
11639
|
-
CompositionCodeSourceSchema
|
|
11900
|
+
CompositionCodeSourceSchema,
|
|
11901
|
+
object({
|
|
11902
|
+
kind: literal("aggregate"),
|
|
11903
|
+
reducer: _enum([
|
|
11904
|
+
"mean",
|
|
11905
|
+
"median",
|
|
11906
|
+
"min",
|
|
11907
|
+
"max",
|
|
11908
|
+
"sum",
|
|
11909
|
+
"any",
|
|
11910
|
+
"all"
|
|
11911
|
+
]),
|
|
11912
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11913
|
+
/**
|
|
11914
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11915
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11916
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11917
|
+
*/
|
|
11918
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11919
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11920
|
+
publish: _enum([
|
|
11921
|
+
"value",
|
|
11922
|
+
"included",
|
|
11923
|
+
"excluded",
|
|
11924
|
+
"total"
|
|
11925
|
+
]),
|
|
11926
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11927
|
+
empty: _enum([
|
|
11928
|
+
"null",
|
|
11929
|
+
"omit",
|
|
11930
|
+
"offline"
|
|
11931
|
+
])
|
|
11932
|
+
}),
|
|
11933
|
+
object({
|
|
11934
|
+
kind: literal("series"),
|
|
11935
|
+
read: CompositionFieldReadSchema,
|
|
11936
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11937
|
+
publish: _enum([
|
|
11938
|
+
"value",
|
|
11939
|
+
"included",
|
|
11940
|
+
"excluded",
|
|
11941
|
+
"total"
|
|
11942
|
+
]),
|
|
11943
|
+
/**
|
|
11944
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11945
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11946
|
+
*/
|
|
11947
|
+
empty: _enum([
|
|
11948
|
+
"null",
|
|
11949
|
+
"omit",
|
|
11950
|
+
"offline"
|
|
11951
|
+
])
|
|
11952
|
+
})
|
|
11640
11953
|
]);
|
|
11641
11954
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11642
11955
|
kind: literal("forward"),
|
|
@@ -11682,7 +11995,13 @@ var CompositionSchema = object({
|
|
|
11682
11995
|
kind: literal("existing"),
|
|
11683
11996
|
device: CompositionSourceRefSchema
|
|
11684
11997
|
})]),
|
|
11685
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
11998
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
11999
|
+
/**
|
|
12000
|
+
* Present when the block is a helper template. Absent on a free
|
|
12001
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12002
|
+
* never the compiled features.
|
|
12003
|
+
*/
|
|
12004
|
+
helper: HelperSpecSchema.optional()
|
|
11686
12005
|
}).superRefine((composition, ctx) => {
|
|
11687
12006
|
const seen = /* @__PURE__ */ new Set();
|
|
11688
12007
|
composition.features.forEach((feature, index) => {
|
|
@@ -16827,7 +17146,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16827
17146
|
*/
|
|
16828
17147
|
interactiveConnectPath: string().min(1).optional(),
|
|
16829
17148
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16830
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17149
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17150
|
+
/**
|
|
17151
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17152
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17153
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17154
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17155
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17156
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17157
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17158
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17159
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17160
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17161
|
+
* offers it as the default path; the fields the session fills are
|
|
17162
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17163
|
+
*/
|
|
17164
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16831
17165
|
}))
|
|
16832
17166
|
});
|
|
16833
17167
|
var ListInputSchema = object({
|
|
@@ -17928,7 +18262,12 @@ var CompositionProblemSchema = object({
|
|
|
17928
18262
|
"item-field-reserved",
|
|
17929
18263
|
"target-missing",
|
|
17930
18264
|
"target-unreadable",
|
|
17931
|
-
"not-replaceable"
|
|
18265
|
+
"not-replaceable",
|
|
18266
|
+
"native-capability-replace",
|
|
18267
|
+
"mixed-quantity",
|
|
18268
|
+
"helper-mismatch",
|
|
18269
|
+
"member-constraint",
|
|
18270
|
+
"retention"
|
|
17932
18271
|
]),
|
|
17933
18272
|
path: string(),
|
|
17934
18273
|
message: string()
|
|
@@ -17949,7 +18288,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17949
18288
|
"null",
|
|
17950
18289
|
"offline",
|
|
17951
18290
|
"unknown",
|
|
17952
|
-
"release"
|
|
18291
|
+
"release",
|
|
18292
|
+
"omit"
|
|
17953
18293
|
]);
|
|
17954
18294
|
/**
|
|
17955
18295
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17986,9 +18326,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17986
18326
|
reads: array(CompositionFieldReadSchema)
|
|
17987
18327
|
});
|
|
17988
18328
|
/**
|
|
17989
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17990
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17991
|
-
*
|
|
18329
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18330
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18331
|
+
* Replacing a capability the device already serves is refused
|
|
18332
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18333
|
+
* wire for a claim the hub already holds.
|
|
17992
18334
|
*/
|
|
17993
18335
|
var CompositionFeatureModeSchema = _enum([
|
|
17994
18336
|
"new",
|
|
@@ -18159,8 +18501,392 @@ Object.freeze({
|
|
|
18159
18501
|
latchedAt: {
|
|
18160
18502
|
kind: "fixed",
|
|
18161
18503
|
result: ["number", "null"]
|
|
18504
|
+
},
|
|
18505
|
+
schmitt: {
|
|
18506
|
+
kind: "fixed",
|
|
18507
|
+
result: ["boolean", "null"]
|
|
18162
18508
|
}
|
|
18163
18509
|
});
|
|
18510
|
+
/**
|
|
18511
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18512
|
+
* Data, not a form default written into the block.
|
|
18513
|
+
*/
|
|
18514
|
+
var NOW$2 = {
|
|
18515
|
+
fieldPath: "lastFetchedAt",
|
|
18516
|
+
expr: "now"
|
|
18517
|
+
};
|
|
18518
|
+
var CHANGED = {
|
|
18519
|
+
fieldPath: "lastChangedAt",
|
|
18520
|
+
expr: "now"
|
|
18521
|
+
};
|
|
18522
|
+
function numeric(input) {
|
|
18523
|
+
return {
|
|
18524
|
+
...input,
|
|
18525
|
+
family: "numeric",
|
|
18526
|
+
deviceType: DeviceType.Sensor,
|
|
18527
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18528
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18529
|
+
activeWhen: void 0,
|
|
18530
|
+
commandCaps: [],
|
|
18531
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18532
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18533
|
+
accept: [{
|
|
18534
|
+
cap: input.outputCap,
|
|
18535
|
+
fieldPath: input.outputField
|
|
18536
|
+
}]
|
|
18537
|
+
};
|
|
18538
|
+
}
|
|
18539
|
+
function binary(input) {
|
|
18540
|
+
return {
|
|
18541
|
+
...input,
|
|
18542
|
+
family: "binary",
|
|
18543
|
+
deviceType: DeviceType.Sensor,
|
|
18544
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18545
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18546
|
+
activeWhen: void 0,
|
|
18547
|
+
commandCaps: [],
|
|
18548
|
+
quantity: "none",
|
|
18549
|
+
baseUnit: void 0,
|
|
18550
|
+
aggregates: BINARY_AGGREGATES,
|
|
18551
|
+
empty: "offline"
|
|
18552
|
+
};
|
|
18553
|
+
}
|
|
18554
|
+
var GROUP_TEMPLATES = [
|
|
18555
|
+
numeric({
|
|
18556
|
+
id: "temperature",
|
|
18557
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18558
|
+
role: DeviceRole.TemperatureSensor,
|
|
18559
|
+
outputCap: "temperature-sensor",
|
|
18560
|
+
outputField: "celsius",
|
|
18561
|
+
quantity: "temperature",
|
|
18562
|
+
defaultAggregate: "mean",
|
|
18563
|
+
empty: "null",
|
|
18564
|
+
companions: [NOW$2]
|
|
18565
|
+
}),
|
|
18566
|
+
numeric({
|
|
18567
|
+
id: "humidity",
|
|
18568
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18569
|
+
role: DeviceRole.HumiditySensor,
|
|
18570
|
+
outputCap: "humidity-sensor",
|
|
18571
|
+
outputField: "percent",
|
|
18572
|
+
quantity: "humidity",
|
|
18573
|
+
defaultAggregate: "mean",
|
|
18574
|
+
empty: "null",
|
|
18575
|
+
companions: [NOW$2]
|
|
18576
|
+
}),
|
|
18577
|
+
numeric({
|
|
18578
|
+
id: "pressure",
|
|
18579
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18580
|
+
role: DeviceRole.PressureSensor,
|
|
18581
|
+
outputCap: "pressure-sensor",
|
|
18582
|
+
outputField: "hpa",
|
|
18583
|
+
quantity: "pressure",
|
|
18584
|
+
defaultAggregate: "mean",
|
|
18585
|
+
empty: "null",
|
|
18586
|
+
companions: [NOW$2]
|
|
18587
|
+
}),
|
|
18588
|
+
numeric({
|
|
18589
|
+
id: "illuminance",
|
|
18590
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18591
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18592
|
+
outputCap: "ambient-light-sensor",
|
|
18593
|
+
outputField: "lux",
|
|
18594
|
+
quantity: "illuminance",
|
|
18595
|
+
defaultAggregate: "mean",
|
|
18596
|
+
empty: "null",
|
|
18597
|
+
companions: [NOW$2]
|
|
18598
|
+
}),
|
|
18599
|
+
numeric({
|
|
18600
|
+
id: "power",
|
|
18601
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18602
|
+
role: DeviceRole.PowerSensor,
|
|
18603
|
+
outputCap: "power-meter",
|
|
18604
|
+
outputField: "watts",
|
|
18605
|
+
quantity: "power",
|
|
18606
|
+
defaultAggregate: "sum",
|
|
18607
|
+
empty: "omit",
|
|
18608
|
+
companions: [NOW$2]
|
|
18609
|
+
}),
|
|
18610
|
+
numeric({
|
|
18611
|
+
id: "energy",
|
|
18612
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18613
|
+
role: DeviceRole.EnergySensor,
|
|
18614
|
+
outputCap: "power-meter",
|
|
18615
|
+
outputField: "kwhTotal",
|
|
18616
|
+
quantity: "energy",
|
|
18617
|
+
defaultAggregate: "sum",
|
|
18618
|
+
empty: "omit",
|
|
18619
|
+
companions: [NOW$2]
|
|
18620
|
+
}),
|
|
18621
|
+
numeric({
|
|
18622
|
+
id: "battery",
|
|
18623
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18624
|
+
role: DeviceRole.BatterySensor,
|
|
18625
|
+
outputCap: "battery",
|
|
18626
|
+
outputField: "percentage",
|
|
18627
|
+
quantity: "percentage",
|
|
18628
|
+
defaultAggregate: "mean",
|
|
18629
|
+
empty: "null",
|
|
18630
|
+
companions: [
|
|
18631
|
+
{
|
|
18632
|
+
fieldPath: "charging",
|
|
18633
|
+
expr: "\"unknown\""
|
|
18634
|
+
},
|
|
18635
|
+
{
|
|
18636
|
+
fieldPath: "sleeping",
|
|
18637
|
+
expr: "false"
|
|
18638
|
+
},
|
|
18639
|
+
{
|
|
18640
|
+
fieldPath: "lastUpdated",
|
|
18641
|
+
expr: "now"
|
|
18642
|
+
}
|
|
18643
|
+
]
|
|
18644
|
+
}),
|
|
18645
|
+
numeric({
|
|
18646
|
+
id: "numeric",
|
|
18647
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18648
|
+
role: DeviceRole.NumericSensor,
|
|
18649
|
+
outputCap: "numeric-sensor",
|
|
18650
|
+
outputField: "value",
|
|
18651
|
+
quantity: "device",
|
|
18652
|
+
defaultAggregate: "mean",
|
|
18653
|
+
empty: "null",
|
|
18654
|
+
companions: [NOW$2]
|
|
18655
|
+
}),
|
|
18656
|
+
binary({
|
|
18657
|
+
id: "motion",
|
|
18658
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18659
|
+
role: DeviceRole.MotionSensor,
|
|
18660
|
+
outputCap: "motion",
|
|
18661
|
+
outputField: "detected",
|
|
18662
|
+
defaultAggregate: "any",
|
|
18663
|
+
accept: [{
|
|
18664
|
+
cap: "motion",
|
|
18665
|
+
fieldPath: "detected"
|
|
18666
|
+
}],
|
|
18667
|
+
companions: [{
|
|
18668
|
+
fieldPath: "lastDetectedAt",
|
|
18669
|
+
expr: "null"
|
|
18670
|
+
}, {
|
|
18671
|
+
fieldPath: "autoClearAfterMs",
|
|
18672
|
+
expr: "null"
|
|
18673
|
+
}]
|
|
18674
|
+
}),
|
|
18675
|
+
binary({
|
|
18676
|
+
id: "contact",
|
|
18677
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18678
|
+
role: DeviceRole.ContactSensor,
|
|
18679
|
+
outputCap: "contact",
|
|
18680
|
+
outputField: "entryOpen",
|
|
18681
|
+
defaultAggregate: "any",
|
|
18682
|
+
accept: [{
|
|
18683
|
+
cap: "contact",
|
|
18684
|
+
fieldPath: "entryOpen"
|
|
18685
|
+
}],
|
|
18686
|
+
companions: [CHANGED]
|
|
18687
|
+
}),
|
|
18688
|
+
binary({
|
|
18689
|
+
id: "leak",
|
|
18690
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18691
|
+
role: DeviceRole.LeakSensor,
|
|
18692
|
+
outputCap: "flood",
|
|
18693
|
+
outputField: "flooded",
|
|
18694
|
+
defaultAggregate: "any",
|
|
18695
|
+
accept: [{
|
|
18696
|
+
cap: "flood",
|
|
18697
|
+
fieldPath: "flooded"
|
|
18698
|
+
}],
|
|
18699
|
+
companions: [CHANGED]
|
|
18700
|
+
}),
|
|
18701
|
+
binary({
|
|
18702
|
+
id: "smoke",
|
|
18703
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18704
|
+
role: DeviceRole.SmokeSensor,
|
|
18705
|
+
outputCap: "smoke",
|
|
18706
|
+
outputField: "detected",
|
|
18707
|
+
defaultAggregate: "any",
|
|
18708
|
+
accept: [{
|
|
18709
|
+
cap: "smoke",
|
|
18710
|
+
fieldPath: "detected"
|
|
18711
|
+
}],
|
|
18712
|
+
companions: [CHANGED]
|
|
18713
|
+
}),
|
|
18714
|
+
binary({
|
|
18715
|
+
id: "occupancy",
|
|
18716
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18717
|
+
role: DeviceRole.BinarySensor,
|
|
18718
|
+
outputCap: "binary",
|
|
18719
|
+
outputField: "on",
|
|
18720
|
+
defaultAggregate: "any",
|
|
18721
|
+
accept: [{
|
|
18722
|
+
cap: "motion",
|
|
18723
|
+
fieldPath: "detected"
|
|
18724
|
+
}, {
|
|
18725
|
+
cap: "binary",
|
|
18726
|
+
fieldPath: "on"
|
|
18727
|
+
}],
|
|
18728
|
+
companions: [CHANGED]
|
|
18729
|
+
}),
|
|
18730
|
+
binary({
|
|
18731
|
+
id: "binary",
|
|
18732
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18733
|
+
role: DeviceRole.BinarySensor,
|
|
18734
|
+
outputCap: "binary",
|
|
18735
|
+
outputField: "on",
|
|
18736
|
+
defaultAggregate: "any",
|
|
18737
|
+
accept: [{
|
|
18738
|
+
cap: "binary",
|
|
18739
|
+
fieldPath: "on"
|
|
18740
|
+
}],
|
|
18741
|
+
companions: [CHANGED]
|
|
18742
|
+
}),
|
|
18743
|
+
actuator({
|
|
18744
|
+
id: "switch",
|
|
18745
|
+
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.",
|
|
18746
|
+
deviceType: DeviceType.Switch,
|
|
18747
|
+
outputCap: "switch",
|
|
18748
|
+
outputField: "on",
|
|
18749
|
+
member: {
|
|
18750
|
+
cap: "switch",
|
|
18751
|
+
fieldPath: "on"
|
|
18752
|
+
},
|
|
18753
|
+
commandCaps: ["switch"]
|
|
18754
|
+
}),
|
|
18755
|
+
actuator({
|
|
18756
|
+
id: "light",
|
|
18757
|
+
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.",
|
|
18758
|
+
deviceType: DeviceType.Light,
|
|
18759
|
+
outputCap: "switch",
|
|
18760
|
+
outputField: "on",
|
|
18761
|
+
member: {
|
|
18762
|
+
cap: "switch",
|
|
18763
|
+
fieldPath: "on"
|
|
18764
|
+
},
|
|
18765
|
+
commandCaps: [
|
|
18766
|
+
"switch",
|
|
18767
|
+
"brightness",
|
|
18768
|
+
"color"
|
|
18769
|
+
]
|
|
18770
|
+
}),
|
|
18771
|
+
actuator({
|
|
18772
|
+
id: "fan",
|
|
18773
|
+
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.",
|
|
18774
|
+
deviceType: DeviceType.Fan,
|
|
18775
|
+
outputCap: "switch",
|
|
18776
|
+
outputField: "on",
|
|
18777
|
+
member: {
|
|
18778
|
+
cap: "switch",
|
|
18779
|
+
fieldPath: "on"
|
|
18780
|
+
},
|
|
18781
|
+
commandCaps: ["switch", "fan-control"]
|
|
18782
|
+
}),
|
|
18783
|
+
actuator({
|
|
18784
|
+
id: "cover",
|
|
18785
|
+
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.",
|
|
18786
|
+
deviceType: DeviceType.Cover,
|
|
18787
|
+
outputCap: "group-active",
|
|
18788
|
+
outputField: "active",
|
|
18789
|
+
member: {
|
|
18790
|
+
cap: "cover",
|
|
18791
|
+
fieldPath: "state"
|
|
18792
|
+
},
|
|
18793
|
+
activeWhen: [
|
|
18794
|
+
"open",
|
|
18795
|
+
"opening",
|
|
18796
|
+
"stopped"
|
|
18797
|
+
],
|
|
18798
|
+
commandCaps: ["cover"]
|
|
18799
|
+
}),
|
|
18800
|
+
actuator({
|
|
18801
|
+
id: "valve",
|
|
18802
|
+
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.",
|
|
18803
|
+
deviceType: DeviceType.Valve,
|
|
18804
|
+
outputCap: "group-active",
|
|
18805
|
+
outputField: "active",
|
|
18806
|
+
member: {
|
|
18807
|
+
cap: "valve",
|
|
18808
|
+
fieldPath: "state"
|
|
18809
|
+
},
|
|
18810
|
+
activeWhen: [
|
|
18811
|
+
"open",
|
|
18812
|
+
"opening",
|
|
18813
|
+
"stopped"
|
|
18814
|
+
],
|
|
18815
|
+
commandCaps: ["valve"]
|
|
18816
|
+
}),
|
|
18817
|
+
actuator({
|
|
18818
|
+
id: "lock",
|
|
18819
|
+
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.",
|
|
18820
|
+
deviceType: DeviceType.Lock,
|
|
18821
|
+
outputCap: "group-active",
|
|
18822
|
+
outputField: "active",
|
|
18823
|
+
member: {
|
|
18824
|
+
cap: "lock-control",
|
|
18825
|
+
fieldPath: "state"
|
|
18826
|
+
},
|
|
18827
|
+
activeWhen: ["locked"],
|
|
18828
|
+
commandCaps: ["lock-control"]
|
|
18829
|
+
}),
|
|
18830
|
+
actuator({
|
|
18831
|
+
id: "media-player",
|
|
18832
|
+
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.",
|
|
18833
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18834
|
+
outputCap: "group-active",
|
|
18835
|
+
outputField: "active",
|
|
18836
|
+
member: {
|
|
18837
|
+
cap: "media-player",
|
|
18838
|
+
fieldPath: "state"
|
|
18839
|
+
},
|
|
18840
|
+
activeWhen: ["playing", "buffering"],
|
|
18841
|
+
commandCaps: ["media-player"]
|
|
18842
|
+
}),
|
|
18843
|
+
actuator({
|
|
18844
|
+
id: "climate",
|
|
18845
|
+
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.",
|
|
18846
|
+
deviceType: DeviceType.Thermostat,
|
|
18847
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18848
|
+
outputCap: "group-active",
|
|
18849
|
+
outputField: "active",
|
|
18850
|
+
member: {
|
|
18851
|
+
cap: "climate-control",
|
|
18852
|
+
fieldPath: "mode"
|
|
18853
|
+
},
|
|
18854
|
+
activeWhen: [
|
|
18855
|
+
"heat",
|
|
18856
|
+
"cool",
|
|
18857
|
+
"auto",
|
|
18858
|
+
"heat_cool",
|
|
18859
|
+
"fan_only",
|
|
18860
|
+
"dry"
|
|
18861
|
+
],
|
|
18862
|
+
commandCaps: ["climate-control"]
|
|
18863
|
+
})
|
|
18864
|
+
];
|
|
18865
|
+
function actuator(input) {
|
|
18866
|
+
return {
|
|
18867
|
+
id: input.id,
|
|
18868
|
+
summary: input.summary,
|
|
18869
|
+
deviceType: input.deviceType,
|
|
18870
|
+
outputCap: input.outputCap,
|
|
18871
|
+
outputField: input.outputField,
|
|
18872
|
+
commandCaps: input.commandCaps,
|
|
18873
|
+
family: "actuator",
|
|
18874
|
+
role: void 0,
|
|
18875
|
+
memberDeviceType: input.deviceType,
|
|
18876
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18877
|
+
activeWhen: input.activeWhen,
|
|
18878
|
+
quantity: "none",
|
|
18879
|
+
baseUnit: void 0,
|
|
18880
|
+
aggregates: BINARY_AGGREGATES,
|
|
18881
|
+
defaultAggregate: "any",
|
|
18882
|
+
empty: "offline",
|
|
18883
|
+
accept: [input.member],
|
|
18884
|
+
companions: [CHANGED]
|
|
18885
|
+
};
|
|
18886
|
+
}
|
|
18887
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18888
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18889
|
+
DeviceType.Camera;
|
|
18164
18890
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18165
18891
|
/**
|
|
18166
18892
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19987,12 +20713,12 @@ function buildDeviceAdminUrl(parts) {
|
|
|
19987
20713
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19988
20714
|
* in-place so dispatch keeps working.
|
|
19989
20715
|
*
|
|
19990
|
-
* **
|
|
19991
|
-
*
|
|
19992
|
-
*
|
|
19993
|
-
*
|
|
19994
|
-
* (`ha-domain-mapping`)
|
|
19995
|
-
* stored after that point.
|
|
20716
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20717
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20718
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20719
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20720
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20721
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19996
20722
|
*
|
|
19997
20723
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19998
20724
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20006,6 +20732,14 @@ var SourceInfoSchema = object({
|
|
|
20006
20732
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20007
20733
|
* Used to detect rename when `id` changes. */
|
|
20008
20734
|
uniqueId: string().optional(),
|
|
20735
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20736
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20737
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20738
|
+
dateTimeShape: _enum([
|
|
20739
|
+
"date",
|
|
20740
|
+
"time",
|
|
20741
|
+
"datetime"
|
|
20742
|
+
]).optional(),
|
|
20009
20743
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20010
20744
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20011
20745
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41110,7 +41844,8 @@ method(object({
|
|
|
41110
41844
|
"enum"
|
|
41111
41845
|
]),
|
|
41112
41846
|
enumValues: array(string()).optional(),
|
|
41113
|
-
item: boolean().optional()
|
|
41847
|
+
item: boolean().optional(),
|
|
41848
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41114
41849
|
})).readonly(),
|
|
41115
41850
|
itemArray: object({
|
|
41116
41851
|
path: string(),
|
|
@@ -43471,7 +44206,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43471
44206
|
});
|
|
43472
44207
|
/**
|
|
43473
44208
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43474
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44209
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43475
44210
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43476
44211
|
* the originating provider config (mode + sourcePort) so the
|
|
43477
44212
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44954,8 +45689,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44954
45689
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44955
45690
|
var MaskGridShapeSchema = object({
|
|
44956
45691
|
kind: literal("grid"),
|
|
44957
|
-
gridWidth: number(),
|
|
44958
|
-
gridHeight: number(),
|
|
45692
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45693
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44959
45694
|
cells: array(boolean())
|
|
44960
45695
|
});
|
|
44961
45696
|
discriminatedUnion("kind", [
|
|
@@ -45067,6 +45802,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45067
45802
|
"detection-blind",
|
|
45068
45803
|
"motion-noisy",
|
|
45069
45804
|
"motion-calm",
|
|
45805
|
+
"package-llm-silent",
|
|
45806
|
+
"package-llm-answered",
|
|
45070
45807
|
"recording-stalled",
|
|
45071
45808
|
"recording-healthy",
|
|
45072
45809
|
"recording-degraded",
|
|
@@ -46156,7 +46893,20 @@ var NcRuleInputSchema = object({
|
|
|
46156
46893
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46157
46894
|
* path does not run Zod defaults.
|
|
46158
46895
|
*/
|
|
46159
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46896
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46897
|
+
/**
|
|
46898
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46899
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46900
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46901
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46902
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46903
|
+
*
|
|
46904
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46905
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46906
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46907
|
+
* `false`, so it needs no `clear` key.
|
|
46908
|
+
*/
|
|
46909
|
+
askVerdict: boolean().optional()
|
|
46160
46910
|
});
|
|
46161
46911
|
/**
|
|
46162
46912
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56671,6 +57421,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56671
57421
|
deprecated: string().optional(),
|
|
56672
57422
|
distTags: array(string()).readonly()
|
|
56673
57423
|
});
|
|
57424
|
+
/**
|
|
57425
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
57426
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
57427
|
+
* tarball failure — never an empty string standing in for either.
|
|
57428
|
+
*/
|
|
57429
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
57430
|
+
object({
|
|
57431
|
+
status: literal("ok"),
|
|
57432
|
+
markdown: string()
|
|
57433
|
+
}),
|
|
57434
|
+
object({ status: literal("missing") }),
|
|
57435
|
+
object({
|
|
57436
|
+
status: literal("error"),
|
|
57437
|
+
message: string()
|
|
57438
|
+
})
|
|
57439
|
+
]);
|
|
57440
|
+
var PackageDocsSchema = object({
|
|
57441
|
+
name: string(),
|
|
57442
|
+
version: string(),
|
|
57443
|
+
readme: PackageDocBodySchema,
|
|
57444
|
+
changelog: PackageDocBodySchema
|
|
57445
|
+
});
|
|
56674
57446
|
var SearchResultSchema = object({
|
|
56675
57447
|
name: string(),
|
|
56676
57448
|
version: string(),
|
|
@@ -56889,7 +57661,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56889
57661
|
}), object({ success: literal(true) }), {
|
|
56890
57662
|
kind: "mutation",
|
|
56891
57663
|
auth: "admin"
|
|
56892
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57664
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57665
|
+
name: string().min(1),
|
|
57666
|
+
version: string().min(1).optional()
|
|
57667
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56893
57668
|
kind: "mutation",
|
|
56894
57669
|
auth: "admin"
|
|
56895
57670
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56948,27 +57723,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56948
57723
|
*/
|
|
56949
57724
|
var AirQualitySensorStatusSchema = object({
|
|
56950
57725
|
/** Carbon dioxide concentration in ppm. */
|
|
56951
|
-
co2Ppm: number().min(0).optional(),
|
|
57726
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56952
57727
|
/** Total volatile organic compounds in ppb. */
|
|
56953
|
-
vocPpb: number().min(0).optional(),
|
|
57728
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56954
57729
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56955
|
-
pm25: number().min(0).optional(),
|
|
57730
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56956
57731
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56957
|
-
pm10: number().min(0).optional(),
|
|
57732
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56958
57733
|
/** Composite AQI value (typically 0..500). */
|
|
56959
|
-
aqi: number().optional(),
|
|
57734
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56960
57735
|
/** Ms epoch when the slice was last updated. */
|
|
56961
|
-
lastFetchedAt: number()
|
|
56962
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56963
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56964
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56965
|
-
* per slice is unambiguous. */
|
|
56966
|
-
unit: string().optional(),
|
|
56967
|
-
/** Suggested decimal places for numeric display.
|
|
56968
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56969
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56970
|
-
* auto-formatting when absent. */
|
|
56971
|
-
precision: number().int().min(0).max(10).optional()
|
|
57736
|
+
lastFetchedAt: number()
|
|
56972
57737
|
});
|
|
56973
57738
|
var airQualitySensorCapability = {
|
|
56974
57739
|
name: "air-quality-sensor",
|
|
@@ -57005,12 +57770,12 @@ var airQualitySensorCapability = {
|
|
|
57005
57770
|
},
|
|
57006
57771
|
pm25: {
|
|
57007
57772
|
kind: "gauge",
|
|
57008
|
-
unit: "
|
|
57773
|
+
unit: "µg/m³",
|
|
57009
57774
|
deadband: 1
|
|
57010
57775
|
},
|
|
57011
57776
|
pm10: {
|
|
57012
57777
|
kind: "gauge",
|
|
57013
|
-
unit: "
|
|
57778
|
+
unit: "µg/m³",
|
|
57014
57779
|
deadband: 1
|
|
57015
57780
|
},
|
|
57016
57781
|
aqi: {
|
|
@@ -57028,22 +57793,13 @@ var airQualitySensorCapability = {
|
|
|
57028
57793
|
* entries with `device_class: illuminance`.
|
|
57029
57794
|
*/
|
|
57030
57795
|
var AmbientLightSensorStatusSchema = object({
|
|
57031
|
-
/** Current illuminance in lux (lx). */
|
|
57032
|
-
lux: number().min(0).meta({
|
|
57033
|
-
|
|
57796
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57797
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57798
|
+
precision: 0,
|
|
57034
57799
|
label: "Illuminance"
|
|
57035
|
-
}),
|
|
57800
|
+
})),
|
|
57036
57801
|
/** Ms epoch when the slice was last updated. */
|
|
57037
|
-
lastFetchedAt: number()
|
|
57038
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
57039
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
57040
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
57041
|
-
unit: string().optional(),
|
|
57042
|
-
/** Suggested decimal places for numeric display.
|
|
57043
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57044
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57045
|
-
* auto-formatting when absent. */
|
|
57046
|
-
precision: number().int().min(0).max(10).optional()
|
|
57802
|
+
lastFetchedAt: number()
|
|
57047
57803
|
});
|
|
57048
57804
|
var ambientLightSensorCapability = {
|
|
57049
57805
|
name: "ambient-light-sensor",
|
|
@@ -57075,12 +57831,7 @@ var ambientLightSensorCapability = {
|
|
|
57075
57831
|
} } },
|
|
57076
57832
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57077
57833
|
* whether persisting is worth a SQLite commit. */
|
|
57078
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
57079
|
-
customize: {
|
|
57080
|
-
version: 1,
|
|
57081
|
-
advanced: "derive",
|
|
57082
|
-
targets: []
|
|
57083
|
-
}
|
|
57834
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
57084
57835
|
};
|
|
57085
57836
|
/**
|
|
57086
57837
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -57307,10 +58058,7 @@ var BatteryStatusSchema = object({
|
|
|
57307
58058
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
57308
58059
|
* declines to band a non-finite reading, which is the correct shape.
|
|
57309
58060
|
*/
|
|
57310
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
57311
|
-
unit: "%",
|
|
57312
|
-
label: "Charge"
|
|
57313
|
-
}),
|
|
58061
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
57314
58062
|
/**
|
|
57315
58063
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
57316
58064
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -57337,7 +58085,14 @@ var BatteryStatusSchema = object({
|
|
|
57337
58085
|
*/
|
|
57338
58086
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
57339
58087
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
57340
|
-
lastUpdated: number(),
|
|
58088
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
58089
|
+
/**
|
|
58090
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
58091
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
58092
|
+
* that only report charge. A second reading on this cap, not a second
|
|
58093
|
+
* `numeric-sensor` on the same device.
|
|
58094
|
+
*/
|
|
58095
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
57341
58096
|
/**
|
|
57342
58097
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
57343
58098
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -57384,12 +58139,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
57384
58139
|
DeviceType.Switch,
|
|
57385
58140
|
DeviceType.PetFeeder,
|
|
57386
58141
|
DeviceType.Container,
|
|
57387
|
-
DeviceType.Thermostat
|
|
58142
|
+
DeviceType.Thermostat,
|
|
58143
|
+
DeviceType.EventEmitter
|
|
57388
58144
|
];
|
|
57389
58145
|
/** Generic Customize target for the percentage reading (D936). */
|
|
57390
58146
|
var batteryCustomize = {
|
|
57391
58147
|
version: 1,
|
|
57392
|
-
advanced: "derive",
|
|
57393
58148
|
targets: [{
|
|
57394
58149
|
id: "percentage",
|
|
57395
58150
|
cardinality: "scalar",
|
|
@@ -57398,7 +58153,7 @@ var batteryCustomize = {
|
|
|
57398
58153
|
stateField: "percentage"
|
|
57399
58154
|
},
|
|
57400
58155
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
57401
|
-
apply: "add
|
|
58156
|
+
apply: "add",
|
|
57402
58157
|
path: "percentage",
|
|
57403
58158
|
sources: [{
|
|
57404
58159
|
kind: "field",
|
|
@@ -57519,10 +58274,16 @@ onStatusChanged: { data: object({
|
|
|
57519
58274
|
/**
|
|
57520
58275
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
57521
58276
|
*/
|
|
57522
|
-
history: { fields: {
|
|
57523
|
-
|
|
57524
|
-
|
|
57525
|
-
|
|
58277
|
+
history: { fields: {
|
|
58278
|
+
percentage: {
|
|
58279
|
+
kind: "gauge",
|
|
58280
|
+
unit: "%"
|
|
58281
|
+
},
|
|
58282
|
+
volts: {
|
|
58283
|
+
kind: "gauge",
|
|
58284
|
+
unit: "V"
|
|
58285
|
+
}
|
|
58286
|
+
} },
|
|
57526
58287
|
customize: batteryCustomize,
|
|
57527
58288
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57528
58289
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57569,12 +58330,7 @@ var binaryCapability = {
|
|
|
57569
58330
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57570
58331
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57571
58332
|
* whether persisting is worth a SQLite commit. */
|
|
57572
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57573
|
-
customize: {
|
|
57574
|
-
version: 1,
|
|
57575
|
-
advanced: "derive",
|
|
57576
|
-
targets: []
|
|
57577
|
-
}
|
|
58333
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57578
58334
|
};
|
|
57579
58335
|
/**
|
|
57580
58336
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57590,7 +58346,7 @@ var binaryCapability = {
|
|
|
57590
58346
|
*/
|
|
57591
58347
|
var BrightnessStatusSchema = object({
|
|
57592
58348
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57593
|
-
percentage: number().min(0).max(100),
|
|
58349
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57594
58350
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57595
58351
|
lastChangedAt: number()
|
|
57596
58352
|
});
|
|
@@ -58044,21 +58800,21 @@ var ClimateControlStatusSchema = object({
|
|
|
58044
58800
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
58045
58801
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
58046
58802
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
58047
|
-
target: number().nullable(),
|
|
58803
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
58048
58804
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
58049
58805
|
* in `heat_cool` mode. */
|
|
58050
|
-
targetHigh: number().nullable(),
|
|
58806
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
58051
58807
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
58052
58808
|
* in `heat_cool` mode. */
|
|
58053
|
-
targetLow: number().nullable(),
|
|
58809
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
58054
58810
|
/** Target relative humidity (0..100). Null when the device has no
|
|
58055
58811
|
* humidity control. */
|
|
58056
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58812
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58057
58813
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
58058
58814
|
* the device's internal sensor. */
|
|
58059
|
-
currentTemp: number().nullable(),
|
|
58815
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
58060
58816
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
58061
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58817
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58062
58818
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
58063
58819
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
58064
58820
|
swingVertical: boolean().nullable(),
|
|
@@ -58066,11 +58822,11 @@ var ClimateControlStatusSchema = object({
|
|
|
58066
58822
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
58067
58823
|
swingHorizontal: boolean().nullable(),
|
|
58068
58824
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58069
|
-
minTemp: number().nullable().optional(),
|
|
58825
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58070
58826
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58071
|
-
maxTemp: number().nullable().optional(),
|
|
58827
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58072
58828
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
58073
|
-
tempStep: number().positive().nullable().optional(),
|
|
58829
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
58074
58830
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
58075
58831
|
lastFetchedAt: number()
|
|
58076
58832
|
});
|
|
@@ -58212,17 +58968,17 @@ var climateControlCapability = {
|
|
|
58212
58968
|
* modes to expose in the picker without a slice fetch.
|
|
58213
58969
|
*/
|
|
58214
58970
|
var RgbTripletSchema = object({
|
|
58215
|
-
r: number().int().min(0).max(255),
|
|
58216
|
-
g: number().int().min(0).max(255),
|
|
58217
|
-
b: number().int().min(0).max(255)
|
|
58971
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58972
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58973
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
58218
58974
|
});
|
|
58219
58975
|
var HsvTripletSchema = object({
|
|
58220
58976
|
/** Hue in degrees, 0..360. */
|
|
58221
|
-
h: number().min(0).max(360),
|
|
58977
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
58222
58978
|
/** Saturation as 0..100 inclusive. */
|
|
58223
|
-
s: number().min(0).max(100),
|
|
58979
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
58224
58980
|
/** Value/brightness as 0..100 inclusive. */
|
|
58225
|
-
v: number().min(0).max(100)
|
|
58981
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
58226
58982
|
});
|
|
58227
58983
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
58228
58984
|
object({
|
|
@@ -58251,7 +59007,7 @@ var ColorStatusSchema = object({
|
|
|
58251
59007
|
/** Populated when `mode === 'hsv'`. */
|
|
58252
59008
|
hsv: HsvTripletSchema.optional(),
|
|
58253
59009
|
/** Populated when `mode === 'mired'`. */
|
|
58254
|
-
mireds: number().int().optional(),
|
|
59010
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
58255
59011
|
/** Ms epoch of the last operator-driven change. */
|
|
58256
59012
|
lastChangedAt: number()
|
|
58257
59013
|
});
|
|
@@ -58446,18 +59202,12 @@ _enum([
|
|
|
58446
59202
|
"empty",
|
|
58447
59203
|
"full"
|
|
58448
59204
|
]);
|
|
58449
|
-
/**
|
|
58450
|
-
|
|
58451
|
-
|
|
58452
|
-
"days",
|
|
58453
|
-
"hours",
|
|
58454
|
-
"cycles"
|
|
58455
|
-
]);
|
|
58456
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
58457
|
-
* days). `value` null = unknown (D393). */
|
|
59205
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
59206
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
59207
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
58458
59208
|
var ConsumableRemainingSchema = object({
|
|
58459
|
-
value: number().min(0).nullable(),
|
|
58460
|
-
|
|
59209
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
59210
|
+
kind: ConsumableRemainingKindSchema
|
|
58461
59211
|
});
|
|
58462
59212
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
58463
59213
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -58470,7 +59220,7 @@ var ConsumableItemSchema = object({
|
|
|
58470
59220
|
/** Display name. */
|
|
58471
59221
|
label: string().min(1),
|
|
58472
59222
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
58473
|
-
level: number().min(0).max(100).nullable(),
|
|
59223
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58474
59224
|
/** The provider's discrete verdict when known (binary mode). */
|
|
58475
59225
|
status: ConsumableStatusSchema.nullable(),
|
|
58476
59226
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58552,8 +59302,8 @@ var consumablesCustomize = {
|
|
|
58552
59302
|
transforms: [{ kind: "identity" }]
|
|
58553
59303
|
}],
|
|
58554
59304
|
literals: [{
|
|
58555
|
-
path: "remaining.
|
|
58556
|
-
values: [...
|
|
59305
|
+
path: "remaining.kind",
|
|
59306
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58557
59307
|
}]
|
|
58558
59308
|
},
|
|
58559
59309
|
{
|
|
@@ -58682,7 +59432,6 @@ reset: method(object({
|
|
|
58682
59432
|
},
|
|
58683
59433
|
"remaining.value": {
|
|
58684
59434
|
kind: "gauge",
|
|
58685
|
-
unitFrom: "remaining.unit",
|
|
58686
59435
|
deadband: 1,
|
|
58687
59436
|
displayName: "Remaining"
|
|
58688
59437
|
}
|
|
@@ -58752,10 +59501,9 @@ var contactCapability = {
|
|
|
58752
59501
|
* (empty array for the other kinds). It lives in the slice because
|
|
58753
59502
|
* HA `select.*` entities may update their options at runtime.
|
|
58754
59503
|
*
|
|
58755
|
-
*
|
|
58756
|
-
*
|
|
58757
|
-
*
|
|
58758
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
59504
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
59505
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
59506
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58759
59507
|
*/
|
|
58760
59508
|
var ControlStatusSchema = object({
|
|
58761
59509
|
kind: _enum([
|
|
@@ -58767,39 +59515,17 @@ var ControlStatusSchema = object({
|
|
|
58767
59515
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58768
59516
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58769
59517
|
* or time-only — HA accepts all three forms). */
|
|
58770
|
-
value: union([number(), string()]),
|
|
59518
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58771
59519
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58772
59520
|
options: array(string()),
|
|
58773
59521
|
/** Ms epoch when the slice was last updated. */
|
|
58774
59522
|
lastChangedAt: number(),
|
|
58775
|
-
/**
|
|
58776
|
-
|
|
58777
|
-
|
|
58778
|
-
|
|
58779
|
-
/**
|
|
58780
|
-
|
|
58781
|
-
min: number().optional(),
|
|
58782
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58783
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58784
|
-
max: number().optional(),
|
|
58785
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58786
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58787
|
-
step: number().optional(),
|
|
58788
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58789
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58790
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58791
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58792
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58793
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58794
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58795
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58796
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58797
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58798
|
-
format: _enum([
|
|
58799
|
-
"date",
|
|
58800
|
-
"time",
|
|
58801
|
-
"datetime"
|
|
58802
|
-
]).optional()
|
|
59523
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
59524
|
+
min: number().optional().meta(readingMeta("device")),
|
|
59525
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
59526
|
+
max: number().optional().meta(readingMeta("device")),
|
|
59527
|
+
/** Step increment, in the device quantity's base unit. */
|
|
59528
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58803
59529
|
});
|
|
58804
59530
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58805
59531
|
object({
|
|
@@ -58865,9 +59591,9 @@ var CoverStatusSchema = object({
|
|
|
58865
59591
|
]),
|
|
58866
59592
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58867
59593
|
* no intermediate position surface. */
|
|
58868
|
-
position: number().min(0).max(100).nullable(),
|
|
59594
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58869
59595
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58870
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59596
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58871
59597
|
/** Ms epoch when the slice was last updated. */
|
|
58872
59598
|
lastChangedAt: number()
|
|
58873
59599
|
});
|
|
@@ -58970,9 +59696,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58970
59696
|
var DayNightStatusSchema = object({
|
|
58971
59697
|
mode: DayNightModeSchema,
|
|
58972
59698
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58973
|
-
sensitivity: number().optional(),
|
|
59699
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58974
59700
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58975
|
-
switchDelaySec: number().optional(),
|
|
59701
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58976
59702
|
lastFetchedAt: number()
|
|
58977
59703
|
});
|
|
58978
59704
|
/**
|
|
@@ -59190,11 +59916,11 @@ var DishwasherStatusSchema = object({
|
|
|
59190
59916
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
59191
59917
|
availablePrograms: array(string()),
|
|
59192
59918
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
59193
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59919
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59194
59920
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
59195
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59921
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59196
59922
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
59197
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59923
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59198
59924
|
/** True when the door is reported open; null when the door state is not known. */
|
|
59199
59925
|
doorOpen: boolean().nullable(),
|
|
59200
59926
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -59218,7 +59944,7 @@ var DishwasherStatusSchema = object({
|
|
|
59218
59944
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
59219
59945
|
machineCareDue: boolean().nullable(),
|
|
59220
59946
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
59221
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59947
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
59222
59948
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
59223
59949
|
halfLoad: boolean().nullable(),
|
|
59224
59950
|
hygienePlus: boolean().nullable(),
|
|
@@ -59233,7 +59959,7 @@ var DishwasherStatusSchema = object({
|
|
|
59233
59959
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
59234
59960
|
activeEvents: array(string()),
|
|
59235
59961
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
59236
|
-
errorCode: number().nullable(),
|
|
59962
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
59237
59963
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
59238
59964
|
errorLabel: string().nullable(),
|
|
59239
59965
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -59464,7 +60190,7 @@ var DoorbellStatusSchema = object({
|
|
|
59464
60190
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
59465
60191
|
lastPressedAt: number().nullable(),
|
|
59466
60192
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
59467
|
-
pressCountSinceStart: number()
|
|
60193
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
59468
60194
|
});
|
|
59469
60195
|
var DoorbellPressEventSchema = object({
|
|
59470
60196
|
deviceId: number(),
|
|
@@ -59529,17 +60255,7 @@ onPressed: {
|
|
|
59529
60255
|
history: "none",
|
|
59530
60256
|
customize: doorbellCustomize
|
|
59531
60257
|
};
|
|
59532
|
-
|
|
59533
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
59534
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
59535
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
59536
|
-
* The option set is stable across observations; it is persisted in the
|
|
59537
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
59538
|
-
* stored in `sourceInfo`.
|
|
59539
|
-
*/
|
|
59540
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
59541
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
59542
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
60258
|
+
_enum([
|
|
59543
60259
|
"date",
|
|
59544
60260
|
"time",
|
|
59545
60261
|
"datetime"
|
|
@@ -59547,12 +60263,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59547
60263
|
var EnumSensorStatusSchema = object({
|
|
59548
60264
|
value: string(),
|
|
59549
60265
|
/**
|
|
59550
|
-
* Set
|
|
59551
|
-
* as
|
|
59552
|
-
*
|
|
59553
|
-
* a time-only sensor → `'time'`.
|
|
60266
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
60267
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
60268
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59554
60269
|
*/
|
|
59555
|
-
|
|
60270
|
+
timestamp: boolean().optional(),
|
|
59556
60271
|
/** Ms epoch when the slice was last updated. */
|
|
59557
60272
|
lastFetchedAt: number()
|
|
59558
60273
|
});
|
|
@@ -59579,11 +60294,11 @@ var enumSensorCapability = {
|
|
|
59579
60294
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59580
60295
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59581
60296
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59582
|
-
* `
|
|
60297
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59583
60298
|
*/
|
|
59584
60299
|
history: { fields: { value: {
|
|
59585
60300
|
kind: "enum",
|
|
59586
|
-
skipWhenSet: "
|
|
60301
|
+
skipWhenSet: "timestamp"
|
|
59587
60302
|
} } },
|
|
59588
60303
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59589
60304
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59603,13 +60318,13 @@ var EventFireSchema = object({
|
|
|
59603
60318
|
deviceId: number(),
|
|
59604
60319
|
eventType: string(),
|
|
59605
60320
|
data: record(string(), unknown()).nullable(),
|
|
59606
|
-
timestamp: number(),
|
|
59607
|
-
seq: number()
|
|
60321
|
+
timestamp: number().meta(readingMeta("none")),
|
|
60322
|
+
seq: number().meta(readingMeta("count"))
|
|
59608
60323
|
});
|
|
59609
60324
|
var EventEmitterStatusSchema = object({
|
|
59610
60325
|
eventTypes: array(string()),
|
|
59611
60326
|
lastEvent: EventFireSchema.nullable(),
|
|
59612
|
-
eventCountSinceStart: number()
|
|
60327
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59613
60328
|
});
|
|
59614
60329
|
var eventEmitterCapability = {
|
|
59615
60330
|
name: "event-emitter",
|
|
@@ -60022,10 +60737,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
60022
60737
|
var FanControlStatusSchema = object({
|
|
60023
60738
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
60024
60739
|
* speed surface (single-speed fan). */
|
|
60025
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60740
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60026
60741
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
60027
60742
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
60028
|
-
percentageStep: number().positive().optional(),
|
|
60743
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
60029
60744
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
60030
60745
|
* — empty string when no preset is active or supported. */
|
|
60031
60746
|
preset: string(),
|
|
@@ -60146,7 +60861,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
60146
60861
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
60147
60862
|
model: string().nullable(),
|
|
60148
60863
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
60149
|
-
channelCount: number().nullable(),
|
|
60864
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
60150
60865
|
/**
|
|
60151
60866
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
60152
60867
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -60269,9 +60984,151 @@ var gasCapability = {
|
|
|
60269
60984
|
* whether persisting is worth a SQLite commit. */
|
|
60270
60985
|
volatileStateFields: ["lastChangedAt"]
|
|
60271
60986
|
};
|
|
60987
|
+
var GroupCommandsSchema = object({
|
|
60988
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60989
|
+
results: array(object({
|
|
60990
|
+
deviceId: number().int().nonnegative(),
|
|
60991
|
+
cap: string().min(1),
|
|
60992
|
+
method: string().min(1),
|
|
60993
|
+
ok: boolean(),
|
|
60994
|
+
error: string().optional(),
|
|
60995
|
+
/** Ms epoch of the attempt. */
|
|
60996
|
+
at: number()
|
|
60997
|
+
})) });
|
|
60998
|
+
var groupCommandsCapability = {
|
|
60999
|
+
name: "group-commands",
|
|
61000
|
+
scope: "device",
|
|
61001
|
+
deviceNative: true,
|
|
61002
|
+
mode: "singleton",
|
|
61003
|
+
deviceTypes: [
|
|
61004
|
+
DeviceType.Switch,
|
|
61005
|
+
DeviceType.Light,
|
|
61006
|
+
DeviceType.Fan,
|
|
61007
|
+
DeviceType.Cover,
|
|
61008
|
+
DeviceType.Valve,
|
|
61009
|
+
DeviceType.Lock,
|
|
61010
|
+
DeviceType.MediaPlayer,
|
|
61011
|
+
DeviceType.Thermostat,
|
|
61012
|
+
DeviceType.Climate
|
|
61013
|
+
],
|
|
61014
|
+
methods: {},
|
|
61015
|
+
status: {
|
|
61016
|
+
schema: GroupCommandsSchema,
|
|
61017
|
+
kind: "push"
|
|
61018
|
+
},
|
|
61019
|
+
runtimeState: GroupCommandsSchema,
|
|
61020
|
+
/**
|
|
61021
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
61022
|
+
* failure would outlive the command that caused it.
|
|
61023
|
+
*
|
|
61024
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61025
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61026
|
+
*/
|
|
61027
|
+
durability: "session",
|
|
61028
|
+
history: "none"
|
|
61029
|
+
};
|
|
61030
|
+
/**
|
|
61031
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
61032
|
+
* included member is, or every included member is. What "active" means is the
|
|
61033
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
61034
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
61035
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
61036
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
61037
|
+
* empty included set takes the device offline, never `active: false`.
|
|
61038
|
+
*/
|
|
61039
|
+
var GroupActiveSchema = object({
|
|
61040
|
+
active: boolean().meta({ label: "Active" }),
|
|
61041
|
+
/** Ms epoch when the slice was last updated. */
|
|
61042
|
+
lastChangedAt: number()
|
|
61043
|
+
});
|
|
61044
|
+
var groupActiveCapability = {
|
|
61045
|
+
name: "group-active",
|
|
61046
|
+
scope: "device",
|
|
61047
|
+
deviceNative: true,
|
|
61048
|
+
mode: "singleton",
|
|
61049
|
+
deviceTypes: [
|
|
61050
|
+
DeviceType.Cover,
|
|
61051
|
+
DeviceType.Valve,
|
|
61052
|
+
DeviceType.Lock,
|
|
61053
|
+
DeviceType.MediaPlayer,
|
|
61054
|
+
DeviceType.Climate,
|
|
61055
|
+
DeviceType.Thermostat
|
|
61056
|
+
],
|
|
61057
|
+
methods: {},
|
|
61058
|
+
status: {
|
|
61059
|
+
schema: GroupActiveSchema,
|
|
61060
|
+
kind: "push"
|
|
61061
|
+
},
|
|
61062
|
+
runtimeState: GroupActiveSchema,
|
|
61063
|
+
/**
|
|
61064
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
61065
|
+
* next source event; a restored value would outlive the members it named.
|
|
61066
|
+
*
|
|
61067
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61068
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61069
|
+
*/
|
|
61070
|
+
durability: "session",
|
|
61071
|
+
history: "none"
|
|
61072
|
+
};
|
|
61073
|
+
/**
|
|
61074
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
61075
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
61076
|
+
* The reading itself stays on the output capability. History is none — the
|
|
61077
|
+
* series that later statistics read is the output cap's own history block.
|
|
61078
|
+
*/
|
|
61079
|
+
var GroupStatusSchema = object({
|
|
61080
|
+
/** Members whose current value entered the aggregate. */
|
|
61081
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
61082
|
+
precision: 0,
|
|
61083
|
+
label: "Reporting"
|
|
61084
|
+
})),
|
|
61085
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
61086
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
61087
|
+
precision: 0,
|
|
61088
|
+
label: "Excluded"
|
|
61089
|
+
})),
|
|
61090
|
+
/** `included` + `excluded`. */
|
|
61091
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
61092
|
+
precision: 0,
|
|
61093
|
+
label: "Members"
|
|
61094
|
+
}))
|
|
61095
|
+
});
|
|
61096
|
+
var groupStatusCapability = {
|
|
61097
|
+
name: "group-status",
|
|
61098
|
+
scope: "device",
|
|
61099
|
+
deviceNative: true,
|
|
61100
|
+
mode: "singleton",
|
|
61101
|
+
deviceTypes: [
|
|
61102
|
+
DeviceType.Sensor,
|
|
61103
|
+
DeviceType.Switch,
|
|
61104
|
+
DeviceType.Light,
|
|
61105
|
+
DeviceType.Fan,
|
|
61106
|
+
DeviceType.Cover,
|
|
61107
|
+
DeviceType.Valve,
|
|
61108
|
+
DeviceType.Lock,
|
|
61109
|
+
DeviceType.MediaPlayer,
|
|
61110
|
+
DeviceType.Thermostat,
|
|
61111
|
+
DeviceType.Climate
|
|
61112
|
+
],
|
|
61113
|
+
methods: {},
|
|
61114
|
+
status: {
|
|
61115
|
+
schema: GroupStatusSchema,
|
|
61116
|
+
kind: "push"
|
|
61117
|
+
},
|
|
61118
|
+
runtimeState: GroupStatusSchema,
|
|
61119
|
+
/**
|
|
61120
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
61121
|
+
* next source event; a restored count would outlive the readings it named.
|
|
61122
|
+
*
|
|
61123
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61124
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61125
|
+
*/
|
|
61126
|
+
durability: "session",
|
|
61127
|
+
history: "none"
|
|
61128
|
+
};
|
|
60272
61129
|
var HeatingValveStatusSchema = object({
|
|
60273
61130
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
60274
|
-
position: number().min(0).max(100).nullable(),
|
|
61131
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60275
61132
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
60276
61133
|
lastFetchedAt: number()
|
|
60277
61134
|
});
|
|
@@ -60314,9 +61171,9 @@ var HumidifierStatusSchema = object({
|
|
|
60314
61171
|
/** Whether the humidifier is currently on. */
|
|
60315
61172
|
on: boolean(),
|
|
60316
61173
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
60317
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
61174
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60318
61175
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
60319
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
61176
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60320
61177
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
60321
61178
|
* device has no mode surface. */
|
|
60322
61179
|
mode: string().nullable(),
|
|
@@ -60326,9 +61183,9 @@ var HumidifierStatusSchema = object({
|
|
|
60326
61183
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
60327
61184
|
action: string().nullable(),
|
|
60328
61185
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
60329
|
-
minHumidity: number().nullable(),
|
|
61186
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60330
61187
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
60331
|
-
maxHumidity: number().nullable(),
|
|
61188
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60332
61189
|
/** Ms epoch when the slice was last updated. */
|
|
60333
61190
|
lastChangedAt: number()
|
|
60334
61191
|
});
|
|
@@ -60398,22 +61255,13 @@ var humidifierCapability = {
|
|
|
60398
61255
|
* `sourceInfo`.
|
|
60399
61256
|
*/
|
|
60400
61257
|
var HumiditySensorStatusSchema = object({
|
|
60401
|
-
/** Current relative humidity, 0..100. */
|
|
60402
|
-
percent: number().min(0).max(100).meta({
|
|
60403
|
-
|
|
61258
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
61259
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
61260
|
+
precision: 0,
|
|
60404
61261
|
label: "Humidity"
|
|
60405
|
-
}),
|
|
61262
|
+
})),
|
|
60406
61263
|
/** Ms epoch when the slice was last updated. */
|
|
60407
|
-
lastFetchedAt: number()
|
|
60408
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
60409
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
60410
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
60411
|
-
unit: string().optional(),
|
|
60412
|
-
/** Suggested decimal places for numeric display.
|
|
60413
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
60414
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
60415
|
-
* auto-formatting when absent. */
|
|
60416
|
-
precision: number().int().min(0).max(10).optional()
|
|
61264
|
+
lastFetchedAt: number()
|
|
60417
61265
|
});
|
|
60418
61266
|
var humiditySensorCapability = {
|
|
60419
61267
|
name: "humidity-sensor",
|
|
@@ -60444,12 +61292,7 @@ var humiditySensorCapability = {
|
|
|
60444
61292
|
} } },
|
|
60445
61293
|
/** Clock fields: written, but excluded from the compare that decides
|
|
60446
61294
|
* whether persisting is worth a SQLite commit. */
|
|
60447
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
60448
|
-
customize: {
|
|
60449
|
-
version: 1,
|
|
60450
|
-
advanced: "derive",
|
|
60451
|
-
targets: []
|
|
60452
|
-
}
|
|
61295
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
60453
61296
|
};
|
|
60454
61297
|
/**
|
|
60455
61298
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -60470,7 +61313,7 @@ var ImageStatusSchema = object({
|
|
|
60470
61313
|
* entity exposes no `entity_picture` (yet). */
|
|
60471
61314
|
url: string().nullable(),
|
|
60472
61315
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
60473
|
-
lastUpdated: number().nullable()
|
|
61316
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
60474
61317
|
});
|
|
60475
61318
|
var imageCapability = {
|
|
60476
61319
|
name: "image",
|
|
@@ -60558,19 +61401,19 @@ var NormalizedRangeSchema = object({
|
|
|
60558
61401
|
*/
|
|
60559
61402
|
var ImageSettingsStatusSchema = object({
|
|
60560
61403
|
/** Normalized 0–100. */
|
|
60561
|
-
brightness: number().optional(),
|
|
61404
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60562
61405
|
/** Normalized 0–100. */
|
|
60563
|
-
contrast: number().optional(),
|
|
61406
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60564
61407
|
/** Normalized 0–100. */
|
|
60565
|
-
saturation: number().optional(),
|
|
61408
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60566
61409
|
/** Normalized 0–100. */
|
|
60567
|
-
sharpness: number().optional(),
|
|
61410
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60568
61411
|
mirror: boolean().optional(),
|
|
60569
61412
|
flip: boolean().optional(),
|
|
60570
61413
|
rotate: ImageRotateSchema.optional(),
|
|
60571
61414
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60572
61415
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60573
|
-
warmth: number().optional(),
|
|
61416
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60574
61417
|
exposureMode: ExposureModeSchema.optional(),
|
|
60575
61418
|
backlightMode: BacklightModeSchema.optional(),
|
|
60576
61419
|
lastFetchedAt: number()
|
|
@@ -60849,10 +61692,10 @@ var IntercomAbilitySchema = object({
|
|
|
60849
61692
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60850
61693
|
codecs: array(string()),
|
|
60851
61694
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60852
|
-
sampleRate: number(),
|
|
61695
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60853
61696
|
duplex: _enum(["half", "full"]),
|
|
60854
61697
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60855
|
-
maxBacklogMs: number()
|
|
61698
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60856
61699
|
});
|
|
60857
61700
|
var IntercomStatusSchema = object({
|
|
60858
61701
|
/** True while a talk session is open. */
|
|
@@ -61079,13 +61922,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
61079
61922
|
activity: LawnMowerActivitySchema,
|
|
61080
61923
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
61081
61924
|
* reading. */
|
|
61082
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61925
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61083
61926
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
61084
61927
|
* task is active / progress is unavailable. */
|
|
61085
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61928
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61086
61929
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
61087
61930
|
* or null when unknown. */
|
|
61088
|
-
currentCode: number().nullable(),
|
|
61931
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
61089
61932
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
61090
61933
|
currentCodeLabel: string().nullable(),
|
|
61091
61934
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61538,7 +62381,14 @@ var lockControlCapability = {
|
|
|
61538
62381
|
}),
|
|
61539
62382
|
unlock: method(object({
|
|
61540
62383
|
deviceId: number().int().nonnegative(),
|
|
61541
|
-
code: string().min(1).optional()
|
|
62384
|
+
code: string().min(1).optional(),
|
|
62385
|
+
/**
|
|
62386
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
62387
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
62388
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
62389
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
62390
|
+
*/
|
|
62391
|
+
confirm: boolean().optional()
|
|
61542
62392
|
}), _void(), {
|
|
61543
62393
|
kind: "mutation",
|
|
61544
62394
|
auth: "protected"
|
|
@@ -61575,6 +62425,44 @@ var lockControlCapability = {
|
|
|
61575
62425
|
volatileStateFields: ["lastChangedAt"]
|
|
61576
62426
|
};
|
|
61577
62427
|
/**
|
|
62428
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
62429
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
62430
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
62431
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
62432
|
+
*/
|
|
62433
|
+
var MeterStatusSchema = object({
|
|
62434
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
62435
|
+
lastFetchedAt: number()
|
|
62436
|
+
});
|
|
62437
|
+
var meterCapability = {
|
|
62438
|
+
name: "meter",
|
|
62439
|
+
scope: "device",
|
|
62440
|
+
deviceNative: true,
|
|
62441
|
+
mode: "singleton",
|
|
62442
|
+
deviceTypes: [DeviceType.Sensor],
|
|
62443
|
+
methods: {},
|
|
62444
|
+
status: {
|
|
62445
|
+
schema: MeterStatusSchema,
|
|
62446
|
+
kind: "push"
|
|
62447
|
+
},
|
|
62448
|
+
runtimeState: MeterStatusSchema,
|
|
62449
|
+
/**
|
|
62450
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
62451
|
+
* history integral. A restart shows it only until the history pass
|
|
62452
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
62453
|
+
*
|
|
62454
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
62455
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
62456
|
+
*/
|
|
62457
|
+
durability: "restored",
|
|
62458
|
+
history: { fields: { value: {
|
|
62459
|
+
kind: "counter",
|
|
62460
|
+
deadband: .001,
|
|
62461
|
+
minIntervalMs: 6e4
|
|
62462
|
+
} } },
|
|
62463
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
62464
|
+
};
|
|
62465
|
+
/**
|
|
61578
62466
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61579
62467
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61580
62468
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -61618,7 +62506,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61618
62506
|
state: MediaPlayerStateSchema,
|
|
61619
62507
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61620
62508
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61621
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
62509
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61622
62510
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61623
62511
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61624
62512
|
isMuted: boolean().nullable(),
|
|
@@ -61631,10 +62519,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61631
62519
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61632
62520
|
/** Current playback position in ms. Null when not seekable or
|
|
61633
62521
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61634
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
62522
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61635
62523
|
/** Total duration of the current media in ms. Null when unknown
|
|
61636
62524
|
* (live stream) or nothing is playing. */
|
|
61637
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
62525
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61638
62526
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61639
62527
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61640
62528
|
shuffle: boolean().nullable(),
|
|
@@ -61943,7 +62831,7 @@ var motionCustomize = {
|
|
|
61943
62831
|
eventName: "onMotionChanged"
|
|
61944
62832
|
},
|
|
61945
62833
|
deviceTypes: [DeviceType.Camera],
|
|
61946
|
-
apply: "
|
|
62834
|
+
apply: "add",
|
|
61947
62835
|
applyAuthority: {
|
|
61948
62836
|
kind: "camera-sensors",
|
|
61949
62837
|
timeoutField: "motionCooldownMs"
|
|
@@ -62015,7 +62903,7 @@ var MotionStatusSchema = object({
|
|
|
62015
62903
|
* it, every provider seeded it at boot, and every session left it
|
|
62016
62904
|
* `detected: true` after its detach.
|
|
62017
62905
|
*/
|
|
62018
|
-
autoClearAfterMs: number().nullable()
|
|
62906
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
62019
62907
|
});
|
|
62020
62908
|
/**
|
|
62021
62909
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -62052,12 +62940,18 @@ var motionCapability = {
|
|
|
62052
62940
|
methods: {
|
|
62053
62941
|
/**
|
|
62054
62942
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
62055
|
-
* for consumers that don't need the full status object
|
|
62056
|
-
*
|
|
62057
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
62058
|
-
* consumer.
|
|
62943
|
+
* for consumers that don't need the full status object. A composed
|
|
62944
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
62059
62945
|
*/
|
|
62060
62946
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62947
|
+
/**
|
|
62948
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62949
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62950
|
+
*/
|
|
62951
|
+
composedMethods: { isDetected: {
|
|
62952
|
+
kind: "slice",
|
|
62953
|
+
field: "detected"
|
|
62954
|
+
} },
|
|
62061
62955
|
events: {
|
|
62062
62956
|
/**
|
|
62063
62957
|
* Fires every time the runner transitions a camera between
|
|
@@ -62197,7 +63091,7 @@ var MotionZoneRegionSchema = object({
|
|
|
62197
63091
|
* the grid region(s). */
|
|
62198
63092
|
var MotionZoneStatusSchema = object({
|
|
62199
63093
|
enabled: boolean(),
|
|
62200
|
-
sensitivity: number(),
|
|
63094
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
62201
63095
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
62202
63096
|
regions: array(MotionZoneRegionSchema),
|
|
62203
63097
|
lastFetchedAt: number()
|
|
@@ -62567,7 +63461,7 @@ var NavigationStatusSchema = object({
|
|
|
62567
63461
|
following: boolean(),
|
|
62568
63462
|
flash: boolean(),
|
|
62569
63463
|
lightMode: NavigationLightModeSchema,
|
|
62570
|
-
lightLevel: number().min(40).max(100),
|
|
63464
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62571
63465
|
/** Ms epoch when the slice was last updated. */
|
|
62572
63466
|
lastChangedAt: number()
|
|
62573
63467
|
});
|
|
@@ -62701,13 +63595,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62701
63595
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62702
63596
|
* SKIP a null rather than coerce it.
|
|
62703
63597
|
*/
|
|
62704
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63598
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62705
63599
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62706
|
-
rssiDbm: number().optional(),
|
|
63600
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62707
63601
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62708
63602
|
ssid: string().optional(),
|
|
62709
63603
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62710
|
-
lastUpdated: number()
|
|
63604
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62711
63605
|
});
|
|
62712
63606
|
var networkLinkCapability = {
|
|
62713
63607
|
name: "network-link",
|
|
@@ -63092,7 +63986,7 @@ var NotifierStatusSchema = object({
|
|
|
63092
63986
|
lastError: string().nullable(),
|
|
63093
63987
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
63094
63988
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
63095
|
-
queueDepth: number().int().nonnegative(),
|
|
63989
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
63096
63990
|
/** Per-feature capability matrix — authoritative source for the
|
|
63097
63991
|
* compose-form field gating. */
|
|
63098
63992
|
supports: NotifierSupportsSchema
|
|
@@ -63184,11 +64078,9 @@ onSent: { data: object({
|
|
|
63184
64078
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
63185
64079
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
63186
64080
|
*
|
|
63187
|
-
* The
|
|
63188
|
-
*
|
|
63189
|
-
*
|
|
63190
|
-
* The UI reads them directly from the slice — they are the single source
|
|
63191
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
64081
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
64082
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
64083
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
63192
64084
|
*
|
|
63193
64085
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
63194
64086
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -63197,15 +64089,8 @@ onSent: { data: object({
|
|
|
63197
64089
|
* numeric values land here.
|
|
63198
64090
|
*/
|
|
63199
64091
|
var NumericSensorStatusSchema = object({
|
|
63200
|
-
|
|
63201
|
-
|
|
63202
|
-
* Populated live from the upstream source on each state push.
|
|
63203
|
-
* Absent for unitless sensors. */
|
|
63204
|
-
unit: string().optional(),
|
|
63205
|
-
/** Suggested decimal places for numeric display.
|
|
63206
|
-
* Populated live from the upstream source when provided.
|
|
63207
|
-
* Falls back to auto-formatting when absent. */
|
|
63208
|
-
precision: number().int().min(0).max(10).optional(),
|
|
64092
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
64093
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
63209
64094
|
/** Ms epoch when the slice was last updated. */
|
|
63210
64095
|
lastFetchedAt: number()
|
|
63211
64096
|
});
|
|
@@ -63229,11 +64114,11 @@ var numericSensorCapability = {
|
|
|
63229
64114
|
*/
|
|
63230
64115
|
durability: "restored",
|
|
63231
64116
|
/**
|
|
63232
|
-
* History (D850): recorded series. The unit is
|
|
64117
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
64118
|
+
* resolved when the series is read — the cap has no single unit.
|
|
63233
64119
|
*/
|
|
63234
64120
|
history: { fields: { value: {
|
|
63235
64121
|
kind: "gauge",
|
|
63236
|
-
unitFrom: "unit",
|
|
63237
64122
|
minIntervalMs: 3e4
|
|
63238
64123
|
} } },
|
|
63239
64124
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -63571,23 +64456,26 @@ var PetFeederStatusSchema = object({
|
|
|
63571
64456
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
63572
64457
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
63573
64458
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
63574
|
-
foodLevel: number().nullable(),
|
|
64459
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
63575
64460
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63576
64461
|
* single-hopper models. */
|
|
63577
|
-
food1: number().nullable(),
|
|
64462
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63578
64463
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63579
64464
|
* single-hopper models. */
|
|
63580
|
-
food2: number().nullable(),
|
|
64465
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63581
64466
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63582
64467
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63583
64468
|
* below the feeder's low threshold. */
|
|
63584
64469
|
lowFood: boolean(),
|
|
63585
64470
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63586
64471
|
* device has no battery reading. */
|
|
63587
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63588
|
-
/**
|
|
63589
|
-
*
|
|
63590
|
-
|
|
64472
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64473
|
+
/**
|
|
64474
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
64475
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
64476
|
+
* model has no desiccant sensor.
|
|
64477
|
+
*/
|
|
64478
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63591
64479
|
/** True while a feed is in progress. */
|
|
63592
64480
|
feeding: boolean(),
|
|
63593
64481
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63598,7 +64486,7 @@ var PetFeederStatusSchema = object({
|
|
|
63598
64486
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63599
64487
|
error: string().nullable(),
|
|
63600
64488
|
/** Raw device error code (0 / null = no error). */
|
|
63601
|
-
errorCode: number().nullable(),
|
|
64489
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63602
64490
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63603
64491
|
isDualHopper: boolean(),
|
|
63604
64492
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63608,7 +64496,7 @@ var PetFeederStatusSchema = object({
|
|
|
63608
64496
|
/** Play a chime when dispensing. */
|
|
63609
64497
|
feedSound: boolean(),
|
|
63610
64498
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63611
|
-
volume: number(),
|
|
64499
|
+
volume: number().meta(readingMeta("none")),
|
|
63612
64500
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63613
64501
|
lastFetchedAt: number()
|
|
63614
64502
|
});
|
|
@@ -63727,7 +64615,7 @@ var petFeederCapability = {
|
|
|
63727
64615
|
},
|
|
63728
64616
|
desiccantLeftDays: {
|
|
63729
64617
|
kind: "gauge",
|
|
63730
|
-
unit: "
|
|
64618
|
+
unit: "s"
|
|
63731
64619
|
}
|
|
63732
64620
|
} }
|
|
63733
64621
|
};
|
|
@@ -64128,43 +65016,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
64128
65016
|
*/
|
|
64129
65017
|
var PowerMeterStatusSchema = object({
|
|
64130
65018
|
/** Instantaneous power draw in watts. */
|
|
64131
|
-
watts: number().optional().meta({
|
|
64132
|
-
unit: "W",
|
|
64133
|
-
label: "Power"
|
|
64134
|
-
}),
|
|
65019
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
64135
65020
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
64136
|
-
kwhTotal: number().optional().meta({
|
|
64137
|
-
unit: "kWh",
|
|
64138
|
-
label: "Energy"
|
|
64139
|
-
}),
|
|
65021
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
64140
65022
|
/** Voltage in volts. */
|
|
64141
|
-
volts: number().optional(),
|
|
65023
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
64142
65024
|
/** Current in amperes. */
|
|
64143
|
-
amps: number().optional(),
|
|
64144
|
-
/** Apparent power in volt-amperes
|
|
64145
|
-
va: number().optional(),
|
|
65025
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
65026
|
+
/** Apparent power in volt-amperes. */
|
|
65027
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
64146
65028
|
/** Power factor (0..1) if reported. */
|
|
64147
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
65029
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
64148
65030
|
/** Ms epoch when the slice was last updated. */
|
|
64149
|
-
lastFetchedAt: number()
|
|
64150
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
64151
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
64152
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
64153
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
64154
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
64155
|
-
unit: string().optional(),
|
|
64156
|
-
/** Suggested decimal places for numeric display.
|
|
64157
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64158
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64159
|
-
* auto-formatting when absent. */
|
|
64160
|
-
precision: number().int().min(0).max(10).optional()
|
|
65031
|
+
lastFetchedAt: number()
|
|
64161
65032
|
});
|
|
65033
|
+
/**
|
|
65034
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
65035
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
65036
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
65037
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
65038
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
65039
|
+
*/
|
|
65040
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
65041
|
+
DeviceType.Sensor,
|
|
65042
|
+
DeviceType.Switch,
|
|
65043
|
+
DeviceType.Light,
|
|
65044
|
+
DeviceType.Fan,
|
|
65045
|
+
DeviceType.Climate,
|
|
65046
|
+
DeviceType.Thermostat,
|
|
65047
|
+
DeviceType.Humidifier,
|
|
65048
|
+
DeviceType.WaterHeater,
|
|
65049
|
+
DeviceType.MediaPlayer,
|
|
65050
|
+
DeviceType.Washer,
|
|
65051
|
+
DeviceType.Dryer,
|
|
65052
|
+
DeviceType.Dishwasher,
|
|
65053
|
+
DeviceType.Vacuum,
|
|
65054
|
+
DeviceType.LawnMower,
|
|
65055
|
+
DeviceType.PetFeeder
|
|
65056
|
+
];
|
|
65057
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
65058
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
65059
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
65060
|
+
function powerTarget(id, unit) {
|
|
65061
|
+
return {
|
|
65062
|
+
id,
|
|
65063
|
+
cardinality: "scalar",
|
|
65064
|
+
vocabulary: {
|
|
65065
|
+
cap: "power-meter",
|
|
65066
|
+
stateField: id
|
|
65067
|
+
},
|
|
65068
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
65069
|
+
apply: "add",
|
|
65070
|
+
path: id,
|
|
65071
|
+
sources: [{
|
|
65072
|
+
kind: "numeric",
|
|
65073
|
+
requiredUnit: unit,
|
|
65074
|
+
transforms: [{ kind: "identity" }]
|
|
65075
|
+
}],
|
|
65076
|
+
companions: [{
|
|
65077
|
+
kind: "clock",
|
|
65078
|
+
path: "lastFetchedAt",
|
|
65079
|
+
when: "always"
|
|
65080
|
+
}],
|
|
65081
|
+
sourceReport: { status: "assignment-status" },
|
|
65082
|
+
advancedExpression: true
|
|
65083
|
+
};
|
|
65084
|
+
}
|
|
65085
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
65086
|
+
var powerMeterCustomize = {
|
|
65087
|
+
version: 1,
|
|
65088
|
+
targets: [
|
|
65089
|
+
powerTarget("watts", "W"),
|
|
65090
|
+
powerTarget("kwhTotal", "kWh"),
|
|
65091
|
+
powerTarget("volts", "V"),
|
|
65092
|
+
powerTarget("amps", "A")
|
|
65093
|
+
]
|
|
65094
|
+
};
|
|
64162
65095
|
var powerMeterCapability = {
|
|
64163
65096
|
name: "power-meter",
|
|
64164
65097
|
scope: "device",
|
|
64165
65098
|
deviceNative: true,
|
|
64166
65099
|
mode: "singleton",
|
|
64167
|
-
deviceTypes:
|
|
65100
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
64168
65101
|
methods: {},
|
|
64169
65102
|
status: {
|
|
64170
65103
|
schema: PowerMeterStatusSchema,
|
|
@@ -64222,11 +65155,7 @@ var powerMeterCapability = {
|
|
|
64222
65155
|
/** Clock fields: written, but excluded from the compare that decides
|
|
64223
65156
|
* whether persisting is worth a SQLite commit. */
|
|
64224
65157
|
volatileStateFields: ["lastFetchedAt"],
|
|
64225
|
-
customize:
|
|
64226
|
-
version: 1,
|
|
64227
|
-
advanced: "derive",
|
|
64228
|
-
targets: []
|
|
64229
|
-
}
|
|
65158
|
+
customize: powerMeterCustomize
|
|
64230
65159
|
};
|
|
64231
65160
|
/**
|
|
64232
65161
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -64246,11 +65175,11 @@ var powerMeterCapability = {
|
|
|
64246
65175
|
*/
|
|
64247
65176
|
var GpsLocationSchema = object({
|
|
64248
65177
|
/** Latitude in decimal degrees, -90..90. */
|
|
64249
|
-
latitude: number().min(-90).max(90),
|
|
65178
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
64250
65179
|
/** Longitude in decimal degrees, -180..180. */
|
|
64251
|
-
longitude: number().min(-180).max(180),
|
|
65180
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
64252
65181
|
/** Reported accuracy in meters (lower = better). */
|
|
64253
|
-
accuracyMeters: number().nonnegative()
|
|
65182
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
64254
65183
|
});
|
|
64255
65184
|
var PresenceStatusSchema = object({
|
|
64256
65185
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -64262,7 +65191,7 @@ var PresenceStatusSchema = object({
|
|
|
64262
65191
|
gps: GpsLocationSchema.nullable(),
|
|
64263
65192
|
/** Optional battery level of the tracking device (0..100). Null
|
|
64264
65193
|
* when not reported. */
|
|
64265
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
65194
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64266
65195
|
/** Ms epoch when the slice was last updated. */
|
|
64267
65196
|
lastChangedAt: number()
|
|
64268
65197
|
});
|
|
@@ -64312,19 +65241,10 @@ var presenceCapability = {
|
|
|
64312
65241
|
* `sourceInfo`.
|
|
64313
65242
|
*/
|
|
64314
65243
|
var PressureSensorStatusSchema = object({
|
|
64315
|
-
/** Current pressure in hPa. */
|
|
64316
|
-
hpa: number(),
|
|
65244
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
65245
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
64317
65246
|
/** Ms epoch when the slice was last updated. */
|
|
64318
|
-
lastFetchedAt: number()
|
|
64319
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64320
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64321
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
64322
|
-
unit: string().optional(),
|
|
64323
|
-
/** Suggested decimal places for numeric display.
|
|
64324
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64325
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64326
|
-
* auto-formatting when absent. */
|
|
64327
|
-
precision: number().int().min(0).max(10).optional()
|
|
65247
|
+
lastFetchedAt: number()
|
|
64328
65248
|
});
|
|
64329
65249
|
var pressureSensorCapability = {
|
|
64330
65250
|
name: "pressure-sensor",
|
|
@@ -64850,8 +65770,8 @@ var ptzCapability = {
|
|
|
64850
65770
|
};
|
|
64851
65771
|
var PtzAutotrackSettingsSchema = object({
|
|
64852
65772
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64853
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64854
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65773
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65774
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64855
65775
|
});
|
|
64856
65776
|
/**
|
|
64857
65777
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -65005,7 +65925,7 @@ var RunningStateStatusSchema = object({
|
|
|
65005
65925
|
/** null = unknown — never coerced to false (D393). */
|
|
65006
65926
|
running: boolean().nullable(),
|
|
65007
65927
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
65008
|
-
since: number().nullable(),
|
|
65928
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
65009
65929
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
65010
65930
|
phase: string().nullable(),
|
|
65011
65931
|
/** null until a reading has been published (D393). */
|
|
@@ -65020,7 +65940,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
65020
65940
|
/** Generic Customize target for the running boolean (D936). */
|
|
65021
65941
|
var runningCustomize = {
|
|
65022
65942
|
version: 1,
|
|
65023
|
-
advanced: "derive",
|
|
65024
65943
|
targets: [{
|
|
65025
65944
|
id: "running",
|
|
65026
65945
|
cardinality: "scalar",
|
|
@@ -65029,6 +65948,8 @@ var runningCustomize = {
|
|
|
65029
65948
|
stateField: "running"
|
|
65030
65949
|
},
|
|
65031
65950
|
deviceTypes: [
|
|
65951
|
+
DeviceType.Washer,
|
|
65952
|
+
DeviceType.Dryer,
|
|
65032
65953
|
DeviceType.Dishwasher,
|
|
65033
65954
|
DeviceType.Vacuum,
|
|
65034
65955
|
DeviceType.LawnMower,
|
|
@@ -65040,7 +65961,7 @@ var runningCustomize = {
|
|
|
65040
65961
|
DeviceType.Thermostat,
|
|
65041
65962
|
DeviceType.PetFeeder
|
|
65042
65963
|
],
|
|
65043
|
-
apply: "add
|
|
65964
|
+
apply: "add",
|
|
65044
65965
|
path: "running",
|
|
65045
65966
|
sources: [
|
|
65046
65967
|
{
|
|
@@ -66308,9 +67229,9 @@ var RecordTriggerSchema = _enum([
|
|
|
66308
67229
|
*/
|
|
66309
67230
|
var RecordWindowSchema = object({
|
|
66310
67231
|
trigger: RecordTriggerSchema,
|
|
66311
|
-
day: number().int().min(0).max(6),
|
|
66312
|
-
startMinute: number().int().min(0).max(1439),
|
|
66313
|
-
endMinute: number().int().min(1).max(1440)
|
|
67232
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
67233
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
67234
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
66314
67235
|
});
|
|
66315
67236
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
66316
67237
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -66386,10 +67307,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
66386
67307
|
/** Master "record to the card at all" switch. */
|
|
66387
67308
|
enabled: boolean().nullable(),
|
|
66388
67309
|
overwriteWhenFull: boolean().nullable(),
|
|
66389
|
-
preRecordSec: number().nullable(),
|
|
66390
|
-
postRecordSec: number().nullable(),
|
|
67310
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
67311
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66391
67312
|
/** Length of one recorded file, in minutes. */
|
|
66392
|
-
segmentMinutes: number().nullable(),
|
|
67313
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
66393
67314
|
/** The primary track's weekly windows, flattened. */
|
|
66394
67315
|
windows: array(RecordWindowSchema),
|
|
66395
67316
|
/**
|
|
@@ -66405,7 +67326,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
66405
67326
|
* provider reporting a non-zero count also reports the schedule as not
|
|
66406
67327
|
* writable.
|
|
66407
67328
|
*/
|
|
66408
|
-
unreadableWindows: number(),
|
|
67329
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
66409
67330
|
/**
|
|
66410
67331
|
* The camera is scheduled to record and has NO usable storage.
|
|
66411
67332
|
*
|
|
@@ -67352,7 +68273,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
67352
68273
|
url: string().optional(),
|
|
67353
68274
|
codec: string().optional(),
|
|
67354
68275
|
resolution: CamStreamResolutionSchema.optional(),
|
|
67355
|
-
fps: number().positive().optional(),
|
|
68276
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
67356
68277
|
label: string().optional(),
|
|
67357
68278
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
67358
68279
|
deviceFeatures: array(string()).optional(),
|
|
@@ -67439,18 +68360,18 @@ var StreamProfileSchema = _enum([
|
|
|
67439
68360
|
]);
|
|
67440
68361
|
/** The current encoding config of one stream profile. */
|
|
67441
68362
|
var StreamProfileConfigSchema = object({
|
|
67442
|
-
width: number(),
|
|
67443
|
-
height: number(),
|
|
68363
|
+
width: number().meta(readingMeta("none")),
|
|
68364
|
+
height: number().meta(readingMeta("none")),
|
|
67444
68365
|
codec: _enum(["h264", "h265"]),
|
|
67445
|
-
framerate: number(),
|
|
67446
|
-
bitrate: number(),
|
|
68366
|
+
framerate: number().meta(readingMeta("rate")),
|
|
68367
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
67447
68368
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
67448
68369
|
encoderProfile: _enum([
|
|
67449
68370
|
"high",
|
|
67450
68371
|
"main",
|
|
67451
68372
|
"baseline"
|
|
67452
68373
|
]).optional(),
|
|
67453
|
-
gop: number().optional(),
|
|
68374
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
67454
68375
|
/**
|
|
67455
68376
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
67456
68377
|
*
|
|
@@ -67822,7 +68743,8 @@ var switchCapability = {
|
|
|
67822
68743
|
deviceTypes: [
|
|
67823
68744
|
DeviceType.Switch,
|
|
67824
68745
|
DeviceType.Siren,
|
|
67825
|
-
DeviceType.Light
|
|
68746
|
+
DeviceType.Light,
|
|
68747
|
+
DeviceType.Fan
|
|
67826
68748
|
],
|
|
67827
68749
|
methods: { setState: method(object({
|
|
67828
68750
|
deviceId: number(),
|
|
@@ -67869,12 +68791,7 @@ var switchCapability = {
|
|
|
67869
68791
|
label: "On",
|
|
67870
68792
|
kind: "boolean"
|
|
67871
68793
|
}
|
|
67872
|
-
}] }
|
|
67873
|
-
customize: {
|
|
67874
|
-
version: 1,
|
|
67875
|
-
advanced: "derive",
|
|
67876
|
-
targets: []
|
|
67877
|
-
}
|
|
68794
|
+
}] }
|
|
67878
68795
|
};
|
|
67879
68796
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
67880
68797
|
function hasControlCharacter(value) {
|
|
@@ -68457,35 +69374,21 @@ var tamperCapability = {
|
|
|
68457
69374
|
* entries with `device_class: temperature` and any future native
|
|
68458
69375
|
* thermometer.
|
|
68459
69376
|
*
|
|
68460
|
-
*
|
|
68461
|
-
*
|
|
68462
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
68463
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
68464
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
68465
|
-
* `sourceInfo`.
|
|
69377
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
69378
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
68466
69379
|
*
|
|
68467
69380
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
68468
69381
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
68469
69382
|
* changed" steady state.
|
|
68470
69383
|
*/
|
|
68471
69384
|
var TemperatureSensorStatusSchema = object({
|
|
68472
|
-
/** Current temperature in Celsius. */
|
|
68473
|
-
celsius: number().meta({
|
|
68474
|
-
|
|
69385
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
69386
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
69387
|
+
precision: 1,
|
|
68475
69388
|
label: "Temperature"
|
|
68476
|
-
}),
|
|
69389
|
+
})),
|
|
68477
69390
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
68478
|
-
lastFetchedAt: number()
|
|
68479
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
68480
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
68481
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
68482
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
68483
|
-
unit: string().optional(),
|
|
68484
|
-
/** Suggested decimal places for numeric display.
|
|
68485
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
68486
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
68487
|
-
* auto-formatting when absent. */
|
|
68488
|
-
precision: number().int().min(0).max(10).optional()
|
|
69391
|
+
lastFetchedAt: number()
|
|
68489
69392
|
});
|
|
68490
69393
|
var temperatureSensorCapability = {
|
|
68491
69394
|
name: "temperature-sensor",
|
|
@@ -68516,12 +69419,7 @@ var temperatureSensorCapability = {
|
|
|
68516
69419
|
} } },
|
|
68517
69420
|
/** Clock fields: written, but excluded from the compare that decides
|
|
68518
69421
|
* whether persisting is worth a SQLite commit. */
|
|
68519
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
68520
|
-
customize: {
|
|
68521
|
-
version: 1,
|
|
68522
|
-
advanced: "derive",
|
|
68523
|
-
targets: []
|
|
68524
|
-
}
|
|
69422
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
68525
69423
|
};
|
|
68526
69424
|
/**
|
|
68527
69425
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -68804,16 +69702,16 @@ var VacuumControlStatusSchema = object({
|
|
|
68804
69702
|
]),
|
|
68805
69703
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
68806
69704
|
* reading. */
|
|
68807
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
69705
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68808
69706
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
68809
69707
|
* the vacuum has no speed control. */
|
|
68810
69708
|
fanSpeed: string().nullable(),
|
|
68811
69709
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
68812
69710
|
availableFanSpeeds: array(string()),
|
|
68813
69711
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
68814
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
69712
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68815
69713
|
/** Current error code (0 / null = no error). */
|
|
68816
|
-
errorCode: number().nullable(),
|
|
69714
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
68817
69715
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
68818
69716
|
errorLabel: string().nullable(),
|
|
68819
69717
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -68891,7 +69789,7 @@ var ValveStatusSchema = object({
|
|
|
68891
69789
|
]),
|
|
68892
69790
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
68893
69791
|
* intermediate position surface. */
|
|
68894
|
-
position: number().min(0).max(100).nullable(),
|
|
69792
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68895
69793
|
/** Ms epoch when the slice was last updated. */
|
|
68896
69794
|
lastChangedAt: number()
|
|
68897
69795
|
});
|
|
@@ -68999,9 +69897,9 @@ var vibrationCapability = {
|
|
|
68999
69897
|
*/
|
|
69000
69898
|
var WaterHeaterStatusSchema = object({
|
|
69001
69899
|
/** Current measured temperature. Null when not reported. */
|
|
69002
|
-
currentTemp: number().nullable(),
|
|
69900
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
69003
69901
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
69004
|
-
targetTemp: number().nullable(),
|
|
69902
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
69005
69903
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
69006
69904
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
69007
69905
|
* device reports an unknown state. */
|
|
@@ -69012,9 +69910,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
69012
69910
|
* has no away surface. */
|
|
69013
69911
|
away: boolean().nullable(),
|
|
69014
69912
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
69015
|
-
minTemp: number().nullable(),
|
|
69913
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
69016
69914
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
69017
|
-
maxTemp: number().nullable(),
|
|
69915
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
69018
69916
|
/** Ms epoch when the slice was last updated. */
|
|
69019
69917
|
lastChangedAt: number()
|
|
69020
69918
|
});
|
|
@@ -69099,25 +69997,18 @@ var waterHeaterCapability = {
|
|
|
69099
69997
|
* Forecast deferred — current conditions only for v1.
|
|
69100
69998
|
*/
|
|
69101
69999
|
var WeatherStatusSchema = object({
|
|
69102
|
-
/** Verbatim
|
|
69103
|
-
* when no condition has been reported yet. */
|
|
70000
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
69104
70001
|
condition: string().nullable(),
|
|
69105
|
-
/** Current temperature in
|
|
69106
|
-
temperature: number().nullable(),
|
|
69107
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
69108
|
-
temperatureUnit: string().nullable(),
|
|
70002
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
70003
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
69109
70004
|
/** Relative humidity (0..100). Null when not provided. */
|
|
69110
|
-
humidity: number().min(0).max(100).nullable(),
|
|
69111
|
-
/** Barometric pressure in
|
|
69112
|
-
pressure: number().nullable(),
|
|
69113
|
-
/**
|
|
69114
|
-
|
|
69115
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
69116
|
-
windSpeed: number().nullable(),
|
|
69117
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
69118
|
-
windSpeedUnit: string().nullable(),
|
|
70005
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
70006
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
70007
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
70008
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
70009
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
69119
70010
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
69120
|
-
windBearing: number().nullable(),
|
|
70011
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
69121
70012
|
/** Ms epoch when the slice was last updated. */
|
|
69122
70013
|
lastFetchedAt: number()
|
|
69123
70014
|
});
|
|
@@ -69145,12 +70036,12 @@ var weatherCapability = {
|
|
|
69145
70036
|
*/
|
|
69146
70037
|
durability: "session",
|
|
69147
70038
|
/**
|
|
69148
|
-
* History (D850): recorded series.
|
|
70039
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
69149
70040
|
*/
|
|
69150
70041
|
history: { fields: {
|
|
69151
70042
|
temperature: {
|
|
69152
70043
|
kind: "gauge",
|
|
69153
|
-
|
|
70044
|
+
unit: "°C",
|
|
69154
70045
|
deadband: .2
|
|
69155
70046
|
},
|
|
69156
70047
|
humidity: {
|
|
@@ -69160,12 +70051,12 @@ var weatherCapability = {
|
|
|
69160
70051
|
},
|
|
69161
70052
|
pressure: {
|
|
69162
70053
|
kind: "gauge",
|
|
69163
|
-
|
|
70054
|
+
unit: "hPa",
|
|
69164
70055
|
deadband: .5
|
|
69165
70056
|
},
|
|
69166
70057
|
windSpeed: {
|
|
69167
70058
|
kind: "gauge",
|
|
69168
|
-
|
|
70059
|
+
unit: "m/s",
|
|
69169
70060
|
deadband: .5
|
|
69170
70061
|
}
|
|
69171
70062
|
} }
|
|
@@ -70199,8 +71090,9 @@ function withClipEventLabels(provider, deps) {
|
|
|
70199
71090
|
listClips
|
|
70200
71091
|
};
|
|
70201
71092
|
}
|
|
71093
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
70202
71094
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
70203
|
-
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;
|
|
71095
|
+
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;
|
|
70204
71096
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
70205
71097
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
70206
71098
|
new Set(CAP_NAMES);
|
|
@@ -70529,6 +71421,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70529
71421
|
featureProbe: featureProbeCapability,
|
|
70530
71422
|
flood: floodCapability,
|
|
70531
71423
|
gas: gasCapability,
|
|
71424
|
+
groupActive: groupActiveCapability,
|
|
71425
|
+
groupCommands: groupCommandsCapability,
|
|
71426
|
+
groupStatus: groupStatusCapability,
|
|
70532
71427
|
heatingValve: heatingValveCapability,
|
|
70533
71428
|
humidifier: humidifierCapability,
|
|
70534
71429
|
humiditySensor: humiditySensorCapability,
|
|
@@ -70538,6 +71433,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70538
71433
|
lawnMowerControl: lawnMowerControlCapability,
|
|
70539
71434
|
lockControl: lockControlCapability,
|
|
70540
71435
|
mediaPlayer: mediaPlayerCapability,
|
|
71436
|
+
meter: meterCapability,
|
|
70541
71437
|
motion: motionCapability,
|
|
70542
71438
|
motionTrigger: motionTriggerCapability,
|
|
70543
71439
|
motionZones: motionZonesCapability,
|
|
@@ -71801,7 +72697,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
71801
72697
|
function widenDeviceConstructor(ctor) {
|
|
71802
72698
|
return ctor;
|
|
71803
72699
|
}
|
|
71804
|
-
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;
|
|
72700
|
+
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;
|
|
71805
72701
|
new Set(Object.values(DeviceType));
|
|
71806
72702
|
Object.freeze({
|
|
71807
72703
|
"accessories.getStatus": {
|
|
@@ -71909,6 +72805,13 @@ Object.freeze({
|
|
|
71909
72805
|
access: "view",
|
|
71910
72806
|
role: "admin"
|
|
71911
72807
|
},
|
|
72808
|
+
"addons.getPackageDocs": {
|
|
72809
|
+
capName: "addons",
|
|
72810
|
+
capScope: "system",
|
|
72811
|
+
addonId: null,
|
|
72812
|
+
access: "view",
|
|
72813
|
+
role: "admin"
|
|
72814
|
+
},
|
|
71912
72815
|
"addons.getVersions": {
|
|
71913
72816
|
capName: "addons",
|
|
71914
72817
|
capScope: "system",
|
|
@@ -75017,6 +75920,27 @@ Object.freeze({
|
|
|
75017
75920
|
access: "view",
|
|
75018
75921
|
role: "viewer"
|
|
75019
75922
|
},
|
|
75923
|
+
"groupActive.getStatus": {
|
|
75924
|
+
capName: "group-active",
|
|
75925
|
+
capScope: "device",
|
|
75926
|
+
addonId: null,
|
|
75927
|
+
access: "view",
|
|
75928
|
+
role: "viewer"
|
|
75929
|
+
},
|
|
75930
|
+
"groupCommands.getStatus": {
|
|
75931
|
+
capName: "group-commands",
|
|
75932
|
+
capScope: "device",
|
|
75933
|
+
addonId: null,
|
|
75934
|
+
access: "view",
|
|
75935
|
+
role: "viewer"
|
|
75936
|
+
},
|
|
75937
|
+
"groupStatus.getStatus": {
|
|
75938
|
+
capName: "group-status",
|
|
75939
|
+
capScope: "device",
|
|
75940
|
+
addonId: null,
|
|
75941
|
+
access: "view",
|
|
75942
|
+
role: "viewer"
|
|
75943
|
+
},
|
|
75020
75944
|
"heatingValve.getStatus": {
|
|
75021
75945
|
capName: "heating-valve",
|
|
75022
75946
|
capScope: "device",
|
|
@@ -75969,6 +76893,13 @@ Object.freeze({
|
|
|
75969
76893
|
access: "create",
|
|
75970
76894
|
role: "admin"
|
|
75971
76895
|
},
|
|
76896
|
+
"meter.getStatus": {
|
|
76897
|
+
capName: "meter",
|
|
76898
|
+
capScope: "device",
|
|
76899
|
+
addonId: null,
|
|
76900
|
+
access: "view",
|
|
76901
|
+
role: "viewer"
|
|
76902
|
+
},
|
|
75972
76903
|
"metricsProvider.collectSnapshot": {
|
|
75973
76904
|
capName: "metrics-provider",
|
|
75974
76905
|
capScope: "system",
|
|
@@ -84067,7 +84998,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
84067
84998
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
84068
84999
|
icon: "square"
|
|
84069
85000
|
}
|
|
84070
|
-
}
|
|
85001
|
+
},
|
|
85002
|
+
overrides: { byType: {
|
|
85003
|
+
[DeviceType.Washer]: {
|
|
85004
|
+
state: { running: {
|
|
85005
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
85006
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
85007
|
+
} },
|
|
85008
|
+
events: {
|
|
85009
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
85010
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
85011
|
+
}
|
|
85012
|
+
},
|
|
85013
|
+
[DeviceType.Dryer]: {
|
|
85014
|
+
state: { running: {
|
|
85015
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
85016
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
85017
|
+
} },
|
|
85018
|
+
events: {
|
|
85019
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
85020
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
85021
|
+
}
|
|
85022
|
+
},
|
|
85023
|
+
[DeviceType.Dishwasher]: {
|
|
85024
|
+
state: { running: {
|
|
85025
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
85026
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
85027
|
+
} },
|
|
85028
|
+
events: {
|
|
85029
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
85030
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
85031
|
+
}
|
|
85032
|
+
}
|
|
85033
|
+
} }
|
|
84071
85034
|
},
|
|
84072
85035
|
update: {
|
|
84073
85036
|
scope: "device",
|
|
@@ -84839,6 +85802,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84839
85802
|
icon: "flame"
|
|
84840
85803
|
}]
|
|
84841
85804
|
},
|
|
85805
|
+
"group-active": {
|
|
85806
|
+
scope: "device",
|
|
85807
|
+
noun: t("Group state", "Stato del gruppo")
|
|
85808
|
+
},
|
|
85809
|
+
"group-commands": {
|
|
85810
|
+
scope: "device",
|
|
85811
|
+
noun: t("Group command", "Comando di gruppo")
|
|
85812
|
+
},
|
|
85813
|
+
"group-status": {
|
|
85814
|
+
scope: "device",
|
|
85815
|
+
noun: t("Group", "Gruppo"),
|
|
85816
|
+
state: [
|
|
85817
|
+
{
|
|
85818
|
+
kind: "numeric",
|
|
85819
|
+
field: "included",
|
|
85820
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
85821
|
+
label: t("Reporting", "Rispondono"),
|
|
85822
|
+
icon: "users"
|
|
85823
|
+
},
|
|
85824
|
+
{
|
|
85825
|
+
kind: "numeric",
|
|
85826
|
+
field: "excluded",
|
|
85827
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
85828
|
+
label: t("Excluded", "Esclusi"),
|
|
85829
|
+
icon: "users"
|
|
85830
|
+
},
|
|
85831
|
+
{
|
|
85832
|
+
kind: "numeric",
|
|
85833
|
+
field: "total",
|
|
85834
|
+
quantity: t("the member count", "il numero di membri"),
|
|
85835
|
+
label: t("Members", "Membri"),
|
|
85836
|
+
icon: "sigma"
|
|
85837
|
+
}
|
|
85838
|
+
]
|
|
85839
|
+
},
|
|
84842
85840
|
"humidity-sensor": {
|
|
84843
85841
|
scope: "device",
|
|
84844
85842
|
noun: t("Humidity", "Umidità"),
|
|
@@ -84864,6 +85862,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84864
85862
|
}],
|
|
84865
85863
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
84866
85864
|
},
|
|
85865
|
+
meter: {
|
|
85866
|
+
scope: "device",
|
|
85867
|
+
noun: t("Meter", "Contatore"),
|
|
85868
|
+
state: [{
|
|
85869
|
+
kind: "numeric",
|
|
85870
|
+
field: "value",
|
|
85871
|
+
quantity: t("the total", "il totale"),
|
|
85872
|
+
label: t("Total", "Totale"),
|
|
85873
|
+
icon: "gauge"
|
|
85874
|
+
}]
|
|
85875
|
+
},
|
|
84867
85876
|
"numeric-sensor": {
|
|
84868
85877
|
scope: "device",
|
|
84869
85878
|
noun: t("Sensor", "Sensore"),
|
|
@@ -84872,7 +85881,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84872
85881
|
field: "value",
|
|
84873
85882
|
quantity: t("the reading", "il valore"),
|
|
84874
85883
|
label: t("Reading", "Valore"),
|
|
84875
|
-
unitField: "unit",
|
|
84876
85884
|
icon: "gauge"
|
|
84877
85885
|
}]
|
|
84878
85886
|
},
|
|
@@ -85008,7 +86016,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85008
86016
|
field: "temperature",
|
|
85009
86017
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
85010
86018
|
label: t("Temperature", "Temperatura"),
|
|
85011
|
-
|
|
86019
|
+
unit: "°C",
|
|
85012
86020
|
icon: "thermometer"
|
|
85013
86021
|
},
|
|
85014
86022
|
{
|
|
@@ -85024,7 +86032,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85024
86032
|
field: "windSpeed",
|
|
85025
86033
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
85026
86034
|
label: t("Wind", "Vento"),
|
|
85027
|
-
|
|
86035
|
+
unit: "m/s",
|
|
85028
86036
|
icon: "wind"
|
|
85029
86037
|
},
|
|
85030
86038
|
{
|
|
@@ -85032,7 +86040,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85032
86040
|
field: "pressure",
|
|
85033
86041
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
85034
86042
|
label: t("Pressure", "Pressione"),
|
|
85035
|
-
|
|
86043
|
+
unit: "hPa",
|
|
85036
86044
|
icon: "gauge"
|
|
85037
86045
|
}
|
|
85038
86046
|
]
|
|
@@ -85337,8 +86345,47 @@ function projectAction(cap, action) {
|
|
|
85337
86345
|
};
|
|
85338
86346
|
}
|
|
85339
86347
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
85340
|
-
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;
|
|
86348
|
+
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;
|
|
85341
86349
|
DeviceFeature.BatteryOperated;
|
|
86350
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
86351
|
+
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.";
|
|
86352
|
+
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.";
|
|
86353
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
86354
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
86355
|
+
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.";
|
|
86356
|
+
function withheld(reason) {
|
|
86357
|
+
return {
|
|
86358
|
+
[DeviceType.Washer]: {
|
|
86359
|
+
exported: false,
|
|
86360
|
+
reason
|
|
86361
|
+
},
|
|
86362
|
+
[DeviceType.Dryer]: {
|
|
86363
|
+
exported: false,
|
|
86364
|
+
reason
|
|
86365
|
+
},
|
|
86366
|
+
[DeviceType.Dishwasher]: {
|
|
86367
|
+
exported: false,
|
|
86368
|
+
reason
|
|
86369
|
+
}
|
|
86370
|
+
};
|
|
86371
|
+
}
|
|
86372
|
+
function offered(received) {
|
|
86373
|
+
return {
|
|
86374
|
+
[DeviceType.Washer]: {
|
|
86375
|
+
exported: true,
|
|
86376
|
+
as: received
|
|
86377
|
+
},
|
|
86378
|
+
[DeviceType.Dryer]: {
|
|
86379
|
+
exported: true,
|
|
86380
|
+
as: received
|
|
86381
|
+
},
|
|
86382
|
+
[DeviceType.Dishwasher]: {
|
|
86383
|
+
exported: true,
|
|
86384
|
+
as: received
|
|
86385
|
+
}
|
|
86386
|
+
};
|
|
86387
|
+
}
|
|
86388
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
85342
86389
|
/** Reject after `ms`; always clears its own timer. */
|
|
85343
86390
|
async function withTimeout$1(promise, ms, label) {
|
|
85344
86391
|
let timer;
|
|
@@ -86511,6 +87558,21 @@ Object.freeze({
|
|
|
86511
87558
|
form: "single",
|
|
86512
87559
|
optional: false
|
|
86513
87560
|
}],
|
|
87561
|
+
"groupActive.getStatus": [{
|
|
87562
|
+
name: "deviceId",
|
|
87563
|
+
form: "single",
|
|
87564
|
+
optional: false
|
|
87565
|
+
}],
|
|
87566
|
+
"groupCommands.getStatus": [{
|
|
87567
|
+
name: "deviceId",
|
|
87568
|
+
form: "single",
|
|
87569
|
+
optional: false
|
|
87570
|
+
}],
|
|
87571
|
+
"groupStatus.getStatus": [{
|
|
87572
|
+
name: "deviceId",
|
|
87573
|
+
form: "single",
|
|
87574
|
+
optional: false
|
|
87575
|
+
}],
|
|
86514
87576
|
"heatingValve.getStatus": [{
|
|
86515
87577
|
name: "deviceId",
|
|
86516
87578
|
form: "single",
|
|
@@ -86711,6 +87773,11 @@ Object.freeze({
|
|
|
86711
87773
|
form: "single",
|
|
86712
87774
|
optional: false
|
|
86713
87775
|
}],
|
|
87776
|
+
"meter.getStatus": [{
|
|
87777
|
+
name: "deviceId",
|
|
87778
|
+
form: "single",
|
|
87779
|
+
optional: false
|
|
87780
|
+
}],
|
|
86714
87781
|
"motion.getStatus": [{
|
|
86715
87782
|
name: "deviceId",
|
|
86716
87783
|
form: "single",
|
|
@@ -88318,7 +89385,6 @@ Object.freeze({
|
|
|
88318
89385
|
"network-access": "ingress",
|
|
88319
89386
|
"smtp-provider": "email"
|
|
88320
89387
|
});
|
|
88321
|
-
DeviceType.Camera;
|
|
88322
89388
|
/**
|
|
88323
89389
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
88324
89390
|
* `z.infer`, they do not restate the shape.
|
|
@@ -88495,6 +89561,8 @@ new Map(Object.entries({
|
|
|
88495
89561
|
"detection-blind": "device-events",
|
|
88496
89562
|
"motion-noisy": "device-events",
|
|
88497
89563
|
"motion-calm": "device-events",
|
|
89564
|
+
"package-llm-silent": "device-events",
|
|
89565
|
+
"package-llm-answered": "device-events",
|
|
88498
89566
|
"recording-stalled": "device-events",
|
|
88499
89567
|
"recording-healthy": "device-events",
|
|
88500
89568
|
"recording-degraded": "device-events",
|
|
@@ -88578,6 +89646,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
88578
89646
|
label: "Motion without a subject",
|
|
88579
89647
|
kinds: ["motion-noisy", "motion-calm"]
|
|
88580
89648
|
},
|
|
89649
|
+
{
|
|
89650
|
+
id: "package-llm",
|
|
89651
|
+
family: "device-events",
|
|
89652
|
+
label: "Package confirm",
|
|
89653
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
89654
|
+
},
|
|
88581
89655
|
{
|
|
88582
89656
|
id: "recording",
|
|
88583
89657
|
family: "device-events",
|
|
@@ -88759,6 +89833,8 @@ var DEVICE_EVENTS = [
|
|
|
88759
89833
|
"detection-blind",
|
|
88760
89834
|
"motion-noisy",
|
|
88761
89835
|
"motion-calm",
|
|
89836
|
+
"package-llm-silent",
|
|
89837
|
+
"package-llm-answered",
|
|
88762
89838
|
"recording-stalled",
|
|
88763
89839
|
"recording-healthy",
|
|
88764
89840
|
"recording-degraded",
|
|
@@ -89027,6 +90103,15 @@ new Map([
|
|
|
89027
90103
|
snapshotLabel: "Cameras with constant motion now",
|
|
89028
90104
|
snapshotSection: null
|
|
89029
90105
|
},
|
|
90106
|
+
{
|
|
90107
|
+
id: "package-llm-confirm",
|
|
90108
|
+
family: "device-events",
|
|
90109
|
+
label: "Package confirm (not answering / answering again)",
|
|
90110
|
+
bad: ["package-llm-silent"],
|
|
90111
|
+
recovery: ["package-llm-answered"],
|
|
90112
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
90113
|
+
snapshotSection: null
|
|
90114
|
+
},
|
|
89030
90115
|
{
|
|
89031
90116
|
id: "recording-health",
|
|
89032
90117
|
family: "device-events",
|