@camstack/addon-notifiers 1.2.621 → 1.2.623
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 +35 -0
- package/dist/addon.js +1369 -450
- package/dist/addon.mjs +1369 -450
- package/i18n/en.json +1 -1
- package/i18n/it.json +1 -1
- package/package.json +6 -4
package/dist/addon.js
CHANGED
|
@@ -29,7 +29,7 @@ let node_fs = require("node:fs");
|
|
|
29
29
|
let node_path = require("node:path");
|
|
30
30
|
node_path = __toESM(node_path);
|
|
31
31
|
let node_url = require("node:url");
|
|
32
|
-
//#region ../types/dist/event-category-
|
|
32
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
33
33
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
34
34
|
EventCategory["SystemBoot"] = "system.boot";
|
|
35
35
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -355,6 +355,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
355
355
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
356
356
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
357
357
|
/**
|
|
358
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
359
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
360
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
361
|
+
*/
|
|
362
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
363
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
364
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
365
|
+
/**
|
|
358
366
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
359
367
|
* (a settings change via `setAgentInferenceDevices` /
|
|
360
368
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5597,7 +5605,7 @@ var ZodIssueCode = {
|
|
|
5597
5605
|
var ZodFirstPartyTypeKind;
|
|
5598
5606
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5599
5607
|
//#endregion
|
|
5600
|
-
//#region ../types/dist/sleep
|
|
5608
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5601
5609
|
/**
|
|
5602
5610
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5603
5611
|
* window to float samples (D455).
|
|
@@ -8297,6 +8305,99 @@ function defineRecordKinds(specs) {
|
|
|
8297
8305
|
}
|
|
8298
8306
|
return out;
|
|
8299
8307
|
}
|
|
8308
|
+
var READING_QUANTITIES = [
|
|
8309
|
+
"temperature",
|
|
8310
|
+
"pressure",
|
|
8311
|
+
"speed",
|
|
8312
|
+
"precipitation",
|
|
8313
|
+
"precipitation-rate",
|
|
8314
|
+
"length",
|
|
8315
|
+
"area",
|
|
8316
|
+
"illuminance",
|
|
8317
|
+
"irradiance",
|
|
8318
|
+
"power",
|
|
8319
|
+
"energy",
|
|
8320
|
+
"voltage",
|
|
8321
|
+
"current",
|
|
8322
|
+
"apparent-power",
|
|
8323
|
+
"humidity",
|
|
8324
|
+
"percentage",
|
|
8325
|
+
"concentration-volume",
|
|
8326
|
+
"concentration-mass",
|
|
8327
|
+
"concentration-ppb",
|
|
8328
|
+
"volume",
|
|
8329
|
+
"duration",
|
|
8330
|
+
"duration-ms",
|
|
8331
|
+
"information",
|
|
8332
|
+
"sound-level",
|
|
8333
|
+
"signal-level",
|
|
8334
|
+
"colour-temperature",
|
|
8335
|
+
"angle",
|
|
8336
|
+
"bitrate",
|
|
8337
|
+
"rate",
|
|
8338
|
+
"mass",
|
|
8339
|
+
"index",
|
|
8340
|
+
"ratio",
|
|
8341
|
+
"count",
|
|
8342
|
+
"none",
|
|
8343
|
+
"device"
|
|
8344
|
+
];
|
|
8345
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8346
|
+
new Set(READING_QUANTITIES);
|
|
8347
|
+
/**
|
|
8348
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8349
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8350
|
+
*/
|
|
8351
|
+
var QUANTITY_BASE = {
|
|
8352
|
+
temperature: "°C",
|
|
8353
|
+
pressure: "hPa",
|
|
8354
|
+
speed: "m/s",
|
|
8355
|
+
precipitation: "mm",
|
|
8356
|
+
"precipitation-rate": "mm/h",
|
|
8357
|
+
length: "m",
|
|
8358
|
+
area: "m²",
|
|
8359
|
+
illuminance: "lx",
|
|
8360
|
+
irradiance: "W/m²",
|
|
8361
|
+
power: "W",
|
|
8362
|
+
energy: "kWh",
|
|
8363
|
+
voltage: "V",
|
|
8364
|
+
current: "A",
|
|
8365
|
+
"apparent-power": "VA",
|
|
8366
|
+
humidity: "%",
|
|
8367
|
+
percentage: "%",
|
|
8368
|
+
"concentration-volume": "ppm",
|
|
8369
|
+
"concentration-mass": "µg/m³",
|
|
8370
|
+
"concentration-ppb": "ppb",
|
|
8371
|
+
volume: "L",
|
|
8372
|
+
duration: "s",
|
|
8373
|
+
"duration-ms": "ms",
|
|
8374
|
+
information: "B",
|
|
8375
|
+
"sound-level": "dBFS",
|
|
8376
|
+
"signal-level": "dBm",
|
|
8377
|
+
"colour-temperature": "mired",
|
|
8378
|
+
angle: "°",
|
|
8379
|
+
bitrate: "kbps",
|
|
8380
|
+
rate: "fps",
|
|
8381
|
+
mass: "kg",
|
|
8382
|
+
index: "none",
|
|
8383
|
+
ratio: "none",
|
|
8384
|
+
count: "none",
|
|
8385
|
+
none: "none",
|
|
8386
|
+
device: "device"
|
|
8387
|
+
};
|
|
8388
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8389
|
+
function baseUnitOf(quantity) {
|
|
8390
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8391
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8392
|
+
return symbol;
|
|
8393
|
+
}
|
|
8394
|
+
function readingMeta(quantity, extras) {
|
|
8395
|
+
return {
|
|
8396
|
+
quantity,
|
|
8397
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8398
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8399
|
+
};
|
|
8400
|
+
}
|
|
8300
8401
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8301
8402
|
var CamProfileSchema = _enum([
|
|
8302
8403
|
"high",
|
|
@@ -8324,8 +8425,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8324
8425
|
"derived"
|
|
8325
8426
|
]);
|
|
8326
8427
|
var CamStreamResolutionSchema = object({
|
|
8327
|
-
width: number().int().positive(),
|
|
8328
|
-
height: number().int().positive()
|
|
8428
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8429
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8329
8430
|
});
|
|
8330
8431
|
var CameraStreamSchema = object({
|
|
8331
8432
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8861,6 +8962,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8861
8962
|
"filesystem-browse",
|
|
8862
8963
|
"flood",
|
|
8863
8964
|
"gas",
|
|
8965
|
+
"group-active",
|
|
8966
|
+
"group-commands",
|
|
8967
|
+
"group-status",
|
|
8864
8968
|
"heating-valve",
|
|
8865
8969
|
"humidifier",
|
|
8866
8970
|
"humidity-sensor",
|
|
@@ -8881,6 +8985,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8881
8985
|
"login-method",
|
|
8882
8986
|
"media-player",
|
|
8883
8987
|
"mesh-network",
|
|
8988
|
+
"meter",
|
|
8884
8989
|
"metrics-provider",
|
|
8885
8990
|
"model-convert",
|
|
8886
8991
|
"model-distributor",
|
|
@@ -8990,14 +9095,6 @@ Object.freeze({
|
|
|
8990
9095
|
{
|
|
8991
9096
|
"path": "aqi",
|
|
8992
9097
|
"valueType": "number"
|
|
8993
|
-
},
|
|
8994
|
-
{
|
|
8995
|
-
"path": "unit",
|
|
8996
|
-
"valueType": "string"
|
|
8997
|
-
},
|
|
8998
|
-
{
|
|
8999
|
-
"path": "precision",
|
|
9000
|
-
"valueType": "number"
|
|
9001
9098
|
}
|
|
9002
9099
|
],
|
|
9003
9100
|
"alarm-panel": [
|
|
@@ -9033,20 +9130,10 @@ Object.freeze({
|
|
|
9033
9130
|
"valueType": "boolean"
|
|
9034
9131
|
}
|
|
9035
9132
|
],
|
|
9036
|
-
"ambient-light-sensor": [
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
},
|
|
9041
|
-
{
|
|
9042
|
-
"path": "unit",
|
|
9043
|
-
"valueType": "string"
|
|
9044
|
-
},
|
|
9045
|
-
{
|
|
9046
|
-
"path": "precision",
|
|
9047
|
-
"valueType": "number"
|
|
9048
|
-
}
|
|
9049
|
-
],
|
|
9133
|
+
"ambient-light-sensor": [{
|
|
9134
|
+
"path": "lux",
|
|
9135
|
+
"valueType": "number"
|
|
9136
|
+
}],
|
|
9050
9137
|
"audio-metrics": [
|
|
9051
9138
|
{
|
|
9052
9139
|
"path": "ts",
|
|
@@ -9126,6 +9213,10 @@ Object.freeze({
|
|
|
9126
9213
|
"path": "lastUpdated",
|
|
9127
9214
|
"valueType": "number"
|
|
9128
9215
|
},
|
|
9216
|
+
{
|
|
9217
|
+
"path": "volts",
|
|
9218
|
+
"valueType": "number"
|
|
9219
|
+
},
|
|
9129
9220
|
{
|
|
9130
9221
|
"path": "lastContactAt",
|
|
9131
9222
|
"valueType": "number"
|
|
@@ -9368,10 +9459,6 @@ Object.freeze({
|
|
|
9368
9459
|
"datetime"
|
|
9369
9460
|
]
|
|
9370
9461
|
},
|
|
9371
|
-
{
|
|
9372
|
-
"path": "unit",
|
|
9373
|
-
"valueType": "string"
|
|
9374
|
-
},
|
|
9375
9462
|
{
|
|
9376
9463
|
"path": "min",
|
|
9377
9464
|
"valueType": "number"
|
|
@@ -9383,19 +9470,6 @@ Object.freeze({
|
|
|
9383
9470
|
{
|
|
9384
9471
|
"path": "step",
|
|
9385
9472
|
"valueType": "number"
|
|
9386
|
-
},
|
|
9387
|
-
{
|
|
9388
|
-
"path": "precision",
|
|
9389
|
-
"valueType": "number"
|
|
9390
|
-
},
|
|
9391
|
-
{
|
|
9392
|
-
"path": "format",
|
|
9393
|
-
"valueType": "enum",
|
|
9394
|
-
"enumValues": [
|
|
9395
|
-
"date",
|
|
9396
|
-
"time",
|
|
9397
|
-
"datetime"
|
|
9398
|
-
]
|
|
9399
9473
|
}
|
|
9400
9474
|
],
|
|
9401
9475
|
"cover": [
|
|
@@ -9636,13 +9710,8 @@ Object.freeze({
|
|
|
9636
9710
|
"path": "value",
|
|
9637
9711
|
"valueType": "string"
|
|
9638
9712
|
}, {
|
|
9639
|
-
"path": "
|
|
9640
|
-
"valueType": "
|
|
9641
|
-
"enumValues": [
|
|
9642
|
-
"date",
|
|
9643
|
-
"time",
|
|
9644
|
-
"datetime"
|
|
9645
|
-
]
|
|
9713
|
+
"path": "timestamp",
|
|
9714
|
+
"valueType": "boolean"
|
|
9646
9715
|
}],
|
|
9647
9716
|
"event-emitter": [
|
|
9648
9717
|
{
|
|
@@ -9715,6 +9784,24 @@ Object.freeze({
|
|
|
9715
9784
|
"path": "detected",
|
|
9716
9785
|
"valueType": "boolean"
|
|
9717
9786
|
}],
|
|
9787
|
+
"group-active": [{
|
|
9788
|
+
"path": "active",
|
|
9789
|
+
"valueType": "boolean"
|
|
9790
|
+
}],
|
|
9791
|
+
"group-status": [
|
|
9792
|
+
{
|
|
9793
|
+
"path": "included",
|
|
9794
|
+
"valueType": "number"
|
|
9795
|
+
},
|
|
9796
|
+
{
|
|
9797
|
+
"path": "excluded",
|
|
9798
|
+
"valueType": "number"
|
|
9799
|
+
},
|
|
9800
|
+
{
|
|
9801
|
+
"path": "total",
|
|
9802
|
+
"valueType": "number"
|
|
9803
|
+
}
|
|
9804
|
+
],
|
|
9718
9805
|
"heating-valve": [{
|
|
9719
9806
|
"path": "position",
|
|
9720
9807
|
"valueType": "number"
|
|
@@ -9749,20 +9836,10 @@ Object.freeze({
|
|
|
9749
9836
|
"valueType": "number"
|
|
9750
9837
|
}
|
|
9751
9838
|
],
|
|
9752
|
-
"humidity-sensor": [
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
},
|
|
9757
|
-
{
|
|
9758
|
-
"path": "unit",
|
|
9759
|
-
"valueType": "string"
|
|
9760
|
-
},
|
|
9761
|
-
{
|
|
9762
|
-
"path": "precision",
|
|
9763
|
-
"valueType": "number"
|
|
9764
|
-
}
|
|
9765
|
-
],
|
|
9839
|
+
"humidity-sensor": [{
|
|
9840
|
+
"path": "percent",
|
|
9841
|
+
"valueType": "number"
|
|
9842
|
+
}],
|
|
9766
9843
|
"image": [{
|
|
9767
9844
|
"path": "url",
|
|
9768
9845
|
"valueType": "string"
|
|
@@ -9970,6 +10047,10 @@ Object.freeze({
|
|
|
9970
10047
|
]
|
|
9971
10048
|
}
|
|
9972
10049
|
],
|
|
10050
|
+
"meter": [{
|
|
10051
|
+
"path": "value",
|
|
10052
|
+
"valueType": "number"
|
|
10053
|
+
}],
|
|
9973
10054
|
"motion": [
|
|
9974
10055
|
{
|
|
9975
10056
|
"path": "detected",
|
|
@@ -10101,20 +10182,10 @@ Object.freeze({
|
|
|
10101
10182
|
"valueType": "boolean"
|
|
10102
10183
|
}
|
|
10103
10184
|
],
|
|
10104
|
-
"numeric-sensor": [
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
},
|
|
10109
|
-
{
|
|
10110
|
-
"path": "unit",
|
|
10111
|
-
"valueType": "string"
|
|
10112
|
-
},
|
|
10113
|
-
{
|
|
10114
|
-
"path": "precision",
|
|
10115
|
-
"valueType": "number"
|
|
10116
|
-
}
|
|
10117
|
-
],
|
|
10185
|
+
"numeric-sensor": [{
|
|
10186
|
+
"path": "value",
|
|
10187
|
+
"valueType": "number"
|
|
10188
|
+
}],
|
|
10118
10189
|
"pet-feeder": [
|
|
10119
10190
|
{
|
|
10120
10191
|
"path": "foodLevel",
|
|
@@ -10206,14 +10277,6 @@ Object.freeze({
|
|
|
10206
10277
|
{
|
|
10207
10278
|
"path": "powerFactor",
|
|
10208
10279
|
"valueType": "number"
|
|
10209
|
-
},
|
|
10210
|
-
{
|
|
10211
|
-
"path": "unit",
|
|
10212
|
-
"valueType": "string"
|
|
10213
|
-
},
|
|
10214
|
-
{
|
|
10215
|
-
"path": "precision",
|
|
10216
|
-
"valueType": "number"
|
|
10217
10280
|
}
|
|
10218
10281
|
],
|
|
10219
10282
|
"presence": [
|
|
@@ -10242,20 +10305,10 @@ Object.freeze({
|
|
|
10242
10305
|
"valueType": "number"
|
|
10243
10306
|
}
|
|
10244
10307
|
],
|
|
10245
|
-
"pressure-sensor": [
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
},
|
|
10250
|
-
{
|
|
10251
|
-
"path": "unit",
|
|
10252
|
-
"valueType": "string"
|
|
10253
|
-
},
|
|
10254
|
-
{
|
|
10255
|
-
"path": "precision",
|
|
10256
|
-
"valueType": "number"
|
|
10257
|
-
}
|
|
10258
|
-
],
|
|
10308
|
+
"pressure-sensor": [{
|
|
10309
|
+
"path": "hpa",
|
|
10310
|
+
"valueType": "number"
|
|
10311
|
+
}],
|
|
10259
10312
|
"privacy-mask": [{
|
|
10260
10313
|
"path": "enabled",
|
|
10261
10314
|
"valueType": "boolean"
|
|
@@ -10566,20 +10619,10 @@ Object.freeze({
|
|
|
10566
10619
|
"path": "tampered",
|
|
10567
10620
|
"valueType": "boolean"
|
|
10568
10621
|
}],
|
|
10569
|
-
"temperature-sensor": [
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
},
|
|
10574
|
-
{
|
|
10575
|
-
"path": "unit",
|
|
10576
|
-
"valueType": "string"
|
|
10577
|
-
},
|
|
10578
|
-
{
|
|
10579
|
-
"path": "precision",
|
|
10580
|
-
"valueType": "number"
|
|
10581
|
-
}
|
|
10582
|
-
],
|
|
10622
|
+
"temperature-sensor": [{
|
|
10623
|
+
"path": "celsius",
|
|
10624
|
+
"valueType": "number"
|
|
10625
|
+
}],
|
|
10583
10626
|
"update": [
|
|
10584
10627
|
{
|
|
10585
10628
|
"path": "currentVersion",
|
|
@@ -10690,10 +10733,6 @@ Object.freeze({
|
|
|
10690
10733
|
"path": "temperature",
|
|
10691
10734
|
"valueType": "number"
|
|
10692
10735
|
},
|
|
10693
|
-
{
|
|
10694
|
-
"path": "temperatureUnit",
|
|
10695
|
-
"valueType": "string"
|
|
10696
|
-
},
|
|
10697
10736
|
{
|
|
10698
10737
|
"path": "humidity",
|
|
10699
10738
|
"valueType": "number"
|
|
@@ -10702,18 +10741,10 @@ Object.freeze({
|
|
|
10702
10741
|
"path": "pressure",
|
|
10703
10742
|
"valueType": "number"
|
|
10704
10743
|
},
|
|
10705
|
-
{
|
|
10706
|
-
"path": "pressureUnit",
|
|
10707
|
-
"valueType": "string"
|
|
10708
|
-
},
|
|
10709
10744
|
{
|
|
10710
10745
|
"path": "windSpeed",
|
|
10711
10746
|
"valueType": "number"
|
|
10712
10747
|
},
|
|
10713
|
-
{
|
|
10714
|
-
"path": "windSpeedUnit",
|
|
10715
|
-
"valueType": "string"
|
|
10716
|
-
},
|
|
10717
10748
|
{
|
|
10718
10749
|
"path": "windBearing",
|
|
10719
10750
|
"valueType": "number"
|
|
@@ -10777,7 +10808,7 @@ function userError(code, params, englishFallback) {
|
|
|
10777
10808
|
return new CamstackError(code, params, englishFallback);
|
|
10778
10809
|
}
|
|
10779
10810
|
//#endregion
|
|
10780
|
-
//#region ../types/dist/err-msg-
|
|
10811
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10781
10812
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10782
10813
|
DeviceType["Camera"] = "camera";
|
|
10783
10814
|
DeviceType["Hub"] = "hub";
|
|
@@ -10871,8 +10902,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10871
10902
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10872
10903
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10873
10904
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10874
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10905
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10906
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10875
10907
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10908
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10909
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10910
|
+
DeviceType["Washer"] = "washer";
|
|
10911
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10912
|
+
DeviceType["Dryer"] = "dryer";
|
|
10876
10913
|
return DeviceType;
|
|
10877
10914
|
}({});
|
|
10878
10915
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11120,7 +11157,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11120
11157
|
return DeviceRole;
|
|
11121
11158
|
}({});
|
|
11122
11159
|
//#endregion
|
|
11123
|
-
//#region ../types/dist/composition-
|
|
11160
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11124
11161
|
/**
|
|
11125
11162
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11126
11163
|
*
|
|
@@ -11435,6 +11472,13 @@ var table = {
|
|
|
11435
11472
|
apply: () => {
|
|
11436
11473
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11437
11474
|
}
|
|
11475
|
+
},
|
|
11476
|
+
schmitt: {
|
|
11477
|
+
minArgs: 3,
|
|
11478
|
+
maxArgs: 5,
|
|
11479
|
+
apply: () => {
|
|
11480
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11481
|
+
}
|
|
11438
11482
|
}
|
|
11439
11483
|
};
|
|
11440
11484
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11875,15 +11919,232 @@ function validateExpressionSource(src) {
|
|
|
11875
11919
|
}
|
|
11876
11920
|
return null;
|
|
11877
11921
|
}
|
|
11878
|
-
/**
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11922
|
+
/**
|
|
11923
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11924
|
+
*
|
|
11925
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11926
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11927
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11928
|
+
*
|
|
11929
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11930
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11931
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11932
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11933
|
+
* can move later without moving the others.
|
|
11934
|
+
*/
|
|
11935
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11936
|
+
var APPLIANCE_KINDS = [
|
|
11937
|
+
"washer",
|
|
11938
|
+
"dryer",
|
|
11939
|
+
"dishwasher"
|
|
11940
|
+
];
|
|
11941
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11942
|
+
/**
|
|
11943
|
+
* Statistics and integrals over a history read (D944).
|
|
11944
|
+
*
|
|
11945
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11946
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11947
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11948
|
+
* as zero. A truncated read is not published.
|
|
11949
|
+
*/
|
|
11950
|
+
var STATISTIC_STATS = [
|
|
11951
|
+
"min",
|
|
11952
|
+
"max",
|
|
11953
|
+
"mean",
|
|
11954
|
+
"sum",
|
|
11955
|
+
"count",
|
|
11956
|
+
"change"
|
|
11957
|
+
];
|
|
11958
|
+
/**
|
|
11959
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11960
|
+
*
|
|
11961
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11962
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11963
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11964
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11965
|
+
*/
|
|
11966
|
+
var MINUTE_MS = 6e4;
|
|
11967
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11968
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11969
|
+
var ROLLING_SPANS = [
|
|
11970
|
+
"1h",
|
|
11971
|
+
"24h",
|
|
11972
|
+
"2d",
|
|
11973
|
+
"7d",
|
|
11974
|
+
"30d",
|
|
11975
|
+
"custom"
|
|
11976
|
+
];
|
|
11977
|
+
var CALENDAR_PERIODS = [
|
|
11978
|
+
"today",
|
|
11979
|
+
"yesterday",
|
|
11980
|
+
"this-week",
|
|
11981
|
+
"this-month"
|
|
11982
|
+
];
|
|
11983
|
+
var RESET_PERIODS = [
|
|
11984
|
+
"never",
|
|
11985
|
+
"daily",
|
|
11986
|
+
"weekly",
|
|
11987
|
+
"monthly"
|
|
11988
|
+
];
|
|
11989
|
+
5 * MINUTE_MS;
|
|
11990
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11991
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11992
|
+
var rollingWindowObject = object({
|
|
11993
|
+
kind: literal("rolling"),
|
|
11994
|
+
span: _enum(ROLLING_SPANS),
|
|
11995
|
+
customMinutes: number().int().min(5).optional()
|
|
11996
|
+
}).check((payload) => {
|
|
11997
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11998
|
+
code: "custom",
|
|
11999
|
+
message: "a custom range needs a duration in minutes",
|
|
12000
|
+
path: ["customMinutes"],
|
|
12001
|
+
input: payload.value
|
|
12002
|
+
});
|
|
12003
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
12004
|
+
code: "custom",
|
|
12005
|
+
message: "only a custom range carries a duration",
|
|
12006
|
+
path: ["customMinutes"],
|
|
12007
|
+
input: payload.value
|
|
12008
|
+
});
|
|
12009
|
+
});
|
|
12010
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12011
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12012
|
+
kind: literal("calendar"),
|
|
12013
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12014
|
+
})]);
|
|
12015
|
+
/**
|
|
12016
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
12017
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
12018
|
+
* `composition.ts` (D659).
|
|
12019
|
+
*/
|
|
11882
12020
|
var CompositionSourceRefSchema = object({
|
|
11883
12021
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11884
12022
|
addonId: string().min(1),
|
|
11885
12023
|
stableId: string().min(1)
|
|
11886
12024
|
});
|
|
12025
|
+
var GROUP_TEMPLATE_IDS = [
|
|
12026
|
+
"temperature",
|
|
12027
|
+
"humidity",
|
|
12028
|
+
"pressure",
|
|
12029
|
+
"illuminance",
|
|
12030
|
+
"power",
|
|
12031
|
+
"energy",
|
|
12032
|
+
"battery",
|
|
12033
|
+
"numeric",
|
|
12034
|
+
"motion",
|
|
12035
|
+
"contact",
|
|
12036
|
+
"leak",
|
|
12037
|
+
"smoke",
|
|
12038
|
+
"occupancy",
|
|
12039
|
+
"binary",
|
|
12040
|
+
"switch",
|
|
12041
|
+
"light",
|
|
12042
|
+
"fan",
|
|
12043
|
+
"cover",
|
|
12044
|
+
"valve",
|
|
12045
|
+
"lock",
|
|
12046
|
+
"media-player",
|
|
12047
|
+
"climate"
|
|
12048
|
+
];
|
|
12049
|
+
var NUMERIC_AGGREGATES = [
|
|
12050
|
+
"mean",
|
|
12051
|
+
"median",
|
|
12052
|
+
"min",
|
|
12053
|
+
"max",
|
|
12054
|
+
"sum"
|
|
12055
|
+
];
|
|
12056
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12057
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12058
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12059
|
+
var AGGREGATE_REDUCERS = [
|
|
12060
|
+
"mean",
|
|
12061
|
+
"median",
|
|
12062
|
+
"min",
|
|
12063
|
+
"max",
|
|
12064
|
+
"sum",
|
|
12065
|
+
"any",
|
|
12066
|
+
"all"
|
|
12067
|
+
];
|
|
12068
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12069
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12070
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12071
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12072
|
+
var HelperMemberSchema = object({
|
|
12073
|
+
source: CompositionSourceRefSchema,
|
|
12074
|
+
cap: string().min(1),
|
|
12075
|
+
fieldPath: string().min(1)
|
|
12076
|
+
});
|
|
12077
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12078
|
+
object({
|
|
12079
|
+
kind: literal("group"),
|
|
12080
|
+
templateId: GroupTemplateIdSchema,
|
|
12081
|
+
aggregate: AggregateReducerSchema,
|
|
12082
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12083
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12084
|
+
active: ActiveCriterionSchema.optional()
|
|
12085
|
+
}),
|
|
12086
|
+
object({
|
|
12087
|
+
kind: literal("appliance"),
|
|
12088
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12089
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12090
|
+
thresholdWatts: number().positive(),
|
|
12091
|
+
startDwellMs: number().int().nonnegative(),
|
|
12092
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12093
|
+
member: HelperMemberSchema
|
|
12094
|
+
}),
|
|
12095
|
+
object({
|
|
12096
|
+
kind: literal("statistic"),
|
|
12097
|
+
stat: _enum(STATISTIC_STATS),
|
|
12098
|
+
window: StatisticWindowSchema,
|
|
12099
|
+
source: HelperMemberSchema
|
|
12100
|
+
}),
|
|
12101
|
+
object({
|
|
12102
|
+
kind: literal("integral"),
|
|
12103
|
+
reset: _enum(RESET_PERIODS),
|
|
12104
|
+
output: _enum(["energy", "meter"]),
|
|
12105
|
+
source: HelperMemberSchema
|
|
12106
|
+
}),
|
|
12107
|
+
object({
|
|
12108
|
+
kind: literal("threshold"),
|
|
12109
|
+
source: HelperMemberSchema,
|
|
12110
|
+
high: number(),
|
|
12111
|
+
low: number(),
|
|
12112
|
+
onForMs: number().int().nonnegative(),
|
|
12113
|
+
offForMs: number().int().nonnegative()
|
|
12114
|
+
}),
|
|
12115
|
+
object({
|
|
12116
|
+
kind: literal("arithmetic"),
|
|
12117
|
+
op: _enum([
|
|
12118
|
+
"sum",
|
|
12119
|
+
"difference",
|
|
12120
|
+
"ratio"
|
|
12121
|
+
]),
|
|
12122
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12123
|
+
}),
|
|
12124
|
+
object({
|
|
12125
|
+
kind: literal("expression"),
|
|
12126
|
+
expr: string().min(1),
|
|
12127
|
+
inputs: array(object({
|
|
12128
|
+
name: string().min(1),
|
|
12129
|
+
member: HelperMemberSchema
|
|
12130
|
+
})).min(1).max(64),
|
|
12131
|
+
output: _enum(["number", "boolean"])
|
|
12132
|
+
}),
|
|
12133
|
+
object({
|
|
12134
|
+
kind: literal("derivative"),
|
|
12135
|
+
window: RollingWindowSchema,
|
|
12136
|
+
per: _enum([
|
|
12137
|
+
"second",
|
|
12138
|
+
"minute",
|
|
12139
|
+
"hour"
|
|
12140
|
+
]),
|
|
12141
|
+
source: HelperMemberSchema
|
|
12142
|
+
})
|
|
12143
|
+
]);
|
|
12144
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12145
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12146
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12147
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11887
12148
|
/** One field of one capability of one source device. */
|
|
11888
12149
|
var CompositionFieldReadSchema = object({
|
|
11889
12150
|
source: CompositionSourceRefSchema,
|
|
@@ -11927,7 +12188,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11927
12188
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11928
12189
|
CompositionFromSourceSchema,
|
|
11929
12190
|
CompositionExpressionSourceSchema,
|
|
11930
|
-
CompositionCodeSourceSchema
|
|
12191
|
+
CompositionCodeSourceSchema,
|
|
12192
|
+
object({
|
|
12193
|
+
kind: literal("aggregate"),
|
|
12194
|
+
reducer: _enum([
|
|
12195
|
+
"mean",
|
|
12196
|
+
"median",
|
|
12197
|
+
"min",
|
|
12198
|
+
"max",
|
|
12199
|
+
"sum",
|
|
12200
|
+
"any",
|
|
12201
|
+
"all"
|
|
12202
|
+
]),
|
|
12203
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12204
|
+
/**
|
|
12205
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12206
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12207
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12208
|
+
*/
|
|
12209
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12210
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12211
|
+
publish: _enum([
|
|
12212
|
+
"value",
|
|
12213
|
+
"included",
|
|
12214
|
+
"excluded",
|
|
12215
|
+
"total"
|
|
12216
|
+
]),
|
|
12217
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12218
|
+
empty: _enum([
|
|
12219
|
+
"null",
|
|
12220
|
+
"omit",
|
|
12221
|
+
"offline"
|
|
12222
|
+
])
|
|
12223
|
+
}),
|
|
12224
|
+
object({
|
|
12225
|
+
kind: literal("series"),
|
|
12226
|
+
read: CompositionFieldReadSchema,
|
|
12227
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12228
|
+
publish: _enum([
|
|
12229
|
+
"value",
|
|
12230
|
+
"included",
|
|
12231
|
+
"excluded",
|
|
12232
|
+
"total"
|
|
12233
|
+
]),
|
|
12234
|
+
/**
|
|
12235
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12236
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12237
|
+
*/
|
|
12238
|
+
empty: _enum([
|
|
12239
|
+
"null",
|
|
12240
|
+
"omit",
|
|
12241
|
+
"offline"
|
|
12242
|
+
])
|
|
12243
|
+
})
|
|
11931
12244
|
]);
|
|
11932
12245
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11933
12246
|
kind: literal("forward"),
|
|
@@ -11973,7 +12286,13 @@ var CompositionSchema = object({
|
|
|
11973
12286
|
kind: literal("existing"),
|
|
11974
12287
|
device: CompositionSourceRefSchema
|
|
11975
12288
|
})]),
|
|
11976
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12289
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12290
|
+
/**
|
|
12291
|
+
* Present when the block is a helper template. Absent on a free
|
|
12292
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12293
|
+
* never the compiled features.
|
|
12294
|
+
*/
|
|
12295
|
+
helper: HelperSpecSchema.optional()
|
|
11977
12296
|
}).superRefine((composition, ctx) => {
|
|
11978
12297
|
const seen = /* @__PURE__ */ new Set();
|
|
11979
12298
|
composition.features.forEach((feature, index) => {
|
|
@@ -17216,7 +17535,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17216
17535
|
*/
|
|
17217
17536
|
interactiveConnectPath: string().min(1).optional(),
|
|
17218
17537
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17219
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17538
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17539
|
+
/**
|
|
17540
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17541
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17542
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17543
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17544
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17545
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17546
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17547
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17548
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17549
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17550
|
+
* offers it as the default path; the fields the session fills are
|
|
17551
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17552
|
+
*/
|
|
17553
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17220
17554
|
}))
|
|
17221
17555
|
});
|
|
17222
17556
|
var ListInputSchema = object({
|
|
@@ -18211,7 +18545,12 @@ var CompositionProblemSchema = object({
|
|
|
18211
18545
|
"item-field-reserved",
|
|
18212
18546
|
"target-missing",
|
|
18213
18547
|
"target-unreadable",
|
|
18214
|
-
"not-replaceable"
|
|
18548
|
+
"not-replaceable",
|
|
18549
|
+
"native-capability-replace",
|
|
18550
|
+
"mixed-quantity",
|
|
18551
|
+
"helper-mismatch",
|
|
18552
|
+
"member-constraint",
|
|
18553
|
+
"retention"
|
|
18215
18554
|
]),
|
|
18216
18555
|
path: string(),
|
|
18217
18556
|
message: string()
|
|
@@ -18232,7 +18571,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18232
18571
|
"null",
|
|
18233
18572
|
"offline",
|
|
18234
18573
|
"unknown",
|
|
18235
|
-
"release"
|
|
18574
|
+
"release",
|
|
18575
|
+
"omit"
|
|
18236
18576
|
]);
|
|
18237
18577
|
/**
|
|
18238
18578
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18269,9 +18609,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18269
18609
|
reads: array(CompositionFieldReadSchema)
|
|
18270
18610
|
});
|
|
18271
18611
|
/**
|
|
18272
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18273
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18274
|
-
*
|
|
18612
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18613
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18614
|
+
* Replacing a capability the device already serves is refused
|
|
18615
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18616
|
+
* wire for a claim the hub already holds.
|
|
18275
18617
|
*/
|
|
18276
18618
|
var CompositionFeatureModeSchema = _enum([
|
|
18277
18619
|
"new",
|
|
@@ -18442,8 +18784,392 @@ Object.freeze({
|
|
|
18442
18784
|
latchedAt: {
|
|
18443
18785
|
kind: "fixed",
|
|
18444
18786
|
result: ["number", "null"]
|
|
18787
|
+
},
|
|
18788
|
+
schmitt: {
|
|
18789
|
+
kind: "fixed",
|
|
18790
|
+
result: ["boolean", "null"]
|
|
18445
18791
|
}
|
|
18446
18792
|
});
|
|
18793
|
+
/**
|
|
18794
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18795
|
+
* Data, not a form default written into the block.
|
|
18796
|
+
*/
|
|
18797
|
+
var NOW$2 = {
|
|
18798
|
+
fieldPath: "lastFetchedAt",
|
|
18799
|
+
expr: "now"
|
|
18800
|
+
};
|
|
18801
|
+
var CHANGED = {
|
|
18802
|
+
fieldPath: "lastChangedAt",
|
|
18803
|
+
expr: "now"
|
|
18804
|
+
};
|
|
18805
|
+
function numeric(input) {
|
|
18806
|
+
return {
|
|
18807
|
+
...input,
|
|
18808
|
+
family: "numeric",
|
|
18809
|
+
deviceType: DeviceType.Sensor,
|
|
18810
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18811
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18812
|
+
activeWhen: void 0,
|
|
18813
|
+
commandCaps: [],
|
|
18814
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18815
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18816
|
+
accept: [{
|
|
18817
|
+
cap: input.outputCap,
|
|
18818
|
+
fieldPath: input.outputField
|
|
18819
|
+
}]
|
|
18820
|
+
};
|
|
18821
|
+
}
|
|
18822
|
+
function binary(input) {
|
|
18823
|
+
return {
|
|
18824
|
+
...input,
|
|
18825
|
+
family: "binary",
|
|
18826
|
+
deviceType: DeviceType.Sensor,
|
|
18827
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18828
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18829
|
+
activeWhen: void 0,
|
|
18830
|
+
commandCaps: [],
|
|
18831
|
+
quantity: "none",
|
|
18832
|
+
baseUnit: void 0,
|
|
18833
|
+
aggregates: BINARY_AGGREGATES,
|
|
18834
|
+
empty: "offline"
|
|
18835
|
+
};
|
|
18836
|
+
}
|
|
18837
|
+
var GROUP_TEMPLATES = [
|
|
18838
|
+
numeric({
|
|
18839
|
+
id: "temperature",
|
|
18840
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18841
|
+
role: DeviceRole.TemperatureSensor,
|
|
18842
|
+
outputCap: "temperature-sensor",
|
|
18843
|
+
outputField: "celsius",
|
|
18844
|
+
quantity: "temperature",
|
|
18845
|
+
defaultAggregate: "mean",
|
|
18846
|
+
empty: "null",
|
|
18847
|
+
companions: [NOW$2]
|
|
18848
|
+
}),
|
|
18849
|
+
numeric({
|
|
18850
|
+
id: "humidity",
|
|
18851
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18852
|
+
role: DeviceRole.HumiditySensor,
|
|
18853
|
+
outputCap: "humidity-sensor",
|
|
18854
|
+
outputField: "percent",
|
|
18855
|
+
quantity: "humidity",
|
|
18856
|
+
defaultAggregate: "mean",
|
|
18857
|
+
empty: "null",
|
|
18858
|
+
companions: [NOW$2]
|
|
18859
|
+
}),
|
|
18860
|
+
numeric({
|
|
18861
|
+
id: "pressure",
|
|
18862
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18863
|
+
role: DeviceRole.PressureSensor,
|
|
18864
|
+
outputCap: "pressure-sensor",
|
|
18865
|
+
outputField: "hpa",
|
|
18866
|
+
quantity: "pressure",
|
|
18867
|
+
defaultAggregate: "mean",
|
|
18868
|
+
empty: "null",
|
|
18869
|
+
companions: [NOW$2]
|
|
18870
|
+
}),
|
|
18871
|
+
numeric({
|
|
18872
|
+
id: "illuminance",
|
|
18873
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18874
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18875
|
+
outputCap: "ambient-light-sensor",
|
|
18876
|
+
outputField: "lux",
|
|
18877
|
+
quantity: "illuminance",
|
|
18878
|
+
defaultAggregate: "mean",
|
|
18879
|
+
empty: "null",
|
|
18880
|
+
companions: [NOW$2]
|
|
18881
|
+
}),
|
|
18882
|
+
numeric({
|
|
18883
|
+
id: "power",
|
|
18884
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18885
|
+
role: DeviceRole.PowerSensor,
|
|
18886
|
+
outputCap: "power-meter",
|
|
18887
|
+
outputField: "watts",
|
|
18888
|
+
quantity: "power",
|
|
18889
|
+
defaultAggregate: "sum",
|
|
18890
|
+
empty: "omit",
|
|
18891
|
+
companions: [NOW$2]
|
|
18892
|
+
}),
|
|
18893
|
+
numeric({
|
|
18894
|
+
id: "energy",
|
|
18895
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18896
|
+
role: DeviceRole.EnergySensor,
|
|
18897
|
+
outputCap: "power-meter",
|
|
18898
|
+
outputField: "kwhTotal",
|
|
18899
|
+
quantity: "energy",
|
|
18900
|
+
defaultAggregate: "sum",
|
|
18901
|
+
empty: "omit",
|
|
18902
|
+
companions: [NOW$2]
|
|
18903
|
+
}),
|
|
18904
|
+
numeric({
|
|
18905
|
+
id: "battery",
|
|
18906
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18907
|
+
role: DeviceRole.BatterySensor,
|
|
18908
|
+
outputCap: "battery",
|
|
18909
|
+
outputField: "percentage",
|
|
18910
|
+
quantity: "percentage",
|
|
18911
|
+
defaultAggregate: "mean",
|
|
18912
|
+
empty: "null",
|
|
18913
|
+
companions: [
|
|
18914
|
+
{
|
|
18915
|
+
fieldPath: "charging",
|
|
18916
|
+
expr: "\"unknown\""
|
|
18917
|
+
},
|
|
18918
|
+
{
|
|
18919
|
+
fieldPath: "sleeping",
|
|
18920
|
+
expr: "false"
|
|
18921
|
+
},
|
|
18922
|
+
{
|
|
18923
|
+
fieldPath: "lastUpdated",
|
|
18924
|
+
expr: "now"
|
|
18925
|
+
}
|
|
18926
|
+
]
|
|
18927
|
+
}),
|
|
18928
|
+
numeric({
|
|
18929
|
+
id: "numeric",
|
|
18930
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18931
|
+
role: DeviceRole.NumericSensor,
|
|
18932
|
+
outputCap: "numeric-sensor",
|
|
18933
|
+
outputField: "value",
|
|
18934
|
+
quantity: "device",
|
|
18935
|
+
defaultAggregate: "mean",
|
|
18936
|
+
empty: "null",
|
|
18937
|
+
companions: [NOW$2]
|
|
18938
|
+
}),
|
|
18939
|
+
binary({
|
|
18940
|
+
id: "motion",
|
|
18941
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18942
|
+
role: DeviceRole.MotionSensor,
|
|
18943
|
+
outputCap: "motion",
|
|
18944
|
+
outputField: "detected",
|
|
18945
|
+
defaultAggregate: "any",
|
|
18946
|
+
accept: [{
|
|
18947
|
+
cap: "motion",
|
|
18948
|
+
fieldPath: "detected"
|
|
18949
|
+
}],
|
|
18950
|
+
companions: [{
|
|
18951
|
+
fieldPath: "lastDetectedAt",
|
|
18952
|
+
expr: "null"
|
|
18953
|
+
}, {
|
|
18954
|
+
fieldPath: "autoClearAfterMs",
|
|
18955
|
+
expr: "null"
|
|
18956
|
+
}]
|
|
18957
|
+
}),
|
|
18958
|
+
binary({
|
|
18959
|
+
id: "contact",
|
|
18960
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18961
|
+
role: DeviceRole.ContactSensor,
|
|
18962
|
+
outputCap: "contact",
|
|
18963
|
+
outputField: "entryOpen",
|
|
18964
|
+
defaultAggregate: "any",
|
|
18965
|
+
accept: [{
|
|
18966
|
+
cap: "contact",
|
|
18967
|
+
fieldPath: "entryOpen"
|
|
18968
|
+
}],
|
|
18969
|
+
companions: [CHANGED]
|
|
18970
|
+
}),
|
|
18971
|
+
binary({
|
|
18972
|
+
id: "leak",
|
|
18973
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18974
|
+
role: DeviceRole.LeakSensor,
|
|
18975
|
+
outputCap: "flood",
|
|
18976
|
+
outputField: "flooded",
|
|
18977
|
+
defaultAggregate: "any",
|
|
18978
|
+
accept: [{
|
|
18979
|
+
cap: "flood",
|
|
18980
|
+
fieldPath: "flooded"
|
|
18981
|
+
}],
|
|
18982
|
+
companions: [CHANGED]
|
|
18983
|
+
}),
|
|
18984
|
+
binary({
|
|
18985
|
+
id: "smoke",
|
|
18986
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18987
|
+
role: DeviceRole.SmokeSensor,
|
|
18988
|
+
outputCap: "smoke",
|
|
18989
|
+
outputField: "detected",
|
|
18990
|
+
defaultAggregate: "any",
|
|
18991
|
+
accept: [{
|
|
18992
|
+
cap: "smoke",
|
|
18993
|
+
fieldPath: "detected"
|
|
18994
|
+
}],
|
|
18995
|
+
companions: [CHANGED]
|
|
18996
|
+
}),
|
|
18997
|
+
binary({
|
|
18998
|
+
id: "occupancy",
|
|
18999
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
19000
|
+
role: DeviceRole.BinarySensor,
|
|
19001
|
+
outputCap: "binary",
|
|
19002
|
+
outputField: "on",
|
|
19003
|
+
defaultAggregate: "any",
|
|
19004
|
+
accept: [{
|
|
19005
|
+
cap: "motion",
|
|
19006
|
+
fieldPath: "detected"
|
|
19007
|
+
}, {
|
|
19008
|
+
cap: "binary",
|
|
19009
|
+
fieldPath: "on"
|
|
19010
|
+
}],
|
|
19011
|
+
companions: [CHANGED]
|
|
19012
|
+
}),
|
|
19013
|
+
binary({
|
|
19014
|
+
id: "binary",
|
|
19015
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
19016
|
+
role: DeviceRole.BinarySensor,
|
|
19017
|
+
outputCap: "binary",
|
|
19018
|
+
outputField: "on",
|
|
19019
|
+
defaultAggregate: "any",
|
|
19020
|
+
accept: [{
|
|
19021
|
+
cap: "binary",
|
|
19022
|
+
fieldPath: "on"
|
|
19023
|
+
}],
|
|
19024
|
+
companions: [CHANGED]
|
|
19025
|
+
}),
|
|
19026
|
+
actuator({
|
|
19027
|
+
id: "switch",
|
|
19028
|
+
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.",
|
|
19029
|
+
deviceType: DeviceType.Switch,
|
|
19030
|
+
outputCap: "switch",
|
|
19031
|
+
outputField: "on",
|
|
19032
|
+
member: {
|
|
19033
|
+
cap: "switch",
|
|
19034
|
+
fieldPath: "on"
|
|
19035
|
+
},
|
|
19036
|
+
commandCaps: ["switch"]
|
|
19037
|
+
}),
|
|
19038
|
+
actuator({
|
|
19039
|
+
id: "light",
|
|
19040
|
+
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.",
|
|
19041
|
+
deviceType: DeviceType.Light,
|
|
19042
|
+
outputCap: "switch",
|
|
19043
|
+
outputField: "on",
|
|
19044
|
+
member: {
|
|
19045
|
+
cap: "switch",
|
|
19046
|
+
fieldPath: "on"
|
|
19047
|
+
},
|
|
19048
|
+
commandCaps: [
|
|
19049
|
+
"switch",
|
|
19050
|
+
"brightness",
|
|
19051
|
+
"color"
|
|
19052
|
+
]
|
|
19053
|
+
}),
|
|
19054
|
+
actuator({
|
|
19055
|
+
id: "fan",
|
|
19056
|
+
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.",
|
|
19057
|
+
deviceType: DeviceType.Fan,
|
|
19058
|
+
outputCap: "switch",
|
|
19059
|
+
outputField: "on",
|
|
19060
|
+
member: {
|
|
19061
|
+
cap: "switch",
|
|
19062
|
+
fieldPath: "on"
|
|
19063
|
+
},
|
|
19064
|
+
commandCaps: ["switch", "fan-control"]
|
|
19065
|
+
}),
|
|
19066
|
+
actuator({
|
|
19067
|
+
id: "cover",
|
|
19068
|
+
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.",
|
|
19069
|
+
deviceType: DeviceType.Cover,
|
|
19070
|
+
outputCap: "group-active",
|
|
19071
|
+
outputField: "active",
|
|
19072
|
+
member: {
|
|
19073
|
+
cap: "cover",
|
|
19074
|
+
fieldPath: "state"
|
|
19075
|
+
},
|
|
19076
|
+
activeWhen: [
|
|
19077
|
+
"open",
|
|
19078
|
+
"opening",
|
|
19079
|
+
"stopped"
|
|
19080
|
+
],
|
|
19081
|
+
commandCaps: ["cover"]
|
|
19082
|
+
}),
|
|
19083
|
+
actuator({
|
|
19084
|
+
id: "valve",
|
|
19085
|
+
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.",
|
|
19086
|
+
deviceType: DeviceType.Valve,
|
|
19087
|
+
outputCap: "group-active",
|
|
19088
|
+
outputField: "active",
|
|
19089
|
+
member: {
|
|
19090
|
+
cap: "valve",
|
|
19091
|
+
fieldPath: "state"
|
|
19092
|
+
},
|
|
19093
|
+
activeWhen: [
|
|
19094
|
+
"open",
|
|
19095
|
+
"opening",
|
|
19096
|
+
"stopped"
|
|
19097
|
+
],
|
|
19098
|
+
commandCaps: ["valve"]
|
|
19099
|
+
}),
|
|
19100
|
+
actuator({
|
|
19101
|
+
id: "lock",
|
|
19102
|
+
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.",
|
|
19103
|
+
deviceType: DeviceType.Lock,
|
|
19104
|
+
outputCap: "group-active",
|
|
19105
|
+
outputField: "active",
|
|
19106
|
+
member: {
|
|
19107
|
+
cap: "lock-control",
|
|
19108
|
+
fieldPath: "state"
|
|
19109
|
+
},
|
|
19110
|
+
activeWhen: ["locked"],
|
|
19111
|
+
commandCaps: ["lock-control"]
|
|
19112
|
+
}),
|
|
19113
|
+
actuator({
|
|
19114
|
+
id: "media-player",
|
|
19115
|
+
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.",
|
|
19116
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19117
|
+
outputCap: "group-active",
|
|
19118
|
+
outputField: "active",
|
|
19119
|
+
member: {
|
|
19120
|
+
cap: "media-player",
|
|
19121
|
+
fieldPath: "state"
|
|
19122
|
+
},
|
|
19123
|
+
activeWhen: ["playing", "buffering"],
|
|
19124
|
+
commandCaps: ["media-player"]
|
|
19125
|
+
}),
|
|
19126
|
+
actuator({
|
|
19127
|
+
id: "climate",
|
|
19128
|
+
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.",
|
|
19129
|
+
deviceType: DeviceType.Thermostat,
|
|
19130
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19131
|
+
outputCap: "group-active",
|
|
19132
|
+
outputField: "active",
|
|
19133
|
+
member: {
|
|
19134
|
+
cap: "climate-control",
|
|
19135
|
+
fieldPath: "mode"
|
|
19136
|
+
},
|
|
19137
|
+
activeWhen: [
|
|
19138
|
+
"heat",
|
|
19139
|
+
"cool",
|
|
19140
|
+
"auto",
|
|
19141
|
+
"heat_cool",
|
|
19142
|
+
"fan_only",
|
|
19143
|
+
"dry"
|
|
19144
|
+
],
|
|
19145
|
+
commandCaps: ["climate-control"]
|
|
19146
|
+
})
|
|
19147
|
+
];
|
|
19148
|
+
function actuator(input) {
|
|
19149
|
+
return {
|
|
19150
|
+
id: input.id,
|
|
19151
|
+
summary: input.summary,
|
|
19152
|
+
deviceType: input.deviceType,
|
|
19153
|
+
outputCap: input.outputCap,
|
|
19154
|
+
outputField: input.outputField,
|
|
19155
|
+
commandCaps: input.commandCaps,
|
|
19156
|
+
family: "actuator",
|
|
19157
|
+
role: void 0,
|
|
19158
|
+
memberDeviceType: input.deviceType,
|
|
19159
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19160
|
+
activeWhen: input.activeWhen,
|
|
19161
|
+
quantity: "none",
|
|
19162
|
+
baseUnit: void 0,
|
|
19163
|
+
aggregates: BINARY_AGGREGATES,
|
|
19164
|
+
defaultAggregate: "any",
|
|
19165
|
+
empty: "offline",
|
|
19166
|
+
accept: [input.member],
|
|
19167
|
+
companions: [CHANGED]
|
|
19168
|
+
};
|
|
19169
|
+
}
|
|
19170
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19171
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19172
|
+
DeviceType.Camera;
|
|
18447
19173
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18448
19174
|
/**
|
|
18449
19175
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20157,12 +20883,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
20157
20883
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20158
20884
|
* in-place so dispatch keeps working.
|
|
20159
20885
|
*
|
|
20160
|
-
* **
|
|
20161
|
-
*
|
|
20162
|
-
*
|
|
20163
|
-
*
|
|
20164
|
-
* (`ha-domain-mapping`)
|
|
20165
|
-
* stored after that point.
|
|
20886
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20887
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20888
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20889
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20890
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20891
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20166
20892
|
*
|
|
20167
20893
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20168
20894
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20176,6 +20902,14 @@ var SourceInfoSchema = object({
|
|
|
20176
20902
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20177
20903
|
* Used to detect rename when `id` changes. */
|
|
20178
20904
|
uniqueId: string().optional(),
|
|
20905
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20906
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20907
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20908
|
+
dateTimeShape: _enum([
|
|
20909
|
+
"date",
|
|
20910
|
+
"time",
|
|
20911
|
+
"datetime"
|
|
20912
|
+
]).optional(),
|
|
20179
20913
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20180
20914
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20181
20915
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41088,7 +41822,8 @@ method(object({
|
|
|
41088
41822
|
"enum"
|
|
41089
41823
|
]),
|
|
41090
41824
|
enumValues: array(string()).optional(),
|
|
41091
|
-
item: boolean().optional()
|
|
41825
|
+
item: boolean().optional(),
|
|
41826
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41092
41827
|
})).readonly(),
|
|
41093
41828
|
itemArray: object({
|
|
41094
41829
|
path: string(),
|
|
@@ -43449,7 +44184,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43449
44184
|
});
|
|
43450
44185
|
/**
|
|
43451
44186
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43452
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44187
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43453
44188
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43454
44189
|
* the originating provider config (mode + sourcePort) so the
|
|
43455
44190
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44910,8 +45645,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44910
45645
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44911
45646
|
var MaskGridShapeSchema = object({
|
|
44912
45647
|
kind: literal("grid"),
|
|
44913
|
-
gridWidth: number(),
|
|
44914
|
-
gridHeight: number(),
|
|
45648
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45649
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44915
45650
|
cells: array(boolean())
|
|
44916
45651
|
});
|
|
44917
45652
|
discriminatedUnion("kind", [
|
|
@@ -45023,6 +45758,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45023
45758
|
"detection-blind",
|
|
45024
45759
|
"motion-noisy",
|
|
45025
45760
|
"motion-calm",
|
|
45761
|
+
"package-llm-silent",
|
|
45762
|
+
"package-llm-answered",
|
|
45026
45763
|
"recording-stalled",
|
|
45027
45764
|
"recording-healthy",
|
|
45028
45765
|
"recording-degraded",
|
|
@@ -46112,7 +46849,20 @@ var NcRuleInputSchema = object({
|
|
|
46112
46849
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46113
46850
|
* path does not run Zod defaults.
|
|
46114
46851
|
*/
|
|
46115
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46852
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46853
|
+
/**
|
|
46854
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46855
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46856
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46857
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46858
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46859
|
+
*
|
|
46860
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46861
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46862
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46863
|
+
* `false`, so it needs no `clear` key.
|
|
46864
|
+
*/
|
|
46865
|
+
askVerdict: boolean().optional()
|
|
46116
46866
|
});
|
|
46117
46867
|
/**
|
|
46118
46868
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56037,6 +56787,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56037
56787
|
deprecated: string().optional(),
|
|
56038
56788
|
distTags: array(string()).readonly()
|
|
56039
56789
|
});
|
|
56790
|
+
/**
|
|
56791
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56792
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56793
|
+
* tarball failure — never an empty string standing in for either.
|
|
56794
|
+
*/
|
|
56795
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56796
|
+
object({
|
|
56797
|
+
status: literal("ok"),
|
|
56798
|
+
markdown: string()
|
|
56799
|
+
}),
|
|
56800
|
+
object({ status: literal("missing") }),
|
|
56801
|
+
object({
|
|
56802
|
+
status: literal("error"),
|
|
56803
|
+
message: string()
|
|
56804
|
+
})
|
|
56805
|
+
]);
|
|
56806
|
+
var PackageDocsSchema = object({
|
|
56807
|
+
name: string(),
|
|
56808
|
+
version: string(),
|
|
56809
|
+
readme: PackageDocBodySchema,
|
|
56810
|
+
changelog: PackageDocBodySchema
|
|
56811
|
+
});
|
|
56040
56812
|
var SearchResultSchema = object({
|
|
56041
56813
|
name: string(),
|
|
56042
56814
|
version: string(),
|
|
@@ -56255,7 +57027,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56255
57027
|
}), object({ success: literal(true) }), {
|
|
56256
57028
|
kind: "mutation",
|
|
56257
57029
|
auth: "admin"
|
|
56258
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57030
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57031
|
+
name: string().min(1),
|
|
57032
|
+
version: string().min(1).optional()
|
|
57033
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56259
57034
|
kind: "mutation",
|
|
56260
57035
|
auth: "admin"
|
|
56261
57036
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56305,46 +57080,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56305
57080
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56306
57081
|
object({
|
|
56307
57082
|
/** Carbon dioxide concentration in ppm. */
|
|
56308
|
-
co2Ppm: number().min(0).optional(),
|
|
57083
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56309
57084
|
/** Total volatile organic compounds in ppb. */
|
|
56310
|
-
vocPpb: number().min(0).optional(),
|
|
57085
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56311
57086
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56312
|
-
pm25: number().min(0).optional(),
|
|
57087
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56313
57088
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56314
|
-
pm10: number().min(0).optional(),
|
|
57089
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56315
57090
|
/** Composite AQI value (typically 0..500). */
|
|
56316
|
-
aqi: number().optional(),
|
|
57091
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56317
57092
|
/** Ms epoch when the slice was last updated. */
|
|
56318
|
-
lastFetchedAt: number()
|
|
56319
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56320
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56321
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56322
|
-
* per slice is unambiguous. */
|
|
56323
|
-
unit: string().optional(),
|
|
56324
|
-
/** Suggested decimal places for numeric display.
|
|
56325
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56326
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56327
|
-
* auto-formatting when absent. */
|
|
56328
|
-
precision: number().int().min(0).max(10).optional()
|
|
57093
|
+
lastFetchedAt: number()
|
|
56329
57094
|
});
|
|
56330
57095
|
DeviceType.Sensor;
|
|
56331
57096
|
object({
|
|
56332
|
-
/** Current illuminance in lux (lx). */
|
|
56333
|
-
lux: number().min(0).meta({
|
|
56334
|
-
|
|
57097
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57098
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57099
|
+
precision: 0,
|
|
56335
57100
|
label: "Illuminance"
|
|
56336
|
-
}),
|
|
57101
|
+
})),
|
|
56337
57102
|
/** Ms epoch when the slice was last updated. */
|
|
56338
|
-
lastFetchedAt: number()
|
|
56339
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56340
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56341
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56342
|
-
unit: string().optional(),
|
|
56343
|
-
/** Suggested decimal places for numeric display.
|
|
56344
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56345
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56346
|
-
* auto-formatting when absent. */
|
|
56347
|
-
precision: number().int().min(0).max(10).optional()
|
|
57103
|
+
lastFetchedAt: number()
|
|
56348
57104
|
});
|
|
56349
57105
|
DeviceType.Sensor;
|
|
56350
57106
|
/**
|
|
@@ -56489,10 +57245,7 @@ var BatteryStatusSchema = object({
|
|
|
56489
57245
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56490
57246
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56491
57247
|
*/
|
|
56492
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56493
|
-
unit: "%",
|
|
56494
|
-
label: "Charge"
|
|
56495
|
-
}),
|
|
57248
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56496
57249
|
/**
|
|
56497
57250
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56498
57251
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56519,7 +57272,14 @@ var BatteryStatusSchema = object({
|
|
|
56519
57272
|
*/
|
|
56520
57273
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56521
57274
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56522
|
-
lastUpdated: number(),
|
|
57275
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57276
|
+
/**
|
|
57277
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57278
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57279
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57280
|
+
* `numeric-sensor` on the same device.
|
|
57281
|
+
*/
|
|
57282
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56523
57283
|
/**
|
|
56524
57284
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56525
57285
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56559,7 +57319,7 @@ var BatteryStatusSchema = object({
|
|
|
56559
57319
|
*/
|
|
56560
57320
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56561
57321
|
});
|
|
56562
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57322
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56563
57323
|
method(object({
|
|
56564
57324
|
deviceId: number(),
|
|
56565
57325
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56579,7 +57339,7 @@ object({
|
|
|
56579
57339
|
DeviceType.Sensor;
|
|
56580
57340
|
object({
|
|
56581
57341
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56582
|
-
percentage: number().min(0).max(100),
|
|
57342
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56583
57343
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56584
57344
|
lastChangedAt: number()
|
|
56585
57345
|
});
|
|
@@ -56964,21 +57724,21 @@ object({
|
|
|
56964
57724
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
56965
57725
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
56966
57726
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
56967
|
-
target: number().nullable(),
|
|
57727
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
56968
57728
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
56969
57729
|
* in `heat_cool` mode. */
|
|
56970
|
-
targetHigh: number().nullable(),
|
|
57730
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
56971
57731
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
56972
57732
|
* in `heat_cool` mode. */
|
|
56973
|
-
targetLow: number().nullable(),
|
|
57733
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
56974
57734
|
/** Target relative humidity (0..100). Null when the device has no
|
|
56975
57735
|
* humidity control. */
|
|
56976
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57736
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56977
57737
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
56978
57738
|
* the device's internal sensor. */
|
|
56979
|
-
currentTemp: number().nullable(),
|
|
57739
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
56980
57740
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
56981
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57741
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56982
57742
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
56983
57743
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
56984
57744
|
swingVertical: boolean().nullable(),
|
|
@@ -56986,11 +57746,11 @@ object({
|
|
|
56986
57746
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
56987
57747
|
swingHorizontal: boolean().nullable(),
|
|
56988
57748
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56989
|
-
minTemp: number().nullable().optional(),
|
|
57749
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56990
57750
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56991
|
-
maxTemp: number().nullable().optional(),
|
|
57751
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56992
57752
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
56993
|
-
tempStep: number().positive().nullable().optional(),
|
|
57753
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
56994
57754
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
56995
57755
|
lastFetchedAt: number()
|
|
56996
57756
|
});
|
|
@@ -57069,17 +57829,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
57069
57829
|
* modes to expose in the picker without a slice fetch.
|
|
57070
57830
|
*/
|
|
57071
57831
|
var RgbTripletSchema = object({
|
|
57072
|
-
r: number().int().min(0).max(255),
|
|
57073
|
-
g: number().int().min(0).max(255),
|
|
57074
|
-
b: number().int().min(0).max(255)
|
|
57832
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57833
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57834
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57075
57835
|
});
|
|
57076
57836
|
var HsvTripletSchema = object({
|
|
57077
57837
|
/** Hue in degrees, 0..360. */
|
|
57078
|
-
h: number().min(0).max(360),
|
|
57838
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57079
57839
|
/** Saturation as 0..100 inclusive. */
|
|
57080
|
-
s: number().min(0).max(100),
|
|
57840
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57081
57841
|
/** Value/brightness as 0..100 inclusive. */
|
|
57082
|
-
v: number().min(0).max(100)
|
|
57842
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57083
57843
|
});
|
|
57084
57844
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57085
57845
|
object({
|
|
@@ -57108,7 +57868,7 @@ object({
|
|
|
57108
57868
|
/** Populated when `mode === 'hsv'`. */
|
|
57109
57869
|
hsv: HsvTripletSchema.optional(),
|
|
57110
57870
|
/** Populated when `mode === 'mired'`. */
|
|
57111
|
-
mireds: number().int().optional(),
|
|
57871
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57112
57872
|
/** Ms epoch of the last operator-driven change. */
|
|
57113
57873
|
lastChangedAt: number()
|
|
57114
57874
|
});
|
|
@@ -57232,18 +57992,12 @@ _enum([
|
|
|
57232
57992
|
"empty",
|
|
57233
57993
|
"full"
|
|
57234
57994
|
]);
|
|
57235
|
-
/**
|
|
57236
|
-
|
|
57237
|
-
|
|
57238
|
-
"days",
|
|
57239
|
-
"hours",
|
|
57240
|
-
"cycles"
|
|
57241
|
-
]);
|
|
57242
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57243
|
-
* days). `value` null = unknown (D393). */
|
|
57995
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
57996
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
57997
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57244
57998
|
var ConsumableRemainingSchema = object({
|
|
57245
|
-
value: number().min(0).nullable(),
|
|
57246
|
-
|
|
57999
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58000
|
+
kind: ConsumableRemainingKindSchema
|
|
57247
58001
|
});
|
|
57248
58002
|
var ConsumablesStatusSchema = object({
|
|
57249
58003
|
items: array(object({
|
|
@@ -57252,7 +58006,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57252
58006
|
/** Display name. */
|
|
57253
58007
|
label: string().min(1),
|
|
57254
58008
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57255
|
-
level: number().min(0).max(100).nullable(),
|
|
58009
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57256
58010
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57257
58011
|
status: ConsumableStatusSchema.nullable(),
|
|
57258
58012
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57269,7 +58023,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57269
58023
|
})),
|
|
57270
58024
|
lastChangedAt: number()
|
|
57271
58025
|
});
|
|
57272
|
-
Object.values(DeviceType), [...
|
|
58026
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57273
58027
|
Object.values(DeviceType), method(object({
|
|
57274
58028
|
deviceId: number().int().nonnegative(),
|
|
57275
58029
|
key: string().min(1)
|
|
@@ -57294,39 +58048,17 @@ object({
|
|
|
57294
58048
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57295
58049
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57296
58050
|
* or time-only — HA accepts all three forms). */
|
|
57297
|
-
value: union([number(), string()]),
|
|
58051
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57298
58052
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57299
58053
|
options: array(string()),
|
|
57300
58054
|
/** Ms epoch when the slice was last updated. */
|
|
57301
58055
|
lastChangedAt: number(),
|
|
57302
|
-
/**
|
|
57303
|
-
|
|
57304
|
-
|
|
57305
|
-
|
|
57306
|
-
/**
|
|
57307
|
-
|
|
57308
|
-
min: number().optional(),
|
|
57309
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57310
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57311
|
-
max: number().optional(),
|
|
57312
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57313
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57314
|
-
step: number().optional(),
|
|
57315
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57316
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57317
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57318
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57319
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57320
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57321
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57322
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57323
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57324
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57325
|
-
format: _enum([
|
|
57326
|
-
"date",
|
|
57327
|
-
"time",
|
|
57328
|
-
"datetime"
|
|
57329
|
-
]).optional()
|
|
58056
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58057
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58058
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58059
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58060
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58061
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57330
58062
|
});
|
|
57331
58063
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57332
58064
|
object({
|
|
@@ -57364,9 +58096,9 @@ object({
|
|
|
57364
58096
|
]),
|
|
57365
58097
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57366
58098
|
* no intermediate position surface. */
|
|
57367
|
-
position: number().min(0).max(100).nullable(),
|
|
58099
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57368
58100
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57369
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58101
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57370
58102
|
/** Ms epoch when the slice was last updated. */
|
|
57371
58103
|
lastChangedAt: number()
|
|
57372
58104
|
});
|
|
@@ -57424,9 +58156,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57424
58156
|
object({
|
|
57425
58157
|
mode: DayNightModeSchema,
|
|
57426
58158
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57427
|
-
sensitivity: number().optional(),
|
|
58159
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57428
58160
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57429
|
-
switchDelaySec: number().optional(),
|
|
58161
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57430
58162
|
lastFetchedAt: number()
|
|
57431
58163
|
});
|
|
57432
58164
|
/**
|
|
@@ -57581,11 +58313,11 @@ object({
|
|
|
57581
58313
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57582
58314
|
availablePrograms: array(string()),
|
|
57583
58315
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57584
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58316
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57585
58317
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57586
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58318
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57587
58319
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57588
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58320
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57589
58321
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57590
58322
|
doorOpen: boolean().nullable(),
|
|
57591
58323
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57609,7 +58341,7 @@ object({
|
|
|
57609
58341
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57610
58342
|
machineCareDue: boolean().nullable(),
|
|
57611
58343
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57612
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58344
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57613
58345
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57614
58346
|
halfLoad: boolean().nullable(),
|
|
57615
58347
|
hygienePlus: boolean().nullable(),
|
|
@@ -57624,7 +58356,7 @@ object({
|
|
|
57624
58356
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57625
58357
|
activeEvents: array(string()),
|
|
57626
58358
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57627
|
-
errorCode: number().nullable(),
|
|
58359
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57628
58360
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57629
58361
|
errorLabel: string().nullable(),
|
|
57630
58362
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -57770,24 +58502,14 @@ object({
|
|
|
57770
58502
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
57771
58503
|
lastPressedAt: number().nullable(),
|
|
57772
58504
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
57773
|
-
pressCountSinceStart: number()
|
|
58505
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
57774
58506
|
});
|
|
57775
58507
|
object({
|
|
57776
58508
|
deviceId: number(),
|
|
57777
58509
|
timestamp: number()
|
|
57778
58510
|
});
|
|
57779
58511
|
DeviceType.Button, DeviceType.Camera;
|
|
57780
|
-
|
|
57781
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
57782
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
57783
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
57784
|
-
* The option set is stable across observations; it is persisted in the
|
|
57785
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
57786
|
-
* stored in `sourceInfo`.
|
|
57787
|
-
*/
|
|
57788
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
57789
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
57790
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58512
|
+
_enum([
|
|
57791
58513
|
"date",
|
|
57792
58514
|
"time",
|
|
57793
58515
|
"datetime"
|
|
@@ -57795,12 +58517,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
57795
58517
|
object({
|
|
57796
58518
|
value: string(),
|
|
57797
58519
|
/**
|
|
57798
|
-
* Set
|
|
57799
|
-
* as
|
|
57800
|
-
*
|
|
57801
|
-
* a time-only sensor → `'time'`.
|
|
58520
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58521
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58522
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
57802
58523
|
*/
|
|
57803
|
-
|
|
58524
|
+
timestamp: boolean().optional(),
|
|
57804
58525
|
/** Ms epoch when the slice was last updated. */
|
|
57805
58526
|
lastFetchedAt: number()
|
|
57806
58527
|
});
|
|
@@ -57819,13 +58540,13 @@ var EventFireSchema = object({
|
|
|
57819
58540
|
deviceId: number(),
|
|
57820
58541
|
eventType: string(),
|
|
57821
58542
|
data: record(string(), unknown()).nullable(),
|
|
57822
|
-
timestamp: number(),
|
|
57823
|
-
seq: number()
|
|
58543
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58544
|
+
seq: number().meta(readingMeta("count"))
|
|
57824
58545
|
});
|
|
57825
58546
|
object({
|
|
57826
58547
|
eventTypes: array(string()),
|
|
57827
58548
|
lastEvent: EventFireSchema.nullable(),
|
|
57828
|
-
eventCountSinceStart: number()
|
|
58549
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
57829
58550
|
});
|
|
57830
58551
|
DeviceType.EventEmitter;
|
|
57831
58552
|
var IdentitySchema = object({
|
|
@@ -58214,10 +58935,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58214
58935
|
object({
|
|
58215
58936
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58216
58937
|
* speed surface (single-speed fan). */
|
|
58217
|
-
percentage: number().min(0).max(100).nullable(),
|
|
58938
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58218
58939
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58219
58940
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58220
|
-
percentageStep: number().positive().optional(),
|
|
58941
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
58221
58942
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
58222
58943
|
* — empty string when no preset is active or supported. */
|
|
58223
58944
|
preset: string(),
|
|
@@ -58299,7 +59020,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58299
59020
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58300
59021
|
model: string().nullable(),
|
|
58301
59022
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58302
|
-
channelCount: number().nullable(),
|
|
59023
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58303
59024
|
/**
|
|
58304
59025
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58305
59026
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58331,9 +59052,45 @@ object({
|
|
|
58331
59052
|
lastChangedAt: number()
|
|
58332
59053
|
});
|
|
58333
59054
|
DeviceType.Sensor;
|
|
59055
|
+
object({
|
|
59056
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
59057
|
+
results: array(object({
|
|
59058
|
+
deviceId: number().int().nonnegative(),
|
|
59059
|
+
cap: string().min(1),
|
|
59060
|
+
method: string().min(1),
|
|
59061
|
+
ok: boolean(),
|
|
59062
|
+
error: string().optional(),
|
|
59063
|
+
/** Ms epoch of the attempt. */
|
|
59064
|
+
at: number()
|
|
59065
|
+
})) });
|
|
59066
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
59067
|
+
object({
|
|
59068
|
+
active: boolean().meta({ label: "Active" }),
|
|
59069
|
+
/** Ms epoch when the slice was last updated. */
|
|
59070
|
+
lastChangedAt: number()
|
|
59071
|
+
});
|
|
59072
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
59073
|
+
object({
|
|
59074
|
+
/** Members whose current value entered the aggregate. */
|
|
59075
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
59076
|
+
precision: 0,
|
|
59077
|
+
label: "Reporting"
|
|
59078
|
+
})),
|
|
59079
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
59080
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
59081
|
+
precision: 0,
|
|
59082
|
+
label: "Excluded"
|
|
59083
|
+
})),
|
|
59084
|
+
/** `included` + `excluded`. */
|
|
59085
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
59086
|
+
precision: 0,
|
|
59087
|
+
label: "Members"
|
|
59088
|
+
}))
|
|
59089
|
+
});
|
|
59090
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58334
59091
|
object({
|
|
58335
59092
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58336
|
-
position: number().min(0).max(100).nullable(),
|
|
59093
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58337
59094
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58338
59095
|
lastFetchedAt: number()
|
|
58339
59096
|
});
|
|
@@ -58342,9 +59099,9 @@ object({
|
|
|
58342
59099
|
/** Whether the humidifier is currently on. */
|
|
58343
59100
|
on: boolean(),
|
|
58344
59101
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58345
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59102
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58346
59103
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58347
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59104
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58348
59105
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58349
59106
|
* device has no mode surface. */
|
|
58350
59107
|
mode: string().nullable(),
|
|
@@ -58354,9 +59111,9 @@ object({
|
|
|
58354
59111
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58355
59112
|
action: string().nullable(),
|
|
58356
59113
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58357
|
-
minHumidity: number().nullable(),
|
|
59114
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58358
59115
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58359
|
-
maxHumidity: number().nullable(),
|
|
59116
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58360
59117
|
/** Ms epoch when the slice was last updated. */
|
|
58361
59118
|
lastChangedAt: number()
|
|
58362
59119
|
});
|
|
@@ -58380,22 +59137,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58380
59137
|
auth: "protected"
|
|
58381
59138
|
});
|
|
58382
59139
|
object({
|
|
58383
|
-
/** Current relative humidity, 0..100. */
|
|
58384
|
-
percent: number().min(0).max(100).meta({
|
|
58385
|
-
|
|
59140
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59141
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59142
|
+
precision: 0,
|
|
58386
59143
|
label: "Humidity"
|
|
58387
|
-
}),
|
|
59144
|
+
})),
|
|
58388
59145
|
/** Ms epoch when the slice was last updated. */
|
|
58389
|
-
lastFetchedAt: number()
|
|
58390
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58391
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58392
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58393
|
-
unit: string().optional(),
|
|
58394
|
-
/** Suggested decimal places for numeric display.
|
|
58395
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58396
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58397
|
-
* auto-formatting when absent. */
|
|
58398
|
-
precision: number().int().min(0).max(10).optional()
|
|
59146
|
+
lastFetchedAt: number()
|
|
58399
59147
|
});
|
|
58400
59148
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58401
59149
|
object({
|
|
@@ -58403,7 +59151,7 @@ object({
|
|
|
58403
59151
|
* entity exposes no `entity_picture` (yet). */
|
|
58404
59152
|
url: string().nullable(),
|
|
58405
59153
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58406
|
-
lastUpdated: number().nullable()
|
|
59154
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58407
59155
|
});
|
|
58408
59156
|
DeviceType.Image;
|
|
58409
59157
|
/**
|
|
@@ -58459,19 +59207,19 @@ var NormalizedRangeSchema = object({
|
|
|
58459
59207
|
});
|
|
58460
59208
|
object({
|
|
58461
59209
|
/** Normalized 0–100. */
|
|
58462
|
-
brightness: number().optional(),
|
|
59210
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58463
59211
|
/** Normalized 0–100. */
|
|
58464
|
-
contrast: number().optional(),
|
|
59212
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58465
59213
|
/** Normalized 0–100. */
|
|
58466
|
-
saturation: number().optional(),
|
|
59214
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58467
59215
|
/** Normalized 0–100. */
|
|
58468
|
-
sharpness: number().optional(),
|
|
59216
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58469
59217
|
mirror: boolean().optional(),
|
|
58470
59218
|
flip: boolean().optional(),
|
|
58471
59219
|
rotate: ImageRotateSchema.optional(),
|
|
58472
59220
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58473
59221
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58474
|
-
warmth: number().optional(),
|
|
59222
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58475
59223
|
exposureMode: ExposureModeSchema.optional(),
|
|
58476
59224
|
backlightMode: BacklightModeSchema.optional(),
|
|
58477
59225
|
lastFetchedAt: number()
|
|
@@ -58716,10 +59464,10 @@ var IntercomAbilitySchema = object({
|
|
|
58716
59464
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58717
59465
|
codecs: array(string()),
|
|
58718
59466
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58719
|
-
sampleRate: number(),
|
|
59467
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58720
59468
|
duplex: _enum(["half", "full"]),
|
|
58721
59469
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58722
|
-
maxBacklogMs: number()
|
|
59470
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58723
59471
|
});
|
|
58724
59472
|
var IntercomStatusSchema = object({
|
|
58725
59473
|
/** True while a talk session is open. */
|
|
@@ -58830,13 +59578,13 @@ object({
|
|
|
58830
59578
|
activity: LawnMowerActivitySchema,
|
|
58831
59579
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
58832
59580
|
* reading. */
|
|
58833
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59581
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58834
59582
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
58835
59583
|
* task is active / progress is unavailable. */
|
|
58836
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59584
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58837
59585
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
58838
59586
|
* or null when unknown. */
|
|
58839
|
-
currentCode: number().nullable(),
|
|
59587
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
58840
59588
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
58841
59589
|
currentCodeLabel: string().nullable(),
|
|
58842
59590
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -59246,7 +59994,14 @@ DeviceType.Lock, method(object({
|
|
|
59246
59994
|
auth: "protected"
|
|
59247
59995
|
}), method(object({
|
|
59248
59996
|
deviceId: number().int().nonnegative(),
|
|
59249
|
-
code: string().min(1).optional()
|
|
59997
|
+
code: string().min(1).optional(),
|
|
59998
|
+
/**
|
|
59999
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
60000
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
60001
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
60002
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
60003
|
+
*/
|
|
60004
|
+
confirm: boolean().optional()
|
|
59250
60005
|
}), _void(), {
|
|
59251
60006
|
kind: "mutation",
|
|
59252
60007
|
auth: "protected"
|
|
@@ -59254,6 +60009,11 @@ DeviceType.Lock, method(object({
|
|
|
59254
60009
|
kind: "mutation",
|
|
59255
60010
|
auth: "protected"
|
|
59256
60011
|
});
|
|
60012
|
+
object({
|
|
60013
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
60014
|
+
lastFetchedAt: number()
|
|
60015
|
+
});
|
|
60016
|
+
DeviceType.Sensor;
|
|
59257
60017
|
/**
|
|
59258
60018
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59259
60019
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59298,7 +60058,7 @@ object({
|
|
|
59298
60058
|
state: MediaPlayerStateSchema,
|
|
59299
60059
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59300
60060
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59301
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
60061
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59302
60062
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59303
60063
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59304
60064
|
isMuted: boolean().nullable(),
|
|
@@ -59311,10 +60071,10 @@ object({
|
|
|
59311
60071
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59312
60072
|
/** Current playback position in ms. Null when not seekable or
|
|
59313
60073
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59314
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
60074
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59315
60075
|
/** Total duration of the current media in ms. Null when unknown
|
|
59316
60076
|
* (live stream) or nothing is playing. */
|
|
59317
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
60077
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59318
60078
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59319
60079
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59320
60080
|
shuffle: boolean().nullable(),
|
|
@@ -59614,7 +60374,7 @@ object({
|
|
|
59614
60374
|
* it, every provider seeded it at boot, and every session left it
|
|
59615
60375
|
* `detected: true` after its detach.
|
|
59616
60376
|
*/
|
|
59617
|
-
autoClearAfterMs: number().nullable()
|
|
60377
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59618
60378
|
});
|
|
59619
60379
|
/**
|
|
59620
60380
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59664,7 +60424,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59664
60424
|
});
|
|
59665
60425
|
object({
|
|
59666
60426
|
enabled: boolean(),
|
|
59667
|
-
sensitivity: number(),
|
|
60427
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59668
60428
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59669
60429
|
regions: array(MotionZoneRegionSchema),
|
|
59670
60430
|
lastFetchedAt: number()
|
|
@@ -59968,7 +60728,7 @@ var NavigationStatusSchema = object({
|
|
|
59968
60728
|
following: boolean(),
|
|
59969
60729
|
flash: boolean(),
|
|
59970
60730
|
lightMode: NavigationLightModeSchema,
|
|
59971
|
-
lightLevel: number().min(40).max(100),
|
|
60731
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
59972
60732
|
/** Ms epoch when the slice was last updated. */
|
|
59973
60733
|
lastChangedAt: number()
|
|
59974
60734
|
});
|
|
@@ -60014,13 +60774,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
60014
60774
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
60015
60775
|
* SKIP a null rather than coerce it.
|
|
60016
60776
|
*/
|
|
60017
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
60777
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60018
60778
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
60019
|
-
rssiDbm: number().optional(),
|
|
60779
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
60020
60780
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
60021
60781
|
ssid: string().optional(),
|
|
60022
60782
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
60023
|
-
lastUpdated: number()
|
|
60783
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
60024
60784
|
});
|
|
60025
60785
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
60026
60786
|
deviceId: number(),
|
|
@@ -60339,7 +61099,7 @@ object({
|
|
|
60339
61099
|
lastError: string().nullable(),
|
|
60340
61100
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60341
61101
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60342
|
-
queueDepth: number().int().nonnegative(),
|
|
61102
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60343
61103
|
/** Per-feature capability matrix — authoritative source for the
|
|
60344
61104
|
* compose-form field gating. */
|
|
60345
61105
|
supports: NotifierSupportsSchema
|
|
@@ -60389,15 +61149,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60389
61149
|
acceptedAt: number()
|
|
60390
61150
|
});
|
|
60391
61151
|
object({
|
|
60392
|
-
|
|
60393
|
-
|
|
60394
|
-
* Populated live from the upstream source on each state push.
|
|
60395
|
-
* Absent for unitless sensors. */
|
|
60396
|
-
unit: string().optional(),
|
|
60397
|
-
/** Suggested decimal places for numeric display.
|
|
60398
|
-
* Populated live from the upstream source when provided.
|
|
60399
|
-
* Falls back to auto-formatting when absent. */
|
|
60400
|
-
precision: number().int().min(0).max(10).optional(),
|
|
61152
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
61153
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60401
61154
|
/** Ms epoch when the slice was last updated. */
|
|
60402
61155
|
lastFetchedAt: number()
|
|
60403
61156
|
});
|
|
@@ -60687,23 +61440,26 @@ object({
|
|
|
60687
61440
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60688
61441
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60689
61442
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60690
|
-
foodLevel: number().nullable(),
|
|
61443
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60691
61444
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60692
61445
|
* single-hopper models. */
|
|
60693
|
-
food1: number().nullable(),
|
|
61446
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60694
61447
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60695
61448
|
* single-hopper models. */
|
|
60696
|
-
food2: number().nullable(),
|
|
61449
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60697
61450
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60698
61451
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60699
61452
|
* below the feeder's low threshold. */
|
|
60700
61453
|
lowFood: boolean(),
|
|
60701
61454
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60702
61455
|
* device has no battery reading. */
|
|
60703
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60704
|
-
/**
|
|
60705
|
-
*
|
|
60706
|
-
|
|
61456
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61457
|
+
/**
|
|
61458
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61459
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61460
|
+
* model has no desiccant sensor.
|
|
61461
|
+
*/
|
|
61462
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60707
61463
|
/** True while a feed is in progress. */
|
|
60708
61464
|
feeding: boolean(),
|
|
60709
61465
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60714,7 +61470,7 @@ object({
|
|
|
60714
61470
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60715
61471
|
error: string().nullable(),
|
|
60716
61472
|
/** Raw device error code (0 / null = no error). */
|
|
60717
|
-
errorCode: number().nullable(),
|
|
61473
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60718
61474
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60719
61475
|
isDualHopper: boolean(),
|
|
60720
61476
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60724,7 +61480,7 @@ object({
|
|
|
60724
61480
|
/** Play a chime when dispensing. */
|
|
60725
61481
|
feedSound: boolean(),
|
|
60726
61482
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60727
|
-
volume: number(),
|
|
61483
|
+
volume: number().meta(readingMeta("none")),
|
|
60728
61484
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60729
61485
|
lastFetchedAt: number()
|
|
60730
61486
|
});
|
|
@@ -61161,38 +61917,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61161
61917
|
});
|
|
61162
61918
|
object({
|
|
61163
61919
|
/** Instantaneous power draw in watts. */
|
|
61164
|
-
watts: number().optional().meta({
|
|
61165
|
-
unit: "W",
|
|
61166
|
-
label: "Power"
|
|
61167
|
-
}),
|
|
61920
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61168
61921
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61169
|
-
kwhTotal: number().optional().meta({
|
|
61170
|
-
unit: "kWh",
|
|
61171
|
-
label: "Energy"
|
|
61172
|
-
}),
|
|
61922
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61173
61923
|
/** Voltage in volts. */
|
|
61174
|
-
volts: number().optional(),
|
|
61924
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61175
61925
|
/** Current in amperes. */
|
|
61176
|
-
amps: number().optional(),
|
|
61177
|
-
/** Apparent power in volt-amperes
|
|
61178
|
-
va: number().optional(),
|
|
61926
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61927
|
+
/** Apparent power in volt-amperes. */
|
|
61928
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61179
61929
|
/** Power factor (0..1) if reported. */
|
|
61180
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
61930
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61181
61931
|
/** Ms epoch when the slice was last updated. */
|
|
61182
|
-
lastFetchedAt: number()
|
|
61183
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
61184
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
61185
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
61186
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
61187
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
61188
|
-
unit: string().optional(),
|
|
61189
|
-
/** Suggested decimal places for numeric display.
|
|
61190
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61191
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61192
|
-
* auto-formatting when absent. */
|
|
61193
|
-
precision: number().int().min(0).max(10).optional()
|
|
61932
|
+
lastFetchedAt: number()
|
|
61194
61933
|
});
|
|
61195
|
-
|
|
61934
|
+
[
|
|
61935
|
+
DeviceType.Sensor,
|
|
61936
|
+
DeviceType.Switch,
|
|
61937
|
+
DeviceType.Light,
|
|
61938
|
+
DeviceType.Fan,
|
|
61939
|
+
DeviceType.Climate,
|
|
61940
|
+
DeviceType.Thermostat,
|
|
61941
|
+
DeviceType.Humidifier,
|
|
61942
|
+
DeviceType.WaterHeater,
|
|
61943
|
+
DeviceType.MediaPlayer,
|
|
61944
|
+
DeviceType.Washer,
|
|
61945
|
+
DeviceType.Dryer,
|
|
61946
|
+
DeviceType.Dishwasher,
|
|
61947
|
+
DeviceType.Vacuum,
|
|
61948
|
+
DeviceType.LawnMower,
|
|
61949
|
+
DeviceType.PetFeeder
|
|
61950
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61196
61951
|
/**
|
|
61197
61952
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61198
61953
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61211,11 +61966,11 @@ DeviceType.Sensor;
|
|
|
61211
61966
|
*/
|
|
61212
61967
|
var GpsLocationSchema = object({
|
|
61213
61968
|
/** Latitude in decimal degrees, -90..90. */
|
|
61214
|
-
latitude: number().min(-90).max(90),
|
|
61969
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
61215
61970
|
/** Longitude in decimal degrees, -180..180. */
|
|
61216
|
-
longitude: number().min(-180).max(180),
|
|
61971
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
61217
61972
|
/** Reported accuracy in meters (lower = better). */
|
|
61218
|
-
accuracyMeters: number().nonnegative()
|
|
61973
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
61219
61974
|
});
|
|
61220
61975
|
object({
|
|
61221
61976
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -61227,25 +61982,16 @@ object({
|
|
|
61227
61982
|
gps: GpsLocationSchema.nullable(),
|
|
61228
61983
|
/** Optional battery level of the tracking device (0..100). Null
|
|
61229
61984
|
* when not reported. */
|
|
61230
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
61985
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61231
61986
|
/** Ms epoch when the slice was last updated. */
|
|
61232
61987
|
lastChangedAt: number()
|
|
61233
61988
|
});
|
|
61234
61989
|
DeviceType.Presence;
|
|
61235
61990
|
object({
|
|
61236
|
-
/** Current pressure in hPa. */
|
|
61237
|
-
hpa: number(),
|
|
61991
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
61992
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61238
61993
|
/** Ms epoch when the slice was last updated. */
|
|
61239
|
-
lastFetchedAt: number()
|
|
61240
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61241
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61242
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61243
|
-
unit: string().optional(),
|
|
61244
|
-
/** Suggested decimal places for numeric display.
|
|
61245
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61246
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61247
|
-
* auto-formatting when absent. */
|
|
61248
|
-
precision: number().int().min(0).max(10).optional()
|
|
61994
|
+
lastFetchedAt: number()
|
|
61249
61995
|
});
|
|
61250
61996
|
DeviceType.Sensor;
|
|
61251
61997
|
/**
|
|
@@ -61578,8 +62324,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61578
62324
|
}), _void(), { kind: "mutation" });
|
|
61579
62325
|
var PtzAutotrackSettingsSchema = object({
|
|
61580
62326
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61581
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61582
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62327
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62328
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61583
62329
|
});
|
|
61584
62330
|
/**
|
|
61585
62331
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61636,7 +62382,7 @@ object({
|
|
|
61636
62382
|
/** null = unknown — never coerced to false (D393). */
|
|
61637
62383
|
running: boolean().nullable(),
|
|
61638
62384
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61639
|
-
since: number().nullable(),
|
|
62385
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61640
62386
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61641
62387
|
phase: string().nullable(),
|
|
61642
62388
|
/** null until a reading has been published (D393). */
|
|
@@ -61648,7 +62394,7 @@ object({
|
|
|
61648
62394
|
phase: string().nullable()
|
|
61649
62395
|
});
|
|
61650
62396
|
Object.values(DeviceType);
|
|
61651
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62397
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61652
62398
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61653
62399
|
kind: "mutation",
|
|
61654
62400
|
auth: "admin"
|
|
@@ -62834,9 +63580,9 @@ var RecordTriggerSchema = _enum([
|
|
|
62834
63580
|
*/
|
|
62835
63581
|
var RecordWindowSchema = object({
|
|
62836
63582
|
trigger: RecordTriggerSchema,
|
|
62837
|
-
day: number().int().min(0).max(6),
|
|
62838
|
-
startMinute: number().int().min(0).max(1439),
|
|
62839
|
-
endMinute: number().int().min(1).max(1440)
|
|
63583
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63584
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63585
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
62840
63586
|
});
|
|
62841
63587
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
62842
63588
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -62905,10 +63651,10 @@ object({
|
|
|
62905
63651
|
/** Master "record to the card at all" switch. */
|
|
62906
63652
|
enabled: boolean().nullable(),
|
|
62907
63653
|
overwriteWhenFull: boolean().nullable(),
|
|
62908
|
-
preRecordSec: number().nullable(),
|
|
62909
|
-
postRecordSec: number().nullable(),
|
|
63654
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63655
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
62910
63656
|
/** Length of one recorded file, in minutes. */
|
|
62911
|
-
segmentMinutes: number().nullable(),
|
|
63657
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
62912
63658
|
/** The primary track's weekly windows, flattened. */
|
|
62913
63659
|
windows: array(RecordWindowSchema),
|
|
62914
63660
|
/**
|
|
@@ -62924,7 +63670,7 @@ object({
|
|
|
62924
63670
|
* provider reporting a non-zero count also reports the schedule as not
|
|
62925
63671
|
* writable.
|
|
62926
63672
|
*/
|
|
62927
|
-
unreadableWindows: number(),
|
|
63673
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
62928
63674
|
/**
|
|
62929
63675
|
* The camera is scheduled to record and has NO usable storage.
|
|
62930
63676
|
*
|
|
@@ -63561,7 +64307,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63561
64307
|
url: string().optional(),
|
|
63562
64308
|
codec: string().optional(),
|
|
63563
64309
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63564
|
-
fps: number().positive().optional(),
|
|
64310
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63565
64311
|
label: string().optional(),
|
|
63566
64312
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63567
64313
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63591,18 +64337,18 @@ var StreamProfileSchema = _enum([
|
|
|
63591
64337
|
]);
|
|
63592
64338
|
/** The current encoding config of one stream profile. */
|
|
63593
64339
|
var StreamProfileConfigSchema = object({
|
|
63594
|
-
width: number(),
|
|
63595
|
-
height: number(),
|
|
64340
|
+
width: number().meta(readingMeta("none")),
|
|
64341
|
+
height: number().meta(readingMeta("none")),
|
|
63596
64342
|
codec: _enum(["h264", "h265"]),
|
|
63597
|
-
framerate: number(),
|
|
63598
|
-
bitrate: number(),
|
|
64343
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64344
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63599
64345
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63600
64346
|
encoderProfile: _enum([
|
|
63601
64347
|
"high",
|
|
63602
64348
|
"main",
|
|
63603
64349
|
"baseline"
|
|
63604
64350
|
]).optional(),
|
|
63605
|
-
gop: number().optional(),
|
|
64351
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63606
64352
|
/**
|
|
63607
64353
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63608
64354
|
*
|
|
@@ -63687,7 +64433,7 @@ object({
|
|
|
63687
64433
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63688
64434
|
lastChangedAt: number()
|
|
63689
64435
|
});
|
|
63690
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64436
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63691
64437
|
deviceId: number(),
|
|
63692
64438
|
on: boolean()
|
|
63693
64439
|
}), _void(), {
|
|
@@ -64245,23 +64991,13 @@ object({
|
|
|
64245
64991
|
});
|
|
64246
64992
|
DeviceType.Sensor;
|
|
64247
64993
|
object({
|
|
64248
|
-
/** Current temperature in Celsius. */
|
|
64249
|
-
celsius: number().meta({
|
|
64250
|
-
|
|
64994
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
64995
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
64996
|
+
precision: 1,
|
|
64251
64997
|
label: "Temperature"
|
|
64252
|
-
}),
|
|
64998
|
+
})),
|
|
64253
64999
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64254
|
-
lastFetchedAt: number()
|
|
64255
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64256
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64257
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64258
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64259
|
-
unit: string().optional(),
|
|
64260
|
-
/** Suggested decimal places for numeric display.
|
|
64261
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64262
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64263
|
-
* auto-formatting when absent. */
|
|
64264
|
-
precision: number().int().min(0).max(10).optional()
|
|
65000
|
+
lastFetchedAt: number()
|
|
64265
65001
|
});
|
|
64266
65002
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64267
65003
|
/**
|
|
@@ -64513,16 +65249,16 @@ object({
|
|
|
64513
65249
|
]),
|
|
64514
65250
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64515
65251
|
* reading. */
|
|
64516
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65252
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64517
65253
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64518
65254
|
* the vacuum has no speed control. */
|
|
64519
65255
|
fanSpeed: string().nullable(),
|
|
64520
65256
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64521
65257
|
availableFanSpeeds: array(string()),
|
|
64522
65258
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64523
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65259
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64524
65260
|
/** Current error code (0 / null = no error). */
|
|
64525
|
-
errorCode: number().nullable(),
|
|
65261
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64526
65262
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64527
65263
|
errorLabel: string().nullable(),
|
|
64528
65264
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64561,7 +65297,7 @@ object({
|
|
|
64561
65297
|
]),
|
|
64562
65298
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64563
65299
|
* intermediate position surface. */
|
|
64564
|
-
position: number().min(0).max(100).nullable(),
|
|
65300
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64565
65301
|
/** Ms epoch when the slice was last updated. */
|
|
64566
65302
|
lastChangedAt: number()
|
|
64567
65303
|
});
|
|
@@ -64589,9 +65325,9 @@ object({
|
|
|
64589
65325
|
DeviceType.Sensor;
|
|
64590
65326
|
object({
|
|
64591
65327
|
/** Current measured temperature. Null when not reported. */
|
|
64592
|
-
currentTemp: number().nullable(),
|
|
65328
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64593
65329
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64594
|
-
targetTemp: number().nullable(),
|
|
65330
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64595
65331
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64596
65332
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64597
65333
|
* device reports an unknown state. */
|
|
@@ -64602,9 +65338,9 @@ object({
|
|
|
64602
65338
|
* has no away surface. */
|
|
64603
65339
|
away: boolean().nullable(),
|
|
64604
65340
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64605
|
-
minTemp: number().nullable(),
|
|
65341
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64606
65342
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64607
|
-
maxTemp: number().nullable(),
|
|
65343
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64608
65344
|
/** Ms epoch when the slice was last updated. */
|
|
64609
65345
|
lastChangedAt: number()
|
|
64610
65346
|
});
|
|
@@ -64628,25 +65364,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64628
65364
|
auth: "protected"
|
|
64629
65365
|
});
|
|
64630
65366
|
object({
|
|
64631
|
-
/** Verbatim
|
|
64632
|
-
* when no condition has been reported yet. */
|
|
65367
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64633
65368
|
condition: string().nullable(),
|
|
64634
|
-
/** Current temperature in
|
|
64635
|
-
temperature: number().nullable(),
|
|
64636
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64637
|
-
temperatureUnit: string().nullable(),
|
|
65369
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65370
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64638
65371
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64639
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64640
|
-
/** Barometric pressure in
|
|
64641
|
-
pressure: number().nullable(),
|
|
64642
|
-
/**
|
|
64643
|
-
|
|
64644
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64645
|
-
windSpeed: number().nullable(),
|
|
64646
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64647
|
-
windSpeedUnit: string().nullable(),
|
|
65372
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65373
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65374
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65375
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65376
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64648
65377
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64649
|
-
windBearing: number().nullable(),
|
|
65378
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64650
65379
|
/** Ms epoch when the slice was last updated. */
|
|
64651
65380
|
lastFetchedAt: number()
|
|
64652
65381
|
});
|
|
@@ -65396,8 +66125,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65396
66125
|
kind: "mutation",
|
|
65397
66126
|
auth: "admin"
|
|
65398
66127
|
});
|
|
66128
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65399
66129
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65400
|
-
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;
|
|
66130
|
+
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;
|
|
65401
66131
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65402
66132
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65403
66133
|
new Set(CAP_NAMES);
|
|
@@ -65450,7 +66180,7 @@ var AccessoryKind = {
|
|
|
65450
66180
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65451
66181
|
};
|
|
65452
66182
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65453
|
-
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;
|
|
66183
|
+
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;
|
|
65454
66184
|
new Set(Object.values(DeviceType));
|
|
65455
66185
|
Object.freeze({
|
|
65456
66186
|
"accessories.getStatus": {
|
|
@@ -65558,6 +66288,13 @@ Object.freeze({
|
|
|
65558
66288
|
access: "view",
|
|
65559
66289
|
role: "admin"
|
|
65560
66290
|
},
|
|
66291
|
+
"addons.getPackageDocs": {
|
|
66292
|
+
capName: "addons",
|
|
66293
|
+
capScope: "system",
|
|
66294
|
+
addonId: null,
|
|
66295
|
+
access: "view",
|
|
66296
|
+
role: "admin"
|
|
66297
|
+
},
|
|
65561
66298
|
"addons.getVersions": {
|
|
65562
66299
|
capName: "addons",
|
|
65563
66300
|
capScope: "system",
|
|
@@ -68666,6 +69403,27 @@ Object.freeze({
|
|
|
68666
69403
|
access: "view",
|
|
68667
69404
|
role: "viewer"
|
|
68668
69405
|
},
|
|
69406
|
+
"groupActive.getStatus": {
|
|
69407
|
+
capName: "group-active",
|
|
69408
|
+
capScope: "device",
|
|
69409
|
+
addonId: null,
|
|
69410
|
+
access: "view",
|
|
69411
|
+
role: "viewer"
|
|
69412
|
+
},
|
|
69413
|
+
"groupCommands.getStatus": {
|
|
69414
|
+
capName: "group-commands",
|
|
69415
|
+
capScope: "device",
|
|
69416
|
+
addonId: null,
|
|
69417
|
+
access: "view",
|
|
69418
|
+
role: "viewer"
|
|
69419
|
+
},
|
|
69420
|
+
"groupStatus.getStatus": {
|
|
69421
|
+
capName: "group-status",
|
|
69422
|
+
capScope: "device",
|
|
69423
|
+
addonId: null,
|
|
69424
|
+
access: "view",
|
|
69425
|
+
role: "viewer"
|
|
69426
|
+
},
|
|
68669
69427
|
"heatingValve.getStatus": {
|
|
68670
69428
|
capName: "heating-valve",
|
|
68671
69429
|
capScope: "device",
|
|
@@ -69618,6 +70376,13 @@ Object.freeze({
|
|
|
69618
70376
|
access: "create",
|
|
69619
70377
|
role: "admin"
|
|
69620
70378
|
},
|
|
70379
|
+
"meter.getStatus": {
|
|
70380
|
+
capName: "meter",
|
|
70381
|
+
capScope: "device",
|
|
70382
|
+
addonId: null,
|
|
70383
|
+
access: "view",
|
|
70384
|
+
role: "viewer"
|
|
70385
|
+
},
|
|
69621
70386
|
"metricsProvider.collectSnapshot": {
|
|
69622
70387
|
capName: "metrics-provider",
|
|
69623
70388
|
capScope: "system",
|
|
@@ -77716,7 +78481,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77716
78481
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77717
78482
|
icon: "square"
|
|
77718
78483
|
}
|
|
77719
|
-
}
|
|
78484
|
+
},
|
|
78485
|
+
overrides: { byType: {
|
|
78486
|
+
[DeviceType.Washer]: {
|
|
78487
|
+
state: { running: {
|
|
78488
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78489
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78490
|
+
} },
|
|
78491
|
+
events: {
|
|
78492
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78493
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78494
|
+
}
|
|
78495
|
+
},
|
|
78496
|
+
[DeviceType.Dryer]: {
|
|
78497
|
+
state: { running: {
|
|
78498
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78499
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78500
|
+
} },
|
|
78501
|
+
events: {
|
|
78502
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78503
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78504
|
+
}
|
|
78505
|
+
},
|
|
78506
|
+
[DeviceType.Dishwasher]: {
|
|
78507
|
+
state: { running: {
|
|
78508
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78509
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78510
|
+
} },
|
|
78511
|
+
events: {
|
|
78512
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78513
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78514
|
+
}
|
|
78515
|
+
}
|
|
78516
|
+
} }
|
|
77720
78517
|
},
|
|
77721
78518
|
update: {
|
|
77722
78519
|
scope: "device",
|
|
@@ -78488,6 +79285,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78488
79285
|
icon: "flame"
|
|
78489
79286
|
}]
|
|
78490
79287
|
},
|
|
79288
|
+
"group-active": {
|
|
79289
|
+
scope: "device",
|
|
79290
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79291
|
+
},
|
|
79292
|
+
"group-commands": {
|
|
79293
|
+
scope: "device",
|
|
79294
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79295
|
+
},
|
|
79296
|
+
"group-status": {
|
|
79297
|
+
scope: "device",
|
|
79298
|
+
noun: t("Group", "Gruppo"),
|
|
79299
|
+
state: [
|
|
79300
|
+
{
|
|
79301
|
+
kind: "numeric",
|
|
79302
|
+
field: "included",
|
|
79303
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79304
|
+
label: t("Reporting", "Rispondono"),
|
|
79305
|
+
icon: "users"
|
|
79306
|
+
},
|
|
79307
|
+
{
|
|
79308
|
+
kind: "numeric",
|
|
79309
|
+
field: "excluded",
|
|
79310
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79311
|
+
label: t("Excluded", "Esclusi"),
|
|
79312
|
+
icon: "users"
|
|
79313
|
+
},
|
|
79314
|
+
{
|
|
79315
|
+
kind: "numeric",
|
|
79316
|
+
field: "total",
|
|
79317
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79318
|
+
label: t("Members", "Membri"),
|
|
79319
|
+
icon: "sigma"
|
|
79320
|
+
}
|
|
79321
|
+
]
|
|
79322
|
+
},
|
|
78491
79323
|
"humidity-sensor": {
|
|
78492
79324
|
scope: "device",
|
|
78493
79325
|
noun: t("Humidity", "Umidità"),
|
|
@@ -78513,6 +79345,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78513
79345
|
}],
|
|
78514
79346
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78515
79347
|
},
|
|
79348
|
+
meter: {
|
|
79349
|
+
scope: "device",
|
|
79350
|
+
noun: t("Meter", "Contatore"),
|
|
79351
|
+
state: [{
|
|
79352
|
+
kind: "numeric",
|
|
79353
|
+
field: "value",
|
|
79354
|
+
quantity: t("the total", "il totale"),
|
|
79355
|
+
label: t("Total", "Totale"),
|
|
79356
|
+
icon: "gauge"
|
|
79357
|
+
}]
|
|
79358
|
+
},
|
|
78516
79359
|
"numeric-sensor": {
|
|
78517
79360
|
scope: "device",
|
|
78518
79361
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78521,7 +79364,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78521
79364
|
field: "value",
|
|
78522
79365
|
quantity: t("the reading", "il valore"),
|
|
78523
79366
|
label: t("Reading", "Valore"),
|
|
78524
|
-
unitField: "unit",
|
|
78525
79367
|
icon: "gauge"
|
|
78526
79368
|
}]
|
|
78527
79369
|
},
|
|
@@ -78657,7 +79499,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78657
79499
|
field: "temperature",
|
|
78658
79500
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78659
79501
|
label: t("Temperature", "Temperatura"),
|
|
78660
|
-
|
|
79502
|
+
unit: "°C",
|
|
78661
79503
|
icon: "thermometer"
|
|
78662
79504
|
},
|
|
78663
79505
|
{
|
|
@@ -78673,7 +79515,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78673
79515
|
field: "windSpeed",
|
|
78674
79516
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78675
79517
|
label: t("Wind", "Vento"),
|
|
78676
|
-
|
|
79518
|
+
unit: "m/s",
|
|
78677
79519
|
icon: "wind"
|
|
78678
79520
|
},
|
|
78679
79521
|
{
|
|
@@ -78681,7 +79523,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78681
79523
|
field: "pressure",
|
|
78682
79524
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78683
79525
|
label: t("Pressure", "Pressione"),
|
|
78684
|
-
|
|
79526
|
+
unit: "hPa",
|
|
78685
79527
|
icon: "gauge"
|
|
78686
79528
|
}
|
|
78687
79529
|
]
|
|
@@ -78986,8 +79828,47 @@ function projectAction(cap, action) {
|
|
|
78986
79828
|
};
|
|
78987
79829
|
}
|
|
78988
79830
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
78989
|
-
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;
|
|
79831
|
+
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;
|
|
78990
79832
|
DeviceFeature.BatteryOperated;
|
|
79833
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79834
|
+
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.";
|
|
79835
|
+
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.";
|
|
79836
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79837
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79838
|
+
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.";
|
|
79839
|
+
function withheld(reason) {
|
|
79840
|
+
return {
|
|
79841
|
+
[DeviceType.Washer]: {
|
|
79842
|
+
exported: false,
|
|
79843
|
+
reason
|
|
79844
|
+
},
|
|
79845
|
+
[DeviceType.Dryer]: {
|
|
79846
|
+
exported: false,
|
|
79847
|
+
reason
|
|
79848
|
+
},
|
|
79849
|
+
[DeviceType.Dishwasher]: {
|
|
79850
|
+
exported: false,
|
|
79851
|
+
reason
|
|
79852
|
+
}
|
|
79853
|
+
};
|
|
79854
|
+
}
|
|
79855
|
+
function offered(received) {
|
|
79856
|
+
return {
|
|
79857
|
+
[DeviceType.Washer]: {
|
|
79858
|
+
exported: true,
|
|
79859
|
+
as: received
|
|
79860
|
+
},
|
|
79861
|
+
[DeviceType.Dryer]: {
|
|
79862
|
+
exported: true,
|
|
79863
|
+
as: received
|
|
79864
|
+
},
|
|
79865
|
+
[DeviceType.Dishwasher]: {
|
|
79866
|
+
exported: true,
|
|
79867
|
+
as: received
|
|
79868
|
+
}
|
|
79869
|
+
};
|
|
79870
|
+
}
|
|
79871
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
78991
79872
|
Object.freeze({
|
|
78992
79873
|
"accessories.getStatus": [{
|
|
78993
79874
|
name: "deviceId",
|
|
@@ -79954,6 +80835,21 @@ Object.freeze({
|
|
|
79954
80835
|
form: "single",
|
|
79955
80836
|
optional: false
|
|
79956
80837
|
}],
|
|
80838
|
+
"groupActive.getStatus": [{
|
|
80839
|
+
name: "deviceId",
|
|
80840
|
+
form: "single",
|
|
80841
|
+
optional: false
|
|
80842
|
+
}],
|
|
80843
|
+
"groupCommands.getStatus": [{
|
|
80844
|
+
name: "deviceId",
|
|
80845
|
+
form: "single",
|
|
80846
|
+
optional: false
|
|
80847
|
+
}],
|
|
80848
|
+
"groupStatus.getStatus": [{
|
|
80849
|
+
name: "deviceId",
|
|
80850
|
+
form: "single",
|
|
80851
|
+
optional: false
|
|
80852
|
+
}],
|
|
79957
80853
|
"heatingValve.getStatus": [{
|
|
79958
80854
|
name: "deviceId",
|
|
79959
80855
|
form: "single",
|
|
@@ -80154,6 +81050,11 @@ Object.freeze({
|
|
|
80154
81050
|
form: "single",
|
|
80155
81051
|
optional: false
|
|
80156
81052
|
}],
|
|
81053
|
+
"meter.getStatus": [{
|
|
81054
|
+
name: "deviceId",
|
|
81055
|
+
form: "single",
|
|
81056
|
+
optional: false
|
|
81057
|
+
}],
|
|
80157
81058
|
"motion.getStatus": [{
|
|
80158
81059
|
name: "deviceId",
|
|
80159
81060
|
form: "single",
|
|
@@ -81761,7 +82662,6 @@ Object.freeze({
|
|
|
81761
82662
|
"network-access": "ingress",
|
|
81762
82663
|
"smtp-provider": "email"
|
|
81763
82664
|
});
|
|
81764
|
-
DeviceType.Camera;
|
|
81765
82665
|
/**
|
|
81766
82666
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
81767
82667
|
* `z.infer`, they do not restate the shape.
|
|
@@ -82145,6 +83045,8 @@ new Map(Object.entries({
|
|
|
82145
83045
|
"detection-blind": "device-events",
|
|
82146
83046
|
"motion-noisy": "device-events",
|
|
82147
83047
|
"motion-calm": "device-events",
|
|
83048
|
+
"package-llm-silent": "device-events",
|
|
83049
|
+
"package-llm-answered": "device-events",
|
|
82148
83050
|
"recording-stalled": "device-events",
|
|
82149
83051
|
"recording-healthy": "device-events",
|
|
82150
83052
|
"recording-degraded": "device-events",
|
|
@@ -82228,6 +83130,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
82228
83130
|
label: "Motion without a subject",
|
|
82229
83131
|
kinds: ["motion-noisy", "motion-calm"]
|
|
82230
83132
|
},
|
|
83133
|
+
{
|
|
83134
|
+
id: "package-llm",
|
|
83135
|
+
family: "device-events",
|
|
83136
|
+
label: "Package confirm",
|
|
83137
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
83138
|
+
},
|
|
82231
83139
|
{
|
|
82232
83140
|
id: "recording",
|
|
82233
83141
|
family: "device-events",
|
|
@@ -82409,6 +83317,8 @@ var DEVICE_EVENTS = [
|
|
|
82409
83317
|
"detection-blind",
|
|
82410
83318
|
"motion-noisy",
|
|
82411
83319
|
"motion-calm",
|
|
83320
|
+
"package-llm-silent",
|
|
83321
|
+
"package-llm-answered",
|
|
82412
83322
|
"recording-stalled",
|
|
82413
83323
|
"recording-healthy",
|
|
82414
83324
|
"recording-degraded",
|
|
@@ -82677,6 +83587,15 @@ new Map([
|
|
|
82677
83587
|
snapshotLabel: "Cameras with constant motion now",
|
|
82678
83588
|
snapshotSection: null
|
|
82679
83589
|
},
|
|
83590
|
+
{
|
|
83591
|
+
id: "package-llm-confirm",
|
|
83592
|
+
family: "device-events",
|
|
83593
|
+
label: "Package confirm (not answering / answering again)",
|
|
83594
|
+
bad: ["package-llm-silent"],
|
|
83595
|
+
recovery: ["package-llm-answered"],
|
|
83596
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
83597
|
+
snapshotSection: null
|
|
83598
|
+
},
|
|
82680
83599
|
{
|
|
82681
83600
|
id: "recording-health",
|
|
82682
83601
|
family: "device-events",
|
|
@@ -83491,7 +84410,7 @@ function buildEmailDescriptor(providers = []) {
|
|
|
83491
84410
|
id: "email",
|
|
83492
84411
|
title: "Email",
|
|
83493
84412
|
titleKey: "notifiers:emailDescriptor.s_email.title",
|
|
83494
|
-
description: "Send via a Connectivity → Email provider (Google
|
|
84413
|
+
description: "Send via a Connectivity → Email provider (Google or Email (SMTP)). Install and Verify a provider first.",
|
|
83495
84414
|
descriptionKey: "notifiers:emailDescriptor.s_email.description",
|
|
83496
84415
|
fields: [
|
|
83497
84416
|
{
|
|
@@ -83508,7 +84427,7 @@ function buildEmailDescriptor(providers = []) {
|
|
|
83508
84427
|
key: "smtpAddonId",
|
|
83509
84428
|
label: "Email provider",
|
|
83510
84429
|
labelKey: "notifiers:emailDescriptor.s_email.smtpAddonId.label",
|
|
83511
|
-
description: options.length === 0 ? "No Email provider installed. Open Connectivity → Email, install Google
|
|
84430
|
+
description: options.length === 0 ? "No Email provider installed. Open Connectivity → Email, install Google or Email (SMTP), then Verify." : "Which Connectivity → Email entry delivers this target. Verify it under Connectivity → Email if the label says not verified.",
|
|
83512
84431
|
required: true,
|
|
83513
84432
|
options
|
|
83514
84433
|
},
|
|
@@ -85808,7 +86727,7 @@ var HTTP_NOTIFIER_ADAPTERS = [
|
|
|
85808
86727
|
*/
|
|
85809
86728
|
function buildNotifierAdapters(smtp) {
|
|
85810
86729
|
const emailSmtp = smtp ?? { async sendEmail() {
|
|
85811
|
-
throw new Error("email: no smtp-provider client — install Google
|
|
86730
|
+
throw new Error("email: no smtp-provider client — install Google or Email (SMTP) under Connectivity → Email and Verify it");
|
|
85812
86731
|
} };
|
|
85813
86732
|
return [...HTTP_NOTIFIER_ADAPTERS, createEmailAdapter(emailSmtp)];
|
|
85814
86733
|
}
|