@camstack/addon-smtp-nodemailer 1.2.141 → 1.2.143
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 +21 -0
- package/dist/smtp.addon.js +1366 -447
- package/dist/smtp.addon.mjs +1366 -447
- package/package.json +6 -4
package/dist/smtp.addon.js
CHANGED
|
@@ -36,7 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
36
36
|
}) : target, mod));
|
|
37
37
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
38
|
//#endregion
|
|
39
|
-
//#region ../types/dist/event-category-
|
|
39
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
40
40
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
41
41
|
EventCategory["SystemBoot"] = "system.boot";
|
|
42
42
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -362,6 +362,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
362
362
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
363
363
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
364
364
|
/**
|
|
365
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
366
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
367
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
368
|
+
*/
|
|
369
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
370
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
371
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
372
|
+
/**
|
|
365
373
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
366
374
|
* (a settings change via `setAgentInferenceDevices` /
|
|
367
375
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5471,7 +5479,7 @@ var ZodIssueCode = {
|
|
|
5471
5479
|
var ZodFirstPartyTypeKind;
|
|
5472
5480
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5473
5481
|
//#endregion
|
|
5474
|
-
//#region ../types/dist/sleep
|
|
5482
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5475
5483
|
/**
|
|
5476
5484
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5477
5485
|
* window to float samples (D455).
|
|
@@ -7958,6 +7966,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
7958
7966
|
}).strict();
|
|
7959
7967
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
7960
7968
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
7969
|
+
var READING_QUANTITIES = [
|
|
7970
|
+
"temperature",
|
|
7971
|
+
"pressure",
|
|
7972
|
+
"speed",
|
|
7973
|
+
"precipitation",
|
|
7974
|
+
"precipitation-rate",
|
|
7975
|
+
"length",
|
|
7976
|
+
"area",
|
|
7977
|
+
"illuminance",
|
|
7978
|
+
"irradiance",
|
|
7979
|
+
"power",
|
|
7980
|
+
"energy",
|
|
7981
|
+
"voltage",
|
|
7982
|
+
"current",
|
|
7983
|
+
"apparent-power",
|
|
7984
|
+
"humidity",
|
|
7985
|
+
"percentage",
|
|
7986
|
+
"concentration-volume",
|
|
7987
|
+
"concentration-mass",
|
|
7988
|
+
"concentration-ppb",
|
|
7989
|
+
"volume",
|
|
7990
|
+
"duration",
|
|
7991
|
+
"duration-ms",
|
|
7992
|
+
"information",
|
|
7993
|
+
"sound-level",
|
|
7994
|
+
"signal-level",
|
|
7995
|
+
"colour-temperature",
|
|
7996
|
+
"angle",
|
|
7997
|
+
"bitrate",
|
|
7998
|
+
"rate",
|
|
7999
|
+
"mass",
|
|
8000
|
+
"index",
|
|
8001
|
+
"ratio",
|
|
8002
|
+
"count",
|
|
8003
|
+
"none",
|
|
8004
|
+
"device"
|
|
8005
|
+
];
|
|
8006
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8007
|
+
new Set(READING_QUANTITIES);
|
|
8008
|
+
/**
|
|
8009
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8010
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8011
|
+
*/
|
|
8012
|
+
var QUANTITY_BASE = {
|
|
8013
|
+
temperature: "°C",
|
|
8014
|
+
pressure: "hPa",
|
|
8015
|
+
speed: "m/s",
|
|
8016
|
+
precipitation: "mm",
|
|
8017
|
+
"precipitation-rate": "mm/h",
|
|
8018
|
+
length: "m",
|
|
8019
|
+
area: "m²",
|
|
8020
|
+
illuminance: "lx",
|
|
8021
|
+
irradiance: "W/m²",
|
|
8022
|
+
power: "W",
|
|
8023
|
+
energy: "kWh",
|
|
8024
|
+
voltage: "V",
|
|
8025
|
+
current: "A",
|
|
8026
|
+
"apparent-power": "VA",
|
|
8027
|
+
humidity: "%",
|
|
8028
|
+
percentage: "%",
|
|
8029
|
+
"concentration-volume": "ppm",
|
|
8030
|
+
"concentration-mass": "µg/m³",
|
|
8031
|
+
"concentration-ppb": "ppb",
|
|
8032
|
+
volume: "L",
|
|
8033
|
+
duration: "s",
|
|
8034
|
+
"duration-ms": "ms",
|
|
8035
|
+
information: "B",
|
|
8036
|
+
"sound-level": "dBFS",
|
|
8037
|
+
"signal-level": "dBm",
|
|
8038
|
+
"colour-temperature": "mired",
|
|
8039
|
+
angle: "°",
|
|
8040
|
+
bitrate: "kbps",
|
|
8041
|
+
rate: "fps",
|
|
8042
|
+
mass: "kg",
|
|
8043
|
+
index: "none",
|
|
8044
|
+
ratio: "none",
|
|
8045
|
+
count: "none",
|
|
8046
|
+
none: "none",
|
|
8047
|
+
device: "device"
|
|
8048
|
+
};
|
|
8049
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8050
|
+
function baseUnitOf(quantity) {
|
|
8051
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8052
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8053
|
+
return symbol;
|
|
8054
|
+
}
|
|
8055
|
+
function readingMeta(quantity, extras) {
|
|
8056
|
+
return {
|
|
8057
|
+
quantity,
|
|
8058
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8059
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8060
|
+
};
|
|
8061
|
+
}
|
|
7961
8062
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
7962
8063
|
var CamProfileSchema = _enum([
|
|
7963
8064
|
"high",
|
|
@@ -7985,8 +8086,8 @@ var CamStreamKindSchema = _enum([
|
|
|
7985
8086
|
"derived"
|
|
7986
8087
|
]);
|
|
7987
8088
|
var CamStreamResolutionSchema = object({
|
|
7988
|
-
width: number().int().positive(),
|
|
7989
|
-
height: number().int().positive()
|
|
8089
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8090
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
7990
8091
|
});
|
|
7991
8092
|
var CameraStreamSchema = object({
|
|
7992
8093
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8500,6 +8601,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8500
8601
|
"filesystem-browse",
|
|
8501
8602
|
"flood",
|
|
8502
8603
|
"gas",
|
|
8604
|
+
"group-active",
|
|
8605
|
+
"group-commands",
|
|
8606
|
+
"group-status",
|
|
8503
8607
|
"heating-valve",
|
|
8504
8608
|
"humidifier",
|
|
8505
8609
|
"humidity-sensor",
|
|
@@ -8520,6 +8624,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8520
8624
|
"login-method",
|
|
8521
8625
|
"media-player",
|
|
8522
8626
|
"mesh-network",
|
|
8627
|
+
"meter",
|
|
8523
8628
|
"metrics-provider",
|
|
8524
8629
|
"model-convert",
|
|
8525
8630
|
"model-distributor",
|
|
@@ -8629,14 +8734,6 @@ Object.freeze({
|
|
|
8629
8734
|
{
|
|
8630
8735
|
"path": "aqi",
|
|
8631
8736
|
"valueType": "number"
|
|
8632
|
-
},
|
|
8633
|
-
{
|
|
8634
|
-
"path": "unit",
|
|
8635
|
-
"valueType": "string"
|
|
8636
|
-
},
|
|
8637
|
-
{
|
|
8638
|
-
"path": "precision",
|
|
8639
|
-
"valueType": "number"
|
|
8640
8737
|
}
|
|
8641
8738
|
],
|
|
8642
8739
|
"alarm-panel": [
|
|
@@ -8672,20 +8769,10 @@ Object.freeze({
|
|
|
8672
8769
|
"valueType": "boolean"
|
|
8673
8770
|
}
|
|
8674
8771
|
],
|
|
8675
|
-
"ambient-light-sensor": [
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
},
|
|
8680
|
-
{
|
|
8681
|
-
"path": "unit",
|
|
8682
|
-
"valueType": "string"
|
|
8683
|
-
},
|
|
8684
|
-
{
|
|
8685
|
-
"path": "precision",
|
|
8686
|
-
"valueType": "number"
|
|
8687
|
-
}
|
|
8688
|
-
],
|
|
8772
|
+
"ambient-light-sensor": [{
|
|
8773
|
+
"path": "lux",
|
|
8774
|
+
"valueType": "number"
|
|
8775
|
+
}],
|
|
8689
8776
|
"audio-metrics": [
|
|
8690
8777
|
{
|
|
8691
8778
|
"path": "ts",
|
|
@@ -8765,6 +8852,10 @@ Object.freeze({
|
|
|
8765
8852
|
"path": "lastUpdated",
|
|
8766
8853
|
"valueType": "number"
|
|
8767
8854
|
},
|
|
8855
|
+
{
|
|
8856
|
+
"path": "volts",
|
|
8857
|
+
"valueType": "number"
|
|
8858
|
+
},
|
|
8768
8859
|
{
|
|
8769
8860
|
"path": "lastContactAt",
|
|
8770
8861
|
"valueType": "number"
|
|
@@ -9007,10 +9098,6 @@ Object.freeze({
|
|
|
9007
9098
|
"datetime"
|
|
9008
9099
|
]
|
|
9009
9100
|
},
|
|
9010
|
-
{
|
|
9011
|
-
"path": "unit",
|
|
9012
|
-
"valueType": "string"
|
|
9013
|
-
},
|
|
9014
9101
|
{
|
|
9015
9102
|
"path": "min",
|
|
9016
9103
|
"valueType": "number"
|
|
@@ -9022,19 +9109,6 @@ Object.freeze({
|
|
|
9022
9109
|
{
|
|
9023
9110
|
"path": "step",
|
|
9024
9111
|
"valueType": "number"
|
|
9025
|
-
},
|
|
9026
|
-
{
|
|
9027
|
-
"path": "precision",
|
|
9028
|
-
"valueType": "number"
|
|
9029
|
-
},
|
|
9030
|
-
{
|
|
9031
|
-
"path": "format",
|
|
9032
|
-
"valueType": "enum",
|
|
9033
|
-
"enumValues": [
|
|
9034
|
-
"date",
|
|
9035
|
-
"time",
|
|
9036
|
-
"datetime"
|
|
9037
|
-
]
|
|
9038
9112
|
}
|
|
9039
9113
|
],
|
|
9040
9114
|
"cover": [
|
|
@@ -9275,13 +9349,8 @@ Object.freeze({
|
|
|
9275
9349
|
"path": "value",
|
|
9276
9350
|
"valueType": "string"
|
|
9277
9351
|
}, {
|
|
9278
|
-
"path": "
|
|
9279
|
-
"valueType": "
|
|
9280
|
-
"enumValues": [
|
|
9281
|
-
"date",
|
|
9282
|
-
"time",
|
|
9283
|
-
"datetime"
|
|
9284
|
-
]
|
|
9352
|
+
"path": "timestamp",
|
|
9353
|
+
"valueType": "boolean"
|
|
9285
9354
|
}],
|
|
9286
9355
|
"event-emitter": [
|
|
9287
9356
|
{
|
|
@@ -9354,6 +9423,24 @@ Object.freeze({
|
|
|
9354
9423
|
"path": "detected",
|
|
9355
9424
|
"valueType": "boolean"
|
|
9356
9425
|
}],
|
|
9426
|
+
"group-active": [{
|
|
9427
|
+
"path": "active",
|
|
9428
|
+
"valueType": "boolean"
|
|
9429
|
+
}],
|
|
9430
|
+
"group-status": [
|
|
9431
|
+
{
|
|
9432
|
+
"path": "included",
|
|
9433
|
+
"valueType": "number"
|
|
9434
|
+
},
|
|
9435
|
+
{
|
|
9436
|
+
"path": "excluded",
|
|
9437
|
+
"valueType": "number"
|
|
9438
|
+
},
|
|
9439
|
+
{
|
|
9440
|
+
"path": "total",
|
|
9441
|
+
"valueType": "number"
|
|
9442
|
+
}
|
|
9443
|
+
],
|
|
9357
9444
|
"heating-valve": [{
|
|
9358
9445
|
"path": "position",
|
|
9359
9446
|
"valueType": "number"
|
|
@@ -9388,20 +9475,10 @@ Object.freeze({
|
|
|
9388
9475
|
"valueType": "number"
|
|
9389
9476
|
}
|
|
9390
9477
|
],
|
|
9391
|
-
"humidity-sensor": [
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
},
|
|
9396
|
-
{
|
|
9397
|
-
"path": "unit",
|
|
9398
|
-
"valueType": "string"
|
|
9399
|
-
},
|
|
9400
|
-
{
|
|
9401
|
-
"path": "precision",
|
|
9402
|
-
"valueType": "number"
|
|
9403
|
-
}
|
|
9404
|
-
],
|
|
9478
|
+
"humidity-sensor": [{
|
|
9479
|
+
"path": "percent",
|
|
9480
|
+
"valueType": "number"
|
|
9481
|
+
}],
|
|
9405
9482
|
"image": [{
|
|
9406
9483
|
"path": "url",
|
|
9407
9484
|
"valueType": "string"
|
|
@@ -9609,6 +9686,10 @@ Object.freeze({
|
|
|
9609
9686
|
]
|
|
9610
9687
|
}
|
|
9611
9688
|
],
|
|
9689
|
+
"meter": [{
|
|
9690
|
+
"path": "value",
|
|
9691
|
+
"valueType": "number"
|
|
9692
|
+
}],
|
|
9612
9693
|
"motion": [
|
|
9613
9694
|
{
|
|
9614
9695
|
"path": "detected",
|
|
@@ -9740,20 +9821,10 @@ Object.freeze({
|
|
|
9740
9821
|
"valueType": "boolean"
|
|
9741
9822
|
}
|
|
9742
9823
|
],
|
|
9743
|
-
"numeric-sensor": [
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
},
|
|
9748
|
-
{
|
|
9749
|
-
"path": "unit",
|
|
9750
|
-
"valueType": "string"
|
|
9751
|
-
},
|
|
9752
|
-
{
|
|
9753
|
-
"path": "precision",
|
|
9754
|
-
"valueType": "number"
|
|
9755
|
-
}
|
|
9756
|
-
],
|
|
9824
|
+
"numeric-sensor": [{
|
|
9825
|
+
"path": "value",
|
|
9826
|
+
"valueType": "number"
|
|
9827
|
+
}],
|
|
9757
9828
|
"pet-feeder": [
|
|
9758
9829
|
{
|
|
9759
9830
|
"path": "foodLevel",
|
|
@@ -9845,14 +9916,6 @@ Object.freeze({
|
|
|
9845
9916
|
{
|
|
9846
9917
|
"path": "powerFactor",
|
|
9847
9918
|
"valueType": "number"
|
|
9848
|
-
},
|
|
9849
|
-
{
|
|
9850
|
-
"path": "unit",
|
|
9851
|
-
"valueType": "string"
|
|
9852
|
-
},
|
|
9853
|
-
{
|
|
9854
|
-
"path": "precision",
|
|
9855
|
-
"valueType": "number"
|
|
9856
9919
|
}
|
|
9857
9920
|
],
|
|
9858
9921
|
"presence": [
|
|
@@ -9881,20 +9944,10 @@ Object.freeze({
|
|
|
9881
9944
|
"valueType": "number"
|
|
9882
9945
|
}
|
|
9883
9946
|
],
|
|
9884
|
-
"pressure-sensor": [
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
},
|
|
9889
|
-
{
|
|
9890
|
-
"path": "unit",
|
|
9891
|
-
"valueType": "string"
|
|
9892
|
-
},
|
|
9893
|
-
{
|
|
9894
|
-
"path": "precision",
|
|
9895
|
-
"valueType": "number"
|
|
9896
|
-
}
|
|
9897
|
-
],
|
|
9947
|
+
"pressure-sensor": [{
|
|
9948
|
+
"path": "hpa",
|
|
9949
|
+
"valueType": "number"
|
|
9950
|
+
}],
|
|
9898
9951
|
"privacy-mask": [{
|
|
9899
9952
|
"path": "enabled",
|
|
9900
9953
|
"valueType": "boolean"
|
|
@@ -10205,20 +10258,10 @@ Object.freeze({
|
|
|
10205
10258
|
"path": "tampered",
|
|
10206
10259
|
"valueType": "boolean"
|
|
10207
10260
|
}],
|
|
10208
|
-
"temperature-sensor": [
|
|
10209
|
-
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
},
|
|
10213
|
-
{
|
|
10214
|
-
"path": "unit",
|
|
10215
|
-
"valueType": "string"
|
|
10216
|
-
},
|
|
10217
|
-
{
|
|
10218
|
-
"path": "precision",
|
|
10219
|
-
"valueType": "number"
|
|
10220
|
-
}
|
|
10221
|
-
],
|
|
10261
|
+
"temperature-sensor": [{
|
|
10262
|
+
"path": "celsius",
|
|
10263
|
+
"valueType": "number"
|
|
10264
|
+
}],
|
|
10222
10265
|
"update": [
|
|
10223
10266
|
{
|
|
10224
10267
|
"path": "currentVersion",
|
|
@@ -10329,10 +10372,6 @@ Object.freeze({
|
|
|
10329
10372
|
"path": "temperature",
|
|
10330
10373
|
"valueType": "number"
|
|
10331
10374
|
},
|
|
10332
|
-
{
|
|
10333
|
-
"path": "temperatureUnit",
|
|
10334
|
-
"valueType": "string"
|
|
10335
|
-
},
|
|
10336
10375
|
{
|
|
10337
10376
|
"path": "humidity",
|
|
10338
10377
|
"valueType": "number"
|
|
@@ -10341,18 +10380,10 @@ Object.freeze({
|
|
|
10341
10380
|
"path": "pressure",
|
|
10342
10381
|
"valueType": "number"
|
|
10343
10382
|
},
|
|
10344
|
-
{
|
|
10345
|
-
"path": "pressureUnit",
|
|
10346
|
-
"valueType": "string"
|
|
10347
|
-
},
|
|
10348
10383
|
{
|
|
10349
10384
|
"path": "windSpeed",
|
|
10350
10385
|
"valueType": "number"
|
|
10351
10386
|
},
|
|
10352
|
-
{
|
|
10353
|
-
"path": "windSpeedUnit",
|
|
10354
|
-
"valueType": "string"
|
|
10355
|
-
},
|
|
10356
10387
|
{
|
|
10357
10388
|
"path": "windBearing",
|
|
10358
10389
|
"valueType": "number"
|
|
@@ -10402,7 +10433,7 @@ object({
|
|
|
10402
10433
|
params: record(string(), union([string(), number()])).optional()
|
|
10403
10434
|
});
|
|
10404
10435
|
//#endregion
|
|
10405
|
-
//#region ../types/dist/err-msg-
|
|
10436
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10406
10437
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10407
10438
|
DeviceType["Camera"] = "camera";
|
|
10408
10439
|
DeviceType["Hub"] = "hub";
|
|
@@ -10496,8 +10527,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10496
10527
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10497
10528
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10498
10529
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10499
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10530
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10531
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10500
10532
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10533
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10534
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10535
|
+
DeviceType["Washer"] = "washer";
|
|
10536
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10537
|
+
DeviceType["Dryer"] = "dryer";
|
|
10501
10538
|
return DeviceType;
|
|
10502
10539
|
}({});
|
|
10503
10540
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -10745,7 +10782,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
10745
10782
|
return DeviceRole;
|
|
10746
10783
|
}({});
|
|
10747
10784
|
//#endregion
|
|
10748
|
-
//#region ../types/dist/composition-
|
|
10785
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
10749
10786
|
/**
|
|
10750
10787
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10751
10788
|
*
|
|
@@ -11060,6 +11097,13 @@ var table = {
|
|
|
11060
11097
|
apply: () => {
|
|
11061
11098
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11062
11099
|
}
|
|
11100
|
+
},
|
|
11101
|
+
schmitt: {
|
|
11102
|
+
minArgs: 3,
|
|
11103
|
+
maxArgs: 5,
|
|
11104
|
+
apply: () => {
|
|
11105
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11106
|
+
}
|
|
11063
11107
|
}
|
|
11064
11108
|
};
|
|
11065
11109
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11500,15 +11544,232 @@ function validateExpressionSource(src) {
|
|
|
11500
11544
|
}
|
|
11501
11545
|
return null;
|
|
11502
11546
|
}
|
|
11503
|
-
/**
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11547
|
+
/**
|
|
11548
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11549
|
+
*
|
|
11550
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11551
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11552
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11553
|
+
*
|
|
11554
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11555
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11556
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11557
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11558
|
+
* can move later without moving the others.
|
|
11559
|
+
*/
|
|
11560
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11561
|
+
var APPLIANCE_KINDS = [
|
|
11562
|
+
"washer",
|
|
11563
|
+
"dryer",
|
|
11564
|
+
"dishwasher"
|
|
11565
|
+
];
|
|
11566
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11567
|
+
/**
|
|
11568
|
+
* Statistics and integrals over a history read (D944).
|
|
11569
|
+
*
|
|
11570
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11571
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11572
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11573
|
+
* as zero. A truncated read is not published.
|
|
11574
|
+
*/
|
|
11575
|
+
var STATISTIC_STATS = [
|
|
11576
|
+
"min",
|
|
11577
|
+
"max",
|
|
11578
|
+
"mean",
|
|
11579
|
+
"sum",
|
|
11580
|
+
"count",
|
|
11581
|
+
"change"
|
|
11582
|
+
];
|
|
11583
|
+
/**
|
|
11584
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11585
|
+
*
|
|
11586
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11587
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11588
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11589
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11590
|
+
*/
|
|
11591
|
+
var MINUTE_MS = 6e4;
|
|
11592
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11593
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11594
|
+
var ROLLING_SPANS = [
|
|
11595
|
+
"1h",
|
|
11596
|
+
"24h",
|
|
11597
|
+
"2d",
|
|
11598
|
+
"7d",
|
|
11599
|
+
"30d",
|
|
11600
|
+
"custom"
|
|
11601
|
+
];
|
|
11602
|
+
var CALENDAR_PERIODS = [
|
|
11603
|
+
"today",
|
|
11604
|
+
"yesterday",
|
|
11605
|
+
"this-week",
|
|
11606
|
+
"this-month"
|
|
11607
|
+
];
|
|
11608
|
+
var RESET_PERIODS = [
|
|
11609
|
+
"never",
|
|
11610
|
+
"daily",
|
|
11611
|
+
"weekly",
|
|
11612
|
+
"monthly"
|
|
11613
|
+
];
|
|
11614
|
+
5 * MINUTE_MS;
|
|
11615
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11616
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11617
|
+
var rollingWindowObject = object({
|
|
11618
|
+
kind: literal("rolling"),
|
|
11619
|
+
span: _enum(ROLLING_SPANS),
|
|
11620
|
+
customMinutes: number().int().min(5).optional()
|
|
11621
|
+
}).check((payload) => {
|
|
11622
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11623
|
+
code: "custom",
|
|
11624
|
+
message: "a custom range needs a duration in minutes",
|
|
11625
|
+
path: ["customMinutes"],
|
|
11626
|
+
input: payload.value
|
|
11627
|
+
});
|
|
11628
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11629
|
+
code: "custom",
|
|
11630
|
+
message: "only a custom range carries a duration",
|
|
11631
|
+
path: ["customMinutes"],
|
|
11632
|
+
input: payload.value
|
|
11633
|
+
});
|
|
11634
|
+
});
|
|
11635
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11636
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11637
|
+
kind: literal("calendar"),
|
|
11638
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11639
|
+
})]);
|
|
11640
|
+
/**
|
|
11641
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11642
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11643
|
+
* `composition.ts` (D659).
|
|
11644
|
+
*/
|
|
11507
11645
|
var CompositionSourceRefSchema = object({
|
|
11508
11646
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11509
11647
|
addonId: string().min(1),
|
|
11510
11648
|
stableId: string().min(1)
|
|
11511
11649
|
});
|
|
11650
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11651
|
+
"temperature",
|
|
11652
|
+
"humidity",
|
|
11653
|
+
"pressure",
|
|
11654
|
+
"illuminance",
|
|
11655
|
+
"power",
|
|
11656
|
+
"energy",
|
|
11657
|
+
"battery",
|
|
11658
|
+
"numeric",
|
|
11659
|
+
"motion",
|
|
11660
|
+
"contact",
|
|
11661
|
+
"leak",
|
|
11662
|
+
"smoke",
|
|
11663
|
+
"occupancy",
|
|
11664
|
+
"binary",
|
|
11665
|
+
"switch",
|
|
11666
|
+
"light",
|
|
11667
|
+
"fan",
|
|
11668
|
+
"cover",
|
|
11669
|
+
"valve",
|
|
11670
|
+
"lock",
|
|
11671
|
+
"media-player",
|
|
11672
|
+
"climate"
|
|
11673
|
+
];
|
|
11674
|
+
var NUMERIC_AGGREGATES = [
|
|
11675
|
+
"mean",
|
|
11676
|
+
"median",
|
|
11677
|
+
"min",
|
|
11678
|
+
"max",
|
|
11679
|
+
"sum"
|
|
11680
|
+
];
|
|
11681
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11682
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11683
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11684
|
+
var AGGREGATE_REDUCERS = [
|
|
11685
|
+
"mean",
|
|
11686
|
+
"median",
|
|
11687
|
+
"min",
|
|
11688
|
+
"max",
|
|
11689
|
+
"sum",
|
|
11690
|
+
"any",
|
|
11691
|
+
"all"
|
|
11692
|
+
];
|
|
11693
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11694
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11695
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11696
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11697
|
+
var HelperMemberSchema = object({
|
|
11698
|
+
source: CompositionSourceRefSchema,
|
|
11699
|
+
cap: string().min(1),
|
|
11700
|
+
fieldPath: string().min(1)
|
|
11701
|
+
});
|
|
11702
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
11703
|
+
object({
|
|
11704
|
+
kind: literal("group"),
|
|
11705
|
+
templateId: GroupTemplateIdSchema,
|
|
11706
|
+
aggregate: AggregateReducerSchema,
|
|
11707
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11708
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11709
|
+
active: ActiveCriterionSchema.optional()
|
|
11710
|
+
}),
|
|
11711
|
+
object({
|
|
11712
|
+
kind: literal("appliance"),
|
|
11713
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
11714
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
11715
|
+
thresholdWatts: number().positive(),
|
|
11716
|
+
startDwellMs: number().int().nonnegative(),
|
|
11717
|
+
stopDwellMs: number().int().nonnegative(),
|
|
11718
|
+
member: HelperMemberSchema
|
|
11719
|
+
}),
|
|
11720
|
+
object({
|
|
11721
|
+
kind: literal("statistic"),
|
|
11722
|
+
stat: _enum(STATISTIC_STATS),
|
|
11723
|
+
window: StatisticWindowSchema,
|
|
11724
|
+
source: HelperMemberSchema
|
|
11725
|
+
}),
|
|
11726
|
+
object({
|
|
11727
|
+
kind: literal("integral"),
|
|
11728
|
+
reset: _enum(RESET_PERIODS),
|
|
11729
|
+
output: _enum(["energy", "meter"]),
|
|
11730
|
+
source: HelperMemberSchema
|
|
11731
|
+
}),
|
|
11732
|
+
object({
|
|
11733
|
+
kind: literal("threshold"),
|
|
11734
|
+
source: HelperMemberSchema,
|
|
11735
|
+
high: number(),
|
|
11736
|
+
low: number(),
|
|
11737
|
+
onForMs: number().int().nonnegative(),
|
|
11738
|
+
offForMs: number().int().nonnegative()
|
|
11739
|
+
}),
|
|
11740
|
+
object({
|
|
11741
|
+
kind: literal("arithmetic"),
|
|
11742
|
+
op: _enum([
|
|
11743
|
+
"sum",
|
|
11744
|
+
"difference",
|
|
11745
|
+
"ratio"
|
|
11746
|
+
]),
|
|
11747
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
11748
|
+
}),
|
|
11749
|
+
object({
|
|
11750
|
+
kind: literal("expression"),
|
|
11751
|
+
expr: string().min(1),
|
|
11752
|
+
inputs: array(object({
|
|
11753
|
+
name: string().min(1),
|
|
11754
|
+
member: HelperMemberSchema
|
|
11755
|
+
})).min(1).max(64),
|
|
11756
|
+
output: _enum(["number", "boolean"])
|
|
11757
|
+
}),
|
|
11758
|
+
object({
|
|
11759
|
+
kind: literal("derivative"),
|
|
11760
|
+
window: RollingWindowSchema,
|
|
11761
|
+
per: _enum([
|
|
11762
|
+
"second",
|
|
11763
|
+
"minute",
|
|
11764
|
+
"hour"
|
|
11765
|
+
]),
|
|
11766
|
+
source: HelperMemberSchema
|
|
11767
|
+
})
|
|
11768
|
+
]);
|
|
11769
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11770
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11771
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11772
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11512
11773
|
/** One field of one capability of one source device. */
|
|
11513
11774
|
var CompositionFieldReadSchema = object({
|
|
11514
11775
|
source: CompositionSourceRefSchema,
|
|
@@ -11552,7 +11813,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11552
11813
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11553
11814
|
CompositionFromSourceSchema,
|
|
11554
11815
|
CompositionExpressionSourceSchema,
|
|
11555
|
-
CompositionCodeSourceSchema
|
|
11816
|
+
CompositionCodeSourceSchema,
|
|
11817
|
+
object({
|
|
11818
|
+
kind: literal("aggregate"),
|
|
11819
|
+
reducer: _enum([
|
|
11820
|
+
"mean",
|
|
11821
|
+
"median",
|
|
11822
|
+
"min",
|
|
11823
|
+
"max",
|
|
11824
|
+
"sum",
|
|
11825
|
+
"any",
|
|
11826
|
+
"all"
|
|
11827
|
+
]),
|
|
11828
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11829
|
+
/**
|
|
11830
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
11831
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
11832
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
11833
|
+
*/
|
|
11834
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
11835
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11836
|
+
publish: _enum([
|
|
11837
|
+
"value",
|
|
11838
|
+
"included",
|
|
11839
|
+
"excluded",
|
|
11840
|
+
"total"
|
|
11841
|
+
]),
|
|
11842
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11843
|
+
empty: _enum([
|
|
11844
|
+
"null",
|
|
11845
|
+
"omit",
|
|
11846
|
+
"offline"
|
|
11847
|
+
])
|
|
11848
|
+
}),
|
|
11849
|
+
object({
|
|
11850
|
+
kind: literal("series"),
|
|
11851
|
+
read: CompositionFieldReadSchema,
|
|
11852
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
11853
|
+
publish: _enum([
|
|
11854
|
+
"value",
|
|
11855
|
+
"included",
|
|
11856
|
+
"excluded",
|
|
11857
|
+
"total"
|
|
11858
|
+
]),
|
|
11859
|
+
/**
|
|
11860
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
11861
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
11862
|
+
*/
|
|
11863
|
+
empty: _enum([
|
|
11864
|
+
"null",
|
|
11865
|
+
"omit",
|
|
11866
|
+
"offline"
|
|
11867
|
+
])
|
|
11868
|
+
})
|
|
11556
11869
|
]);
|
|
11557
11870
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11558
11871
|
kind: literal("forward"),
|
|
@@ -11598,7 +11911,13 @@ var CompositionSchema = object({
|
|
|
11598
11911
|
kind: literal("existing"),
|
|
11599
11912
|
device: CompositionSourceRefSchema
|
|
11600
11913
|
})]),
|
|
11601
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
11914
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
11915
|
+
/**
|
|
11916
|
+
* Present when the block is a helper template. Absent on a free
|
|
11917
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
11918
|
+
* never the compiled features.
|
|
11919
|
+
*/
|
|
11920
|
+
helper: HelperSpecSchema.optional()
|
|
11602
11921
|
}).superRefine((composition, ctx) => {
|
|
11603
11922
|
const seen = /* @__PURE__ */ new Set();
|
|
11604
11923
|
composition.features.forEach((feature, index) => {
|
|
@@ -16705,7 +17024,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
16705
17024
|
*/
|
|
16706
17025
|
interactiveConnectPath: string().min(1).optional(),
|
|
16707
17026
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
16708
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17027
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17028
|
+
/**
|
|
17029
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17030
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17031
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17032
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17033
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17034
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17035
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17036
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17037
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17038
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17039
|
+
* offers it as the default path; the fields the session fills are
|
|
17040
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17041
|
+
*/
|
|
17042
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
16709
17043
|
}))
|
|
16710
17044
|
});
|
|
16711
17045
|
var ListInputSchema = object({
|
|
@@ -17700,7 +18034,12 @@ var CompositionProblemSchema = object({
|
|
|
17700
18034
|
"item-field-reserved",
|
|
17701
18035
|
"target-missing",
|
|
17702
18036
|
"target-unreadable",
|
|
17703
|
-
"not-replaceable"
|
|
18037
|
+
"not-replaceable",
|
|
18038
|
+
"native-capability-replace",
|
|
18039
|
+
"mixed-quantity",
|
|
18040
|
+
"helper-mismatch",
|
|
18041
|
+
"member-constraint",
|
|
18042
|
+
"retention"
|
|
17704
18043
|
]),
|
|
17705
18044
|
path: string(),
|
|
17706
18045
|
message: string()
|
|
@@ -17721,7 +18060,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17721
18060
|
"null",
|
|
17722
18061
|
"offline",
|
|
17723
18062
|
"unknown",
|
|
17724
|
-
"release"
|
|
18063
|
+
"release",
|
|
18064
|
+
"omit"
|
|
17725
18065
|
]);
|
|
17726
18066
|
/**
|
|
17727
18067
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17758,9 +18098,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17758
18098
|
reads: array(CompositionFieldReadSchema)
|
|
17759
18099
|
});
|
|
17760
18100
|
/**
|
|
17761
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17762
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17763
|
-
*
|
|
18101
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18102
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18103
|
+
* Replacing a capability the device already serves is refused
|
|
18104
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18105
|
+
* wire for a claim the hub already holds.
|
|
17764
18106
|
*/
|
|
17765
18107
|
var CompositionFeatureModeSchema = _enum([
|
|
17766
18108
|
"new",
|
|
@@ -17931,8 +18273,392 @@ Object.freeze({
|
|
|
17931
18273
|
latchedAt: {
|
|
17932
18274
|
kind: "fixed",
|
|
17933
18275
|
result: ["number", "null"]
|
|
18276
|
+
},
|
|
18277
|
+
schmitt: {
|
|
18278
|
+
kind: "fixed",
|
|
18279
|
+
result: ["boolean", "null"]
|
|
17934
18280
|
}
|
|
17935
18281
|
});
|
|
18282
|
+
/**
|
|
18283
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18284
|
+
* Data, not a form default written into the block.
|
|
18285
|
+
*/
|
|
18286
|
+
var NOW$2 = {
|
|
18287
|
+
fieldPath: "lastFetchedAt",
|
|
18288
|
+
expr: "now"
|
|
18289
|
+
};
|
|
18290
|
+
var CHANGED = {
|
|
18291
|
+
fieldPath: "lastChangedAt",
|
|
18292
|
+
expr: "now"
|
|
18293
|
+
};
|
|
18294
|
+
function numeric(input) {
|
|
18295
|
+
return {
|
|
18296
|
+
...input,
|
|
18297
|
+
family: "numeric",
|
|
18298
|
+
deviceType: DeviceType.Sensor,
|
|
18299
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18300
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18301
|
+
activeWhen: void 0,
|
|
18302
|
+
commandCaps: [],
|
|
18303
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18304
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18305
|
+
accept: [{
|
|
18306
|
+
cap: input.outputCap,
|
|
18307
|
+
fieldPath: input.outputField
|
|
18308
|
+
}]
|
|
18309
|
+
};
|
|
18310
|
+
}
|
|
18311
|
+
function binary(input) {
|
|
18312
|
+
return {
|
|
18313
|
+
...input,
|
|
18314
|
+
family: "binary",
|
|
18315
|
+
deviceType: DeviceType.Sensor,
|
|
18316
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18317
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18318
|
+
activeWhen: void 0,
|
|
18319
|
+
commandCaps: [],
|
|
18320
|
+
quantity: "none",
|
|
18321
|
+
baseUnit: void 0,
|
|
18322
|
+
aggregates: BINARY_AGGREGATES,
|
|
18323
|
+
empty: "offline"
|
|
18324
|
+
};
|
|
18325
|
+
}
|
|
18326
|
+
var GROUP_TEMPLATES = [
|
|
18327
|
+
numeric({
|
|
18328
|
+
id: "temperature",
|
|
18329
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18330
|
+
role: DeviceRole.TemperatureSensor,
|
|
18331
|
+
outputCap: "temperature-sensor",
|
|
18332
|
+
outputField: "celsius",
|
|
18333
|
+
quantity: "temperature",
|
|
18334
|
+
defaultAggregate: "mean",
|
|
18335
|
+
empty: "null",
|
|
18336
|
+
companions: [NOW$2]
|
|
18337
|
+
}),
|
|
18338
|
+
numeric({
|
|
18339
|
+
id: "humidity",
|
|
18340
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18341
|
+
role: DeviceRole.HumiditySensor,
|
|
18342
|
+
outputCap: "humidity-sensor",
|
|
18343
|
+
outputField: "percent",
|
|
18344
|
+
quantity: "humidity",
|
|
18345
|
+
defaultAggregate: "mean",
|
|
18346
|
+
empty: "null",
|
|
18347
|
+
companions: [NOW$2]
|
|
18348
|
+
}),
|
|
18349
|
+
numeric({
|
|
18350
|
+
id: "pressure",
|
|
18351
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18352
|
+
role: DeviceRole.PressureSensor,
|
|
18353
|
+
outputCap: "pressure-sensor",
|
|
18354
|
+
outputField: "hpa",
|
|
18355
|
+
quantity: "pressure",
|
|
18356
|
+
defaultAggregate: "mean",
|
|
18357
|
+
empty: "null",
|
|
18358
|
+
companions: [NOW$2]
|
|
18359
|
+
}),
|
|
18360
|
+
numeric({
|
|
18361
|
+
id: "illuminance",
|
|
18362
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18363
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18364
|
+
outputCap: "ambient-light-sensor",
|
|
18365
|
+
outputField: "lux",
|
|
18366
|
+
quantity: "illuminance",
|
|
18367
|
+
defaultAggregate: "mean",
|
|
18368
|
+
empty: "null",
|
|
18369
|
+
companions: [NOW$2]
|
|
18370
|
+
}),
|
|
18371
|
+
numeric({
|
|
18372
|
+
id: "power",
|
|
18373
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18374
|
+
role: DeviceRole.PowerSensor,
|
|
18375
|
+
outputCap: "power-meter",
|
|
18376
|
+
outputField: "watts",
|
|
18377
|
+
quantity: "power",
|
|
18378
|
+
defaultAggregate: "sum",
|
|
18379
|
+
empty: "omit",
|
|
18380
|
+
companions: [NOW$2]
|
|
18381
|
+
}),
|
|
18382
|
+
numeric({
|
|
18383
|
+
id: "energy",
|
|
18384
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18385
|
+
role: DeviceRole.EnergySensor,
|
|
18386
|
+
outputCap: "power-meter",
|
|
18387
|
+
outputField: "kwhTotal",
|
|
18388
|
+
quantity: "energy",
|
|
18389
|
+
defaultAggregate: "sum",
|
|
18390
|
+
empty: "omit",
|
|
18391
|
+
companions: [NOW$2]
|
|
18392
|
+
}),
|
|
18393
|
+
numeric({
|
|
18394
|
+
id: "battery",
|
|
18395
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18396
|
+
role: DeviceRole.BatterySensor,
|
|
18397
|
+
outputCap: "battery",
|
|
18398
|
+
outputField: "percentage",
|
|
18399
|
+
quantity: "percentage",
|
|
18400
|
+
defaultAggregate: "mean",
|
|
18401
|
+
empty: "null",
|
|
18402
|
+
companions: [
|
|
18403
|
+
{
|
|
18404
|
+
fieldPath: "charging",
|
|
18405
|
+
expr: "\"unknown\""
|
|
18406
|
+
},
|
|
18407
|
+
{
|
|
18408
|
+
fieldPath: "sleeping",
|
|
18409
|
+
expr: "false"
|
|
18410
|
+
},
|
|
18411
|
+
{
|
|
18412
|
+
fieldPath: "lastUpdated",
|
|
18413
|
+
expr: "now"
|
|
18414
|
+
}
|
|
18415
|
+
]
|
|
18416
|
+
}),
|
|
18417
|
+
numeric({
|
|
18418
|
+
id: "numeric",
|
|
18419
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18420
|
+
role: DeviceRole.NumericSensor,
|
|
18421
|
+
outputCap: "numeric-sensor",
|
|
18422
|
+
outputField: "value",
|
|
18423
|
+
quantity: "device",
|
|
18424
|
+
defaultAggregate: "mean",
|
|
18425
|
+
empty: "null",
|
|
18426
|
+
companions: [NOW$2]
|
|
18427
|
+
}),
|
|
18428
|
+
binary({
|
|
18429
|
+
id: "motion",
|
|
18430
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18431
|
+
role: DeviceRole.MotionSensor,
|
|
18432
|
+
outputCap: "motion",
|
|
18433
|
+
outputField: "detected",
|
|
18434
|
+
defaultAggregate: "any",
|
|
18435
|
+
accept: [{
|
|
18436
|
+
cap: "motion",
|
|
18437
|
+
fieldPath: "detected"
|
|
18438
|
+
}],
|
|
18439
|
+
companions: [{
|
|
18440
|
+
fieldPath: "lastDetectedAt",
|
|
18441
|
+
expr: "null"
|
|
18442
|
+
}, {
|
|
18443
|
+
fieldPath: "autoClearAfterMs",
|
|
18444
|
+
expr: "null"
|
|
18445
|
+
}]
|
|
18446
|
+
}),
|
|
18447
|
+
binary({
|
|
18448
|
+
id: "contact",
|
|
18449
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18450
|
+
role: DeviceRole.ContactSensor,
|
|
18451
|
+
outputCap: "contact",
|
|
18452
|
+
outputField: "entryOpen",
|
|
18453
|
+
defaultAggregate: "any",
|
|
18454
|
+
accept: [{
|
|
18455
|
+
cap: "contact",
|
|
18456
|
+
fieldPath: "entryOpen"
|
|
18457
|
+
}],
|
|
18458
|
+
companions: [CHANGED]
|
|
18459
|
+
}),
|
|
18460
|
+
binary({
|
|
18461
|
+
id: "leak",
|
|
18462
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18463
|
+
role: DeviceRole.LeakSensor,
|
|
18464
|
+
outputCap: "flood",
|
|
18465
|
+
outputField: "flooded",
|
|
18466
|
+
defaultAggregate: "any",
|
|
18467
|
+
accept: [{
|
|
18468
|
+
cap: "flood",
|
|
18469
|
+
fieldPath: "flooded"
|
|
18470
|
+
}],
|
|
18471
|
+
companions: [CHANGED]
|
|
18472
|
+
}),
|
|
18473
|
+
binary({
|
|
18474
|
+
id: "smoke",
|
|
18475
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18476
|
+
role: DeviceRole.SmokeSensor,
|
|
18477
|
+
outputCap: "smoke",
|
|
18478
|
+
outputField: "detected",
|
|
18479
|
+
defaultAggregate: "any",
|
|
18480
|
+
accept: [{
|
|
18481
|
+
cap: "smoke",
|
|
18482
|
+
fieldPath: "detected"
|
|
18483
|
+
}],
|
|
18484
|
+
companions: [CHANGED]
|
|
18485
|
+
}),
|
|
18486
|
+
binary({
|
|
18487
|
+
id: "occupancy",
|
|
18488
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18489
|
+
role: DeviceRole.BinarySensor,
|
|
18490
|
+
outputCap: "binary",
|
|
18491
|
+
outputField: "on",
|
|
18492
|
+
defaultAggregate: "any",
|
|
18493
|
+
accept: [{
|
|
18494
|
+
cap: "motion",
|
|
18495
|
+
fieldPath: "detected"
|
|
18496
|
+
}, {
|
|
18497
|
+
cap: "binary",
|
|
18498
|
+
fieldPath: "on"
|
|
18499
|
+
}],
|
|
18500
|
+
companions: [CHANGED]
|
|
18501
|
+
}),
|
|
18502
|
+
binary({
|
|
18503
|
+
id: "binary",
|
|
18504
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18505
|
+
role: DeviceRole.BinarySensor,
|
|
18506
|
+
outputCap: "binary",
|
|
18507
|
+
outputField: "on",
|
|
18508
|
+
defaultAggregate: "any",
|
|
18509
|
+
accept: [{
|
|
18510
|
+
cap: "binary",
|
|
18511
|
+
fieldPath: "on"
|
|
18512
|
+
}],
|
|
18513
|
+
companions: [CHANGED]
|
|
18514
|
+
}),
|
|
18515
|
+
actuator({
|
|
18516
|
+
id: "switch",
|
|
18517
|
+
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.",
|
|
18518
|
+
deviceType: DeviceType.Switch,
|
|
18519
|
+
outputCap: "switch",
|
|
18520
|
+
outputField: "on",
|
|
18521
|
+
member: {
|
|
18522
|
+
cap: "switch",
|
|
18523
|
+
fieldPath: "on"
|
|
18524
|
+
},
|
|
18525
|
+
commandCaps: ["switch"]
|
|
18526
|
+
}),
|
|
18527
|
+
actuator({
|
|
18528
|
+
id: "light",
|
|
18529
|
+
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.",
|
|
18530
|
+
deviceType: DeviceType.Light,
|
|
18531
|
+
outputCap: "switch",
|
|
18532
|
+
outputField: "on",
|
|
18533
|
+
member: {
|
|
18534
|
+
cap: "switch",
|
|
18535
|
+
fieldPath: "on"
|
|
18536
|
+
},
|
|
18537
|
+
commandCaps: [
|
|
18538
|
+
"switch",
|
|
18539
|
+
"brightness",
|
|
18540
|
+
"color"
|
|
18541
|
+
]
|
|
18542
|
+
}),
|
|
18543
|
+
actuator({
|
|
18544
|
+
id: "fan",
|
|
18545
|
+
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.",
|
|
18546
|
+
deviceType: DeviceType.Fan,
|
|
18547
|
+
outputCap: "switch",
|
|
18548
|
+
outputField: "on",
|
|
18549
|
+
member: {
|
|
18550
|
+
cap: "switch",
|
|
18551
|
+
fieldPath: "on"
|
|
18552
|
+
},
|
|
18553
|
+
commandCaps: ["switch", "fan-control"]
|
|
18554
|
+
}),
|
|
18555
|
+
actuator({
|
|
18556
|
+
id: "cover",
|
|
18557
|
+
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.",
|
|
18558
|
+
deviceType: DeviceType.Cover,
|
|
18559
|
+
outputCap: "group-active",
|
|
18560
|
+
outputField: "active",
|
|
18561
|
+
member: {
|
|
18562
|
+
cap: "cover",
|
|
18563
|
+
fieldPath: "state"
|
|
18564
|
+
},
|
|
18565
|
+
activeWhen: [
|
|
18566
|
+
"open",
|
|
18567
|
+
"opening",
|
|
18568
|
+
"stopped"
|
|
18569
|
+
],
|
|
18570
|
+
commandCaps: ["cover"]
|
|
18571
|
+
}),
|
|
18572
|
+
actuator({
|
|
18573
|
+
id: "valve",
|
|
18574
|
+
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.",
|
|
18575
|
+
deviceType: DeviceType.Valve,
|
|
18576
|
+
outputCap: "group-active",
|
|
18577
|
+
outputField: "active",
|
|
18578
|
+
member: {
|
|
18579
|
+
cap: "valve",
|
|
18580
|
+
fieldPath: "state"
|
|
18581
|
+
},
|
|
18582
|
+
activeWhen: [
|
|
18583
|
+
"open",
|
|
18584
|
+
"opening",
|
|
18585
|
+
"stopped"
|
|
18586
|
+
],
|
|
18587
|
+
commandCaps: ["valve"]
|
|
18588
|
+
}),
|
|
18589
|
+
actuator({
|
|
18590
|
+
id: "lock",
|
|
18591
|
+
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.",
|
|
18592
|
+
deviceType: DeviceType.Lock,
|
|
18593
|
+
outputCap: "group-active",
|
|
18594
|
+
outputField: "active",
|
|
18595
|
+
member: {
|
|
18596
|
+
cap: "lock-control",
|
|
18597
|
+
fieldPath: "state"
|
|
18598
|
+
},
|
|
18599
|
+
activeWhen: ["locked"],
|
|
18600
|
+
commandCaps: ["lock-control"]
|
|
18601
|
+
}),
|
|
18602
|
+
actuator({
|
|
18603
|
+
id: "media-player",
|
|
18604
|
+
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.",
|
|
18605
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18606
|
+
outputCap: "group-active",
|
|
18607
|
+
outputField: "active",
|
|
18608
|
+
member: {
|
|
18609
|
+
cap: "media-player",
|
|
18610
|
+
fieldPath: "state"
|
|
18611
|
+
},
|
|
18612
|
+
activeWhen: ["playing", "buffering"],
|
|
18613
|
+
commandCaps: ["media-player"]
|
|
18614
|
+
}),
|
|
18615
|
+
actuator({
|
|
18616
|
+
id: "climate",
|
|
18617
|
+
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.",
|
|
18618
|
+
deviceType: DeviceType.Thermostat,
|
|
18619
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
18620
|
+
outputCap: "group-active",
|
|
18621
|
+
outputField: "active",
|
|
18622
|
+
member: {
|
|
18623
|
+
cap: "climate-control",
|
|
18624
|
+
fieldPath: "mode"
|
|
18625
|
+
},
|
|
18626
|
+
activeWhen: [
|
|
18627
|
+
"heat",
|
|
18628
|
+
"cool",
|
|
18629
|
+
"auto",
|
|
18630
|
+
"heat_cool",
|
|
18631
|
+
"fan_only",
|
|
18632
|
+
"dry"
|
|
18633
|
+
],
|
|
18634
|
+
commandCaps: ["climate-control"]
|
|
18635
|
+
})
|
|
18636
|
+
];
|
|
18637
|
+
function actuator(input) {
|
|
18638
|
+
return {
|
|
18639
|
+
id: input.id,
|
|
18640
|
+
summary: input.summary,
|
|
18641
|
+
deviceType: input.deviceType,
|
|
18642
|
+
outputCap: input.outputCap,
|
|
18643
|
+
outputField: input.outputField,
|
|
18644
|
+
commandCaps: input.commandCaps,
|
|
18645
|
+
family: "actuator",
|
|
18646
|
+
role: void 0,
|
|
18647
|
+
memberDeviceType: input.deviceType,
|
|
18648
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
18649
|
+
activeWhen: input.activeWhen,
|
|
18650
|
+
quantity: "none",
|
|
18651
|
+
baseUnit: void 0,
|
|
18652
|
+
aggregates: BINARY_AGGREGATES,
|
|
18653
|
+
defaultAggregate: "any",
|
|
18654
|
+
empty: "offline",
|
|
18655
|
+
accept: [input.member],
|
|
18656
|
+
companions: [CHANGED]
|
|
18657
|
+
};
|
|
18658
|
+
}
|
|
18659
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18660
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18661
|
+
DeviceType.Camera;
|
|
17936
18662
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
17937
18663
|
/**
|
|
17938
18664
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19646,12 +20372,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
19646
20372
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19647
20373
|
* in-place so dispatch keeps working.
|
|
19648
20374
|
*
|
|
19649
|
-
* **
|
|
19650
|
-
*
|
|
19651
|
-
*
|
|
19652
|
-
*
|
|
19653
|
-
* (`ha-domain-mapping`)
|
|
19654
|
-
* stored after that point.
|
|
20375
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20376
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20377
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20378
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20379
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20380
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19655
20381
|
*
|
|
19656
20382
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19657
20383
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19665,6 +20391,14 @@ var SourceInfoSchema = object({
|
|
|
19665
20391
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19666
20392
|
* Used to detect rename when `id` changes. */
|
|
19667
20393
|
uniqueId: string().optional(),
|
|
20394
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20395
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20396
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20397
|
+
dateTimeShape: _enum([
|
|
20398
|
+
"date",
|
|
20399
|
+
"time",
|
|
20400
|
+
"datetime"
|
|
20401
|
+
]).optional(),
|
|
19668
20402
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19669
20403
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19670
20404
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -40577,7 +41311,8 @@ method(object({
|
|
|
40577
41311
|
"enum"
|
|
40578
41312
|
]),
|
|
40579
41313
|
enumValues: array(string()).optional(),
|
|
40580
|
-
item: boolean().optional()
|
|
41314
|
+
item: boolean().optional(),
|
|
41315
|
+
quantity: ReadingQuantitySchema.optional()
|
|
40581
41316
|
})).readonly(),
|
|
40582
41317
|
itemArray: object({
|
|
40583
41318
|
path: string(),
|
|
@@ -42938,7 +43673,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
42938
43673
|
});
|
|
42939
43674
|
/**
|
|
42940
43675
|
* Optional, richer endpoint shape returned by providers that expose
|
|
42941
|
-
* MORE than one ingress concurrently (Tailscale
|
|
43676
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
42942
43677
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
42943
43678
|
* the originating provider config (mode + sourcePort) so the
|
|
42944
43679
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44377,8 +45112,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44377
45112
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44378
45113
|
var MaskGridShapeSchema = object({
|
|
44379
45114
|
kind: literal("grid"),
|
|
44380
|
-
gridWidth: number(),
|
|
44381
|
-
gridHeight: number(),
|
|
45115
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45116
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44382
45117
|
cells: array(boolean())
|
|
44383
45118
|
});
|
|
44384
45119
|
discriminatedUnion("kind", [
|
|
@@ -44490,6 +45225,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44490
45225
|
"detection-blind",
|
|
44491
45226
|
"motion-noisy",
|
|
44492
45227
|
"motion-calm",
|
|
45228
|
+
"package-llm-silent",
|
|
45229
|
+
"package-llm-answered",
|
|
44493
45230
|
"recording-stalled",
|
|
44494
45231
|
"recording-healthy",
|
|
44495
45232
|
"recording-degraded",
|
|
@@ -45579,7 +46316,20 @@ var NcRuleInputSchema = object({
|
|
|
45579
46316
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
45580
46317
|
* path does not run Zod defaults.
|
|
45581
46318
|
*/
|
|
45582
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46319
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46320
|
+
/**
|
|
46321
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46322
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46323
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46324
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46325
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46326
|
+
*
|
|
46327
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46328
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46329
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46330
|
+
* `false`, so it needs no `clear` key.
|
|
46331
|
+
*/
|
|
46332
|
+
askVerdict: boolean().optional()
|
|
45583
46333
|
});
|
|
45584
46334
|
/**
|
|
45585
46335
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -55517,6 +56267,28 @@ var PackageVersionInfoSchema = object({
|
|
|
55517
56267
|
deprecated: string().optional(),
|
|
55518
56268
|
distTags: array(string()).readonly()
|
|
55519
56269
|
});
|
|
56270
|
+
/**
|
|
56271
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56272
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56273
|
+
* tarball failure — never an empty string standing in for either.
|
|
56274
|
+
*/
|
|
56275
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56276
|
+
object({
|
|
56277
|
+
status: literal("ok"),
|
|
56278
|
+
markdown: string()
|
|
56279
|
+
}),
|
|
56280
|
+
object({ status: literal("missing") }),
|
|
56281
|
+
object({
|
|
56282
|
+
status: literal("error"),
|
|
56283
|
+
message: string()
|
|
56284
|
+
})
|
|
56285
|
+
]);
|
|
56286
|
+
var PackageDocsSchema = object({
|
|
56287
|
+
name: string(),
|
|
56288
|
+
version: string(),
|
|
56289
|
+
readme: PackageDocBodySchema,
|
|
56290
|
+
changelog: PackageDocBodySchema
|
|
56291
|
+
});
|
|
55520
56292
|
var SearchResultSchema = object({
|
|
55521
56293
|
name: string(),
|
|
55522
56294
|
version: string(),
|
|
@@ -55735,7 +56507,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
55735
56507
|
}), object({ success: literal(true) }), {
|
|
55736
56508
|
kind: "mutation",
|
|
55737
56509
|
auth: "admin"
|
|
55738
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56510
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56511
|
+
name: string().min(1),
|
|
56512
|
+
version: string().min(1).optional()
|
|
56513
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
55739
56514
|
kind: "mutation",
|
|
55740
56515
|
auth: "admin"
|
|
55741
56516
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -55785,46 +56560,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
55785
56560
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
55786
56561
|
object({
|
|
55787
56562
|
/** Carbon dioxide concentration in ppm. */
|
|
55788
|
-
co2Ppm: number().min(0).optional(),
|
|
56563
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
55789
56564
|
/** Total volatile organic compounds in ppb. */
|
|
55790
|
-
vocPpb: number().min(0).optional(),
|
|
56565
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
55791
56566
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
55792
|
-
pm25: number().min(0).optional(),
|
|
56567
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
55793
56568
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
55794
|
-
pm10: number().min(0).optional(),
|
|
56569
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
55795
56570
|
/** Composite AQI value (typically 0..500). */
|
|
55796
|
-
aqi: number().optional(),
|
|
56571
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
55797
56572
|
/** Ms epoch when the slice was last updated. */
|
|
55798
|
-
lastFetchedAt: number()
|
|
55799
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
55800
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
55801
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
55802
|
-
* per slice is unambiguous. */
|
|
55803
|
-
unit: string().optional(),
|
|
55804
|
-
/** Suggested decimal places for numeric display.
|
|
55805
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
55806
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
55807
|
-
* auto-formatting when absent. */
|
|
55808
|
-
precision: number().int().min(0).max(10).optional()
|
|
56573
|
+
lastFetchedAt: number()
|
|
55809
56574
|
});
|
|
55810
56575
|
DeviceType.Sensor;
|
|
55811
56576
|
object({
|
|
55812
|
-
/** Current illuminance in lux (lx). */
|
|
55813
|
-
lux: number().min(0).meta({
|
|
55814
|
-
|
|
56577
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
56578
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
56579
|
+
precision: 0,
|
|
55815
56580
|
label: "Illuminance"
|
|
55816
|
-
}),
|
|
56581
|
+
})),
|
|
55817
56582
|
/** Ms epoch when the slice was last updated. */
|
|
55818
|
-
lastFetchedAt: number()
|
|
55819
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
55820
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
55821
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
55822
|
-
unit: string().optional(),
|
|
55823
|
-
/** Suggested decimal places for numeric display.
|
|
55824
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
55825
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
55826
|
-
* auto-formatting when absent. */
|
|
55827
|
-
precision: number().int().min(0).max(10).optional()
|
|
56583
|
+
lastFetchedAt: number()
|
|
55828
56584
|
});
|
|
55829
56585
|
DeviceType.Sensor;
|
|
55830
56586
|
/**
|
|
@@ -55969,10 +56725,7 @@ var BatteryStatusSchema = object({
|
|
|
55969
56725
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
55970
56726
|
* declines to band a non-finite reading, which is the correct shape.
|
|
55971
56727
|
*/
|
|
55972
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
55973
|
-
unit: "%",
|
|
55974
|
-
label: "Charge"
|
|
55975
|
-
}),
|
|
56728
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
55976
56729
|
/**
|
|
55977
56730
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
55978
56731
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -55999,7 +56752,14 @@ var BatteryStatusSchema = object({
|
|
|
55999
56752
|
*/
|
|
56000
56753
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56001
56754
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56002
|
-
lastUpdated: number(),
|
|
56755
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
56756
|
+
/**
|
|
56757
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
56758
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
56759
|
+
* that only report charge. A second reading on this cap, not a second
|
|
56760
|
+
* `numeric-sensor` on the same device.
|
|
56761
|
+
*/
|
|
56762
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56003
56763
|
/**
|
|
56004
56764
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56005
56765
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56039,7 +56799,7 @@ var BatteryStatusSchema = object({
|
|
|
56039
56799
|
*/
|
|
56040
56800
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56041
56801
|
});
|
|
56042
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
56802
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56043
56803
|
method(object({
|
|
56044
56804
|
deviceId: number(),
|
|
56045
56805
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56059,7 +56819,7 @@ object({
|
|
|
56059
56819
|
DeviceType.Sensor;
|
|
56060
56820
|
object({
|
|
56061
56821
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56062
|
-
percentage: number().min(0).max(100),
|
|
56822
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56063
56823
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56064
56824
|
lastChangedAt: number()
|
|
56065
56825
|
});
|
|
@@ -56444,21 +57204,21 @@ object({
|
|
|
56444
57204
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
56445
57205
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
56446
57206
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
56447
|
-
target: number().nullable(),
|
|
57207
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
56448
57208
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
56449
57209
|
* in `heat_cool` mode. */
|
|
56450
|
-
targetHigh: number().nullable(),
|
|
57210
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
56451
57211
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
56452
57212
|
* in `heat_cool` mode. */
|
|
56453
|
-
targetLow: number().nullable(),
|
|
57213
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
56454
57214
|
/** Target relative humidity (0..100). Null when the device has no
|
|
56455
57215
|
* humidity control. */
|
|
56456
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57216
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56457
57217
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
56458
57218
|
* the device's internal sensor. */
|
|
56459
|
-
currentTemp: number().nullable(),
|
|
57219
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
56460
57220
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
56461
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57221
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56462
57222
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
56463
57223
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
56464
57224
|
swingVertical: boolean().nullable(),
|
|
@@ -56466,11 +57226,11 @@ object({
|
|
|
56466
57226
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
56467
57227
|
swingHorizontal: boolean().nullable(),
|
|
56468
57228
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56469
|
-
minTemp: number().nullable().optional(),
|
|
57229
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56470
57230
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56471
|
-
maxTemp: number().nullable().optional(),
|
|
57231
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56472
57232
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
56473
|
-
tempStep: number().positive().nullable().optional(),
|
|
57233
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
56474
57234
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
56475
57235
|
lastFetchedAt: number()
|
|
56476
57236
|
});
|
|
@@ -56549,17 +57309,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
56549
57309
|
* modes to expose in the picker without a slice fetch.
|
|
56550
57310
|
*/
|
|
56551
57311
|
var RgbTripletSchema = object({
|
|
56552
|
-
r: number().int().min(0).max(255),
|
|
56553
|
-
g: number().int().min(0).max(255),
|
|
56554
|
-
b: number().int().min(0).max(255)
|
|
57312
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57313
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57314
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
56555
57315
|
});
|
|
56556
57316
|
var HsvTripletSchema = object({
|
|
56557
57317
|
/** Hue in degrees, 0..360. */
|
|
56558
|
-
h: number().min(0).max(360),
|
|
57318
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
56559
57319
|
/** Saturation as 0..100 inclusive. */
|
|
56560
|
-
s: number().min(0).max(100),
|
|
57320
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
56561
57321
|
/** Value/brightness as 0..100 inclusive. */
|
|
56562
|
-
v: number().min(0).max(100)
|
|
57322
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
56563
57323
|
});
|
|
56564
57324
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
56565
57325
|
object({
|
|
@@ -56588,7 +57348,7 @@ object({
|
|
|
56588
57348
|
/** Populated when `mode === 'hsv'`. */
|
|
56589
57349
|
hsv: HsvTripletSchema.optional(),
|
|
56590
57350
|
/** Populated when `mode === 'mired'`. */
|
|
56591
|
-
mireds: number().int().optional(),
|
|
57351
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
56592
57352
|
/** Ms epoch of the last operator-driven change. */
|
|
56593
57353
|
lastChangedAt: number()
|
|
56594
57354
|
});
|
|
@@ -56712,18 +57472,12 @@ _enum([
|
|
|
56712
57472
|
"empty",
|
|
56713
57473
|
"full"
|
|
56714
57474
|
]);
|
|
56715
|
-
/**
|
|
56716
|
-
|
|
56717
|
-
|
|
56718
|
-
"days",
|
|
56719
|
-
"hours",
|
|
56720
|
-
"cycles"
|
|
56721
|
-
]);
|
|
56722
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
56723
|
-
* days). `value` null = unknown (D393). */
|
|
57475
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
57476
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
57477
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
56724
57478
|
var ConsumableRemainingSchema = object({
|
|
56725
|
-
value: number().min(0).nullable(),
|
|
56726
|
-
|
|
57479
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
57480
|
+
kind: ConsumableRemainingKindSchema
|
|
56727
57481
|
});
|
|
56728
57482
|
var ConsumablesStatusSchema = object({
|
|
56729
57483
|
items: array(object({
|
|
@@ -56732,7 +57486,7 @@ var ConsumablesStatusSchema = object({
|
|
|
56732
57486
|
/** Display name. */
|
|
56733
57487
|
label: string().min(1),
|
|
56734
57488
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
56735
|
-
level: number().min(0).max(100).nullable(),
|
|
57489
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
56736
57490
|
/** The provider's discrete verdict when known (binary mode). */
|
|
56737
57491
|
status: ConsumableStatusSchema.nullable(),
|
|
56738
57492
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -56749,7 +57503,7 @@ var ConsumablesStatusSchema = object({
|
|
|
56749
57503
|
})),
|
|
56750
57504
|
lastChangedAt: number()
|
|
56751
57505
|
});
|
|
56752
|
-
Object.values(DeviceType), [...
|
|
57506
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
56753
57507
|
Object.values(DeviceType), method(object({
|
|
56754
57508
|
deviceId: number().int().nonnegative(),
|
|
56755
57509
|
key: string().min(1)
|
|
@@ -56774,39 +57528,17 @@ object({
|
|
|
56774
57528
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
56775
57529
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
56776
57530
|
* or time-only — HA accepts all three forms). */
|
|
56777
|
-
value: union([number(), string()]),
|
|
57531
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
56778
57532
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
56779
57533
|
options: array(string()),
|
|
56780
57534
|
/** Ms epoch when the slice was last updated. */
|
|
56781
57535
|
lastChangedAt: number(),
|
|
56782
|
-
/**
|
|
56783
|
-
|
|
56784
|
-
|
|
56785
|
-
|
|
56786
|
-
/**
|
|
56787
|
-
|
|
56788
|
-
min: number().optional(),
|
|
56789
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
56790
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
56791
|
-
max: number().optional(),
|
|
56792
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
56793
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
56794
|
-
step: number().optional(),
|
|
56795
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
56796
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
56797
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
56798
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
56799
|
-
precision: number().int().min(0).max(10).optional(),
|
|
56800
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
56801
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
56802
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
56803
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
56804
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
56805
|
-
format: _enum([
|
|
56806
|
-
"date",
|
|
56807
|
-
"time",
|
|
56808
|
-
"datetime"
|
|
56809
|
-
]).optional()
|
|
57536
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
57537
|
+
min: number().optional().meta(readingMeta("device")),
|
|
57538
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
57539
|
+
max: number().optional().meta(readingMeta("device")),
|
|
57540
|
+
/** Step increment, in the device quantity's base unit. */
|
|
57541
|
+
step: number().optional().meta(readingMeta("device"))
|
|
56810
57542
|
});
|
|
56811
57543
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
56812
57544
|
object({
|
|
@@ -56844,9 +57576,9 @@ object({
|
|
|
56844
57576
|
]),
|
|
56845
57577
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
56846
57578
|
* no intermediate position surface. */
|
|
56847
|
-
position: number().min(0).max(100).nullable(),
|
|
57579
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
56848
57580
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
56849
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
57581
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
56850
57582
|
/** Ms epoch when the slice was last updated. */
|
|
56851
57583
|
lastChangedAt: number()
|
|
56852
57584
|
});
|
|
@@ -56904,9 +57636,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
56904
57636
|
object({
|
|
56905
57637
|
mode: DayNightModeSchema,
|
|
56906
57638
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
56907
|
-
sensitivity: number().optional(),
|
|
57639
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
56908
57640
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
56909
|
-
switchDelaySec: number().optional(),
|
|
57641
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
56910
57642
|
lastFetchedAt: number()
|
|
56911
57643
|
});
|
|
56912
57644
|
/**
|
|
@@ -57061,11 +57793,11 @@ object({
|
|
|
57061
57793
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57062
57794
|
availablePrograms: array(string()),
|
|
57063
57795
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57064
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
57796
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57065
57797
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57066
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
57798
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57067
57799
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57068
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
57800
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57069
57801
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57070
57802
|
doorOpen: boolean().nullable(),
|
|
57071
57803
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57089,7 +57821,7 @@ object({
|
|
|
57089
57821
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57090
57822
|
machineCareDue: boolean().nullable(),
|
|
57091
57823
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57092
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
57824
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57093
57825
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57094
57826
|
halfLoad: boolean().nullable(),
|
|
57095
57827
|
hygienePlus: boolean().nullable(),
|
|
@@ -57104,7 +57836,7 @@ object({
|
|
|
57104
57836
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57105
57837
|
activeEvents: array(string()),
|
|
57106
57838
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57107
|
-
errorCode: number().nullable(),
|
|
57839
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57108
57840
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57109
57841
|
errorLabel: string().nullable(),
|
|
57110
57842
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -57250,24 +57982,14 @@ object({
|
|
|
57250
57982
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
57251
57983
|
lastPressedAt: number().nullable(),
|
|
57252
57984
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
57253
|
-
pressCountSinceStart: number()
|
|
57985
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
57254
57986
|
});
|
|
57255
57987
|
object({
|
|
57256
57988
|
deviceId: number(),
|
|
57257
57989
|
timestamp: number()
|
|
57258
57990
|
});
|
|
57259
57991
|
DeviceType.Button, DeviceType.Camera;
|
|
57260
|
-
|
|
57261
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
57262
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
57263
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
57264
|
-
* The option set is stable across observations; it is persisted in the
|
|
57265
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
57266
|
-
* stored in `sourceInfo`.
|
|
57267
|
-
*/
|
|
57268
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
57269
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
57270
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
57992
|
+
_enum([
|
|
57271
57993
|
"date",
|
|
57272
57994
|
"time",
|
|
57273
57995
|
"datetime"
|
|
@@ -57275,12 +57997,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
57275
57997
|
object({
|
|
57276
57998
|
value: string(),
|
|
57277
57999
|
/**
|
|
57278
|
-
* Set
|
|
57279
|
-
* as
|
|
57280
|
-
*
|
|
57281
|
-
* a time-only sensor → `'time'`.
|
|
58000
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58001
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58002
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
57282
58003
|
*/
|
|
57283
|
-
|
|
58004
|
+
timestamp: boolean().optional(),
|
|
57284
58005
|
/** Ms epoch when the slice was last updated. */
|
|
57285
58006
|
lastFetchedAt: number()
|
|
57286
58007
|
});
|
|
@@ -57299,13 +58020,13 @@ var EventFireSchema = object({
|
|
|
57299
58020
|
deviceId: number(),
|
|
57300
58021
|
eventType: string(),
|
|
57301
58022
|
data: record(string(), unknown()).nullable(),
|
|
57302
|
-
timestamp: number(),
|
|
57303
|
-
seq: number()
|
|
58023
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58024
|
+
seq: number().meta(readingMeta("count"))
|
|
57304
58025
|
});
|
|
57305
58026
|
object({
|
|
57306
58027
|
eventTypes: array(string()),
|
|
57307
58028
|
lastEvent: EventFireSchema.nullable(),
|
|
57308
|
-
eventCountSinceStart: number()
|
|
58029
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
57309
58030
|
});
|
|
57310
58031
|
DeviceType.EventEmitter;
|
|
57311
58032
|
var IdentitySchema = object({
|
|
@@ -57694,10 +58415,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
57694
58415
|
object({
|
|
57695
58416
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
57696
58417
|
* speed surface (single-speed fan). */
|
|
57697
|
-
percentage: number().min(0).max(100).nullable(),
|
|
58418
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57698
58419
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
57699
58420
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
57700
|
-
percentageStep: number().positive().optional(),
|
|
58421
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
57701
58422
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
57702
58423
|
* — empty string when no preset is active or supported. */
|
|
57703
58424
|
preset: string(),
|
|
@@ -57779,7 +58500,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
57779
58500
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
57780
58501
|
model: string().nullable(),
|
|
57781
58502
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
57782
|
-
channelCount: number().nullable(),
|
|
58503
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
57783
58504
|
/**
|
|
57784
58505
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
57785
58506
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -57811,9 +58532,45 @@ object({
|
|
|
57811
58532
|
lastChangedAt: number()
|
|
57812
58533
|
});
|
|
57813
58534
|
DeviceType.Sensor;
|
|
58535
|
+
object({
|
|
58536
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
58537
|
+
results: array(object({
|
|
58538
|
+
deviceId: number().int().nonnegative(),
|
|
58539
|
+
cap: string().min(1),
|
|
58540
|
+
method: string().min(1),
|
|
58541
|
+
ok: boolean(),
|
|
58542
|
+
error: string().optional(),
|
|
58543
|
+
/** Ms epoch of the attempt. */
|
|
58544
|
+
at: number()
|
|
58545
|
+
})) });
|
|
58546
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58547
|
+
object({
|
|
58548
|
+
active: boolean().meta({ label: "Active" }),
|
|
58549
|
+
/** Ms epoch when the slice was last updated. */
|
|
58550
|
+
lastChangedAt: number()
|
|
58551
|
+
});
|
|
58552
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
58553
|
+
object({
|
|
58554
|
+
/** Members whose current value entered the aggregate. */
|
|
58555
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
58556
|
+
precision: 0,
|
|
58557
|
+
label: "Reporting"
|
|
58558
|
+
})),
|
|
58559
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
58560
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
58561
|
+
precision: 0,
|
|
58562
|
+
label: "Excluded"
|
|
58563
|
+
})),
|
|
58564
|
+
/** `included` + `excluded`. */
|
|
58565
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
58566
|
+
precision: 0,
|
|
58567
|
+
label: "Members"
|
|
58568
|
+
}))
|
|
58569
|
+
});
|
|
58570
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
57814
58571
|
object({
|
|
57815
58572
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
57816
|
-
position: number().min(0).max(100).nullable(),
|
|
58573
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57817
58574
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
57818
58575
|
lastFetchedAt: number()
|
|
57819
58576
|
});
|
|
@@ -57822,9 +58579,9 @@ object({
|
|
|
57822
58579
|
/** Whether the humidifier is currently on. */
|
|
57823
58580
|
on: boolean(),
|
|
57824
58581
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
57825
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58582
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57826
58583
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
57827
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58584
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57828
58585
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
57829
58586
|
* device has no mode surface. */
|
|
57830
58587
|
mode: string().nullable(),
|
|
@@ -57834,9 +58591,9 @@ object({
|
|
|
57834
58591
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
57835
58592
|
action: string().nullable(),
|
|
57836
58593
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
57837
|
-
minHumidity: number().nullable(),
|
|
58594
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
57838
58595
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
57839
|
-
maxHumidity: number().nullable(),
|
|
58596
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
57840
58597
|
/** Ms epoch when the slice was last updated. */
|
|
57841
58598
|
lastChangedAt: number()
|
|
57842
58599
|
});
|
|
@@ -57860,22 +58617,13 @@ DeviceType.Humidifier, method(object({
|
|
|
57860
58617
|
auth: "protected"
|
|
57861
58618
|
});
|
|
57862
58619
|
object({
|
|
57863
|
-
/** Current relative humidity, 0..100. */
|
|
57864
|
-
percent: number().min(0).max(100).meta({
|
|
57865
|
-
|
|
58620
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
58621
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
58622
|
+
precision: 0,
|
|
57866
58623
|
label: "Humidity"
|
|
57867
|
-
}),
|
|
58624
|
+
})),
|
|
57868
58625
|
/** Ms epoch when the slice was last updated. */
|
|
57869
|
-
lastFetchedAt: number()
|
|
57870
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
57871
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
57872
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
57873
|
-
unit: string().optional(),
|
|
57874
|
-
/** Suggested decimal places for numeric display.
|
|
57875
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57876
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57877
|
-
* auto-formatting when absent. */
|
|
57878
|
-
precision: number().int().min(0).max(10).optional()
|
|
58626
|
+
lastFetchedAt: number()
|
|
57879
58627
|
});
|
|
57880
58628
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
57881
58629
|
object({
|
|
@@ -57883,7 +58631,7 @@ object({
|
|
|
57883
58631
|
* entity exposes no `entity_picture` (yet). */
|
|
57884
58632
|
url: string().nullable(),
|
|
57885
58633
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
57886
|
-
lastUpdated: number().nullable()
|
|
58634
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
57887
58635
|
});
|
|
57888
58636
|
DeviceType.Image;
|
|
57889
58637
|
/**
|
|
@@ -57939,19 +58687,19 @@ var NormalizedRangeSchema = object({
|
|
|
57939
58687
|
});
|
|
57940
58688
|
object({
|
|
57941
58689
|
/** Normalized 0–100. */
|
|
57942
|
-
brightness: number().optional(),
|
|
58690
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
57943
58691
|
/** Normalized 0–100. */
|
|
57944
|
-
contrast: number().optional(),
|
|
58692
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
57945
58693
|
/** Normalized 0–100. */
|
|
57946
|
-
saturation: number().optional(),
|
|
58694
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
57947
58695
|
/** Normalized 0–100. */
|
|
57948
|
-
sharpness: number().optional(),
|
|
58696
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
57949
58697
|
mirror: boolean().optional(),
|
|
57950
58698
|
flip: boolean().optional(),
|
|
57951
58699
|
rotate: ImageRotateSchema.optional(),
|
|
57952
58700
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
57953
58701
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
57954
|
-
warmth: number().optional(),
|
|
58702
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
57955
58703
|
exposureMode: ExposureModeSchema.optional(),
|
|
57956
58704
|
backlightMode: BacklightModeSchema.optional(),
|
|
57957
58705
|
lastFetchedAt: number()
|
|
@@ -58196,10 +58944,10 @@ var IntercomAbilitySchema = object({
|
|
|
58196
58944
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58197
58945
|
codecs: array(string()),
|
|
58198
58946
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58199
|
-
sampleRate: number(),
|
|
58947
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58200
58948
|
duplex: _enum(["half", "full"]),
|
|
58201
58949
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58202
|
-
maxBacklogMs: number()
|
|
58950
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58203
58951
|
});
|
|
58204
58952
|
var IntercomStatusSchema = object({
|
|
58205
58953
|
/** True while a talk session is open. */
|
|
@@ -58310,13 +59058,13 @@ object({
|
|
|
58310
59058
|
activity: LawnMowerActivitySchema,
|
|
58311
59059
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
58312
59060
|
* reading. */
|
|
58313
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59061
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58314
59062
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
58315
59063
|
* task is active / progress is unavailable. */
|
|
58316
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59064
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58317
59065
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
58318
59066
|
* or null when unknown. */
|
|
58319
|
-
currentCode: number().nullable(),
|
|
59067
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
58320
59068
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
58321
59069
|
currentCodeLabel: string().nullable(),
|
|
58322
59070
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -58726,7 +59474,14 @@ DeviceType.Lock, method(object({
|
|
|
58726
59474
|
auth: "protected"
|
|
58727
59475
|
}), method(object({
|
|
58728
59476
|
deviceId: number().int().nonnegative(),
|
|
58729
|
-
code: string().min(1).optional()
|
|
59477
|
+
code: string().min(1).optional(),
|
|
59478
|
+
/**
|
|
59479
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
59480
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
59481
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
59482
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
59483
|
+
*/
|
|
59484
|
+
confirm: boolean().optional()
|
|
58730
59485
|
}), _void(), {
|
|
58731
59486
|
kind: "mutation",
|
|
58732
59487
|
auth: "protected"
|
|
@@ -58734,6 +59489,11 @@ DeviceType.Lock, method(object({
|
|
|
58734
59489
|
kind: "mutation",
|
|
58735
59490
|
auth: "protected"
|
|
58736
59491
|
});
|
|
59492
|
+
object({
|
|
59493
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
59494
|
+
lastFetchedAt: number()
|
|
59495
|
+
});
|
|
59496
|
+
DeviceType.Sensor;
|
|
58737
59497
|
/**
|
|
58738
59498
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
58739
59499
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -58778,7 +59538,7 @@ object({
|
|
|
58778
59538
|
state: MediaPlayerStateSchema,
|
|
58779
59539
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
58780
59540
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
58781
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
59541
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58782
59542
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
58783
59543
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
58784
59544
|
isMuted: boolean().nullable(),
|
|
@@ -58791,10 +59551,10 @@ object({
|
|
|
58791
59551
|
currentMedia: MediaInfoSchema.nullable(),
|
|
58792
59552
|
/** Current playback position in ms. Null when not seekable or
|
|
58793
59553
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
58794
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
59554
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
58795
59555
|
/** Total duration of the current media in ms. Null when unknown
|
|
58796
59556
|
* (live stream) or nothing is playing. */
|
|
58797
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
59557
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
58798
59558
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
58799
59559
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
58800
59560
|
shuffle: boolean().nullable(),
|
|
@@ -59094,7 +59854,7 @@ object({
|
|
|
59094
59854
|
* it, every provider seeded it at boot, and every session left it
|
|
59095
59855
|
* `detected: true` after its detach.
|
|
59096
59856
|
*/
|
|
59097
|
-
autoClearAfterMs: number().nullable()
|
|
59857
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59098
59858
|
});
|
|
59099
59859
|
/**
|
|
59100
59860
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59144,7 +59904,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59144
59904
|
});
|
|
59145
59905
|
object({
|
|
59146
59906
|
enabled: boolean(),
|
|
59147
|
-
sensitivity: number(),
|
|
59907
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59148
59908
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59149
59909
|
regions: array(MotionZoneRegionSchema),
|
|
59150
59910
|
lastFetchedAt: number()
|
|
@@ -59448,7 +60208,7 @@ var NavigationStatusSchema = object({
|
|
|
59448
60208
|
following: boolean(),
|
|
59449
60209
|
flash: boolean(),
|
|
59450
60210
|
lightMode: NavigationLightModeSchema,
|
|
59451
|
-
lightLevel: number().min(40).max(100),
|
|
60211
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
59452
60212
|
/** Ms epoch when the slice was last updated. */
|
|
59453
60213
|
lastChangedAt: number()
|
|
59454
60214
|
});
|
|
@@ -59494,13 +60254,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
59494
60254
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
59495
60255
|
* SKIP a null rather than coerce it.
|
|
59496
60256
|
*/
|
|
59497
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
60257
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59498
60258
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
59499
|
-
rssiDbm: number().optional(),
|
|
60259
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
59500
60260
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
59501
60261
|
ssid: string().optional(),
|
|
59502
60262
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
59503
|
-
lastUpdated: number()
|
|
60263
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
59504
60264
|
});
|
|
59505
60265
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
59506
60266
|
deviceId: number(),
|
|
@@ -59819,7 +60579,7 @@ object({
|
|
|
59819
60579
|
lastError: string().nullable(),
|
|
59820
60580
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
59821
60581
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
59822
|
-
queueDepth: number().int().nonnegative(),
|
|
60582
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
59823
60583
|
/** Per-feature capability matrix — authoritative source for the
|
|
59824
60584
|
* compose-form field gating. */
|
|
59825
60585
|
supports: NotifierSupportsSchema
|
|
@@ -59869,15 +60629,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
59869
60629
|
acceptedAt: number()
|
|
59870
60630
|
});
|
|
59871
60631
|
object({
|
|
59872
|
-
|
|
59873
|
-
|
|
59874
|
-
* Populated live from the upstream source on each state push.
|
|
59875
|
-
* Absent for unitless sensors. */
|
|
59876
|
-
unit: string().optional(),
|
|
59877
|
-
/** Suggested decimal places for numeric display.
|
|
59878
|
-
* Populated live from the upstream source when provided.
|
|
59879
|
-
* Falls back to auto-formatting when absent. */
|
|
59880
|
-
precision: number().int().min(0).max(10).optional(),
|
|
60632
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
60633
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
59881
60634
|
/** Ms epoch when the slice was last updated. */
|
|
59882
60635
|
lastFetchedAt: number()
|
|
59883
60636
|
});
|
|
@@ -60167,23 +60920,26 @@ object({
|
|
|
60167
60920
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60168
60921
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60169
60922
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60170
|
-
foodLevel: number().nullable(),
|
|
60923
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60171
60924
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60172
60925
|
* single-hopper models. */
|
|
60173
|
-
food1: number().nullable(),
|
|
60926
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60174
60927
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60175
60928
|
* single-hopper models. */
|
|
60176
|
-
food2: number().nullable(),
|
|
60929
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60177
60930
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60178
60931
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60179
60932
|
* below the feeder's low threshold. */
|
|
60180
60933
|
lowFood: boolean(),
|
|
60181
60934
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60182
60935
|
* device has no battery reading. */
|
|
60183
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60184
|
-
/**
|
|
60185
|
-
*
|
|
60186
|
-
|
|
60936
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60937
|
+
/**
|
|
60938
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
60939
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
60940
|
+
* model has no desiccant sensor.
|
|
60941
|
+
*/
|
|
60942
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60187
60943
|
/** True while a feed is in progress. */
|
|
60188
60944
|
feeding: boolean(),
|
|
60189
60945
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60194,7 +60950,7 @@ object({
|
|
|
60194
60950
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60195
60951
|
error: string().nullable(),
|
|
60196
60952
|
/** Raw device error code (0 / null = no error). */
|
|
60197
|
-
errorCode: number().nullable(),
|
|
60953
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60198
60954
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60199
60955
|
isDualHopper: boolean(),
|
|
60200
60956
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60204,7 +60960,7 @@ object({
|
|
|
60204
60960
|
/** Play a chime when dispensing. */
|
|
60205
60961
|
feedSound: boolean(),
|
|
60206
60962
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60207
|
-
volume: number(),
|
|
60963
|
+
volume: number().meta(readingMeta("none")),
|
|
60208
60964
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60209
60965
|
lastFetchedAt: number()
|
|
60210
60966
|
});
|
|
@@ -60641,38 +61397,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
60641
61397
|
});
|
|
60642
61398
|
object({
|
|
60643
61399
|
/** Instantaneous power draw in watts. */
|
|
60644
|
-
watts: number().optional().meta({
|
|
60645
|
-
unit: "W",
|
|
60646
|
-
label: "Power"
|
|
60647
|
-
}),
|
|
61400
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
60648
61401
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
60649
|
-
kwhTotal: number().optional().meta({
|
|
60650
|
-
unit: "kWh",
|
|
60651
|
-
label: "Energy"
|
|
60652
|
-
}),
|
|
61402
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
60653
61403
|
/** Voltage in volts. */
|
|
60654
|
-
volts: number().optional(),
|
|
61404
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
60655
61405
|
/** Current in amperes. */
|
|
60656
|
-
amps: number().optional(),
|
|
60657
|
-
/** Apparent power in volt-amperes
|
|
60658
|
-
va: number().optional(),
|
|
61406
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61407
|
+
/** Apparent power in volt-amperes. */
|
|
61408
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
60659
61409
|
/** Power factor (0..1) if reported. */
|
|
60660
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
61410
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
60661
61411
|
/** Ms epoch when the slice was last updated. */
|
|
60662
|
-
lastFetchedAt: number()
|
|
60663
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
60664
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
60665
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
60666
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
60667
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
60668
|
-
unit: string().optional(),
|
|
60669
|
-
/** Suggested decimal places for numeric display.
|
|
60670
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
60671
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
60672
|
-
* auto-formatting when absent. */
|
|
60673
|
-
precision: number().int().min(0).max(10).optional()
|
|
61412
|
+
lastFetchedAt: number()
|
|
60674
61413
|
});
|
|
60675
|
-
|
|
61414
|
+
[
|
|
61415
|
+
DeviceType.Sensor,
|
|
61416
|
+
DeviceType.Switch,
|
|
61417
|
+
DeviceType.Light,
|
|
61418
|
+
DeviceType.Fan,
|
|
61419
|
+
DeviceType.Climate,
|
|
61420
|
+
DeviceType.Thermostat,
|
|
61421
|
+
DeviceType.Humidifier,
|
|
61422
|
+
DeviceType.WaterHeater,
|
|
61423
|
+
DeviceType.MediaPlayer,
|
|
61424
|
+
DeviceType.Washer,
|
|
61425
|
+
DeviceType.Dryer,
|
|
61426
|
+
DeviceType.Dishwasher,
|
|
61427
|
+
DeviceType.Vacuum,
|
|
61428
|
+
DeviceType.LawnMower,
|
|
61429
|
+
DeviceType.PetFeeder
|
|
61430
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
60676
61431
|
/**
|
|
60677
61432
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
60678
61433
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -60691,11 +61446,11 @@ DeviceType.Sensor;
|
|
|
60691
61446
|
*/
|
|
60692
61447
|
var GpsLocationSchema = object({
|
|
60693
61448
|
/** Latitude in decimal degrees, -90..90. */
|
|
60694
|
-
latitude: number().min(-90).max(90),
|
|
61449
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
60695
61450
|
/** Longitude in decimal degrees, -180..180. */
|
|
60696
|
-
longitude: number().min(-180).max(180),
|
|
61451
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
60697
61452
|
/** Reported accuracy in meters (lower = better). */
|
|
60698
|
-
accuracyMeters: number().nonnegative()
|
|
61453
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
60699
61454
|
});
|
|
60700
61455
|
object({
|
|
60701
61456
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -60707,25 +61462,16 @@ object({
|
|
|
60707
61462
|
gps: GpsLocationSchema.nullable(),
|
|
60708
61463
|
/** Optional battery level of the tracking device (0..100). Null
|
|
60709
61464
|
* when not reported. */
|
|
60710
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
61465
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60711
61466
|
/** Ms epoch when the slice was last updated. */
|
|
60712
61467
|
lastChangedAt: number()
|
|
60713
61468
|
});
|
|
60714
61469
|
DeviceType.Presence;
|
|
60715
61470
|
object({
|
|
60716
|
-
/** Current pressure in hPa. */
|
|
60717
|
-
hpa: number(),
|
|
61471
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
61472
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
60718
61473
|
/** Ms epoch when the slice was last updated. */
|
|
60719
|
-
lastFetchedAt: number()
|
|
60720
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
60721
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
60722
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
60723
|
-
unit: string().optional(),
|
|
60724
|
-
/** Suggested decimal places for numeric display.
|
|
60725
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
60726
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
60727
|
-
* auto-formatting when absent. */
|
|
60728
|
-
precision: number().int().min(0).max(10).optional()
|
|
61474
|
+
lastFetchedAt: number()
|
|
60729
61475
|
});
|
|
60730
61476
|
DeviceType.Sensor;
|
|
60731
61477
|
/**
|
|
@@ -61058,8 +61804,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61058
61804
|
}), _void(), { kind: "mutation" });
|
|
61059
61805
|
var PtzAutotrackSettingsSchema = object({
|
|
61060
61806
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61061
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61062
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
61807
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
61808
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61063
61809
|
});
|
|
61064
61810
|
/**
|
|
61065
61811
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61116,7 +61862,7 @@ object({
|
|
|
61116
61862
|
/** null = unknown — never coerced to false (D393). */
|
|
61117
61863
|
running: boolean().nullable(),
|
|
61118
61864
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61119
|
-
since: number().nullable(),
|
|
61865
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61120
61866
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61121
61867
|
phase: string().nullable(),
|
|
61122
61868
|
/** null until a reading has been published (D393). */
|
|
@@ -61128,7 +61874,7 @@ object({
|
|
|
61128
61874
|
phase: string().nullable()
|
|
61129
61875
|
});
|
|
61130
61876
|
Object.values(DeviceType);
|
|
61131
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61877
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61132
61878
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61133
61879
|
kind: "mutation",
|
|
61134
61880
|
auth: "admin"
|
|
@@ -62314,9 +63060,9 @@ var RecordTriggerSchema = _enum([
|
|
|
62314
63060
|
*/
|
|
62315
63061
|
var RecordWindowSchema = object({
|
|
62316
63062
|
trigger: RecordTriggerSchema,
|
|
62317
|
-
day: number().int().min(0).max(6),
|
|
62318
|
-
startMinute: number().int().min(0).max(1439),
|
|
62319
|
-
endMinute: number().int().min(1).max(1440)
|
|
63063
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63064
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63065
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
62320
63066
|
});
|
|
62321
63067
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
62322
63068
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -62385,10 +63131,10 @@ object({
|
|
|
62385
63131
|
/** Master "record to the card at all" switch. */
|
|
62386
63132
|
enabled: boolean().nullable(),
|
|
62387
63133
|
overwriteWhenFull: boolean().nullable(),
|
|
62388
|
-
preRecordSec: number().nullable(),
|
|
62389
|
-
postRecordSec: number().nullable(),
|
|
63134
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63135
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
62390
63136
|
/** Length of one recorded file, in minutes. */
|
|
62391
|
-
segmentMinutes: number().nullable(),
|
|
63137
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
62392
63138
|
/** The primary track's weekly windows, flattened. */
|
|
62393
63139
|
windows: array(RecordWindowSchema),
|
|
62394
63140
|
/**
|
|
@@ -62404,7 +63150,7 @@ object({
|
|
|
62404
63150
|
* provider reporting a non-zero count also reports the schedule as not
|
|
62405
63151
|
* writable.
|
|
62406
63152
|
*/
|
|
62407
|
-
unreadableWindows: number(),
|
|
63153
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
62408
63154
|
/**
|
|
62409
63155
|
* The camera is scheduled to record and has NO usable storage.
|
|
62410
63156
|
*
|
|
@@ -63041,7 +63787,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63041
63787
|
url: string().optional(),
|
|
63042
63788
|
codec: string().optional(),
|
|
63043
63789
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63044
|
-
fps: number().positive().optional(),
|
|
63790
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63045
63791
|
label: string().optional(),
|
|
63046
63792
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63047
63793
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63071,18 +63817,18 @@ var StreamProfileSchema = _enum([
|
|
|
63071
63817
|
]);
|
|
63072
63818
|
/** The current encoding config of one stream profile. */
|
|
63073
63819
|
var StreamProfileConfigSchema = object({
|
|
63074
|
-
width: number(),
|
|
63075
|
-
height: number(),
|
|
63820
|
+
width: number().meta(readingMeta("none")),
|
|
63821
|
+
height: number().meta(readingMeta("none")),
|
|
63076
63822
|
codec: _enum(["h264", "h265"]),
|
|
63077
|
-
framerate: number(),
|
|
63078
|
-
bitrate: number(),
|
|
63823
|
+
framerate: number().meta(readingMeta("rate")),
|
|
63824
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63079
63825
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63080
63826
|
encoderProfile: _enum([
|
|
63081
63827
|
"high",
|
|
63082
63828
|
"main",
|
|
63083
63829
|
"baseline"
|
|
63084
63830
|
]).optional(),
|
|
63085
|
-
gop: number().optional(),
|
|
63831
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63086
63832
|
/**
|
|
63087
63833
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63088
63834
|
*
|
|
@@ -63167,7 +63913,7 @@ object({
|
|
|
63167
63913
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63168
63914
|
lastChangedAt: number()
|
|
63169
63915
|
});
|
|
63170
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
63916
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63171
63917
|
deviceId: number(),
|
|
63172
63918
|
on: boolean()
|
|
63173
63919
|
}), _void(), {
|
|
@@ -63725,23 +64471,13 @@ object({
|
|
|
63725
64471
|
});
|
|
63726
64472
|
DeviceType.Sensor;
|
|
63727
64473
|
object({
|
|
63728
|
-
/** Current temperature in Celsius. */
|
|
63729
|
-
celsius: number().meta({
|
|
63730
|
-
|
|
64474
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
64475
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
64476
|
+
precision: 1,
|
|
63731
64477
|
label: "Temperature"
|
|
63732
|
-
}),
|
|
64478
|
+
})),
|
|
63733
64479
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
63734
|
-
lastFetchedAt: number()
|
|
63735
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63736
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63737
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
63738
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
63739
|
-
unit: string().optional(),
|
|
63740
|
-
/** Suggested decimal places for numeric display.
|
|
63741
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63742
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63743
|
-
* auto-formatting when absent. */
|
|
63744
|
-
precision: number().int().min(0).max(10).optional()
|
|
64480
|
+
lastFetchedAt: number()
|
|
63745
64481
|
});
|
|
63746
64482
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
63747
64483
|
/**
|
|
@@ -63993,16 +64729,16 @@ object({
|
|
|
63993
64729
|
]),
|
|
63994
64730
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
63995
64731
|
* reading. */
|
|
63996
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
64732
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63997
64733
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
63998
64734
|
* the vacuum has no speed control. */
|
|
63999
64735
|
fanSpeed: string().nullable(),
|
|
64000
64736
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64001
64737
|
availableFanSpeeds: array(string()),
|
|
64002
64738
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64003
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
64739
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64004
64740
|
/** Current error code (0 / null = no error). */
|
|
64005
|
-
errorCode: number().nullable(),
|
|
64741
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64006
64742
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64007
64743
|
errorLabel: string().nullable(),
|
|
64008
64744
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64041,7 +64777,7 @@ object({
|
|
|
64041
64777
|
]),
|
|
64042
64778
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64043
64779
|
* intermediate position surface. */
|
|
64044
|
-
position: number().min(0).max(100).nullable(),
|
|
64780
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64045
64781
|
/** Ms epoch when the slice was last updated. */
|
|
64046
64782
|
lastChangedAt: number()
|
|
64047
64783
|
});
|
|
@@ -64069,9 +64805,9 @@ object({
|
|
|
64069
64805
|
DeviceType.Sensor;
|
|
64070
64806
|
object({
|
|
64071
64807
|
/** Current measured temperature. Null when not reported. */
|
|
64072
|
-
currentTemp: number().nullable(),
|
|
64808
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64073
64809
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64074
|
-
targetTemp: number().nullable(),
|
|
64810
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64075
64811
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64076
64812
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64077
64813
|
* device reports an unknown state. */
|
|
@@ -64082,9 +64818,9 @@ object({
|
|
|
64082
64818
|
* has no away surface. */
|
|
64083
64819
|
away: boolean().nullable(),
|
|
64084
64820
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64085
|
-
minTemp: number().nullable(),
|
|
64821
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64086
64822
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64087
|
-
maxTemp: number().nullable(),
|
|
64823
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64088
64824
|
/** Ms epoch when the slice was last updated. */
|
|
64089
64825
|
lastChangedAt: number()
|
|
64090
64826
|
});
|
|
@@ -64108,25 +64844,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64108
64844
|
auth: "protected"
|
|
64109
64845
|
});
|
|
64110
64846
|
object({
|
|
64111
|
-
/** Verbatim
|
|
64112
|
-
* when no condition has been reported yet. */
|
|
64847
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64113
64848
|
condition: string().nullable(),
|
|
64114
|
-
/** Current temperature in
|
|
64115
|
-
temperature: number().nullable(),
|
|
64116
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64117
|
-
temperatureUnit: string().nullable(),
|
|
64849
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
64850
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64118
64851
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64119
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64120
|
-
/** Barometric pressure in
|
|
64121
|
-
pressure: number().nullable(),
|
|
64122
|
-
/**
|
|
64123
|
-
|
|
64124
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64125
|
-
windSpeed: number().nullable(),
|
|
64126
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64127
|
-
windSpeedUnit: string().nullable(),
|
|
64852
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
64853
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
64854
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
64855
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
64856
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64128
64857
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64129
|
-
windBearing: number().nullable(),
|
|
64858
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64130
64859
|
/** Ms epoch when the slice was last updated. */
|
|
64131
64860
|
lastFetchedAt: number()
|
|
64132
64861
|
});
|
|
@@ -64876,8 +65605,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
64876
65605
|
kind: "mutation",
|
|
64877
65606
|
auth: "admin"
|
|
64878
65607
|
});
|
|
65608
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
64879
65609
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
64880
|
-
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;
|
|
65610
|
+
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;
|
|
64881
65611
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
64882
65612
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
64883
65613
|
new Set(CAP_NAMES);
|
|
@@ -64930,7 +65660,7 @@ var AccessoryKind = {
|
|
|
64930
65660
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
64931
65661
|
};
|
|
64932
65662
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
64933
|
-
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;
|
|
65663
|
+
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;
|
|
64934
65664
|
new Set(Object.values(DeviceType));
|
|
64935
65665
|
Object.freeze({
|
|
64936
65666
|
"accessories.getStatus": {
|
|
@@ -65038,6 +65768,13 @@ Object.freeze({
|
|
|
65038
65768
|
access: "view",
|
|
65039
65769
|
role: "admin"
|
|
65040
65770
|
},
|
|
65771
|
+
"addons.getPackageDocs": {
|
|
65772
|
+
capName: "addons",
|
|
65773
|
+
capScope: "system",
|
|
65774
|
+
addonId: null,
|
|
65775
|
+
access: "view",
|
|
65776
|
+
role: "admin"
|
|
65777
|
+
},
|
|
65041
65778
|
"addons.getVersions": {
|
|
65042
65779
|
capName: "addons",
|
|
65043
65780
|
capScope: "system",
|
|
@@ -68146,6 +68883,27 @@ Object.freeze({
|
|
|
68146
68883
|
access: "view",
|
|
68147
68884
|
role: "viewer"
|
|
68148
68885
|
},
|
|
68886
|
+
"groupActive.getStatus": {
|
|
68887
|
+
capName: "group-active",
|
|
68888
|
+
capScope: "device",
|
|
68889
|
+
addonId: null,
|
|
68890
|
+
access: "view",
|
|
68891
|
+
role: "viewer"
|
|
68892
|
+
},
|
|
68893
|
+
"groupCommands.getStatus": {
|
|
68894
|
+
capName: "group-commands",
|
|
68895
|
+
capScope: "device",
|
|
68896
|
+
addonId: null,
|
|
68897
|
+
access: "view",
|
|
68898
|
+
role: "viewer"
|
|
68899
|
+
},
|
|
68900
|
+
"groupStatus.getStatus": {
|
|
68901
|
+
capName: "group-status",
|
|
68902
|
+
capScope: "device",
|
|
68903
|
+
addonId: null,
|
|
68904
|
+
access: "view",
|
|
68905
|
+
role: "viewer"
|
|
68906
|
+
},
|
|
68149
68907
|
"heatingValve.getStatus": {
|
|
68150
68908
|
capName: "heating-valve",
|
|
68151
68909
|
capScope: "device",
|
|
@@ -69098,6 +69856,13 @@ Object.freeze({
|
|
|
69098
69856
|
access: "create",
|
|
69099
69857
|
role: "admin"
|
|
69100
69858
|
},
|
|
69859
|
+
"meter.getStatus": {
|
|
69860
|
+
capName: "meter",
|
|
69861
|
+
capScope: "device",
|
|
69862
|
+
addonId: null,
|
|
69863
|
+
access: "view",
|
|
69864
|
+
role: "viewer"
|
|
69865
|
+
},
|
|
69101
69866
|
"metricsProvider.collectSnapshot": {
|
|
69102
69867
|
capName: "metrics-provider",
|
|
69103
69868
|
capScope: "system",
|
|
@@ -77196,7 +77961,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77196
77961
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77197
77962
|
icon: "square"
|
|
77198
77963
|
}
|
|
77199
|
-
}
|
|
77964
|
+
},
|
|
77965
|
+
overrides: { byType: {
|
|
77966
|
+
[DeviceType.Washer]: {
|
|
77967
|
+
state: { running: {
|
|
77968
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
77969
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
77970
|
+
} },
|
|
77971
|
+
events: {
|
|
77972
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
77973
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
77974
|
+
}
|
|
77975
|
+
},
|
|
77976
|
+
[DeviceType.Dryer]: {
|
|
77977
|
+
state: { running: {
|
|
77978
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
77979
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
77980
|
+
} },
|
|
77981
|
+
events: {
|
|
77982
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
77983
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
77984
|
+
}
|
|
77985
|
+
},
|
|
77986
|
+
[DeviceType.Dishwasher]: {
|
|
77987
|
+
state: { running: {
|
|
77988
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
77989
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
77990
|
+
} },
|
|
77991
|
+
events: {
|
|
77992
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
77993
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
77994
|
+
}
|
|
77995
|
+
}
|
|
77996
|
+
} }
|
|
77200
77997
|
},
|
|
77201
77998
|
update: {
|
|
77202
77999
|
scope: "device",
|
|
@@ -77968,6 +78765,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
77968
78765
|
icon: "flame"
|
|
77969
78766
|
}]
|
|
77970
78767
|
},
|
|
78768
|
+
"group-active": {
|
|
78769
|
+
scope: "device",
|
|
78770
|
+
noun: t("Group state", "Stato del gruppo")
|
|
78771
|
+
},
|
|
78772
|
+
"group-commands": {
|
|
78773
|
+
scope: "device",
|
|
78774
|
+
noun: t("Group command", "Comando di gruppo")
|
|
78775
|
+
},
|
|
78776
|
+
"group-status": {
|
|
78777
|
+
scope: "device",
|
|
78778
|
+
noun: t("Group", "Gruppo"),
|
|
78779
|
+
state: [
|
|
78780
|
+
{
|
|
78781
|
+
kind: "numeric",
|
|
78782
|
+
field: "included",
|
|
78783
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
78784
|
+
label: t("Reporting", "Rispondono"),
|
|
78785
|
+
icon: "users"
|
|
78786
|
+
},
|
|
78787
|
+
{
|
|
78788
|
+
kind: "numeric",
|
|
78789
|
+
field: "excluded",
|
|
78790
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
78791
|
+
label: t("Excluded", "Esclusi"),
|
|
78792
|
+
icon: "users"
|
|
78793
|
+
},
|
|
78794
|
+
{
|
|
78795
|
+
kind: "numeric",
|
|
78796
|
+
field: "total",
|
|
78797
|
+
quantity: t("the member count", "il numero di membri"),
|
|
78798
|
+
label: t("Members", "Membri"),
|
|
78799
|
+
icon: "sigma"
|
|
78800
|
+
}
|
|
78801
|
+
]
|
|
78802
|
+
},
|
|
77971
78803
|
"humidity-sensor": {
|
|
77972
78804
|
scope: "device",
|
|
77973
78805
|
noun: t("Humidity", "Umidità"),
|
|
@@ -77993,6 +78825,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
77993
78825
|
}],
|
|
77994
78826
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
77995
78827
|
},
|
|
78828
|
+
meter: {
|
|
78829
|
+
scope: "device",
|
|
78830
|
+
noun: t("Meter", "Contatore"),
|
|
78831
|
+
state: [{
|
|
78832
|
+
kind: "numeric",
|
|
78833
|
+
field: "value",
|
|
78834
|
+
quantity: t("the total", "il totale"),
|
|
78835
|
+
label: t("Total", "Totale"),
|
|
78836
|
+
icon: "gauge"
|
|
78837
|
+
}]
|
|
78838
|
+
},
|
|
77996
78839
|
"numeric-sensor": {
|
|
77997
78840
|
scope: "device",
|
|
77998
78841
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78001,7 +78844,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78001
78844
|
field: "value",
|
|
78002
78845
|
quantity: t("the reading", "il valore"),
|
|
78003
78846
|
label: t("Reading", "Valore"),
|
|
78004
|
-
unitField: "unit",
|
|
78005
78847
|
icon: "gauge"
|
|
78006
78848
|
}]
|
|
78007
78849
|
},
|
|
@@ -78137,7 +78979,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78137
78979
|
field: "temperature",
|
|
78138
78980
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78139
78981
|
label: t("Temperature", "Temperatura"),
|
|
78140
|
-
|
|
78982
|
+
unit: "°C",
|
|
78141
78983
|
icon: "thermometer"
|
|
78142
78984
|
},
|
|
78143
78985
|
{
|
|
@@ -78153,7 +78995,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78153
78995
|
field: "windSpeed",
|
|
78154
78996
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78155
78997
|
label: t("Wind", "Vento"),
|
|
78156
|
-
|
|
78998
|
+
unit: "m/s",
|
|
78157
78999
|
icon: "wind"
|
|
78158
79000
|
},
|
|
78159
79001
|
{
|
|
@@ -78161,7 +79003,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78161
79003
|
field: "pressure",
|
|
78162
79004
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78163
79005
|
label: t("Pressure", "Pressione"),
|
|
78164
|
-
|
|
79006
|
+
unit: "hPa",
|
|
78165
79007
|
icon: "gauge"
|
|
78166
79008
|
}
|
|
78167
79009
|
]
|
|
@@ -78466,8 +79308,47 @@ function projectAction(cap, action) {
|
|
|
78466
79308
|
};
|
|
78467
79309
|
}
|
|
78468
79310
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
78469
|
-
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;
|
|
79311
|
+
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;
|
|
78470
79312
|
DeviceFeature.BatteryOperated;
|
|
79313
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79314
|
+
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.";
|
|
79315
|
+
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.";
|
|
79316
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79317
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79318
|
+
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.";
|
|
79319
|
+
function withheld(reason) {
|
|
79320
|
+
return {
|
|
79321
|
+
[DeviceType.Washer]: {
|
|
79322
|
+
exported: false,
|
|
79323
|
+
reason
|
|
79324
|
+
},
|
|
79325
|
+
[DeviceType.Dryer]: {
|
|
79326
|
+
exported: false,
|
|
79327
|
+
reason
|
|
79328
|
+
},
|
|
79329
|
+
[DeviceType.Dishwasher]: {
|
|
79330
|
+
exported: false,
|
|
79331
|
+
reason
|
|
79332
|
+
}
|
|
79333
|
+
};
|
|
79334
|
+
}
|
|
79335
|
+
function offered(received) {
|
|
79336
|
+
return {
|
|
79337
|
+
[DeviceType.Washer]: {
|
|
79338
|
+
exported: true,
|
|
79339
|
+
as: received
|
|
79340
|
+
},
|
|
79341
|
+
[DeviceType.Dryer]: {
|
|
79342
|
+
exported: true,
|
|
79343
|
+
as: received
|
|
79344
|
+
},
|
|
79345
|
+
[DeviceType.Dishwasher]: {
|
|
79346
|
+
exported: true,
|
|
79347
|
+
as: received
|
|
79348
|
+
}
|
|
79349
|
+
};
|
|
79350
|
+
}
|
|
79351
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
78471
79352
|
Object.freeze({
|
|
78472
79353
|
"accessories.getStatus": [{
|
|
78473
79354
|
name: "deviceId",
|
|
@@ -79434,6 +80315,21 @@ Object.freeze({
|
|
|
79434
80315
|
form: "single",
|
|
79435
80316
|
optional: false
|
|
79436
80317
|
}],
|
|
80318
|
+
"groupActive.getStatus": [{
|
|
80319
|
+
name: "deviceId",
|
|
80320
|
+
form: "single",
|
|
80321
|
+
optional: false
|
|
80322
|
+
}],
|
|
80323
|
+
"groupCommands.getStatus": [{
|
|
80324
|
+
name: "deviceId",
|
|
80325
|
+
form: "single",
|
|
80326
|
+
optional: false
|
|
80327
|
+
}],
|
|
80328
|
+
"groupStatus.getStatus": [{
|
|
80329
|
+
name: "deviceId",
|
|
80330
|
+
form: "single",
|
|
80331
|
+
optional: false
|
|
80332
|
+
}],
|
|
79437
80333
|
"heatingValve.getStatus": [{
|
|
79438
80334
|
name: "deviceId",
|
|
79439
80335
|
form: "single",
|
|
@@ -79634,6 +80530,11 @@ Object.freeze({
|
|
|
79634
80530
|
form: "single",
|
|
79635
80531
|
optional: false
|
|
79636
80532
|
}],
|
|
80533
|
+
"meter.getStatus": [{
|
|
80534
|
+
name: "deviceId",
|
|
80535
|
+
form: "single",
|
|
80536
|
+
optional: false
|
|
80537
|
+
}],
|
|
79637
80538
|
"motion.getStatus": [{
|
|
79638
80539
|
name: "deviceId",
|
|
79639
80540
|
form: "single",
|
|
@@ -81241,7 +82142,6 @@ Object.freeze({
|
|
|
81241
82142
|
"network-access": "ingress",
|
|
81242
82143
|
"smtp-provider": "email"
|
|
81243
82144
|
});
|
|
81244
|
-
DeviceType.Camera;
|
|
81245
82145
|
/**
|
|
81246
82146
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
81247
82147
|
* `z.infer`, they do not restate the shape.
|
|
@@ -81418,6 +82318,8 @@ new Map(Object.entries({
|
|
|
81418
82318
|
"detection-blind": "device-events",
|
|
81419
82319
|
"motion-noisy": "device-events",
|
|
81420
82320
|
"motion-calm": "device-events",
|
|
82321
|
+
"package-llm-silent": "device-events",
|
|
82322
|
+
"package-llm-answered": "device-events",
|
|
81421
82323
|
"recording-stalled": "device-events",
|
|
81422
82324
|
"recording-healthy": "device-events",
|
|
81423
82325
|
"recording-degraded": "device-events",
|
|
@@ -81501,6 +82403,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
81501
82403
|
label: "Motion without a subject",
|
|
81502
82404
|
kinds: ["motion-noisy", "motion-calm"]
|
|
81503
82405
|
},
|
|
82406
|
+
{
|
|
82407
|
+
id: "package-llm",
|
|
82408
|
+
family: "device-events",
|
|
82409
|
+
label: "Package confirm",
|
|
82410
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
82411
|
+
},
|
|
81504
82412
|
{
|
|
81505
82413
|
id: "recording",
|
|
81506
82414
|
family: "device-events",
|
|
@@ -81682,6 +82590,8 @@ var DEVICE_EVENTS = [
|
|
|
81682
82590
|
"detection-blind",
|
|
81683
82591
|
"motion-noisy",
|
|
81684
82592
|
"motion-calm",
|
|
82593
|
+
"package-llm-silent",
|
|
82594
|
+
"package-llm-answered",
|
|
81685
82595
|
"recording-stalled",
|
|
81686
82596
|
"recording-healthy",
|
|
81687
82597
|
"recording-degraded",
|
|
@@ -81950,6 +82860,15 @@ new Map([
|
|
|
81950
82860
|
snapshotLabel: "Cameras with constant motion now",
|
|
81951
82861
|
snapshotSection: null
|
|
81952
82862
|
},
|
|
82863
|
+
{
|
|
82864
|
+
id: "package-llm-confirm",
|
|
82865
|
+
family: "device-events",
|
|
82866
|
+
label: "Package confirm (not answering / answering again)",
|
|
82867
|
+
bad: ["package-llm-silent"],
|
|
82868
|
+
recovery: ["package-llm-answered"],
|
|
82869
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
82870
|
+
snapshotSection: null
|
|
82871
|
+
},
|
|
81953
82872
|
{
|
|
81954
82873
|
id: "recording-health",
|
|
81955
82874
|
family: "device-events",
|