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