@camstack/addon-terminal 0.1.153 → 0.1.155
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +26 -0
- package/dist/addon.js +1607 -522
- package/dist/addon.mjs +1607 -522
- package/package.json +4 -2
package/dist/addon.js
CHANGED
|
@@ -31,7 +31,7 @@ let node_module = require("node:module");
|
|
|
31
31
|
let sharp = require("sharp");
|
|
32
32
|
sharp = __toESM(sharp);
|
|
33
33
|
let node_http = require("node:http");
|
|
34
|
-
//#region ../types/dist/event-category-
|
|
34
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
35
35
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
36
36
|
EventCategory["SystemBoot"] = "system.boot";
|
|
37
37
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -357,6 +357,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
357
357
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
358
358
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
359
359
|
/**
|
|
360
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
361
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
362
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
363
|
+
*/
|
|
364
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
365
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
366
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
367
|
+
/**
|
|
360
368
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
361
369
|
* (a settings change via `setAgentInferenceDevices` /
|
|
362
370
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5466,7 +5474,7 @@ var ZodIssueCode = {
|
|
|
5466
5474
|
var ZodFirstPartyTypeKind;
|
|
5467
5475
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5468
5476
|
//#endregion
|
|
5469
|
-
//#region ../types/dist/sleep
|
|
5477
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5470
5478
|
/**
|
|
5471
5479
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5472
5480
|
* window to float samples (D455).
|
|
@@ -8020,6 +8028,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
8020
8028
|
}).strict();
|
|
8021
8029
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8022
8030
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8031
|
+
var READING_QUANTITIES = [
|
|
8032
|
+
"temperature",
|
|
8033
|
+
"pressure",
|
|
8034
|
+
"speed",
|
|
8035
|
+
"precipitation",
|
|
8036
|
+
"precipitation-rate",
|
|
8037
|
+
"length",
|
|
8038
|
+
"area",
|
|
8039
|
+
"illuminance",
|
|
8040
|
+
"irradiance",
|
|
8041
|
+
"power",
|
|
8042
|
+
"energy",
|
|
8043
|
+
"voltage",
|
|
8044
|
+
"current",
|
|
8045
|
+
"apparent-power",
|
|
8046
|
+
"humidity",
|
|
8047
|
+
"percentage",
|
|
8048
|
+
"concentration-volume",
|
|
8049
|
+
"concentration-mass",
|
|
8050
|
+
"concentration-ppb",
|
|
8051
|
+
"volume",
|
|
8052
|
+
"duration",
|
|
8053
|
+
"duration-ms",
|
|
8054
|
+
"information",
|
|
8055
|
+
"sound-level",
|
|
8056
|
+
"signal-level",
|
|
8057
|
+
"colour-temperature",
|
|
8058
|
+
"angle",
|
|
8059
|
+
"bitrate",
|
|
8060
|
+
"rate",
|
|
8061
|
+
"mass",
|
|
8062
|
+
"index",
|
|
8063
|
+
"ratio",
|
|
8064
|
+
"count",
|
|
8065
|
+
"none",
|
|
8066
|
+
"device"
|
|
8067
|
+
];
|
|
8068
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8069
|
+
new Set(READING_QUANTITIES);
|
|
8070
|
+
/**
|
|
8071
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8072
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8073
|
+
*/
|
|
8074
|
+
var QUANTITY_BASE = {
|
|
8075
|
+
temperature: "°C",
|
|
8076
|
+
pressure: "hPa",
|
|
8077
|
+
speed: "m/s",
|
|
8078
|
+
precipitation: "mm",
|
|
8079
|
+
"precipitation-rate": "mm/h",
|
|
8080
|
+
length: "m",
|
|
8081
|
+
area: "m²",
|
|
8082
|
+
illuminance: "lx",
|
|
8083
|
+
irradiance: "W/m²",
|
|
8084
|
+
power: "W",
|
|
8085
|
+
energy: "kWh",
|
|
8086
|
+
voltage: "V",
|
|
8087
|
+
current: "A",
|
|
8088
|
+
"apparent-power": "VA",
|
|
8089
|
+
humidity: "%",
|
|
8090
|
+
percentage: "%",
|
|
8091
|
+
"concentration-volume": "ppm",
|
|
8092
|
+
"concentration-mass": "µg/m³",
|
|
8093
|
+
"concentration-ppb": "ppb",
|
|
8094
|
+
volume: "L",
|
|
8095
|
+
duration: "s",
|
|
8096
|
+
"duration-ms": "ms",
|
|
8097
|
+
information: "B",
|
|
8098
|
+
"sound-level": "dBFS",
|
|
8099
|
+
"signal-level": "dBm",
|
|
8100
|
+
"colour-temperature": "mired",
|
|
8101
|
+
angle: "°",
|
|
8102
|
+
bitrate: "kbps",
|
|
8103
|
+
rate: "fps",
|
|
8104
|
+
mass: "kg",
|
|
8105
|
+
index: "none",
|
|
8106
|
+
ratio: "none",
|
|
8107
|
+
count: "none",
|
|
8108
|
+
none: "none",
|
|
8109
|
+
device: "device"
|
|
8110
|
+
};
|
|
8111
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8112
|
+
function baseUnitOf(quantity) {
|
|
8113
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8114
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8115
|
+
return symbol;
|
|
8116
|
+
}
|
|
8117
|
+
function readingMeta(quantity, extras) {
|
|
8118
|
+
return {
|
|
8119
|
+
quantity,
|
|
8120
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8121
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8122
|
+
};
|
|
8123
|
+
}
|
|
8023
8124
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8024
8125
|
var CamProfileSchema = _enum([
|
|
8025
8126
|
"high",
|
|
@@ -8047,8 +8148,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8047
8148
|
"derived"
|
|
8048
8149
|
]);
|
|
8049
8150
|
var CamStreamResolutionSchema = object({
|
|
8050
|
-
width: number().int().positive(),
|
|
8051
|
-
height: number().int().positive()
|
|
8151
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8152
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8052
8153
|
});
|
|
8053
8154
|
var CameraStreamSchema = object({
|
|
8054
8155
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8625,6 +8726,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8625
8726
|
"filesystem-browse",
|
|
8626
8727
|
"flood",
|
|
8627
8728
|
"gas",
|
|
8729
|
+
"group-active",
|
|
8730
|
+
"group-commands",
|
|
8731
|
+
"group-status",
|
|
8628
8732
|
"heating-valve",
|
|
8629
8733
|
"humidifier",
|
|
8630
8734
|
"humidity-sensor",
|
|
@@ -8645,6 +8749,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8645
8749
|
"login-method",
|
|
8646
8750
|
"media-player",
|
|
8647
8751
|
"mesh-network",
|
|
8752
|
+
"meter",
|
|
8648
8753
|
"metrics-provider",
|
|
8649
8754
|
"model-convert",
|
|
8650
8755
|
"model-distributor",
|
|
@@ -8754,14 +8859,6 @@ Object.freeze({
|
|
|
8754
8859
|
{
|
|
8755
8860
|
"path": "aqi",
|
|
8756
8861
|
"valueType": "number"
|
|
8757
|
-
},
|
|
8758
|
-
{
|
|
8759
|
-
"path": "unit",
|
|
8760
|
-
"valueType": "string"
|
|
8761
|
-
},
|
|
8762
|
-
{
|
|
8763
|
-
"path": "precision",
|
|
8764
|
-
"valueType": "number"
|
|
8765
8862
|
}
|
|
8766
8863
|
],
|
|
8767
8864
|
"alarm-panel": [
|
|
@@ -8797,20 +8894,10 @@ Object.freeze({
|
|
|
8797
8894
|
"valueType": "boolean"
|
|
8798
8895
|
}
|
|
8799
8896
|
],
|
|
8800
|
-
"ambient-light-sensor": [
|
|
8801
|
-
|
|
8802
|
-
|
|
8803
|
-
|
|
8804
|
-
},
|
|
8805
|
-
{
|
|
8806
|
-
"path": "unit",
|
|
8807
|
-
"valueType": "string"
|
|
8808
|
-
},
|
|
8809
|
-
{
|
|
8810
|
-
"path": "precision",
|
|
8811
|
-
"valueType": "number"
|
|
8812
|
-
}
|
|
8813
|
-
],
|
|
8897
|
+
"ambient-light-sensor": [{
|
|
8898
|
+
"path": "lux",
|
|
8899
|
+
"valueType": "number"
|
|
8900
|
+
}],
|
|
8814
8901
|
"audio-metrics": [
|
|
8815
8902
|
{
|
|
8816
8903
|
"path": "ts",
|
|
@@ -8890,6 +8977,10 @@ Object.freeze({
|
|
|
8890
8977
|
"path": "lastUpdated",
|
|
8891
8978
|
"valueType": "number"
|
|
8892
8979
|
},
|
|
8980
|
+
{
|
|
8981
|
+
"path": "volts",
|
|
8982
|
+
"valueType": "number"
|
|
8983
|
+
},
|
|
8893
8984
|
{
|
|
8894
8985
|
"path": "lastContactAt",
|
|
8895
8986
|
"valueType": "number"
|
|
@@ -9132,10 +9223,6 @@ Object.freeze({
|
|
|
9132
9223
|
"datetime"
|
|
9133
9224
|
]
|
|
9134
9225
|
},
|
|
9135
|
-
{
|
|
9136
|
-
"path": "unit",
|
|
9137
|
-
"valueType": "string"
|
|
9138
|
-
},
|
|
9139
9226
|
{
|
|
9140
9227
|
"path": "min",
|
|
9141
9228
|
"valueType": "number"
|
|
@@ -9147,19 +9234,6 @@ Object.freeze({
|
|
|
9147
9234
|
{
|
|
9148
9235
|
"path": "step",
|
|
9149
9236
|
"valueType": "number"
|
|
9150
|
-
},
|
|
9151
|
-
{
|
|
9152
|
-
"path": "precision",
|
|
9153
|
-
"valueType": "number"
|
|
9154
|
-
},
|
|
9155
|
-
{
|
|
9156
|
-
"path": "format",
|
|
9157
|
-
"valueType": "enum",
|
|
9158
|
-
"enumValues": [
|
|
9159
|
-
"date",
|
|
9160
|
-
"time",
|
|
9161
|
-
"datetime"
|
|
9162
|
-
]
|
|
9163
9237
|
}
|
|
9164
9238
|
],
|
|
9165
9239
|
"cover": [
|
|
@@ -9400,13 +9474,8 @@ Object.freeze({
|
|
|
9400
9474
|
"path": "value",
|
|
9401
9475
|
"valueType": "string"
|
|
9402
9476
|
}, {
|
|
9403
|
-
"path": "
|
|
9404
|
-
"valueType": "
|
|
9405
|
-
"enumValues": [
|
|
9406
|
-
"date",
|
|
9407
|
-
"time",
|
|
9408
|
-
"datetime"
|
|
9409
|
-
]
|
|
9477
|
+
"path": "timestamp",
|
|
9478
|
+
"valueType": "boolean"
|
|
9410
9479
|
}],
|
|
9411
9480
|
"event-emitter": [
|
|
9412
9481
|
{
|
|
@@ -9479,6 +9548,24 @@ Object.freeze({
|
|
|
9479
9548
|
"path": "detected",
|
|
9480
9549
|
"valueType": "boolean"
|
|
9481
9550
|
}],
|
|
9551
|
+
"group-active": [{
|
|
9552
|
+
"path": "active",
|
|
9553
|
+
"valueType": "boolean"
|
|
9554
|
+
}],
|
|
9555
|
+
"group-status": [
|
|
9556
|
+
{
|
|
9557
|
+
"path": "included",
|
|
9558
|
+
"valueType": "number"
|
|
9559
|
+
},
|
|
9560
|
+
{
|
|
9561
|
+
"path": "excluded",
|
|
9562
|
+
"valueType": "number"
|
|
9563
|
+
},
|
|
9564
|
+
{
|
|
9565
|
+
"path": "total",
|
|
9566
|
+
"valueType": "number"
|
|
9567
|
+
}
|
|
9568
|
+
],
|
|
9482
9569
|
"heating-valve": [{
|
|
9483
9570
|
"path": "position",
|
|
9484
9571
|
"valueType": "number"
|
|
@@ -9513,20 +9600,10 @@ Object.freeze({
|
|
|
9513
9600
|
"valueType": "number"
|
|
9514
9601
|
}
|
|
9515
9602
|
],
|
|
9516
|
-
"humidity-sensor": [
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
},
|
|
9521
|
-
{
|
|
9522
|
-
"path": "unit",
|
|
9523
|
-
"valueType": "string"
|
|
9524
|
-
},
|
|
9525
|
-
{
|
|
9526
|
-
"path": "precision",
|
|
9527
|
-
"valueType": "number"
|
|
9528
|
-
}
|
|
9529
|
-
],
|
|
9603
|
+
"humidity-sensor": [{
|
|
9604
|
+
"path": "percent",
|
|
9605
|
+
"valueType": "number"
|
|
9606
|
+
}],
|
|
9530
9607
|
"image": [{
|
|
9531
9608
|
"path": "url",
|
|
9532
9609
|
"valueType": "string"
|
|
@@ -9734,6 +9811,10 @@ Object.freeze({
|
|
|
9734
9811
|
]
|
|
9735
9812
|
}
|
|
9736
9813
|
],
|
|
9814
|
+
"meter": [{
|
|
9815
|
+
"path": "value",
|
|
9816
|
+
"valueType": "number"
|
|
9817
|
+
}],
|
|
9737
9818
|
"motion": [
|
|
9738
9819
|
{
|
|
9739
9820
|
"path": "detected",
|
|
@@ -9865,20 +9946,10 @@ Object.freeze({
|
|
|
9865
9946
|
"valueType": "boolean"
|
|
9866
9947
|
}
|
|
9867
9948
|
],
|
|
9868
|
-
"numeric-sensor": [
|
|
9869
|
-
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
},
|
|
9873
|
-
{
|
|
9874
|
-
"path": "unit",
|
|
9875
|
-
"valueType": "string"
|
|
9876
|
-
},
|
|
9877
|
-
{
|
|
9878
|
-
"path": "precision",
|
|
9879
|
-
"valueType": "number"
|
|
9880
|
-
}
|
|
9881
|
-
],
|
|
9949
|
+
"numeric-sensor": [{
|
|
9950
|
+
"path": "value",
|
|
9951
|
+
"valueType": "number"
|
|
9952
|
+
}],
|
|
9882
9953
|
"pet-feeder": [
|
|
9883
9954
|
{
|
|
9884
9955
|
"path": "foodLevel",
|
|
@@ -9970,14 +10041,6 @@ Object.freeze({
|
|
|
9970
10041
|
{
|
|
9971
10042
|
"path": "powerFactor",
|
|
9972
10043
|
"valueType": "number"
|
|
9973
|
-
},
|
|
9974
|
-
{
|
|
9975
|
-
"path": "unit",
|
|
9976
|
-
"valueType": "string"
|
|
9977
|
-
},
|
|
9978
|
-
{
|
|
9979
|
-
"path": "precision",
|
|
9980
|
-
"valueType": "number"
|
|
9981
10044
|
}
|
|
9982
10045
|
],
|
|
9983
10046
|
"presence": [
|
|
@@ -10006,20 +10069,10 @@ Object.freeze({
|
|
|
10006
10069
|
"valueType": "number"
|
|
10007
10070
|
}
|
|
10008
10071
|
],
|
|
10009
|
-
"pressure-sensor": [
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
},
|
|
10014
|
-
{
|
|
10015
|
-
"path": "unit",
|
|
10016
|
-
"valueType": "string"
|
|
10017
|
-
},
|
|
10018
|
-
{
|
|
10019
|
-
"path": "precision",
|
|
10020
|
-
"valueType": "number"
|
|
10021
|
-
}
|
|
10022
|
-
],
|
|
10072
|
+
"pressure-sensor": [{
|
|
10073
|
+
"path": "hpa",
|
|
10074
|
+
"valueType": "number"
|
|
10075
|
+
}],
|
|
10023
10076
|
"privacy-mask": [{
|
|
10024
10077
|
"path": "enabled",
|
|
10025
10078
|
"valueType": "boolean"
|
|
@@ -10330,20 +10383,10 @@ Object.freeze({
|
|
|
10330
10383
|
"path": "tampered",
|
|
10331
10384
|
"valueType": "boolean"
|
|
10332
10385
|
}],
|
|
10333
|
-
"temperature-sensor": [
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
},
|
|
10338
|
-
{
|
|
10339
|
-
"path": "unit",
|
|
10340
|
-
"valueType": "string"
|
|
10341
|
-
},
|
|
10342
|
-
{
|
|
10343
|
-
"path": "precision",
|
|
10344
|
-
"valueType": "number"
|
|
10345
|
-
}
|
|
10346
|
-
],
|
|
10386
|
+
"temperature-sensor": [{
|
|
10387
|
+
"path": "celsius",
|
|
10388
|
+
"valueType": "number"
|
|
10389
|
+
}],
|
|
10347
10390
|
"update": [
|
|
10348
10391
|
{
|
|
10349
10392
|
"path": "currentVersion",
|
|
@@ -10454,10 +10497,6 @@ Object.freeze({
|
|
|
10454
10497
|
"path": "temperature",
|
|
10455
10498
|
"valueType": "number"
|
|
10456
10499
|
},
|
|
10457
|
-
{
|
|
10458
|
-
"path": "temperatureUnit",
|
|
10459
|
-
"valueType": "string"
|
|
10460
|
-
},
|
|
10461
10500
|
{
|
|
10462
10501
|
"path": "humidity",
|
|
10463
10502
|
"valueType": "number"
|
|
@@ -10466,18 +10505,10 @@ Object.freeze({
|
|
|
10466
10505
|
"path": "pressure",
|
|
10467
10506
|
"valueType": "number"
|
|
10468
10507
|
},
|
|
10469
|
-
{
|
|
10470
|
-
"path": "pressureUnit",
|
|
10471
|
-
"valueType": "string"
|
|
10472
|
-
},
|
|
10473
10508
|
{
|
|
10474
10509
|
"path": "windSpeed",
|
|
10475
10510
|
"valueType": "number"
|
|
10476
10511
|
},
|
|
10477
|
-
{
|
|
10478
|
-
"path": "windSpeedUnit",
|
|
10479
|
-
"valueType": "string"
|
|
10480
|
-
},
|
|
10481
10512
|
{
|
|
10482
10513
|
"path": "windBearing",
|
|
10483
10514
|
"valueType": "number"
|
|
@@ -10527,7 +10558,7 @@ object({
|
|
|
10527
10558
|
params: record(string(), union([string(), number()])).optional()
|
|
10528
10559
|
});
|
|
10529
10560
|
//#endregion
|
|
10530
|
-
//#region ../types/dist/err-msg-
|
|
10561
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10531
10562
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10532
10563
|
DeviceType["Camera"] = "camera";
|
|
10533
10564
|
DeviceType["Hub"] = "hub";
|
|
@@ -10621,8 +10652,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10621
10652
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10622
10653
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10623
10654
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10624
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10655
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10656
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10625
10657
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10658
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10659
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10660
|
+
DeviceType["Washer"] = "washer";
|
|
10661
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10662
|
+
DeviceType["Dryer"] = "dryer";
|
|
10626
10663
|
return DeviceType;
|
|
10627
10664
|
}({});
|
|
10628
10665
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10880,7 +10917,7 @@ function errMsg(err) {
|
|
|
10880
10917
|
return String(err);
|
|
10881
10918
|
}
|
|
10882
10919
|
//#endregion
|
|
10883
|
-
//#region ../types/dist/composition-
|
|
10920
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10884
10921
|
/**
|
|
10885
10922
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10886
10923
|
*
|
|
@@ -11195,6 +11232,13 @@ var table = {
|
|
|
11195
11232
|
apply: () => {
|
|
11196
11233
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11197
11234
|
}
|
|
11235
|
+
},
|
|
11236
|
+
schmitt: {
|
|
11237
|
+
minArgs: 3,
|
|
11238
|
+
maxArgs: 5,
|
|
11239
|
+
apply: () => {
|
|
11240
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11241
|
+
}
|
|
11198
11242
|
}
|
|
11199
11243
|
};
|
|
11200
11244
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11635,15 +11679,232 @@ function validateExpressionSource(src) {
|
|
|
11635
11679
|
}
|
|
11636
11680
|
return null;
|
|
11637
11681
|
}
|
|
11638
|
-
/**
|
|
11639
|
-
|
|
11640
|
-
|
|
11641
|
-
|
|
11682
|
+
/**
|
|
11683
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11684
|
+
*
|
|
11685
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11686
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11687
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11688
|
+
*
|
|
11689
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11690
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11691
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11692
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11693
|
+
* can move later without moving the others.
|
|
11694
|
+
*/
|
|
11695
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11696
|
+
var APPLIANCE_KINDS = [
|
|
11697
|
+
"washer",
|
|
11698
|
+
"dryer",
|
|
11699
|
+
"dishwasher"
|
|
11700
|
+
];
|
|
11701
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11702
|
+
/**
|
|
11703
|
+
* Statistics and integrals over a history read (D944).
|
|
11704
|
+
*
|
|
11705
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11706
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11707
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11708
|
+
* as zero. A truncated read is not published.
|
|
11709
|
+
*/
|
|
11710
|
+
var STATISTIC_STATS = [
|
|
11711
|
+
"min",
|
|
11712
|
+
"max",
|
|
11713
|
+
"mean",
|
|
11714
|
+
"sum",
|
|
11715
|
+
"count",
|
|
11716
|
+
"change"
|
|
11717
|
+
];
|
|
11718
|
+
/**
|
|
11719
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11720
|
+
*
|
|
11721
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11722
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11723
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11724
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11725
|
+
*/
|
|
11726
|
+
var MINUTE_MS = 6e4;
|
|
11727
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11728
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11729
|
+
var ROLLING_SPANS = [
|
|
11730
|
+
"1h",
|
|
11731
|
+
"24h",
|
|
11732
|
+
"2d",
|
|
11733
|
+
"7d",
|
|
11734
|
+
"30d",
|
|
11735
|
+
"custom"
|
|
11736
|
+
];
|
|
11737
|
+
var CALENDAR_PERIODS = [
|
|
11738
|
+
"today",
|
|
11739
|
+
"yesterday",
|
|
11740
|
+
"this-week",
|
|
11741
|
+
"this-month"
|
|
11742
|
+
];
|
|
11743
|
+
var RESET_PERIODS = [
|
|
11744
|
+
"never",
|
|
11745
|
+
"daily",
|
|
11746
|
+
"weekly",
|
|
11747
|
+
"monthly"
|
|
11748
|
+
];
|
|
11749
|
+
5 * MINUTE_MS;
|
|
11750
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11751
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11752
|
+
var rollingWindowObject = object({
|
|
11753
|
+
kind: literal("rolling"),
|
|
11754
|
+
span: _enum(ROLLING_SPANS),
|
|
11755
|
+
customMinutes: number().int().min(5).optional()
|
|
11756
|
+
}).check((payload) => {
|
|
11757
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11758
|
+
code: "custom",
|
|
11759
|
+
message: "a custom range needs a duration in minutes",
|
|
11760
|
+
path: ["customMinutes"],
|
|
11761
|
+
input: payload.value
|
|
11762
|
+
});
|
|
11763
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11764
|
+
code: "custom",
|
|
11765
|
+
message: "only a custom range carries a duration",
|
|
11766
|
+
path: ["customMinutes"],
|
|
11767
|
+
input: payload.value
|
|
11768
|
+
});
|
|
11769
|
+
});
|
|
11770
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11771
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11772
|
+
kind: literal("calendar"),
|
|
11773
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11774
|
+
})]);
|
|
11775
|
+
/**
|
|
11776
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11777
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11778
|
+
* `composition.ts` (D659).
|
|
11779
|
+
*/
|
|
11642
11780
|
var CompositionSourceRefSchema = object({
|
|
11643
11781
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11644
11782
|
addonId: string().min(1),
|
|
11645
11783
|
stableId: string().min(1)
|
|
11646
11784
|
});
|
|
11785
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11786
|
+
"temperature",
|
|
11787
|
+
"humidity",
|
|
11788
|
+
"pressure",
|
|
11789
|
+
"illuminance",
|
|
11790
|
+
"power",
|
|
11791
|
+
"energy",
|
|
11792
|
+
"battery",
|
|
11793
|
+
"numeric",
|
|
11794
|
+
"motion",
|
|
11795
|
+
"contact",
|
|
11796
|
+
"leak",
|
|
11797
|
+
"smoke",
|
|
11798
|
+
"occupancy",
|
|
11799
|
+
"binary",
|
|
11800
|
+
"switch",
|
|
11801
|
+
"light",
|
|
11802
|
+
"fan",
|
|
11803
|
+
"cover",
|
|
11804
|
+
"valve",
|
|
11805
|
+
"lock",
|
|
11806
|
+
"media-player",
|
|
11807
|
+
"climate"
|
|
11808
|
+
];
|
|
11809
|
+
var NUMERIC_AGGREGATES = [
|
|
11810
|
+
"mean",
|
|
11811
|
+
"median",
|
|
11812
|
+
"min",
|
|
11813
|
+
"max",
|
|
11814
|
+
"sum"
|
|
11815
|
+
];
|
|
11816
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11817
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11818
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11819
|
+
var AGGREGATE_REDUCERS = [
|
|
11820
|
+
"mean",
|
|
11821
|
+
"median",
|
|
11822
|
+
"min",
|
|
11823
|
+
"max",
|
|
11824
|
+
"sum",
|
|
11825
|
+
"any",
|
|
11826
|
+
"all"
|
|
11827
|
+
];
|
|
11828
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11829
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11830
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11831
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11832
|
+
var HelperMemberSchema = object({
|
|
11833
|
+
source: CompositionSourceRefSchema,
|
|
11834
|
+
cap: string().min(1),
|
|
11835
|
+
fieldPath: string().min(1)
|
|
11836
|
+
});
|
|
11837
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11838
|
+
object({
|
|
11839
|
+
kind: literal("group"),
|
|
11840
|
+
templateId: GroupTemplateIdSchema,
|
|
11841
|
+
aggregate: AggregateReducerSchema,
|
|
11842
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11843
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11844
|
+
active: ActiveCriterionSchema.optional()
|
|
11845
|
+
}),
|
|
11846
|
+
object({
|
|
11847
|
+
kind: literal("appliance"),
|
|
11848
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11849
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11850
|
+
thresholdWatts: number().positive(),
|
|
11851
|
+
startDwellMs: number().int().nonnegative(),
|
|
11852
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11853
|
+
member: HelperMemberSchema
|
|
11854
|
+
}),
|
|
11855
|
+
object({
|
|
11856
|
+
kind: literal("statistic"),
|
|
11857
|
+
stat: _enum(STATISTIC_STATS),
|
|
11858
|
+
window: StatisticWindowSchema,
|
|
11859
|
+
source: HelperMemberSchema
|
|
11860
|
+
}),
|
|
11861
|
+
object({
|
|
11862
|
+
kind: literal("integral"),
|
|
11863
|
+
reset: _enum(RESET_PERIODS),
|
|
11864
|
+
output: _enum(["energy", "meter"]),
|
|
11865
|
+
source: HelperMemberSchema
|
|
11866
|
+
}),
|
|
11867
|
+
object({
|
|
11868
|
+
kind: literal("threshold"),
|
|
11869
|
+
source: HelperMemberSchema,
|
|
11870
|
+
high: number(),
|
|
11871
|
+
low: number(),
|
|
11872
|
+
onForMs: number().int().nonnegative(),
|
|
11873
|
+
offForMs: number().int().nonnegative()
|
|
11874
|
+
}),
|
|
11875
|
+
object({
|
|
11876
|
+
kind: literal("arithmetic"),
|
|
11877
|
+
op: _enum([
|
|
11878
|
+
"sum",
|
|
11879
|
+
"difference",
|
|
11880
|
+
"ratio"
|
|
11881
|
+
]),
|
|
11882
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11883
|
+
}),
|
|
11884
|
+
object({
|
|
11885
|
+
kind: literal("expression"),
|
|
11886
|
+
expr: string().min(1),
|
|
11887
|
+
inputs: array(object({
|
|
11888
|
+
name: string().min(1),
|
|
11889
|
+
member: HelperMemberSchema
|
|
11890
|
+
})).min(1).max(64),
|
|
11891
|
+
output: _enum(["number", "boolean"])
|
|
11892
|
+
}),
|
|
11893
|
+
object({
|
|
11894
|
+
kind: literal("derivative"),
|
|
11895
|
+
window: RollingWindowSchema,
|
|
11896
|
+
per: _enum([
|
|
11897
|
+
"second",
|
|
11898
|
+
"minute",
|
|
11899
|
+
"hour"
|
|
11900
|
+
]),
|
|
11901
|
+
source: HelperMemberSchema
|
|
11902
|
+
})
|
|
11903
|
+
]);
|
|
11904
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11905
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11906
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11907
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11647
11908
|
/** One field of one capability of one source device. */
|
|
11648
11909
|
var CompositionFieldReadSchema = object({
|
|
11649
11910
|
source: CompositionSourceRefSchema,
|
|
@@ -11687,7 +11948,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11687
11948
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11688
11949
|
CompositionFromSourceSchema,
|
|
11689
11950
|
CompositionExpressionSourceSchema,
|
|
11690
|
-
CompositionCodeSourceSchema
|
|
11951
|
+
CompositionCodeSourceSchema,
|
|
11952
|
+
object({
|
|
11953
|
+
kind: literal("aggregate"),
|
|
11954
|
+
reducer: _enum([
|
|
11955
|
+
"mean",
|
|
11956
|
+
"median",
|
|
11957
|
+
"min",
|
|
11958
|
+
"max",
|
|
11959
|
+
"sum",
|
|
11960
|
+
"any",
|
|
11961
|
+
"all"
|
|
11962
|
+
]),
|
|
11963
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11964
|
+
/**
|
|
11965
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11966
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11967
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11968
|
+
*/
|
|
11969
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11970
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11971
|
+
publish: _enum([
|
|
11972
|
+
"value",
|
|
11973
|
+
"included",
|
|
11974
|
+
"excluded",
|
|
11975
|
+
"total"
|
|
11976
|
+
]),
|
|
11977
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11978
|
+
empty: _enum([
|
|
11979
|
+
"null",
|
|
11980
|
+
"omit",
|
|
11981
|
+
"offline"
|
|
11982
|
+
])
|
|
11983
|
+
}),
|
|
11984
|
+
object({
|
|
11985
|
+
kind: literal("series"),
|
|
11986
|
+
read: CompositionFieldReadSchema,
|
|
11987
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11988
|
+
publish: _enum([
|
|
11989
|
+
"value",
|
|
11990
|
+
"included",
|
|
11991
|
+
"excluded",
|
|
11992
|
+
"total"
|
|
11993
|
+
]),
|
|
11994
|
+
/**
|
|
11995
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11996
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11997
|
+
*/
|
|
11998
|
+
empty: _enum([
|
|
11999
|
+
"null",
|
|
12000
|
+
"omit",
|
|
12001
|
+
"offline"
|
|
12002
|
+
])
|
|
12003
|
+
})
|
|
11691
12004
|
]);
|
|
11692
12005
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11693
12006
|
kind: literal("forward"),
|
|
@@ -11733,7 +12046,13 @@ var CompositionSchema = object({
|
|
|
11733
12046
|
kind: literal("existing"),
|
|
11734
12047
|
device: CompositionSourceRefSchema
|
|
11735
12048
|
})]),
|
|
11736
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12049
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12050
|
+
/**
|
|
12051
|
+
* Present when the block is a helper template. Absent on a free
|
|
12052
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12053
|
+
* never the compiled features.
|
|
12054
|
+
*/
|
|
12055
|
+
helper: HelperSpecSchema.optional()
|
|
11737
12056
|
}).superRefine((composition, ctx) => {
|
|
11738
12057
|
const seen = /* @__PURE__ */ new Set();
|
|
11739
12058
|
composition.features.forEach((feature, index) => {
|
|
@@ -16872,7 +17191,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16872
17191
|
*/
|
|
16873
17192
|
interactiveConnectPath: string().min(1).optional(),
|
|
16874
17193
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16875
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17194
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17195
|
+
/**
|
|
17196
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17197
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17198
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17199
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17200
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17201
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17202
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17203
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17204
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17205
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17206
|
+
* offers it as the default path; the fields the session fills are
|
|
17207
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17208
|
+
*/
|
|
17209
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16876
17210
|
}))
|
|
16877
17211
|
});
|
|
16878
17212
|
var ListInputSchema = object({
|
|
@@ -17973,7 +18307,12 @@ var CompositionProblemSchema = object({
|
|
|
17973
18307
|
"item-field-reserved",
|
|
17974
18308
|
"target-missing",
|
|
17975
18309
|
"target-unreadable",
|
|
17976
|
-
"not-replaceable"
|
|
18310
|
+
"not-replaceable",
|
|
18311
|
+
"native-capability-replace",
|
|
18312
|
+
"mixed-quantity",
|
|
18313
|
+
"helper-mismatch",
|
|
18314
|
+
"member-constraint",
|
|
18315
|
+
"retention"
|
|
17977
18316
|
]),
|
|
17978
18317
|
path: string(),
|
|
17979
18318
|
message: string()
|
|
@@ -17994,7 +18333,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17994
18333
|
"null",
|
|
17995
18334
|
"offline",
|
|
17996
18335
|
"unknown",
|
|
17997
|
-
"release"
|
|
18336
|
+
"release",
|
|
18337
|
+
"omit"
|
|
17998
18338
|
]);
|
|
17999
18339
|
/**
|
|
18000
18340
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18031,9 +18371,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18031
18371
|
reads: array(CompositionFieldReadSchema)
|
|
18032
18372
|
});
|
|
18033
18373
|
/**
|
|
18034
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18035
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18036
|
-
*
|
|
18374
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18375
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18376
|
+
* Replacing a capability the device already serves is refused
|
|
18377
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18378
|
+
* wire for a claim the hub already holds.
|
|
18037
18379
|
*/
|
|
18038
18380
|
var CompositionFeatureModeSchema = _enum([
|
|
18039
18381
|
"new",
|
|
@@ -18204,8 +18546,392 @@ Object.freeze({
|
|
|
18204
18546
|
latchedAt: {
|
|
18205
18547
|
kind: "fixed",
|
|
18206
18548
|
result: ["number", "null"]
|
|
18549
|
+
},
|
|
18550
|
+
schmitt: {
|
|
18551
|
+
kind: "fixed",
|
|
18552
|
+
result: ["boolean", "null"]
|
|
18207
18553
|
}
|
|
18208
18554
|
});
|
|
18555
|
+
/**
|
|
18556
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18557
|
+
* Data, not a form default written into the block.
|
|
18558
|
+
*/
|
|
18559
|
+
var NOW$2 = {
|
|
18560
|
+
fieldPath: "lastFetchedAt",
|
|
18561
|
+
expr: "now"
|
|
18562
|
+
};
|
|
18563
|
+
var CHANGED = {
|
|
18564
|
+
fieldPath: "lastChangedAt",
|
|
18565
|
+
expr: "now"
|
|
18566
|
+
};
|
|
18567
|
+
function numeric(input) {
|
|
18568
|
+
return {
|
|
18569
|
+
...input,
|
|
18570
|
+
family: "numeric",
|
|
18571
|
+
deviceType: DeviceType.Sensor,
|
|
18572
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18573
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18574
|
+
activeWhen: void 0,
|
|
18575
|
+
commandCaps: [],
|
|
18576
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18577
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18578
|
+
accept: [{
|
|
18579
|
+
cap: input.outputCap,
|
|
18580
|
+
fieldPath: input.outputField
|
|
18581
|
+
}]
|
|
18582
|
+
};
|
|
18583
|
+
}
|
|
18584
|
+
function binary(input) {
|
|
18585
|
+
return {
|
|
18586
|
+
...input,
|
|
18587
|
+
family: "binary",
|
|
18588
|
+
deviceType: DeviceType.Sensor,
|
|
18589
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18590
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18591
|
+
activeWhen: void 0,
|
|
18592
|
+
commandCaps: [],
|
|
18593
|
+
quantity: "none",
|
|
18594
|
+
baseUnit: void 0,
|
|
18595
|
+
aggregates: BINARY_AGGREGATES,
|
|
18596
|
+
empty: "offline"
|
|
18597
|
+
};
|
|
18598
|
+
}
|
|
18599
|
+
var GROUP_TEMPLATES = [
|
|
18600
|
+
numeric({
|
|
18601
|
+
id: "temperature",
|
|
18602
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18603
|
+
role: DeviceRole.TemperatureSensor,
|
|
18604
|
+
outputCap: "temperature-sensor",
|
|
18605
|
+
outputField: "celsius",
|
|
18606
|
+
quantity: "temperature",
|
|
18607
|
+
defaultAggregate: "mean",
|
|
18608
|
+
empty: "null",
|
|
18609
|
+
companions: [NOW$2]
|
|
18610
|
+
}),
|
|
18611
|
+
numeric({
|
|
18612
|
+
id: "humidity",
|
|
18613
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18614
|
+
role: DeviceRole.HumiditySensor,
|
|
18615
|
+
outputCap: "humidity-sensor",
|
|
18616
|
+
outputField: "percent",
|
|
18617
|
+
quantity: "humidity",
|
|
18618
|
+
defaultAggregate: "mean",
|
|
18619
|
+
empty: "null",
|
|
18620
|
+
companions: [NOW$2]
|
|
18621
|
+
}),
|
|
18622
|
+
numeric({
|
|
18623
|
+
id: "pressure",
|
|
18624
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18625
|
+
role: DeviceRole.PressureSensor,
|
|
18626
|
+
outputCap: "pressure-sensor",
|
|
18627
|
+
outputField: "hpa",
|
|
18628
|
+
quantity: "pressure",
|
|
18629
|
+
defaultAggregate: "mean",
|
|
18630
|
+
empty: "null",
|
|
18631
|
+
companions: [NOW$2]
|
|
18632
|
+
}),
|
|
18633
|
+
numeric({
|
|
18634
|
+
id: "illuminance",
|
|
18635
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18636
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18637
|
+
outputCap: "ambient-light-sensor",
|
|
18638
|
+
outputField: "lux",
|
|
18639
|
+
quantity: "illuminance",
|
|
18640
|
+
defaultAggregate: "mean",
|
|
18641
|
+
empty: "null",
|
|
18642
|
+
companions: [NOW$2]
|
|
18643
|
+
}),
|
|
18644
|
+
numeric({
|
|
18645
|
+
id: "power",
|
|
18646
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18647
|
+
role: DeviceRole.PowerSensor,
|
|
18648
|
+
outputCap: "power-meter",
|
|
18649
|
+
outputField: "watts",
|
|
18650
|
+
quantity: "power",
|
|
18651
|
+
defaultAggregate: "sum",
|
|
18652
|
+
empty: "omit",
|
|
18653
|
+
companions: [NOW$2]
|
|
18654
|
+
}),
|
|
18655
|
+
numeric({
|
|
18656
|
+
id: "energy",
|
|
18657
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18658
|
+
role: DeviceRole.EnergySensor,
|
|
18659
|
+
outputCap: "power-meter",
|
|
18660
|
+
outputField: "kwhTotal",
|
|
18661
|
+
quantity: "energy",
|
|
18662
|
+
defaultAggregate: "sum",
|
|
18663
|
+
empty: "omit",
|
|
18664
|
+
companions: [NOW$2]
|
|
18665
|
+
}),
|
|
18666
|
+
numeric({
|
|
18667
|
+
id: "battery",
|
|
18668
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18669
|
+
role: DeviceRole.BatterySensor,
|
|
18670
|
+
outputCap: "battery",
|
|
18671
|
+
outputField: "percentage",
|
|
18672
|
+
quantity: "percentage",
|
|
18673
|
+
defaultAggregate: "mean",
|
|
18674
|
+
empty: "null",
|
|
18675
|
+
companions: [
|
|
18676
|
+
{
|
|
18677
|
+
fieldPath: "charging",
|
|
18678
|
+
expr: "\"unknown\""
|
|
18679
|
+
},
|
|
18680
|
+
{
|
|
18681
|
+
fieldPath: "sleeping",
|
|
18682
|
+
expr: "false"
|
|
18683
|
+
},
|
|
18684
|
+
{
|
|
18685
|
+
fieldPath: "lastUpdated",
|
|
18686
|
+
expr: "now"
|
|
18687
|
+
}
|
|
18688
|
+
]
|
|
18689
|
+
}),
|
|
18690
|
+
numeric({
|
|
18691
|
+
id: "numeric",
|
|
18692
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18693
|
+
role: DeviceRole.NumericSensor,
|
|
18694
|
+
outputCap: "numeric-sensor",
|
|
18695
|
+
outputField: "value",
|
|
18696
|
+
quantity: "device",
|
|
18697
|
+
defaultAggregate: "mean",
|
|
18698
|
+
empty: "null",
|
|
18699
|
+
companions: [NOW$2]
|
|
18700
|
+
}),
|
|
18701
|
+
binary({
|
|
18702
|
+
id: "motion",
|
|
18703
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18704
|
+
role: DeviceRole.MotionSensor,
|
|
18705
|
+
outputCap: "motion",
|
|
18706
|
+
outputField: "detected",
|
|
18707
|
+
defaultAggregate: "any",
|
|
18708
|
+
accept: [{
|
|
18709
|
+
cap: "motion",
|
|
18710
|
+
fieldPath: "detected"
|
|
18711
|
+
}],
|
|
18712
|
+
companions: [{
|
|
18713
|
+
fieldPath: "lastDetectedAt",
|
|
18714
|
+
expr: "null"
|
|
18715
|
+
}, {
|
|
18716
|
+
fieldPath: "autoClearAfterMs",
|
|
18717
|
+
expr: "null"
|
|
18718
|
+
}]
|
|
18719
|
+
}),
|
|
18720
|
+
binary({
|
|
18721
|
+
id: "contact",
|
|
18722
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18723
|
+
role: DeviceRole.ContactSensor,
|
|
18724
|
+
outputCap: "contact",
|
|
18725
|
+
outputField: "entryOpen",
|
|
18726
|
+
defaultAggregate: "any",
|
|
18727
|
+
accept: [{
|
|
18728
|
+
cap: "contact",
|
|
18729
|
+
fieldPath: "entryOpen"
|
|
18730
|
+
}],
|
|
18731
|
+
companions: [CHANGED]
|
|
18732
|
+
}),
|
|
18733
|
+
binary({
|
|
18734
|
+
id: "leak",
|
|
18735
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18736
|
+
role: DeviceRole.LeakSensor,
|
|
18737
|
+
outputCap: "flood",
|
|
18738
|
+
outputField: "flooded",
|
|
18739
|
+
defaultAggregate: "any",
|
|
18740
|
+
accept: [{
|
|
18741
|
+
cap: "flood",
|
|
18742
|
+
fieldPath: "flooded"
|
|
18743
|
+
}],
|
|
18744
|
+
companions: [CHANGED]
|
|
18745
|
+
}),
|
|
18746
|
+
binary({
|
|
18747
|
+
id: "smoke",
|
|
18748
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18749
|
+
role: DeviceRole.SmokeSensor,
|
|
18750
|
+
outputCap: "smoke",
|
|
18751
|
+
outputField: "detected",
|
|
18752
|
+
defaultAggregate: "any",
|
|
18753
|
+
accept: [{
|
|
18754
|
+
cap: "smoke",
|
|
18755
|
+
fieldPath: "detected"
|
|
18756
|
+
}],
|
|
18757
|
+
companions: [CHANGED]
|
|
18758
|
+
}),
|
|
18759
|
+
binary({
|
|
18760
|
+
id: "occupancy",
|
|
18761
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18762
|
+
role: DeviceRole.BinarySensor,
|
|
18763
|
+
outputCap: "binary",
|
|
18764
|
+
outputField: "on",
|
|
18765
|
+
defaultAggregate: "any",
|
|
18766
|
+
accept: [{
|
|
18767
|
+
cap: "motion",
|
|
18768
|
+
fieldPath: "detected"
|
|
18769
|
+
}, {
|
|
18770
|
+
cap: "binary",
|
|
18771
|
+
fieldPath: "on"
|
|
18772
|
+
}],
|
|
18773
|
+
companions: [CHANGED]
|
|
18774
|
+
}),
|
|
18775
|
+
binary({
|
|
18776
|
+
id: "binary",
|
|
18777
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18778
|
+
role: DeviceRole.BinarySensor,
|
|
18779
|
+
outputCap: "binary",
|
|
18780
|
+
outputField: "on",
|
|
18781
|
+
defaultAggregate: "any",
|
|
18782
|
+
accept: [{
|
|
18783
|
+
cap: "binary",
|
|
18784
|
+
fieldPath: "on"
|
|
18785
|
+
}],
|
|
18786
|
+
companions: [CHANGED]
|
|
18787
|
+
}),
|
|
18788
|
+
actuator({
|
|
18789
|
+
id: "switch",
|
|
18790
|
+
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.",
|
|
18791
|
+
deviceType: DeviceType.Switch,
|
|
18792
|
+
outputCap: "switch",
|
|
18793
|
+
outputField: "on",
|
|
18794
|
+
member: {
|
|
18795
|
+
cap: "switch",
|
|
18796
|
+
fieldPath: "on"
|
|
18797
|
+
},
|
|
18798
|
+
commandCaps: ["switch"]
|
|
18799
|
+
}),
|
|
18800
|
+
actuator({
|
|
18801
|
+
id: "light",
|
|
18802
|
+
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.",
|
|
18803
|
+
deviceType: DeviceType.Light,
|
|
18804
|
+
outputCap: "switch",
|
|
18805
|
+
outputField: "on",
|
|
18806
|
+
member: {
|
|
18807
|
+
cap: "switch",
|
|
18808
|
+
fieldPath: "on"
|
|
18809
|
+
},
|
|
18810
|
+
commandCaps: [
|
|
18811
|
+
"switch",
|
|
18812
|
+
"brightness",
|
|
18813
|
+
"color"
|
|
18814
|
+
]
|
|
18815
|
+
}),
|
|
18816
|
+
actuator({
|
|
18817
|
+
id: "fan",
|
|
18818
|
+
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.",
|
|
18819
|
+
deviceType: DeviceType.Fan,
|
|
18820
|
+
outputCap: "switch",
|
|
18821
|
+
outputField: "on",
|
|
18822
|
+
member: {
|
|
18823
|
+
cap: "switch",
|
|
18824
|
+
fieldPath: "on"
|
|
18825
|
+
},
|
|
18826
|
+
commandCaps: ["switch", "fan-control"]
|
|
18827
|
+
}),
|
|
18828
|
+
actuator({
|
|
18829
|
+
id: "cover",
|
|
18830
|
+
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.",
|
|
18831
|
+
deviceType: DeviceType.Cover,
|
|
18832
|
+
outputCap: "group-active",
|
|
18833
|
+
outputField: "active",
|
|
18834
|
+
member: {
|
|
18835
|
+
cap: "cover",
|
|
18836
|
+
fieldPath: "state"
|
|
18837
|
+
},
|
|
18838
|
+
activeWhen: [
|
|
18839
|
+
"open",
|
|
18840
|
+
"opening",
|
|
18841
|
+
"stopped"
|
|
18842
|
+
],
|
|
18843
|
+
commandCaps: ["cover"]
|
|
18844
|
+
}),
|
|
18845
|
+
actuator({
|
|
18846
|
+
id: "valve",
|
|
18847
|
+
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.",
|
|
18848
|
+
deviceType: DeviceType.Valve,
|
|
18849
|
+
outputCap: "group-active",
|
|
18850
|
+
outputField: "active",
|
|
18851
|
+
member: {
|
|
18852
|
+
cap: "valve",
|
|
18853
|
+
fieldPath: "state"
|
|
18854
|
+
},
|
|
18855
|
+
activeWhen: [
|
|
18856
|
+
"open",
|
|
18857
|
+
"opening",
|
|
18858
|
+
"stopped"
|
|
18859
|
+
],
|
|
18860
|
+
commandCaps: ["valve"]
|
|
18861
|
+
}),
|
|
18862
|
+
actuator({
|
|
18863
|
+
id: "lock",
|
|
18864
|
+
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.",
|
|
18865
|
+
deviceType: DeviceType.Lock,
|
|
18866
|
+
outputCap: "group-active",
|
|
18867
|
+
outputField: "active",
|
|
18868
|
+
member: {
|
|
18869
|
+
cap: "lock-control",
|
|
18870
|
+
fieldPath: "state"
|
|
18871
|
+
},
|
|
18872
|
+
activeWhen: ["locked"],
|
|
18873
|
+
commandCaps: ["lock-control"]
|
|
18874
|
+
}),
|
|
18875
|
+
actuator({
|
|
18876
|
+
id: "media-player",
|
|
18877
|
+
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.",
|
|
18878
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18879
|
+
outputCap: "group-active",
|
|
18880
|
+
outputField: "active",
|
|
18881
|
+
member: {
|
|
18882
|
+
cap: "media-player",
|
|
18883
|
+
fieldPath: "state"
|
|
18884
|
+
},
|
|
18885
|
+
activeWhen: ["playing", "buffering"],
|
|
18886
|
+
commandCaps: ["media-player"]
|
|
18887
|
+
}),
|
|
18888
|
+
actuator({
|
|
18889
|
+
id: "climate",
|
|
18890
|
+
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.",
|
|
18891
|
+
deviceType: DeviceType.Thermostat,
|
|
18892
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18893
|
+
outputCap: "group-active",
|
|
18894
|
+
outputField: "active",
|
|
18895
|
+
member: {
|
|
18896
|
+
cap: "climate-control",
|
|
18897
|
+
fieldPath: "mode"
|
|
18898
|
+
},
|
|
18899
|
+
activeWhen: [
|
|
18900
|
+
"heat",
|
|
18901
|
+
"cool",
|
|
18902
|
+
"auto",
|
|
18903
|
+
"heat_cool",
|
|
18904
|
+
"fan_only",
|
|
18905
|
+
"dry"
|
|
18906
|
+
],
|
|
18907
|
+
commandCaps: ["climate-control"]
|
|
18908
|
+
})
|
|
18909
|
+
];
|
|
18910
|
+
function actuator(input) {
|
|
18911
|
+
return {
|
|
18912
|
+
id: input.id,
|
|
18913
|
+
summary: input.summary,
|
|
18914
|
+
deviceType: input.deviceType,
|
|
18915
|
+
outputCap: input.outputCap,
|
|
18916
|
+
outputField: input.outputField,
|
|
18917
|
+
commandCaps: input.commandCaps,
|
|
18918
|
+
family: "actuator",
|
|
18919
|
+
role: void 0,
|
|
18920
|
+
memberDeviceType: input.deviceType,
|
|
18921
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18922
|
+
activeWhen: input.activeWhen,
|
|
18923
|
+
quantity: "none",
|
|
18924
|
+
baseUnit: void 0,
|
|
18925
|
+
aggregates: BINARY_AGGREGATES,
|
|
18926
|
+
defaultAggregate: "any",
|
|
18927
|
+
empty: "offline",
|
|
18928
|
+
accept: [input.member],
|
|
18929
|
+
companions: [CHANGED]
|
|
18930
|
+
};
|
|
18931
|
+
}
|
|
18932
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18933
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18934
|
+
DeviceType.Camera;
|
|
18209
18935
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18210
18936
|
/**
|
|
18211
18937
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19919,12 +20645,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
19919
20645
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19920
20646
|
* in-place so dispatch keeps working.
|
|
19921
20647
|
*
|
|
19922
|
-
* **
|
|
19923
|
-
*
|
|
19924
|
-
*
|
|
19925
|
-
*
|
|
19926
|
-
* (`ha-domain-mapping`)
|
|
19927
|
-
* stored after that point.
|
|
20648
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20649
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20650
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20651
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20652
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20653
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19928
20654
|
*
|
|
19929
20655
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19930
20656
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19938,6 +20664,14 @@ var SourceInfoSchema = object({
|
|
|
19938
20664
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19939
20665
|
* Used to detect rename when `id` changes. */
|
|
19940
20666
|
uniqueId: string().optional(),
|
|
20667
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20668
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20669
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20670
|
+
dateTimeShape: _enum([
|
|
20671
|
+
"date",
|
|
20672
|
+
"time",
|
|
20673
|
+
"datetime"
|
|
20674
|
+
]).optional(),
|
|
19941
20675
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19942
20676
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19943
20677
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -40961,7 +41695,8 @@ method(object({
|
|
|
40961
41695
|
"enum"
|
|
40962
41696
|
]),
|
|
40963
41697
|
enumValues: array(string()).optional(),
|
|
40964
|
-
item: boolean().optional()
|
|
41698
|
+
item: boolean().optional(),
|
|
41699
|
+
quantity: ReadingQuantitySchema.optional()
|
|
40965
41700
|
})).readonly(),
|
|
40966
41701
|
itemArray: object({
|
|
40967
41702
|
path: string(),
|
|
@@ -43322,7 +44057,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43322
44057
|
});
|
|
43323
44058
|
/**
|
|
43324
44059
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43325
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44060
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43326
44061
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43327
44062
|
* the originating provider config (mode + sourcePort) so the
|
|
43328
44063
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44805,8 +45540,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44805
45540
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44806
45541
|
var MaskGridShapeSchema = object({
|
|
44807
45542
|
kind: literal("grid"),
|
|
44808
|
-
gridWidth: number(),
|
|
44809
|
-
gridHeight: number(),
|
|
45543
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45544
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44810
45545
|
cells: array(boolean())
|
|
44811
45546
|
});
|
|
44812
45547
|
discriminatedUnion("kind", [
|
|
@@ -44918,6 +45653,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44918
45653
|
"detection-blind",
|
|
44919
45654
|
"motion-noisy",
|
|
44920
45655
|
"motion-calm",
|
|
45656
|
+
"package-llm-silent",
|
|
45657
|
+
"package-llm-answered",
|
|
44921
45658
|
"recording-stalled",
|
|
44922
45659
|
"recording-healthy",
|
|
44923
45660
|
"recording-degraded",
|
|
@@ -46007,7 +46744,20 @@ var NcRuleInputSchema = object({
|
|
|
46007
46744
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46008
46745
|
* path does not run Zod defaults.
|
|
46009
46746
|
*/
|
|
46010
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46747
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46748
|
+
/**
|
|
46749
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46750
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46751
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46752
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46753
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46754
|
+
*
|
|
46755
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46756
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46757
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46758
|
+
* `false`, so it needs no `clear` key.
|
|
46759
|
+
*/
|
|
46760
|
+
askVerdict: boolean().optional()
|
|
46011
46761
|
});
|
|
46012
46762
|
/**
|
|
46013
46763
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56157,6 +56907,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56157
56907
|
deprecated: string().optional(),
|
|
56158
56908
|
distTags: array(string()).readonly()
|
|
56159
56909
|
});
|
|
56910
|
+
/**
|
|
56911
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56912
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56913
|
+
* tarball failure — never an empty string standing in for either.
|
|
56914
|
+
*/
|
|
56915
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56916
|
+
object({
|
|
56917
|
+
status: literal("ok"),
|
|
56918
|
+
markdown: string()
|
|
56919
|
+
}),
|
|
56920
|
+
object({ status: literal("missing") }),
|
|
56921
|
+
object({
|
|
56922
|
+
status: literal("error"),
|
|
56923
|
+
message: string()
|
|
56924
|
+
})
|
|
56925
|
+
]);
|
|
56926
|
+
var PackageDocsSchema = object({
|
|
56927
|
+
name: string(),
|
|
56928
|
+
version: string(),
|
|
56929
|
+
readme: PackageDocBodySchema,
|
|
56930
|
+
changelog: PackageDocBodySchema
|
|
56931
|
+
});
|
|
56160
56932
|
var SearchResultSchema = object({
|
|
56161
56933
|
name: string(),
|
|
56162
56934
|
version: string(),
|
|
@@ -56375,7 +57147,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56375
57147
|
}), object({ success: literal(true) }), {
|
|
56376
57148
|
kind: "mutation",
|
|
56377
57149
|
auth: "admin"
|
|
56378
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57150
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57151
|
+
name: string().min(1),
|
|
57152
|
+
version: string().min(1).optional()
|
|
57153
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56379
57154
|
kind: "mutation",
|
|
56380
57155
|
auth: "admin"
|
|
56381
57156
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56434,27 +57209,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56434
57209
|
*/
|
|
56435
57210
|
var AirQualitySensorStatusSchema = object({
|
|
56436
57211
|
/** Carbon dioxide concentration in ppm. */
|
|
56437
|
-
co2Ppm: number().min(0).optional(),
|
|
57212
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56438
57213
|
/** Total volatile organic compounds in ppb. */
|
|
56439
|
-
vocPpb: number().min(0).optional(),
|
|
57214
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56440
57215
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56441
|
-
pm25: number().min(0).optional(),
|
|
57216
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56442
57217
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56443
|
-
pm10: number().min(0).optional(),
|
|
57218
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56444
57219
|
/** Composite AQI value (typically 0..500). */
|
|
56445
|
-
aqi: number().optional(),
|
|
57220
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56446
57221
|
/** Ms epoch when the slice was last updated. */
|
|
56447
|
-
lastFetchedAt: number()
|
|
56448
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56449
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56450
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56451
|
-
* per slice is unambiguous. */
|
|
56452
|
-
unit: string().optional(),
|
|
56453
|
-
/** Suggested decimal places for numeric display.
|
|
56454
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56455
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56456
|
-
* auto-formatting when absent. */
|
|
56457
|
-
precision: number().int().min(0).max(10).optional()
|
|
57222
|
+
lastFetchedAt: number()
|
|
56458
57223
|
});
|
|
56459
57224
|
var airQualitySensorCapability = {
|
|
56460
57225
|
name: "air-quality-sensor",
|
|
@@ -56491,12 +57256,12 @@ var airQualitySensorCapability = {
|
|
|
56491
57256
|
},
|
|
56492
57257
|
pm25: {
|
|
56493
57258
|
kind: "gauge",
|
|
56494
|
-
unit: "
|
|
57259
|
+
unit: "µg/m³",
|
|
56495
57260
|
deadband: 1
|
|
56496
57261
|
},
|
|
56497
57262
|
pm10: {
|
|
56498
57263
|
kind: "gauge",
|
|
56499
|
-
unit: "
|
|
57264
|
+
unit: "µg/m³",
|
|
56500
57265
|
deadband: 1
|
|
56501
57266
|
},
|
|
56502
57267
|
aqi: {
|
|
@@ -56514,22 +57279,13 @@ var airQualitySensorCapability = {
|
|
|
56514
57279
|
* entries with `device_class: illuminance`.
|
|
56515
57280
|
*/
|
|
56516
57281
|
var AmbientLightSensorStatusSchema = object({
|
|
56517
|
-
/** Current illuminance in lux (lx). */
|
|
56518
|
-
lux: number().min(0).meta({
|
|
56519
|
-
|
|
57282
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57283
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57284
|
+
precision: 0,
|
|
56520
57285
|
label: "Illuminance"
|
|
56521
|
-
}),
|
|
57286
|
+
})),
|
|
56522
57287
|
/** Ms epoch when the slice was last updated. */
|
|
56523
|
-
lastFetchedAt: number()
|
|
56524
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56525
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56526
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56527
|
-
unit: string().optional(),
|
|
56528
|
-
/** Suggested decimal places for numeric display.
|
|
56529
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56530
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56531
|
-
* auto-formatting when absent. */
|
|
56532
|
-
precision: number().int().min(0).max(10).optional()
|
|
57288
|
+
lastFetchedAt: number()
|
|
56533
57289
|
});
|
|
56534
57290
|
var ambientLightSensorCapability = {
|
|
56535
57291
|
name: "ambient-light-sensor",
|
|
@@ -56561,12 +57317,7 @@ var ambientLightSensorCapability = {
|
|
|
56561
57317
|
} } },
|
|
56562
57318
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56563
57319
|
* whether persisting is worth a SQLite commit. */
|
|
56564
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56565
|
-
customize: {
|
|
56566
|
-
version: 1,
|
|
56567
|
-
advanced: "derive",
|
|
56568
|
-
targets: []
|
|
56569
|
-
}
|
|
57320
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56570
57321
|
};
|
|
56571
57322
|
/**
|
|
56572
57323
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56793,10 +57544,7 @@ var BatteryStatusSchema = object({
|
|
|
56793
57544
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56794
57545
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56795
57546
|
*/
|
|
56796
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56797
|
-
unit: "%",
|
|
56798
|
-
label: "Charge"
|
|
56799
|
-
}),
|
|
57547
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56800
57548
|
/**
|
|
56801
57549
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56802
57550
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56823,7 +57571,14 @@ var BatteryStatusSchema = object({
|
|
|
56823
57571
|
*/
|
|
56824
57572
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56825
57573
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56826
|
-
lastUpdated: number(),
|
|
57574
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57575
|
+
/**
|
|
57576
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57577
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57578
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57579
|
+
* `numeric-sensor` on the same device.
|
|
57580
|
+
*/
|
|
57581
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56827
57582
|
/**
|
|
56828
57583
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56829
57584
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56870,12 +57625,12 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56870
57625
|
DeviceType.Switch,
|
|
56871
57626
|
DeviceType.PetFeeder,
|
|
56872
57627
|
DeviceType.Container,
|
|
56873
|
-
DeviceType.Thermostat
|
|
57628
|
+
DeviceType.Thermostat,
|
|
57629
|
+
DeviceType.EventEmitter
|
|
56874
57630
|
];
|
|
56875
57631
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56876
57632
|
var batteryCustomize = {
|
|
56877
57633
|
version: 1,
|
|
56878
|
-
advanced: "derive",
|
|
56879
57634
|
targets: [{
|
|
56880
57635
|
id: "percentage",
|
|
56881
57636
|
cardinality: "scalar",
|
|
@@ -56884,7 +57639,7 @@ var batteryCustomize = {
|
|
|
56884
57639
|
stateField: "percentage"
|
|
56885
57640
|
},
|
|
56886
57641
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56887
|
-
apply: "add
|
|
57642
|
+
apply: "add",
|
|
56888
57643
|
path: "percentage",
|
|
56889
57644
|
sources: [{
|
|
56890
57645
|
kind: "field",
|
|
@@ -57005,10 +57760,16 @@ onStatusChanged: { data: object({
|
|
|
57005
57760
|
/**
|
|
57006
57761
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
57007
57762
|
*/
|
|
57008
|
-
history: { fields: {
|
|
57009
|
-
|
|
57010
|
-
|
|
57011
|
-
|
|
57763
|
+
history: { fields: {
|
|
57764
|
+
percentage: {
|
|
57765
|
+
kind: "gauge",
|
|
57766
|
+
unit: "%"
|
|
57767
|
+
},
|
|
57768
|
+
volts: {
|
|
57769
|
+
kind: "gauge",
|
|
57770
|
+
unit: "V"
|
|
57771
|
+
}
|
|
57772
|
+
} },
|
|
57012
57773
|
customize: batteryCustomize,
|
|
57013
57774
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57014
57775
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57055,12 +57816,7 @@ var binaryCapability = {
|
|
|
57055
57816
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57056
57817
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57057
57818
|
* whether persisting is worth a SQLite commit. */
|
|
57058
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57059
|
-
customize: {
|
|
57060
|
-
version: 1,
|
|
57061
|
-
advanced: "derive",
|
|
57062
|
-
targets: []
|
|
57063
|
-
}
|
|
57819
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57064
57820
|
};
|
|
57065
57821
|
/**
|
|
57066
57822
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57076,7 +57832,7 @@ var binaryCapability = {
|
|
|
57076
57832
|
*/
|
|
57077
57833
|
var BrightnessStatusSchema = object({
|
|
57078
57834
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57079
|
-
percentage: number().min(0).max(100),
|
|
57835
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57080
57836
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57081
57837
|
lastChangedAt: number()
|
|
57082
57838
|
});
|
|
@@ -57530,21 +58286,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57530
58286
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57531
58287
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57532
58288
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57533
|
-
target: number().nullable(),
|
|
58289
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57534
58290
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57535
58291
|
* in `heat_cool` mode. */
|
|
57536
|
-
targetHigh: number().nullable(),
|
|
58292
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57537
58293
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57538
58294
|
* in `heat_cool` mode. */
|
|
57539
|
-
targetLow: number().nullable(),
|
|
58295
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57540
58296
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57541
58297
|
* humidity control. */
|
|
57542
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58298
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57543
58299
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57544
58300
|
* the device's internal sensor. */
|
|
57545
|
-
currentTemp: number().nullable(),
|
|
58301
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57546
58302
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57547
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58303
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57548
58304
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57549
58305
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57550
58306
|
swingVertical: boolean().nullable(),
|
|
@@ -57552,11 +58308,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57552
58308
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57553
58309
|
swingHorizontal: boolean().nullable(),
|
|
57554
58310
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57555
|
-
minTemp: number().nullable().optional(),
|
|
58311
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57556
58312
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57557
|
-
maxTemp: number().nullable().optional(),
|
|
58313
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57558
58314
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57559
|
-
tempStep: number().positive().nullable().optional(),
|
|
58315
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57560
58316
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57561
58317
|
lastFetchedAt: number()
|
|
57562
58318
|
});
|
|
@@ -57698,17 +58454,17 @@ var climateControlCapability = {
|
|
|
57698
58454
|
* modes to expose in the picker without a slice fetch.
|
|
57699
58455
|
*/
|
|
57700
58456
|
var RgbTripletSchema = object({
|
|
57701
|
-
r: number().int().min(0).max(255),
|
|
57702
|
-
g: number().int().min(0).max(255),
|
|
57703
|
-
b: number().int().min(0).max(255)
|
|
58457
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58458
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58459
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57704
58460
|
});
|
|
57705
58461
|
var HsvTripletSchema = object({
|
|
57706
58462
|
/** Hue in degrees, 0..360. */
|
|
57707
|
-
h: number().min(0).max(360),
|
|
58463
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57708
58464
|
/** Saturation as 0..100 inclusive. */
|
|
57709
|
-
s: number().min(0).max(100),
|
|
58465
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57710
58466
|
/** Value/brightness as 0..100 inclusive. */
|
|
57711
|
-
v: number().min(0).max(100)
|
|
58467
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57712
58468
|
});
|
|
57713
58469
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57714
58470
|
object({
|
|
@@ -57737,7 +58493,7 @@ var ColorStatusSchema = object({
|
|
|
57737
58493
|
/** Populated when `mode === 'hsv'`. */
|
|
57738
58494
|
hsv: HsvTripletSchema.optional(),
|
|
57739
58495
|
/** Populated when `mode === 'mired'`. */
|
|
57740
|
-
mireds: number().int().optional(),
|
|
58496
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57741
58497
|
/** Ms epoch of the last operator-driven change. */
|
|
57742
58498
|
lastChangedAt: number()
|
|
57743
58499
|
});
|
|
@@ -57932,18 +58688,12 @@ _enum([
|
|
|
57932
58688
|
"empty",
|
|
57933
58689
|
"full"
|
|
57934
58690
|
]);
|
|
57935
|
-
/**
|
|
57936
|
-
|
|
57937
|
-
|
|
57938
|
-
"days",
|
|
57939
|
-
"hours",
|
|
57940
|
-
"cycles"
|
|
57941
|
-
]);
|
|
57942
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57943
|
-
* days). `value` null = unknown (D393). */
|
|
58691
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58692
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58693
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57944
58694
|
var ConsumableRemainingSchema = object({
|
|
57945
|
-
value: number().min(0).nullable(),
|
|
57946
|
-
|
|
58695
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58696
|
+
kind: ConsumableRemainingKindSchema
|
|
57947
58697
|
});
|
|
57948
58698
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
57949
58699
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -57956,7 +58706,7 @@ var ConsumableItemSchema = object({
|
|
|
57956
58706
|
/** Display name. */
|
|
57957
58707
|
label: string().min(1),
|
|
57958
58708
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57959
|
-
level: number().min(0).max(100).nullable(),
|
|
58709
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57960
58710
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57961
58711
|
status: ConsumableStatusSchema.nullable(),
|
|
57962
58712
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58038,8 +58788,8 @@ var consumablesCustomize = {
|
|
|
58038
58788
|
transforms: [{ kind: "identity" }]
|
|
58039
58789
|
}],
|
|
58040
58790
|
literals: [{
|
|
58041
|
-
path: "remaining.
|
|
58042
|
-
values: [...
|
|
58791
|
+
path: "remaining.kind",
|
|
58792
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58043
58793
|
}]
|
|
58044
58794
|
},
|
|
58045
58795
|
{
|
|
@@ -58168,7 +58918,6 @@ reset: method(object({
|
|
|
58168
58918
|
},
|
|
58169
58919
|
"remaining.value": {
|
|
58170
58920
|
kind: "gauge",
|
|
58171
|
-
unitFrom: "remaining.unit",
|
|
58172
58921
|
deadband: 1,
|
|
58173
58922
|
displayName: "Remaining"
|
|
58174
58923
|
}
|
|
@@ -58238,10 +58987,9 @@ var contactCapability = {
|
|
|
58238
58987
|
* (empty array for the other kinds). It lives in the slice because
|
|
58239
58988
|
* HA `select.*` entities may update their options at runtime.
|
|
58240
58989
|
*
|
|
58241
|
-
*
|
|
58242
|
-
*
|
|
58243
|
-
*
|
|
58244
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
58990
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
58991
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
58992
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58245
58993
|
*/
|
|
58246
58994
|
var ControlStatusSchema = object({
|
|
58247
58995
|
kind: _enum([
|
|
@@ -58253,39 +59001,17 @@ var ControlStatusSchema = object({
|
|
|
58253
59001
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58254
59002
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58255
59003
|
* or time-only — HA accepts all three forms). */
|
|
58256
|
-
value: union([number(), string()]),
|
|
59004
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58257
59005
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58258
59006
|
options: array(string()),
|
|
58259
59007
|
/** Ms epoch when the slice was last updated. */
|
|
58260
59008
|
lastChangedAt: number(),
|
|
58261
|
-
/**
|
|
58262
|
-
|
|
58263
|
-
|
|
58264
|
-
|
|
58265
|
-
/**
|
|
58266
|
-
|
|
58267
|
-
min: number().optional(),
|
|
58268
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58269
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58270
|
-
max: number().optional(),
|
|
58271
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58272
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58273
|
-
step: number().optional(),
|
|
58274
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58275
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58276
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58277
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58278
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58279
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58280
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58281
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58282
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58283
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58284
|
-
format: _enum([
|
|
58285
|
-
"date",
|
|
58286
|
-
"time",
|
|
58287
|
-
"datetime"
|
|
58288
|
-
]).optional()
|
|
59009
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
59010
|
+
min: number().optional().meta(readingMeta("device")),
|
|
59011
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
59012
|
+
max: number().optional().meta(readingMeta("device")),
|
|
59013
|
+
/** Step increment, in the device quantity's base unit. */
|
|
59014
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58289
59015
|
});
|
|
58290
59016
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58291
59017
|
object({
|
|
@@ -58351,9 +59077,9 @@ var CoverStatusSchema = object({
|
|
|
58351
59077
|
]),
|
|
58352
59078
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58353
59079
|
* no intermediate position surface. */
|
|
58354
|
-
position: number().min(0).max(100).nullable(),
|
|
59080
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58355
59081
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58356
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59082
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58357
59083
|
/** Ms epoch when the slice was last updated. */
|
|
58358
59084
|
lastChangedAt: number()
|
|
58359
59085
|
});
|
|
@@ -58456,9 +59182,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58456
59182
|
var DayNightStatusSchema = object({
|
|
58457
59183
|
mode: DayNightModeSchema,
|
|
58458
59184
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58459
|
-
sensitivity: number().optional(),
|
|
59185
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58460
59186
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58461
|
-
switchDelaySec: number().optional(),
|
|
59187
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58462
59188
|
lastFetchedAt: number()
|
|
58463
59189
|
});
|
|
58464
59190
|
/**
|
|
@@ -58676,11 +59402,11 @@ var DishwasherStatusSchema = object({
|
|
|
58676
59402
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58677
59403
|
availablePrograms: array(string()),
|
|
58678
59404
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58679
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59405
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58680
59406
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58681
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59407
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58682
59408
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58683
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59409
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58684
59410
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58685
59411
|
doorOpen: boolean().nullable(),
|
|
58686
59412
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58704,7 +59430,7 @@ var DishwasherStatusSchema = object({
|
|
|
58704
59430
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58705
59431
|
machineCareDue: boolean().nullable(),
|
|
58706
59432
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58707
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59433
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58708
59434
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58709
59435
|
halfLoad: boolean().nullable(),
|
|
58710
59436
|
hygienePlus: boolean().nullable(),
|
|
@@ -58719,7 +59445,7 @@ var DishwasherStatusSchema = object({
|
|
|
58719
59445
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58720
59446
|
activeEvents: array(string()),
|
|
58721
59447
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58722
|
-
errorCode: number().nullable(),
|
|
59448
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58723
59449
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58724
59450
|
errorLabel: string().nullable(),
|
|
58725
59451
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58950,7 +59676,7 @@ var DoorbellStatusSchema = object({
|
|
|
58950
59676
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58951
59677
|
lastPressedAt: number().nullable(),
|
|
58952
59678
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58953
|
-
pressCountSinceStart: number()
|
|
59679
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58954
59680
|
});
|
|
58955
59681
|
var DoorbellPressEventSchema = object({
|
|
58956
59682
|
deviceId: number(),
|
|
@@ -59015,17 +59741,7 @@ onPressed: {
|
|
|
59015
59741
|
history: "none",
|
|
59016
59742
|
customize: doorbellCustomize
|
|
59017
59743
|
};
|
|
59018
|
-
|
|
59019
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
59020
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
59021
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
59022
|
-
* The option set is stable across observations; it is persisted in the
|
|
59023
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
59024
|
-
* stored in `sourceInfo`.
|
|
59025
|
-
*/
|
|
59026
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
59027
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
59028
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
59744
|
+
_enum([
|
|
59029
59745
|
"date",
|
|
59030
59746
|
"time",
|
|
59031
59747
|
"datetime"
|
|
@@ -59033,12 +59749,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59033
59749
|
var EnumSensorStatusSchema = object({
|
|
59034
59750
|
value: string(),
|
|
59035
59751
|
/**
|
|
59036
|
-
* Set
|
|
59037
|
-
* as
|
|
59038
|
-
*
|
|
59039
|
-
* a time-only sensor → `'time'`.
|
|
59752
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
59753
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
59754
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59040
59755
|
*/
|
|
59041
|
-
|
|
59756
|
+
timestamp: boolean().optional(),
|
|
59042
59757
|
/** Ms epoch when the slice was last updated. */
|
|
59043
59758
|
lastFetchedAt: number()
|
|
59044
59759
|
});
|
|
@@ -59065,11 +59780,11 @@ var enumSensorCapability = {
|
|
|
59065
59780
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59066
59781
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59067
59782
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59068
|
-
* `
|
|
59783
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59069
59784
|
*/
|
|
59070
59785
|
history: { fields: { value: {
|
|
59071
59786
|
kind: "enum",
|
|
59072
|
-
skipWhenSet: "
|
|
59787
|
+
skipWhenSet: "timestamp"
|
|
59073
59788
|
} } },
|
|
59074
59789
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59075
59790
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59089,13 +59804,13 @@ var EventFireSchema = object({
|
|
|
59089
59804
|
deviceId: number(),
|
|
59090
59805
|
eventType: string(),
|
|
59091
59806
|
data: record(string(), unknown()).nullable(),
|
|
59092
|
-
timestamp: number(),
|
|
59093
|
-
seq: number()
|
|
59807
|
+
timestamp: number().meta(readingMeta("none")),
|
|
59808
|
+
seq: number().meta(readingMeta("count"))
|
|
59094
59809
|
});
|
|
59095
59810
|
var EventEmitterStatusSchema = object({
|
|
59096
59811
|
eventTypes: array(string()),
|
|
59097
59812
|
lastEvent: EventFireSchema.nullable(),
|
|
59098
|
-
eventCountSinceStart: number()
|
|
59813
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59099
59814
|
});
|
|
59100
59815
|
var eventEmitterCapability = {
|
|
59101
59816
|
name: "event-emitter",
|
|
@@ -59508,10 +60223,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59508
60223
|
var FanControlStatusSchema = object({
|
|
59509
60224
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59510
60225
|
* speed surface (single-speed fan). */
|
|
59511
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60226
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59512
60227
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59513
60228
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59514
|
-
percentageStep: number().positive().optional(),
|
|
60229
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59515
60230
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59516
60231
|
* — empty string when no preset is active or supported. */
|
|
59517
60232
|
preset: string(),
|
|
@@ -59632,7 +60347,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59632
60347
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59633
60348
|
model: string().nullable(),
|
|
59634
60349
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59635
|
-
channelCount: number().nullable(),
|
|
60350
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59636
60351
|
/**
|
|
59637
60352
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59638
60353
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59755,9 +60470,151 @@ var gasCapability = {
|
|
|
59755
60470
|
* whether persisting is worth a SQLite commit. */
|
|
59756
60471
|
volatileStateFields: ["lastChangedAt"]
|
|
59757
60472
|
};
|
|
60473
|
+
var GroupCommandsSchema = object({
|
|
60474
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60475
|
+
results: array(object({
|
|
60476
|
+
deviceId: number().int().nonnegative(),
|
|
60477
|
+
cap: string().min(1),
|
|
60478
|
+
method: string().min(1),
|
|
60479
|
+
ok: boolean(),
|
|
60480
|
+
error: string().optional(),
|
|
60481
|
+
/** Ms epoch of the attempt. */
|
|
60482
|
+
at: number()
|
|
60483
|
+
})) });
|
|
60484
|
+
var groupCommandsCapability = {
|
|
60485
|
+
name: "group-commands",
|
|
60486
|
+
scope: "device",
|
|
60487
|
+
deviceNative: true,
|
|
60488
|
+
mode: "singleton",
|
|
60489
|
+
deviceTypes: [
|
|
60490
|
+
DeviceType.Switch,
|
|
60491
|
+
DeviceType.Light,
|
|
60492
|
+
DeviceType.Fan,
|
|
60493
|
+
DeviceType.Cover,
|
|
60494
|
+
DeviceType.Valve,
|
|
60495
|
+
DeviceType.Lock,
|
|
60496
|
+
DeviceType.MediaPlayer,
|
|
60497
|
+
DeviceType.Thermostat,
|
|
60498
|
+
DeviceType.Climate
|
|
60499
|
+
],
|
|
60500
|
+
methods: {},
|
|
60501
|
+
status: {
|
|
60502
|
+
schema: GroupCommandsSchema,
|
|
60503
|
+
kind: "push"
|
|
60504
|
+
},
|
|
60505
|
+
runtimeState: GroupCommandsSchema,
|
|
60506
|
+
/**
|
|
60507
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
60508
|
+
* failure would outlive the command that caused it.
|
|
60509
|
+
*
|
|
60510
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60511
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60512
|
+
*/
|
|
60513
|
+
durability: "session",
|
|
60514
|
+
history: "none"
|
|
60515
|
+
};
|
|
60516
|
+
/**
|
|
60517
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
60518
|
+
* included member is, or every included member is. What "active" means is the
|
|
60519
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
60520
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
60521
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
60522
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
60523
|
+
* empty included set takes the device offline, never `active: false`.
|
|
60524
|
+
*/
|
|
60525
|
+
var GroupActiveSchema = object({
|
|
60526
|
+
active: boolean().meta({ label: "Active" }),
|
|
60527
|
+
/** Ms epoch when the slice was last updated. */
|
|
60528
|
+
lastChangedAt: number()
|
|
60529
|
+
});
|
|
60530
|
+
var groupActiveCapability = {
|
|
60531
|
+
name: "group-active",
|
|
60532
|
+
scope: "device",
|
|
60533
|
+
deviceNative: true,
|
|
60534
|
+
mode: "singleton",
|
|
60535
|
+
deviceTypes: [
|
|
60536
|
+
DeviceType.Cover,
|
|
60537
|
+
DeviceType.Valve,
|
|
60538
|
+
DeviceType.Lock,
|
|
60539
|
+
DeviceType.MediaPlayer,
|
|
60540
|
+
DeviceType.Climate,
|
|
60541
|
+
DeviceType.Thermostat
|
|
60542
|
+
],
|
|
60543
|
+
methods: {},
|
|
60544
|
+
status: {
|
|
60545
|
+
schema: GroupActiveSchema,
|
|
60546
|
+
kind: "push"
|
|
60547
|
+
},
|
|
60548
|
+
runtimeState: GroupActiveSchema,
|
|
60549
|
+
/**
|
|
60550
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
60551
|
+
* next source event; a restored value would outlive the members it named.
|
|
60552
|
+
*
|
|
60553
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60554
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60555
|
+
*/
|
|
60556
|
+
durability: "session",
|
|
60557
|
+
history: "none"
|
|
60558
|
+
};
|
|
60559
|
+
/**
|
|
60560
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60561
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60562
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60563
|
+
* series that later statistics read is the output cap's own history block.
|
|
60564
|
+
*/
|
|
60565
|
+
var GroupStatusSchema = object({
|
|
60566
|
+
/** Members whose current value entered the aggregate. */
|
|
60567
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60568
|
+
precision: 0,
|
|
60569
|
+
label: "Reporting"
|
|
60570
|
+
})),
|
|
60571
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60572
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60573
|
+
precision: 0,
|
|
60574
|
+
label: "Excluded"
|
|
60575
|
+
})),
|
|
60576
|
+
/** `included` + `excluded`. */
|
|
60577
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60578
|
+
precision: 0,
|
|
60579
|
+
label: "Members"
|
|
60580
|
+
}))
|
|
60581
|
+
});
|
|
60582
|
+
var groupStatusCapability = {
|
|
60583
|
+
name: "group-status",
|
|
60584
|
+
scope: "device",
|
|
60585
|
+
deviceNative: true,
|
|
60586
|
+
mode: "singleton",
|
|
60587
|
+
deviceTypes: [
|
|
60588
|
+
DeviceType.Sensor,
|
|
60589
|
+
DeviceType.Switch,
|
|
60590
|
+
DeviceType.Light,
|
|
60591
|
+
DeviceType.Fan,
|
|
60592
|
+
DeviceType.Cover,
|
|
60593
|
+
DeviceType.Valve,
|
|
60594
|
+
DeviceType.Lock,
|
|
60595
|
+
DeviceType.MediaPlayer,
|
|
60596
|
+
DeviceType.Thermostat,
|
|
60597
|
+
DeviceType.Climate
|
|
60598
|
+
],
|
|
60599
|
+
methods: {},
|
|
60600
|
+
status: {
|
|
60601
|
+
schema: GroupStatusSchema,
|
|
60602
|
+
kind: "push"
|
|
60603
|
+
},
|
|
60604
|
+
runtimeState: GroupStatusSchema,
|
|
60605
|
+
/**
|
|
60606
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60607
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60608
|
+
*
|
|
60609
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60610
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60611
|
+
*/
|
|
60612
|
+
durability: "session",
|
|
60613
|
+
history: "none"
|
|
60614
|
+
};
|
|
59758
60615
|
var HeatingValveStatusSchema = object({
|
|
59759
60616
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59760
|
-
position: number().min(0).max(100).nullable(),
|
|
60617
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59761
60618
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59762
60619
|
lastFetchedAt: number()
|
|
59763
60620
|
});
|
|
@@ -59800,9 +60657,9 @@ var HumidifierStatusSchema = object({
|
|
|
59800
60657
|
/** Whether the humidifier is currently on. */
|
|
59801
60658
|
on: boolean(),
|
|
59802
60659
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59803
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60660
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59804
60661
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59805
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60662
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59806
60663
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59807
60664
|
* device has no mode surface. */
|
|
59808
60665
|
mode: string().nullable(),
|
|
@@ -59812,9 +60669,9 @@ var HumidifierStatusSchema = object({
|
|
|
59812
60669
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59813
60670
|
action: string().nullable(),
|
|
59814
60671
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59815
|
-
minHumidity: number().nullable(),
|
|
60672
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59816
60673
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59817
|
-
maxHumidity: number().nullable(),
|
|
60674
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59818
60675
|
/** Ms epoch when the slice was last updated. */
|
|
59819
60676
|
lastChangedAt: number()
|
|
59820
60677
|
});
|
|
@@ -59884,22 +60741,13 @@ var humidifierCapability = {
|
|
|
59884
60741
|
* `sourceInfo`.
|
|
59885
60742
|
*/
|
|
59886
60743
|
var HumiditySensorStatusSchema = object({
|
|
59887
|
-
/** Current relative humidity, 0..100. */
|
|
59888
|
-
percent: number().min(0).max(100).meta({
|
|
59889
|
-
|
|
60744
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60745
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60746
|
+
precision: 0,
|
|
59890
60747
|
label: "Humidity"
|
|
59891
|
-
}),
|
|
60748
|
+
})),
|
|
59892
60749
|
/** Ms epoch when the slice was last updated. */
|
|
59893
|
-
lastFetchedAt: number()
|
|
59894
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59895
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59896
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59897
|
-
unit: string().optional(),
|
|
59898
|
-
/** Suggested decimal places for numeric display.
|
|
59899
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59900
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59901
|
-
* auto-formatting when absent. */
|
|
59902
|
-
precision: number().int().min(0).max(10).optional()
|
|
60750
|
+
lastFetchedAt: number()
|
|
59903
60751
|
});
|
|
59904
60752
|
var humiditySensorCapability = {
|
|
59905
60753
|
name: "humidity-sensor",
|
|
@@ -59930,12 +60778,7 @@ var humiditySensorCapability = {
|
|
|
59930
60778
|
} } },
|
|
59931
60779
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59932
60780
|
* whether persisting is worth a SQLite commit. */
|
|
59933
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
59934
|
-
customize: {
|
|
59935
|
-
version: 1,
|
|
59936
|
-
advanced: "derive",
|
|
59937
|
-
targets: []
|
|
59938
|
-
}
|
|
60781
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
59939
60782
|
};
|
|
59940
60783
|
/**
|
|
59941
60784
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -59956,7 +60799,7 @@ var ImageStatusSchema = object({
|
|
|
59956
60799
|
* entity exposes no `entity_picture` (yet). */
|
|
59957
60800
|
url: string().nullable(),
|
|
59958
60801
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
59959
|
-
lastUpdated: number().nullable()
|
|
60802
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
59960
60803
|
});
|
|
59961
60804
|
var imageCapability = {
|
|
59962
60805
|
name: "image",
|
|
@@ -60044,19 +60887,19 @@ var NormalizedRangeSchema = object({
|
|
|
60044
60887
|
*/
|
|
60045
60888
|
var ImageSettingsStatusSchema = object({
|
|
60046
60889
|
/** Normalized 0–100. */
|
|
60047
|
-
brightness: number().optional(),
|
|
60890
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60048
60891
|
/** Normalized 0–100. */
|
|
60049
|
-
contrast: number().optional(),
|
|
60892
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60050
60893
|
/** Normalized 0–100. */
|
|
60051
|
-
saturation: number().optional(),
|
|
60894
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60052
60895
|
/** Normalized 0–100. */
|
|
60053
|
-
sharpness: number().optional(),
|
|
60896
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60054
60897
|
mirror: boolean().optional(),
|
|
60055
60898
|
flip: boolean().optional(),
|
|
60056
60899
|
rotate: ImageRotateSchema.optional(),
|
|
60057
60900
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60058
60901
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60059
|
-
warmth: number().optional(),
|
|
60902
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60060
60903
|
exposureMode: ExposureModeSchema.optional(),
|
|
60061
60904
|
backlightMode: BacklightModeSchema.optional(),
|
|
60062
60905
|
lastFetchedAt: number()
|
|
@@ -60335,10 +61178,10 @@ var IntercomAbilitySchema = object({
|
|
|
60335
61178
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60336
61179
|
codecs: array(string()),
|
|
60337
61180
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60338
|
-
sampleRate: number(),
|
|
61181
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60339
61182
|
duplex: _enum(["half", "full"]),
|
|
60340
61183
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60341
|
-
maxBacklogMs: number()
|
|
61184
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60342
61185
|
});
|
|
60343
61186
|
var IntercomStatusSchema = object({
|
|
60344
61187
|
/** True while a talk session is open. */
|
|
@@ -60565,13 +61408,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60565
61408
|
activity: LawnMowerActivitySchema,
|
|
60566
61409
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60567
61410
|
* reading. */
|
|
60568
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61411
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60569
61412
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60570
61413
|
* task is active / progress is unavailable. */
|
|
60571
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61414
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60572
61415
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60573
61416
|
* or null when unknown. */
|
|
60574
|
-
currentCode: number().nullable(),
|
|
61417
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60575
61418
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60576
61419
|
currentCodeLabel: string().nullable(),
|
|
60577
61420
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61024,7 +61867,14 @@ var lockControlCapability = {
|
|
|
61024
61867
|
}),
|
|
61025
61868
|
unlock: method(object({
|
|
61026
61869
|
deviceId: number().int().nonnegative(),
|
|
61027
|
-
code: string().min(1).optional()
|
|
61870
|
+
code: string().min(1).optional(),
|
|
61871
|
+
/**
|
|
61872
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
61873
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
61874
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
61875
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
61876
|
+
*/
|
|
61877
|
+
confirm: boolean().optional()
|
|
61028
61878
|
}), _void(), {
|
|
61029
61879
|
kind: "mutation",
|
|
61030
61880
|
auth: "protected"
|
|
@@ -61061,6 +61911,44 @@ var lockControlCapability = {
|
|
|
61061
61911
|
volatileStateFields: ["lastChangedAt"]
|
|
61062
61912
|
};
|
|
61063
61913
|
/**
|
|
61914
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
|
|
61915
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
61916
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
61917
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
61918
|
+
*/
|
|
61919
|
+
var MeterStatusSchema = object({
|
|
61920
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
61921
|
+
lastFetchedAt: number()
|
|
61922
|
+
});
|
|
61923
|
+
var meterCapability = {
|
|
61924
|
+
name: "meter",
|
|
61925
|
+
scope: "device",
|
|
61926
|
+
deviceNative: true,
|
|
61927
|
+
mode: "singleton",
|
|
61928
|
+
deviceTypes: [DeviceType.Sensor],
|
|
61929
|
+
methods: {},
|
|
61930
|
+
status: {
|
|
61931
|
+
schema: MeterStatusSchema,
|
|
61932
|
+
kind: "push"
|
|
61933
|
+
},
|
|
61934
|
+
runtimeState: MeterStatusSchema,
|
|
61935
|
+
/**
|
|
61936
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
61937
|
+
* history integral. A restart shows it only until the history pass
|
|
61938
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
61939
|
+
*
|
|
61940
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61941
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61942
|
+
*/
|
|
61943
|
+
durability: "restored",
|
|
61944
|
+
history: { fields: { value: {
|
|
61945
|
+
kind: "counter",
|
|
61946
|
+
deadband: .001,
|
|
61947
|
+
minIntervalMs: 6e4
|
|
61948
|
+
} } },
|
|
61949
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
61950
|
+
};
|
|
61951
|
+
/**
|
|
61064
61952
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
61065
61953
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
61066
61954
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -61104,7 +61992,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61104
61992
|
state: MediaPlayerStateSchema,
|
|
61105
61993
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61106
61994
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61107
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
61995
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61108
61996
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61109
61997
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61110
61998
|
isMuted: boolean().nullable(),
|
|
@@ -61117,10 +62005,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61117
62005
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61118
62006
|
/** Current playback position in ms. Null when not seekable or
|
|
61119
62007
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61120
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
62008
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61121
62009
|
/** Total duration of the current media in ms. Null when unknown
|
|
61122
62010
|
* (live stream) or nothing is playing. */
|
|
61123
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
62011
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61124
62012
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61125
62013
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61126
62014
|
shuffle: boolean().nullable(),
|
|
@@ -61429,7 +62317,7 @@ var motionCustomize = {
|
|
|
61429
62317
|
eventName: "onMotionChanged"
|
|
61430
62318
|
},
|
|
61431
62319
|
deviceTypes: [DeviceType.Camera],
|
|
61432
|
-
apply: "
|
|
62320
|
+
apply: "add",
|
|
61433
62321
|
applyAuthority: {
|
|
61434
62322
|
kind: "camera-sensors",
|
|
61435
62323
|
timeoutField: "motionCooldownMs"
|
|
@@ -61501,7 +62389,7 @@ var MotionStatusSchema = object({
|
|
|
61501
62389
|
* it, every provider seeded it at boot, and every session left it
|
|
61502
62390
|
* `detected: true` after its detach.
|
|
61503
62391
|
*/
|
|
61504
|
-
autoClearAfterMs: number().nullable()
|
|
62392
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61505
62393
|
});
|
|
61506
62394
|
/**
|
|
61507
62395
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61538,12 +62426,18 @@ var motionCapability = {
|
|
|
61538
62426
|
methods: {
|
|
61539
62427
|
/**
|
|
61540
62428
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
61541
|
-
* for consumers that don't need the full status object
|
|
61542
|
-
*
|
|
61543
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
61544
|
-
* consumer.
|
|
62429
|
+
* for consumers that don't need the full status object. A composed
|
|
62430
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
61545
62431
|
*/
|
|
61546
62432
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62433
|
+
/**
|
|
62434
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62435
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62436
|
+
*/
|
|
62437
|
+
composedMethods: { isDetected: {
|
|
62438
|
+
kind: "slice",
|
|
62439
|
+
field: "detected"
|
|
62440
|
+
} },
|
|
61547
62441
|
events: {
|
|
61548
62442
|
/**
|
|
61549
62443
|
* Fires every time the runner transitions a camera between
|
|
@@ -61683,7 +62577,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61683
62577
|
* the grid region(s). */
|
|
61684
62578
|
var MotionZoneStatusSchema = object({
|
|
61685
62579
|
enabled: boolean(),
|
|
61686
|
-
sensitivity: number(),
|
|
62580
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61687
62581
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61688
62582
|
regions: array(MotionZoneRegionSchema),
|
|
61689
62583
|
lastFetchedAt: number()
|
|
@@ -62053,7 +62947,7 @@ var NavigationStatusSchema = object({
|
|
|
62053
62947
|
following: boolean(),
|
|
62054
62948
|
flash: boolean(),
|
|
62055
62949
|
lightMode: NavigationLightModeSchema,
|
|
62056
|
-
lightLevel: number().min(40).max(100),
|
|
62950
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62057
62951
|
/** Ms epoch when the slice was last updated. */
|
|
62058
62952
|
lastChangedAt: number()
|
|
62059
62953
|
});
|
|
@@ -62187,13 +63081,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62187
63081
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62188
63082
|
* SKIP a null rather than coerce it.
|
|
62189
63083
|
*/
|
|
62190
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63084
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62191
63085
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62192
|
-
rssiDbm: number().optional(),
|
|
63086
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62193
63087
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62194
63088
|
ssid: string().optional(),
|
|
62195
63089
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62196
|
-
lastUpdated: number()
|
|
63090
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62197
63091
|
});
|
|
62198
63092
|
var networkLinkCapability = {
|
|
62199
63093
|
name: "network-link",
|
|
@@ -62578,7 +63472,7 @@ var NotifierStatusSchema = object({
|
|
|
62578
63472
|
lastError: string().nullable(),
|
|
62579
63473
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62580
63474
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62581
|
-
queueDepth: number().int().nonnegative(),
|
|
63475
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62582
63476
|
/** Per-feature capability matrix — authoritative source for the
|
|
62583
63477
|
* compose-form field gating. */
|
|
62584
63478
|
supports: NotifierSupportsSchema
|
|
@@ -62670,11 +63564,9 @@ onSent: { data: object({
|
|
|
62670
63564
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62671
63565
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62672
63566
|
*
|
|
62673
|
-
* The
|
|
62674
|
-
*
|
|
62675
|
-
*
|
|
62676
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62677
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63567
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63568
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63569
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62678
63570
|
*
|
|
62679
63571
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62680
63572
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62683,15 +63575,8 @@ onSent: { data: object({
|
|
|
62683
63575
|
* numeric values land here.
|
|
62684
63576
|
*/
|
|
62685
63577
|
var NumericSensorStatusSchema = object({
|
|
62686
|
-
|
|
62687
|
-
|
|
62688
|
-
* Populated live from the upstream source on each state push.
|
|
62689
|
-
* Absent for unitless sensors. */
|
|
62690
|
-
unit: string().optional(),
|
|
62691
|
-
/** Suggested decimal places for numeric display.
|
|
62692
|
-
* Populated live from the upstream source when provided.
|
|
62693
|
-
* Falls back to auto-formatting when absent. */
|
|
62694
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63578
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63579
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62695
63580
|
/** Ms epoch when the slice was last updated. */
|
|
62696
63581
|
lastFetchedAt: number()
|
|
62697
63582
|
});
|
|
@@ -62715,11 +63600,11 @@ var numericSensorCapability = {
|
|
|
62715
63600
|
*/
|
|
62716
63601
|
durability: "restored",
|
|
62717
63602
|
/**
|
|
62718
|
-
* History (D850): recorded series. The unit is
|
|
63603
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63604
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62719
63605
|
*/
|
|
62720
63606
|
history: { fields: { value: {
|
|
62721
63607
|
kind: "gauge",
|
|
62722
|
-
unitFrom: "unit",
|
|
62723
63608
|
minIntervalMs: 3e4
|
|
62724
63609
|
} } },
|
|
62725
63610
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -63011,23 +63896,26 @@ var PetFeederStatusSchema = object({
|
|
|
63011
63896
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
63012
63897
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
63013
63898
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
63014
|
-
foodLevel: number().nullable(),
|
|
63899
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
63015
63900
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63016
63901
|
* single-hopper models. */
|
|
63017
|
-
food1: number().nullable(),
|
|
63902
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63018
63903
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63019
63904
|
* single-hopper models. */
|
|
63020
|
-
food2: number().nullable(),
|
|
63905
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63021
63906
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63022
63907
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63023
63908
|
* below the feeder's low threshold. */
|
|
63024
63909
|
lowFood: boolean(),
|
|
63025
63910
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63026
63911
|
* device has no battery reading. */
|
|
63027
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63028
|
-
/**
|
|
63029
|
-
*
|
|
63030
|
-
|
|
63912
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63913
|
+
/**
|
|
63914
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
63915
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
63916
|
+
* model has no desiccant sensor.
|
|
63917
|
+
*/
|
|
63918
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63031
63919
|
/** True while a feed is in progress. */
|
|
63032
63920
|
feeding: boolean(),
|
|
63033
63921
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63038,7 +63926,7 @@ var PetFeederStatusSchema = object({
|
|
|
63038
63926
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63039
63927
|
error: string().nullable(),
|
|
63040
63928
|
/** Raw device error code (0 / null = no error). */
|
|
63041
|
-
errorCode: number().nullable(),
|
|
63929
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63042
63930
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63043
63931
|
isDualHopper: boolean(),
|
|
63044
63932
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63048,7 +63936,7 @@ var PetFeederStatusSchema = object({
|
|
|
63048
63936
|
/** Play a chime when dispensing. */
|
|
63049
63937
|
feedSound: boolean(),
|
|
63050
63938
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63051
|
-
volume: number(),
|
|
63939
|
+
volume: number().meta(readingMeta("none")),
|
|
63052
63940
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63053
63941
|
lastFetchedAt: number()
|
|
63054
63942
|
});
|
|
@@ -63167,7 +64055,7 @@ var petFeederCapability = {
|
|
|
63167
64055
|
},
|
|
63168
64056
|
desiccantLeftDays: {
|
|
63169
64057
|
kind: "gauge",
|
|
63170
|
-
unit: "
|
|
64058
|
+
unit: "s"
|
|
63171
64059
|
}
|
|
63172
64060
|
} }
|
|
63173
64061
|
};
|
|
@@ -63568,43 +64456,88 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63568
64456
|
*/
|
|
63569
64457
|
var PowerMeterStatusSchema = object({
|
|
63570
64458
|
/** Instantaneous power draw in watts. */
|
|
63571
|
-
watts: number().optional().meta({
|
|
63572
|
-
unit: "W",
|
|
63573
|
-
label: "Power"
|
|
63574
|
-
}),
|
|
64459
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63575
64460
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63576
|
-
kwhTotal: number().optional().meta({
|
|
63577
|
-
unit: "kWh",
|
|
63578
|
-
label: "Energy"
|
|
63579
|
-
}),
|
|
64461
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63580
64462
|
/** Voltage in volts. */
|
|
63581
|
-
volts: number().optional(),
|
|
64463
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
63582
64464
|
/** Current in amperes. */
|
|
63583
|
-
amps: number().optional(),
|
|
63584
|
-
/** Apparent power in volt-amperes
|
|
63585
|
-
va: number().optional(),
|
|
64465
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
64466
|
+
/** Apparent power in volt-amperes. */
|
|
64467
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63586
64468
|
/** Power factor (0..1) if reported. */
|
|
63587
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
64469
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63588
64470
|
/** Ms epoch when the slice was last updated. */
|
|
63589
|
-
lastFetchedAt: number()
|
|
63590
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63591
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63592
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63593
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63594
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63595
|
-
unit: string().optional(),
|
|
63596
|
-
/** Suggested decimal places for numeric display.
|
|
63597
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63598
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63599
|
-
* auto-formatting when absent. */
|
|
63600
|
-
precision: number().int().min(0).max(10).optional()
|
|
64471
|
+
lastFetchedAt: number()
|
|
63601
64472
|
});
|
|
64473
|
+
/**
|
|
64474
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
64475
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
64476
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
64477
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
64478
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
64479
|
+
*/
|
|
64480
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
64481
|
+
DeviceType.Sensor,
|
|
64482
|
+
DeviceType.Switch,
|
|
64483
|
+
DeviceType.Light,
|
|
64484
|
+
DeviceType.Fan,
|
|
64485
|
+
DeviceType.Climate,
|
|
64486
|
+
DeviceType.Thermostat,
|
|
64487
|
+
DeviceType.Humidifier,
|
|
64488
|
+
DeviceType.WaterHeater,
|
|
64489
|
+
DeviceType.MediaPlayer,
|
|
64490
|
+
DeviceType.Washer,
|
|
64491
|
+
DeviceType.Dryer,
|
|
64492
|
+
DeviceType.Dishwasher,
|
|
64493
|
+
DeviceType.Vacuum,
|
|
64494
|
+
DeviceType.LawnMower,
|
|
64495
|
+
DeviceType.PetFeeder
|
|
64496
|
+
];
|
|
64497
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
64498
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
64499
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
64500
|
+
function powerTarget(id, unit) {
|
|
64501
|
+
return {
|
|
64502
|
+
id,
|
|
64503
|
+
cardinality: "scalar",
|
|
64504
|
+
vocabulary: {
|
|
64505
|
+
cap: "power-meter",
|
|
64506
|
+
stateField: id
|
|
64507
|
+
},
|
|
64508
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
64509
|
+
apply: "add",
|
|
64510
|
+
path: id,
|
|
64511
|
+
sources: [{
|
|
64512
|
+
kind: "numeric",
|
|
64513
|
+
requiredUnit: unit,
|
|
64514
|
+
transforms: [{ kind: "identity" }]
|
|
64515
|
+
}],
|
|
64516
|
+
companions: [{
|
|
64517
|
+
kind: "clock",
|
|
64518
|
+
path: "lastFetchedAt",
|
|
64519
|
+
when: "always"
|
|
64520
|
+
}],
|
|
64521
|
+
sourceReport: { status: "assignment-status" },
|
|
64522
|
+
advancedExpression: true
|
|
64523
|
+
};
|
|
64524
|
+
}
|
|
64525
|
+
/** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
|
|
64526
|
+
var powerMeterCustomize = {
|
|
64527
|
+
version: 1,
|
|
64528
|
+
targets: [
|
|
64529
|
+
powerTarget("watts", "W"),
|
|
64530
|
+
powerTarget("kwhTotal", "kWh"),
|
|
64531
|
+
powerTarget("volts", "V"),
|
|
64532
|
+
powerTarget("amps", "A")
|
|
64533
|
+
]
|
|
64534
|
+
};
|
|
63602
64535
|
var powerMeterCapability = {
|
|
63603
64536
|
name: "power-meter",
|
|
63604
64537
|
scope: "device",
|
|
63605
64538
|
deviceNative: true,
|
|
63606
64539
|
mode: "singleton",
|
|
63607
|
-
deviceTypes:
|
|
64540
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
63608
64541
|
methods: {},
|
|
63609
64542
|
status: {
|
|
63610
64543
|
schema: PowerMeterStatusSchema,
|
|
@@ -63662,11 +64595,7 @@ var powerMeterCapability = {
|
|
|
63662
64595
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63663
64596
|
* whether persisting is worth a SQLite commit. */
|
|
63664
64597
|
volatileStateFields: ["lastFetchedAt"],
|
|
63665
|
-
customize:
|
|
63666
|
-
version: 1,
|
|
63667
|
-
advanced: "derive",
|
|
63668
|
-
targets: []
|
|
63669
|
-
}
|
|
64598
|
+
customize: powerMeterCustomize
|
|
63670
64599
|
};
|
|
63671
64600
|
/**
|
|
63672
64601
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63686,11 +64615,11 @@ var powerMeterCapability = {
|
|
|
63686
64615
|
*/
|
|
63687
64616
|
var GpsLocationSchema = object({
|
|
63688
64617
|
/** Latitude in decimal degrees, -90..90. */
|
|
63689
|
-
latitude: number().min(-90).max(90),
|
|
64618
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63690
64619
|
/** Longitude in decimal degrees, -180..180. */
|
|
63691
|
-
longitude: number().min(-180).max(180),
|
|
64620
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63692
64621
|
/** Reported accuracy in meters (lower = better). */
|
|
63693
|
-
accuracyMeters: number().nonnegative()
|
|
64622
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63694
64623
|
});
|
|
63695
64624
|
var PresenceStatusSchema = object({
|
|
63696
64625
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63702,7 +64631,7 @@ var PresenceStatusSchema = object({
|
|
|
63702
64631
|
gps: GpsLocationSchema.nullable(),
|
|
63703
64632
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63704
64633
|
* when not reported. */
|
|
63705
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64634
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63706
64635
|
/** Ms epoch when the slice was last updated. */
|
|
63707
64636
|
lastChangedAt: number()
|
|
63708
64637
|
});
|
|
@@ -63752,19 +64681,10 @@ var presenceCapability = {
|
|
|
63752
64681
|
* `sourceInfo`.
|
|
63753
64682
|
*/
|
|
63754
64683
|
var PressureSensorStatusSchema = object({
|
|
63755
|
-
/** Current pressure in hPa. */
|
|
63756
|
-
hpa: number(),
|
|
64684
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64685
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63757
64686
|
/** Ms epoch when the slice was last updated. */
|
|
63758
|
-
lastFetchedAt: number()
|
|
63759
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63760
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63761
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63762
|
-
unit: string().optional(),
|
|
63763
|
-
/** Suggested decimal places for numeric display.
|
|
63764
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63765
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63766
|
-
* auto-formatting when absent. */
|
|
63767
|
-
precision: number().int().min(0).max(10).optional()
|
|
64687
|
+
lastFetchedAt: number()
|
|
63768
64688
|
});
|
|
63769
64689
|
var pressureSensorCapability = {
|
|
63770
64690
|
name: "pressure-sensor",
|
|
@@ -64178,8 +65098,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64178
65098
|
}), _void(), { kind: "mutation" });
|
|
64179
65099
|
var PtzAutotrackSettingsSchema = object({
|
|
64180
65100
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64181
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64182
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65101
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65102
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64183
65103
|
});
|
|
64184
65104
|
/**
|
|
64185
65105
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64333,7 +65253,7 @@ var RunningStateStatusSchema = object({
|
|
|
64333
65253
|
/** null = unknown — never coerced to false (D393). */
|
|
64334
65254
|
running: boolean().nullable(),
|
|
64335
65255
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64336
|
-
since: number().nullable(),
|
|
65256
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64337
65257
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64338
65258
|
phase: string().nullable(),
|
|
64339
65259
|
/** null until a reading has been published (D393). */
|
|
@@ -64348,7 +65268,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64348
65268
|
/** Generic Customize target for the running boolean (D936). */
|
|
64349
65269
|
var runningCustomize = {
|
|
64350
65270
|
version: 1,
|
|
64351
|
-
advanced: "derive",
|
|
64352
65271
|
targets: [{
|
|
64353
65272
|
id: "running",
|
|
64354
65273
|
cardinality: "scalar",
|
|
@@ -64357,6 +65276,8 @@ var runningCustomize = {
|
|
|
64357
65276
|
stateField: "running"
|
|
64358
65277
|
},
|
|
64359
65278
|
deviceTypes: [
|
|
65279
|
+
DeviceType.Washer,
|
|
65280
|
+
DeviceType.Dryer,
|
|
64360
65281
|
DeviceType.Dishwasher,
|
|
64361
65282
|
DeviceType.Vacuum,
|
|
64362
65283
|
DeviceType.LawnMower,
|
|
@@ -64368,7 +65289,7 @@ var runningCustomize = {
|
|
|
64368
65289
|
DeviceType.Thermostat,
|
|
64369
65290
|
DeviceType.PetFeeder
|
|
64370
65291
|
],
|
|
64371
|
-
apply: "add
|
|
65292
|
+
apply: "add",
|
|
64372
65293
|
path: "running",
|
|
64373
65294
|
sources: [
|
|
64374
65295
|
{
|
|
@@ -65632,9 +66553,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65632
66553
|
*/
|
|
65633
66554
|
var RecordWindowSchema = object({
|
|
65634
66555
|
trigger: RecordTriggerSchema,
|
|
65635
|
-
day: number().int().min(0).max(6),
|
|
65636
|
-
startMinute: number().int().min(0).max(1439),
|
|
65637
|
-
endMinute: number().int().min(1).max(1440)
|
|
66556
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
66557
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
66558
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65638
66559
|
});
|
|
65639
66560
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65640
66561
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65710,10 +66631,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65710
66631
|
/** Master "record to the card at all" switch. */
|
|
65711
66632
|
enabled: boolean().nullable(),
|
|
65712
66633
|
overwriteWhenFull: boolean().nullable(),
|
|
65713
|
-
preRecordSec: number().nullable(),
|
|
65714
|
-
postRecordSec: number().nullable(),
|
|
66634
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66635
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65715
66636
|
/** Length of one recorded file, in minutes. */
|
|
65716
|
-
segmentMinutes: number().nullable(),
|
|
66637
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65717
66638
|
/** The primary track's weekly windows, flattened. */
|
|
65718
66639
|
windows: array(RecordWindowSchema),
|
|
65719
66640
|
/**
|
|
@@ -65729,7 +66650,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65729
66650
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65730
66651
|
* writable.
|
|
65731
66652
|
*/
|
|
65732
|
-
unreadableWindows: number(),
|
|
66653
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65733
66654
|
/**
|
|
65734
66655
|
* The camera is scheduled to record and has NO usable storage.
|
|
65735
66656
|
*
|
|
@@ -66574,7 +67495,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66574
67495
|
url: string().optional(),
|
|
66575
67496
|
codec: string().optional(),
|
|
66576
67497
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66577
|
-
fps: number().positive().optional(),
|
|
67498
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66578
67499
|
label: string().optional(),
|
|
66579
67500
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66580
67501
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66661,18 +67582,18 @@ var StreamProfileSchema = _enum([
|
|
|
66661
67582
|
]);
|
|
66662
67583
|
/** The current encoding config of one stream profile. */
|
|
66663
67584
|
var StreamProfileConfigSchema = object({
|
|
66664
|
-
width: number(),
|
|
66665
|
-
height: number(),
|
|
67585
|
+
width: number().meta(readingMeta("none")),
|
|
67586
|
+
height: number().meta(readingMeta("none")),
|
|
66666
67587
|
codec: _enum(["h264", "h265"]),
|
|
66667
|
-
framerate: number(),
|
|
66668
|
-
bitrate: number(),
|
|
67588
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67589
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66669
67590
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66670
67591
|
encoderProfile: _enum([
|
|
66671
67592
|
"high",
|
|
66672
67593
|
"main",
|
|
66673
67594
|
"baseline"
|
|
66674
67595
|
]).optional(),
|
|
66675
|
-
gop: number().optional(),
|
|
67596
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66676
67597
|
/**
|
|
66677
67598
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66678
67599
|
*
|
|
@@ -66846,7 +67767,8 @@ var switchCapability = {
|
|
|
66846
67767
|
deviceTypes: [
|
|
66847
67768
|
DeviceType.Switch,
|
|
66848
67769
|
DeviceType.Siren,
|
|
66849
|
-
DeviceType.Light
|
|
67770
|
+
DeviceType.Light,
|
|
67771
|
+
DeviceType.Fan
|
|
66850
67772
|
],
|
|
66851
67773
|
methods: { setState: method(object({
|
|
66852
67774
|
deviceId: number(),
|
|
@@ -66893,12 +67815,7 @@ var switchCapability = {
|
|
|
66893
67815
|
label: "On",
|
|
66894
67816
|
kind: "boolean"
|
|
66895
67817
|
}
|
|
66896
|
-
}] }
|
|
66897
|
-
customize: {
|
|
66898
|
-
version: 1,
|
|
66899
|
-
advanced: "derive",
|
|
66900
|
-
targets: []
|
|
66901
|
-
}
|
|
67818
|
+
}] }
|
|
66902
67819
|
};
|
|
66903
67820
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66904
67821
|
function hasControlCharacter(value) {
|
|
@@ -67481,35 +68398,21 @@ var tamperCapability = {
|
|
|
67481
68398
|
* entries with `device_class: temperature` and any future native
|
|
67482
68399
|
* thermometer.
|
|
67483
68400
|
*
|
|
67484
|
-
*
|
|
67485
|
-
*
|
|
67486
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67487
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67488
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67489
|
-
* `sourceInfo`.
|
|
68401
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
68402
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67490
68403
|
*
|
|
67491
68404
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67492
68405
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67493
68406
|
* changed" steady state.
|
|
67494
68407
|
*/
|
|
67495
68408
|
var TemperatureSensorStatusSchema = object({
|
|
67496
|
-
/** Current temperature in Celsius. */
|
|
67497
|
-
celsius: number().meta({
|
|
67498
|
-
|
|
68409
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68410
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
68411
|
+
precision: 1,
|
|
67499
68412
|
label: "Temperature"
|
|
67500
|
-
}),
|
|
68413
|
+
})),
|
|
67501
68414
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67502
|
-
lastFetchedAt: number()
|
|
67503
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67504
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67505
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67506
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67507
|
-
unit: string().optional(),
|
|
67508
|
-
/** Suggested decimal places for numeric display.
|
|
67509
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67510
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67511
|
-
* auto-formatting when absent. */
|
|
67512
|
-
precision: number().int().min(0).max(10).optional()
|
|
68415
|
+
lastFetchedAt: number()
|
|
67513
68416
|
});
|
|
67514
68417
|
var temperatureSensorCapability = {
|
|
67515
68418
|
name: "temperature-sensor",
|
|
@@ -67540,12 +68443,7 @@ var temperatureSensorCapability = {
|
|
|
67540
68443
|
} } },
|
|
67541
68444
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67542
68445
|
* whether persisting is worth a SQLite commit. */
|
|
67543
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67544
|
-
customize: {
|
|
67545
|
-
version: 1,
|
|
67546
|
-
advanced: "derive",
|
|
67547
|
-
targets: []
|
|
67548
|
-
}
|
|
68446
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67549
68447
|
};
|
|
67550
68448
|
/**
|
|
67551
68449
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67828,16 +68726,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67828
68726
|
]),
|
|
67829
68727
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67830
68728
|
* reading. */
|
|
67831
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68729
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67832
68730
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67833
68731
|
* the vacuum has no speed control. */
|
|
67834
68732
|
fanSpeed: string().nullable(),
|
|
67835
68733
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67836
68734
|
availableFanSpeeds: array(string()),
|
|
67837
68735
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67838
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68736
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67839
68737
|
/** Current error code (0 / null = no error). */
|
|
67840
|
-
errorCode: number().nullable(),
|
|
68738
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67841
68739
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67842
68740
|
errorLabel: string().nullable(),
|
|
67843
68741
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67915,7 +68813,7 @@ var ValveStatusSchema = object({
|
|
|
67915
68813
|
]),
|
|
67916
68814
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
67917
68815
|
* intermediate position surface. */
|
|
67918
|
-
position: number().min(0).max(100).nullable(),
|
|
68816
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67919
68817
|
/** Ms epoch when the slice was last updated. */
|
|
67920
68818
|
lastChangedAt: number()
|
|
67921
68819
|
});
|
|
@@ -68023,9 +68921,9 @@ var vibrationCapability = {
|
|
|
68023
68921
|
*/
|
|
68024
68922
|
var WaterHeaterStatusSchema = object({
|
|
68025
68923
|
/** Current measured temperature. Null when not reported. */
|
|
68026
|
-
currentTemp: number().nullable(),
|
|
68924
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68027
68925
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68028
|
-
targetTemp: number().nullable(),
|
|
68926
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68029
68927
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68030
68928
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68031
68929
|
* device reports an unknown state. */
|
|
@@ -68036,9 +68934,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68036
68934
|
* has no away surface. */
|
|
68037
68935
|
away: boolean().nullable(),
|
|
68038
68936
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68039
|
-
minTemp: number().nullable(),
|
|
68937
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68040
68938
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68041
|
-
maxTemp: number().nullable(),
|
|
68939
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68042
68940
|
/** Ms epoch when the slice was last updated. */
|
|
68043
68941
|
lastChangedAt: number()
|
|
68044
68942
|
});
|
|
@@ -68123,25 +69021,18 @@ var waterHeaterCapability = {
|
|
|
68123
69021
|
* Forecast deferred — current conditions only for v1.
|
|
68124
69022
|
*/
|
|
68125
69023
|
var WeatherStatusSchema = object({
|
|
68126
|
-
/** Verbatim
|
|
68127
|
-
* when no condition has been reported yet. */
|
|
69024
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68128
69025
|
condition: string().nullable(),
|
|
68129
|
-
/** Current temperature in
|
|
68130
|
-
temperature: number().nullable(),
|
|
68131
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68132
|
-
temperatureUnit: string().nullable(),
|
|
69026
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
69027
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68133
69028
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68134
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68135
|
-
/** Barometric pressure in
|
|
68136
|
-
pressure: number().nullable(),
|
|
68137
|
-
/**
|
|
68138
|
-
|
|
68139
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68140
|
-
windSpeed: number().nullable(),
|
|
68141
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68142
|
-
windSpeedUnit: string().nullable(),
|
|
69029
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
69030
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
69031
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
69032
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
69033
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68143
69034
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68144
|
-
windBearing: number().nullable(),
|
|
69035
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68145
69036
|
/** Ms epoch when the slice was last updated. */
|
|
68146
69037
|
lastFetchedAt: number()
|
|
68147
69038
|
});
|
|
@@ -68169,12 +69060,12 @@ var weatherCapability = {
|
|
|
68169
69060
|
*/
|
|
68170
69061
|
durability: "session",
|
|
68171
69062
|
/**
|
|
68172
|
-
* History (D850): recorded series.
|
|
69063
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68173
69064
|
*/
|
|
68174
69065
|
history: { fields: {
|
|
68175
69066
|
temperature: {
|
|
68176
69067
|
kind: "gauge",
|
|
68177
|
-
|
|
69068
|
+
unit: "°C",
|
|
68178
69069
|
deadband: .2
|
|
68179
69070
|
},
|
|
68180
69071
|
humidity: {
|
|
@@ -68184,12 +69075,12 @@ var weatherCapability = {
|
|
|
68184
69075
|
},
|
|
68185
69076
|
pressure: {
|
|
68186
69077
|
kind: "gauge",
|
|
68187
|
-
|
|
69078
|
+
unit: "hPa",
|
|
68188
69079
|
deadband: .5
|
|
68189
69080
|
},
|
|
68190
69081
|
windSpeed: {
|
|
68191
69082
|
kind: "gauge",
|
|
68192
|
-
|
|
69083
|
+
unit: "m/s",
|
|
68193
69084
|
deadband: .5
|
|
68194
69085
|
}
|
|
68195
69086
|
} }
|
|
@@ -69090,8 +69981,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
69090
69981
|
kind: "mutation",
|
|
69091
69982
|
auth: "admin"
|
|
69092
69983
|
});
|
|
69984
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
69093
69985
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
69094
|
-
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;
|
|
69986
|
+
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;
|
|
69095
69987
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
69096
69988
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
69097
69989
|
new Set(CAP_NAMES);
|
|
@@ -69420,6 +70312,9 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69420
70312
|
featureProbe: featureProbeCapability,
|
|
69421
70313
|
flood: floodCapability,
|
|
69422
70314
|
gas: gasCapability,
|
|
70315
|
+
groupActive: groupActiveCapability,
|
|
70316
|
+
groupCommands: groupCommandsCapability,
|
|
70317
|
+
groupStatus: groupStatusCapability,
|
|
69423
70318
|
heatingValve: heatingValveCapability,
|
|
69424
70319
|
humidifier: humidifierCapability,
|
|
69425
70320
|
humiditySensor: humiditySensorCapability,
|
|
@@ -69429,6 +70324,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69429
70324
|
lawnMowerControl: lawnMowerControlCapability,
|
|
69430
70325
|
lockControl: lockControlCapability,
|
|
69431
70326
|
mediaPlayer: mediaPlayerCapability,
|
|
70327
|
+
meter: meterCapability,
|
|
69432
70328
|
motion: motionCapability,
|
|
69433
70329
|
motionTrigger: motionTriggerCapability,
|
|
69434
70330
|
motionZones: motionZonesCapability,
|
|
@@ -70205,7 +71101,7 @@ var DeclaredDevices = class {
|
|
|
70205
71101
|
return removed;
|
|
70206
71102
|
}
|
|
70207
71103
|
};
|
|
70208
|
-
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;
|
|
71104
|
+
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;
|
|
70209
71105
|
new Set(Object.values(DeviceType));
|
|
70210
71106
|
Object.freeze({
|
|
70211
71107
|
"accessories.getStatus": {
|
|
@@ -70313,6 +71209,13 @@ Object.freeze({
|
|
|
70313
71209
|
access: "view",
|
|
70314
71210
|
role: "admin"
|
|
70315
71211
|
},
|
|
71212
|
+
"addons.getPackageDocs": {
|
|
71213
|
+
capName: "addons",
|
|
71214
|
+
capScope: "system",
|
|
71215
|
+
addonId: null,
|
|
71216
|
+
access: "view",
|
|
71217
|
+
role: "admin"
|
|
71218
|
+
},
|
|
70316
71219
|
"addons.getVersions": {
|
|
70317
71220
|
capName: "addons",
|
|
70318
71221
|
capScope: "system",
|
|
@@ -73421,6 +74324,27 @@ Object.freeze({
|
|
|
73421
74324
|
access: "view",
|
|
73422
74325
|
role: "viewer"
|
|
73423
74326
|
},
|
|
74327
|
+
"groupActive.getStatus": {
|
|
74328
|
+
capName: "group-active",
|
|
74329
|
+
capScope: "device",
|
|
74330
|
+
addonId: null,
|
|
74331
|
+
access: "view",
|
|
74332
|
+
role: "viewer"
|
|
74333
|
+
},
|
|
74334
|
+
"groupCommands.getStatus": {
|
|
74335
|
+
capName: "group-commands",
|
|
74336
|
+
capScope: "device",
|
|
74337
|
+
addonId: null,
|
|
74338
|
+
access: "view",
|
|
74339
|
+
role: "viewer"
|
|
74340
|
+
},
|
|
74341
|
+
"groupStatus.getStatus": {
|
|
74342
|
+
capName: "group-status",
|
|
74343
|
+
capScope: "device",
|
|
74344
|
+
addonId: null,
|
|
74345
|
+
access: "view",
|
|
74346
|
+
role: "viewer"
|
|
74347
|
+
},
|
|
73424
74348
|
"heatingValve.getStatus": {
|
|
73425
74349
|
capName: "heating-valve",
|
|
73426
74350
|
capScope: "device",
|
|
@@ -74373,6 +75297,13 @@ Object.freeze({
|
|
|
74373
75297
|
access: "create",
|
|
74374
75298
|
role: "admin"
|
|
74375
75299
|
},
|
|
75300
|
+
"meter.getStatus": {
|
|
75301
|
+
capName: "meter",
|
|
75302
|
+
capScope: "device",
|
|
75303
|
+
addonId: null,
|
|
75304
|
+
access: "view",
|
|
75305
|
+
role: "viewer"
|
|
75306
|
+
},
|
|
74376
75307
|
"metricsProvider.collectSnapshot": {
|
|
74377
75308
|
capName: "metrics-provider",
|
|
74378
75309
|
capScope: "system",
|
|
@@ -82471,7 +83402,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
82471
83402
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
82472
83403
|
icon: "square"
|
|
82473
83404
|
}
|
|
82474
|
-
}
|
|
83405
|
+
},
|
|
83406
|
+
overrides: { byType: {
|
|
83407
|
+
[DeviceType.Washer]: {
|
|
83408
|
+
state: { running: {
|
|
83409
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
83410
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
83411
|
+
} },
|
|
83412
|
+
events: {
|
|
83413
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
83414
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
83415
|
+
}
|
|
83416
|
+
},
|
|
83417
|
+
[DeviceType.Dryer]: {
|
|
83418
|
+
state: { running: {
|
|
83419
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
83420
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
83421
|
+
} },
|
|
83422
|
+
events: {
|
|
83423
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
83424
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
83425
|
+
}
|
|
83426
|
+
},
|
|
83427
|
+
[DeviceType.Dishwasher]: {
|
|
83428
|
+
state: { running: {
|
|
83429
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
83430
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
83431
|
+
} },
|
|
83432
|
+
events: {
|
|
83433
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
83434
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
83435
|
+
}
|
|
83436
|
+
}
|
|
83437
|
+
} }
|
|
82475
83438
|
},
|
|
82476
83439
|
update: {
|
|
82477
83440
|
scope: "device",
|
|
@@ -83243,6 +84206,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83243
84206
|
icon: "flame"
|
|
83244
84207
|
}]
|
|
83245
84208
|
},
|
|
84209
|
+
"group-active": {
|
|
84210
|
+
scope: "device",
|
|
84211
|
+
noun: t("Group state", "Stato del gruppo")
|
|
84212
|
+
},
|
|
84213
|
+
"group-commands": {
|
|
84214
|
+
scope: "device",
|
|
84215
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84216
|
+
},
|
|
84217
|
+
"group-status": {
|
|
84218
|
+
scope: "device",
|
|
84219
|
+
noun: t("Group", "Gruppo"),
|
|
84220
|
+
state: [
|
|
84221
|
+
{
|
|
84222
|
+
kind: "numeric",
|
|
84223
|
+
field: "included",
|
|
84224
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84225
|
+
label: t("Reporting", "Rispondono"),
|
|
84226
|
+
icon: "users"
|
|
84227
|
+
},
|
|
84228
|
+
{
|
|
84229
|
+
kind: "numeric",
|
|
84230
|
+
field: "excluded",
|
|
84231
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84232
|
+
label: t("Excluded", "Esclusi"),
|
|
84233
|
+
icon: "users"
|
|
84234
|
+
},
|
|
84235
|
+
{
|
|
84236
|
+
kind: "numeric",
|
|
84237
|
+
field: "total",
|
|
84238
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84239
|
+
label: t("Members", "Membri"),
|
|
84240
|
+
icon: "sigma"
|
|
84241
|
+
}
|
|
84242
|
+
]
|
|
84243
|
+
},
|
|
83246
84244
|
"humidity-sensor": {
|
|
83247
84245
|
scope: "device",
|
|
83248
84246
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83268,6 +84266,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83268
84266
|
}],
|
|
83269
84267
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
83270
84268
|
},
|
|
84269
|
+
meter: {
|
|
84270
|
+
scope: "device",
|
|
84271
|
+
noun: t("Meter", "Contatore"),
|
|
84272
|
+
state: [{
|
|
84273
|
+
kind: "numeric",
|
|
84274
|
+
field: "value",
|
|
84275
|
+
quantity: t("the total", "il totale"),
|
|
84276
|
+
label: t("Total", "Totale"),
|
|
84277
|
+
icon: "gauge"
|
|
84278
|
+
}]
|
|
84279
|
+
},
|
|
83271
84280
|
"numeric-sensor": {
|
|
83272
84281
|
scope: "device",
|
|
83273
84282
|
noun: t("Sensor", "Sensore"),
|
|
@@ -83276,7 +84285,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83276
84285
|
field: "value",
|
|
83277
84286
|
quantity: t("the reading", "il valore"),
|
|
83278
84287
|
label: t("Reading", "Valore"),
|
|
83279
|
-
unitField: "unit",
|
|
83280
84288
|
icon: "gauge"
|
|
83281
84289
|
}]
|
|
83282
84290
|
},
|
|
@@ -83412,7 +84420,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83412
84420
|
field: "temperature",
|
|
83413
84421
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
83414
84422
|
label: t("Temperature", "Temperatura"),
|
|
83415
|
-
|
|
84423
|
+
unit: "°C",
|
|
83416
84424
|
icon: "thermometer"
|
|
83417
84425
|
},
|
|
83418
84426
|
{
|
|
@@ -83428,7 +84436,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83428
84436
|
field: "windSpeed",
|
|
83429
84437
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
83430
84438
|
label: t("Wind", "Vento"),
|
|
83431
|
-
|
|
84439
|
+
unit: "m/s",
|
|
83432
84440
|
icon: "wind"
|
|
83433
84441
|
},
|
|
83434
84442
|
{
|
|
@@ -83436,7 +84444,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83436
84444
|
field: "pressure",
|
|
83437
84445
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
83438
84446
|
label: t("Pressure", "Pressione"),
|
|
83439
|
-
|
|
84447
|
+
unit: "hPa",
|
|
83440
84448
|
icon: "gauge"
|
|
83441
84449
|
}
|
|
83442
84450
|
]
|
|
@@ -83741,8 +84749,47 @@ function projectAction(cap, action) {
|
|
|
83741
84749
|
};
|
|
83742
84750
|
}
|
|
83743
84751
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
83744
|
-
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;
|
|
84752
|
+
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;
|
|
83745
84753
|
DeviceFeature.BatteryOperated;
|
|
84754
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
84755
|
+
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.";
|
|
84756
|
+
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.";
|
|
84757
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
84758
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
84759
|
+
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.";
|
|
84760
|
+
function withheld(reason) {
|
|
84761
|
+
return {
|
|
84762
|
+
[DeviceType.Washer]: {
|
|
84763
|
+
exported: false,
|
|
84764
|
+
reason
|
|
84765
|
+
},
|
|
84766
|
+
[DeviceType.Dryer]: {
|
|
84767
|
+
exported: false,
|
|
84768
|
+
reason
|
|
84769
|
+
},
|
|
84770
|
+
[DeviceType.Dishwasher]: {
|
|
84771
|
+
exported: false,
|
|
84772
|
+
reason
|
|
84773
|
+
}
|
|
84774
|
+
};
|
|
84775
|
+
}
|
|
84776
|
+
function offered(received) {
|
|
84777
|
+
return {
|
|
84778
|
+
[DeviceType.Washer]: {
|
|
84779
|
+
exported: true,
|
|
84780
|
+
as: received
|
|
84781
|
+
},
|
|
84782
|
+
[DeviceType.Dryer]: {
|
|
84783
|
+
exported: true,
|
|
84784
|
+
as: received
|
|
84785
|
+
},
|
|
84786
|
+
[DeviceType.Dishwasher]: {
|
|
84787
|
+
exported: true,
|
|
84788
|
+
as: received
|
|
84789
|
+
}
|
|
84790
|
+
};
|
|
84791
|
+
}
|
|
84792
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
83746
84793
|
Object.freeze({
|
|
83747
84794
|
"accessories.getStatus": [{
|
|
83748
84795
|
name: "deviceId",
|
|
@@ -84709,6 +85756,21 @@ Object.freeze({
|
|
|
84709
85756
|
form: "single",
|
|
84710
85757
|
optional: false
|
|
84711
85758
|
}],
|
|
85759
|
+
"groupActive.getStatus": [{
|
|
85760
|
+
name: "deviceId",
|
|
85761
|
+
form: "single",
|
|
85762
|
+
optional: false
|
|
85763
|
+
}],
|
|
85764
|
+
"groupCommands.getStatus": [{
|
|
85765
|
+
name: "deviceId",
|
|
85766
|
+
form: "single",
|
|
85767
|
+
optional: false
|
|
85768
|
+
}],
|
|
85769
|
+
"groupStatus.getStatus": [{
|
|
85770
|
+
name: "deviceId",
|
|
85771
|
+
form: "single",
|
|
85772
|
+
optional: false
|
|
85773
|
+
}],
|
|
84712
85774
|
"heatingValve.getStatus": [{
|
|
84713
85775
|
name: "deviceId",
|
|
84714
85776
|
form: "single",
|
|
@@ -84909,6 +85971,11 @@ Object.freeze({
|
|
|
84909
85971
|
form: "single",
|
|
84910
85972
|
optional: false
|
|
84911
85973
|
}],
|
|
85974
|
+
"meter.getStatus": [{
|
|
85975
|
+
name: "deviceId",
|
|
85976
|
+
form: "single",
|
|
85977
|
+
optional: false
|
|
85978
|
+
}],
|
|
84912
85979
|
"motion.getStatus": [{
|
|
84913
85980
|
name: "deviceId",
|
|
84914
85981
|
form: "single",
|
|
@@ -86516,7 +87583,6 @@ Object.freeze({
|
|
|
86516
87583
|
"network-access": "ingress",
|
|
86517
87584
|
"smtp-provider": "email"
|
|
86518
87585
|
});
|
|
86519
|
-
DeviceType.Camera;
|
|
86520
87586
|
/**
|
|
86521
87587
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
86522
87588
|
* `z.infer`, they do not restate the shape.
|
|
@@ -86693,6 +87759,8 @@ new Map(Object.entries({
|
|
|
86693
87759
|
"detection-blind": "device-events",
|
|
86694
87760
|
"motion-noisy": "device-events",
|
|
86695
87761
|
"motion-calm": "device-events",
|
|
87762
|
+
"package-llm-silent": "device-events",
|
|
87763
|
+
"package-llm-answered": "device-events",
|
|
86696
87764
|
"recording-stalled": "device-events",
|
|
86697
87765
|
"recording-healthy": "device-events",
|
|
86698
87766
|
"recording-degraded": "device-events",
|
|
@@ -86776,6 +87844,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
86776
87844
|
label: "Motion without a subject",
|
|
86777
87845
|
kinds: ["motion-noisy", "motion-calm"]
|
|
86778
87846
|
},
|
|
87847
|
+
{
|
|
87848
|
+
id: "package-llm",
|
|
87849
|
+
family: "device-events",
|
|
87850
|
+
label: "Package confirm",
|
|
87851
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
87852
|
+
},
|
|
86779
87853
|
{
|
|
86780
87854
|
id: "recording",
|
|
86781
87855
|
family: "device-events",
|
|
@@ -86957,6 +88031,8 @@ var DEVICE_EVENTS = [
|
|
|
86957
88031
|
"detection-blind",
|
|
86958
88032
|
"motion-noisy",
|
|
86959
88033
|
"motion-calm",
|
|
88034
|
+
"package-llm-silent",
|
|
88035
|
+
"package-llm-answered",
|
|
86960
88036
|
"recording-stalled",
|
|
86961
88037
|
"recording-healthy",
|
|
86962
88038
|
"recording-degraded",
|
|
@@ -87225,6 +88301,15 @@ new Map([
|
|
|
87225
88301
|
snapshotLabel: "Cameras with constant motion now",
|
|
87226
88302
|
snapshotSection: null
|
|
87227
88303
|
},
|
|
88304
|
+
{
|
|
88305
|
+
id: "package-llm-confirm",
|
|
88306
|
+
family: "device-events",
|
|
88307
|
+
label: "Package confirm (not answering / answering again)",
|
|
88308
|
+
bad: ["package-llm-silent"],
|
|
88309
|
+
recovery: ["package-llm-answered"],
|
|
88310
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88311
|
+
snapshotSection: null
|
|
88312
|
+
},
|
|
87228
88313
|
{
|
|
87229
88314
|
id: "recording-health",
|
|
87230
88315
|
family: "device-events",
|