@camstack/addon-waste-collections 0.1.29 → 0.1.31
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 +28 -0
- package/dist/waste-collections.addon.js +1366 -447
- package/dist/waste-collections.addon.mjs +1366 -447
- package/package.json +6 -4
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
//#region ../types/dist/event-category-
|
|
5
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
6
6
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
7
7
|
EventCategory["SystemBoot"] = "system.boot";
|
|
8
8
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -328,6 +328,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
328
328
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
329
329
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
330
330
|
/**
|
|
331
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
332
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
333
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
334
|
+
*/
|
|
335
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
336
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
337
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
338
|
+
/**
|
|
331
339
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
332
340
|
* (a settings change via `setAgentInferenceDevices` /
|
|
333
341
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5570,7 +5578,7 @@ var ZodIssueCode = {
|
|
|
5570
5578
|
var ZodFirstPartyTypeKind;
|
|
5571
5579
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5572
5580
|
//#endregion
|
|
5573
|
-
//#region ../types/dist/sleep
|
|
5581
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5574
5582
|
/**
|
|
5575
5583
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5576
5584
|
* window to float samples (D455).
|
|
@@ -8322,6 +8330,99 @@ function defineEntryKind(name, spec) {
|
|
|
8322
8330
|
if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
|
|
8323
8331
|
return defined;
|
|
8324
8332
|
}
|
|
8333
|
+
var READING_QUANTITIES = [
|
|
8334
|
+
"temperature",
|
|
8335
|
+
"pressure",
|
|
8336
|
+
"speed",
|
|
8337
|
+
"precipitation",
|
|
8338
|
+
"precipitation-rate",
|
|
8339
|
+
"length",
|
|
8340
|
+
"area",
|
|
8341
|
+
"illuminance",
|
|
8342
|
+
"irradiance",
|
|
8343
|
+
"power",
|
|
8344
|
+
"energy",
|
|
8345
|
+
"voltage",
|
|
8346
|
+
"current",
|
|
8347
|
+
"apparent-power",
|
|
8348
|
+
"humidity",
|
|
8349
|
+
"percentage",
|
|
8350
|
+
"concentration-volume",
|
|
8351
|
+
"concentration-mass",
|
|
8352
|
+
"concentration-ppb",
|
|
8353
|
+
"volume",
|
|
8354
|
+
"duration",
|
|
8355
|
+
"duration-ms",
|
|
8356
|
+
"information",
|
|
8357
|
+
"sound-level",
|
|
8358
|
+
"signal-level",
|
|
8359
|
+
"colour-temperature",
|
|
8360
|
+
"angle",
|
|
8361
|
+
"bitrate",
|
|
8362
|
+
"rate",
|
|
8363
|
+
"mass",
|
|
8364
|
+
"index",
|
|
8365
|
+
"ratio",
|
|
8366
|
+
"count",
|
|
8367
|
+
"none",
|
|
8368
|
+
"device"
|
|
8369
|
+
];
|
|
8370
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8371
|
+
new Set(READING_QUANTITIES);
|
|
8372
|
+
/**
|
|
8373
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8374
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8375
|
+
*/
|
|
8376
|
+
var QUANTITY_BASE = {
|
|
8377
|
+
temperature: "°C",
|
|
8378
|
+
pressure: "hPa",
|
|
8379
|
+
speed: "m/s",
|
|
8380
|
+
precipitation: "mm",
|
|
8381
|
+
"precipitation-rate": "mm/h",
|
|
8382
|
+
length: "m",
|
|
8383
|
+
area: "m²",
|
|
8384
|
+
illuminance: "lx",
|
|
8385
|
+
irradiance: "W/m²",
|
|
8386
|
+
power: "W",
|
|
8387
|
+
energy: "kWh",
|
|
8388
|
+
voltage: "V",
|
|
8389
|
+
current: "A",
|
|
8390
|
+
"apparent-power": "VA",
|
|
8391
|
+
humidity: "%",
|
|
8392
|
+
percentage: "%",
|
|
8393
|
+
"concentration-volume": "ppm",
|
|
8394
|
+
"concentration-mass": "µg/m³",
|
|
8395
|
+
"concentration-ppb": "ppb",
|
|
8396
|
+
volume: "L",
|
|
8397
|
+
duration: "s",
|
|
8398
|
+
"duration-ms": "ms",
|
|
8399
|
+
information: "B",
|
|
8400
|
+
"sound-level": "dBFS",
|
|
8401
|
+
"signal-level": "dBm",
|
|
8402
|
+
"colour-temperature": "mired",
|
|
8403
|
+
angle: "°",
|
|
8404
|
+
bitrate: "kbps",
|
|
8405
|
+
rate: "fps",
|
|
8406
|
+
mass: "kg",
|
|
8407
|
+
index: "none",
|
|
8408
|
+
ratio: "none",
|
|
8409
|
+
count: "none",
|
|
8410
|
+
none: "none",
|
|
8411
|
+
device: "device"
|
|
8412
|
+
};
|
|
8413
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8414
|
+
function baseUnitOf(quantity) {
|
|
8415
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8416
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8417
|
+
return symbol;
|
|
8418
|
+
}
|
|
8419
|
+
function readingMeta(quantity, extras) {
|
|
8420
|
+
return {
|
|
8421
|
+
quantity,
|
|
8422
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8423
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8424
|
+
};
|
|
8425
|
+
}
|
|
8325
8426
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8326
8427
|
var CamProfileSchema = _enum([
|
|
8327
8428
|
"high",
|
|
@@ -8349,8 +8450,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8349
8450
|
"derived"
|
|
8350
8451
|
]);
|
|
8351
8452
|
var CamStreamResolutionSchema = object({
|
|
8352
|
-
width: number().int().positive(),
|
|
8353
|
-
height: number().int().positive()
|
|
8453
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8454
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8354
8455
|
});
|
|
8355
8456
|
var CameraStreamSchema = object({
|
|
8356
8457
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8886,6 +8987,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8886
8987
|
"filesystem-browse",
|
|
8887
8988
|
"flood",
|
|
8888
8989
|
"gas",
|
|
8990
|
+
"group-active",
|
|
8991
|
+
"group-commands",
|
|
8992
|
+
"group-status",
|
|
8889
8993
|
"heating-valve",
|
|
8890
8994
|
"humidifier",
|
|
8891
8995
|
"humidity-sensor",
|
|
@@ -8906,6 +9010,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8906
9010
|
"login-method",
|
|
8907
9011
|
"media-player",
|
|
8908
9012
|
"mesh-network",
|
|
9013
|
+
"meter",
|
|
8909
9014
|
"metrics-provider",
|
|
8910
9015
|
"model-convert",
|
|
8911
9016
|
"model-distributor",
|
|
@@ -9015,14 +9120,6 @@ Object.freeze({
|
|
|
9015
9120
|
{
|
|
9016
9121
|
"path": "aqi",
|
|
9017
9122
|
"valueType": "number"
|
|
9018
|
-
},
|
|
9019
|
-
{
|
|
9020
|
-
"path": "unit",
|
|
9021
|
-
"valueType": "string"
|
|
9022
|
-
},
|
|
9023
|
-
{
|
|
9024
|
-
"path": "precision",
|
|
9025
|
-
"valueType": "number"
|
|
9026
9123
|
}
|
|
9027
9124
|
],
|
|
9028
9125
|
"alarm-panel": [
|
|
@@ -9058,20 +9155,10 @@ Object.freeze({
|
|
|
9058
9155
|
"valueType": "boolean"
|
|
9059
9156
|
}
|
|
9060
9157
|
],
|
|
9061
|
-
"ambient-light-sensor": [
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
},
|
|
9066
|
-
{
|
|
9067
|
-
"path": "unit",
|
|
9068
|
-
"valueType": "string"
|
|
9069
|
-
},
|
|
9070
|
-
{
|
|
9071
|
-
"path": "precision",
|
|
9072
|
-
"valueType": "number"
|
|
9073
|
-
}
|
|
9074
|
-
],
|
|
9158
|
+
"ambient-light-sensor": [{
|
|
9159
|
+
"path": "lux",
|
|
9160
|
+
"valueType": "number"
|
|
9161
|
+
}],
|
|
9075
9162
|
"audio-metrics": [
|
|
9076
9163
|
{
|
|
9077
9164
|
"path": "ts",
|
|
@@ -9151,6 +9238,10 @@ Object.freeze({
|
|
|
9151
9238
|
"path": "lastUpdated",
|
|
9152
9239
|
"valueType": "number"
|
|
9153
9240
|
},
|
|
9241
|
+
{
|
|
9242
|
+
"path": "volts",
|
|
9243
|
+
"valueType": "number"
|
|
9244
|
+
},
|
|
9154
9245
|
{
|
|
9155
9246
|
"path": "lastContactAt",
|
|
9156
9247
|
"valueType": "number"
|
|
@@ -9393,10 +9484,6 @@ Object.freeze({
|
|
|
9393
9484
|
"datetime"
|
|
9394
9485
|
]
|
|
9395
9486
|
},
|
|
9396
|
-
{
|
|
9397
|
-
"path": "unit",
|
|
9398
|
-
"valueType": "string"
|
|
9399
|
-
},
|
|
9400
9487
|
{
|
|
9401
9488
|
"path": "min",
|
|
9402
9489
|
"valueType": "number"
|
|
@@ -9408,19 +9495,6 @@ Object.freeze({
|
|
|
9408
9495
|
{
|
|
9409
9496
|
"path": "step",
|
|
9410
9497
|
"valueType": "number"
|
|
9411
|
-
},
|
|
9412
|
-
{
|
|
9413
|
-
"path": "precision",
|
|
9414
|
-
"valueType": "number"
|
|
9415
|
-
},
|
|
9416
|
-
{
|
|
9417
|
-
"path": "format",
|
|
9418
|
-
"valueType": "enum",
|
|
9419
|
-
"enumValues": [
|
|
9420
|
-
"date",
|
|
9421
|
-
"time",
|
|
9422
|
-
"datetime"
|
|
9423
|
-
]
|
|
9424
9498
|
}
|
|
9425
9499
|
],
|
|
9426
9500
|
"cover": [
|
|
@@ -9661,13 +9735,8 @@ Object.freeze({
|
|
|
9661
9735
|
"path": "value",
|
|
9662
9736
|
"valueType": "string"
|
|
9663
9737
|
}, {
|
|
9664
|
-
"path": "
|
|
9665
|
-
"valueType": "
|
|
9666
|
-
"enumValues": [
|
|
9667
|
-
"date",
|
|
9668
|
-
"time",
|
|
9669
|
-
"datetime"
|
|
9670
|
-
]
|
|
9738
|
+
"path": "timestamp",
|
|
9739
|
+
"valueType": "boolean"
|
|
9671
9740
|
}],
|
|
9672
9741
|
"event-emitter": [
|
|
9673
9742
|
{
|
|
@@ -9740,6 +9809,24 @@ Object.freeze({
|
|
|
9740
9809
|
"path": "detected",
|
|
9741
9810
|
"valueType": "boolean"
|
|
9742
9811
|
}],
|
|
9812
|
+
"group-active": [{
|
|
9813
|
+
"path": "active",
|
|
9814
|
+
"valueType": "boolean"
|
|
9815
|
+
}],
|
|
9816
|
+
"group-status": [
|
|
9817
|
+
{
|
|
9818
|
+
"path": "included",
|
|
9819
|
+
"valueType": "number"
|
|
9820
|
+
},
|
|
9821
|
+
{
|
|
9822
|
+
"path": "excluded",
|
|
9823
|
+
"valueType": "number"
|
|
9824
|
+
},
|
|
9825
|
+
{
|
|
9826
|
+
"path": "total",
|
|
9827
|
+
"valueType": "number"
|
|
9828
|
+
}
|
|
9829
|
+
],
|
|
9743
9830
|
"heating-valve": [{
|
|
9744
9831
|
"path": "position",
|
|
9745
9832
|
"valueType": "number"
|
|
@@ -9774,20 +9861,10 @@ Object.freeze({
|
|
|
9774
9861
|
"valueType": "number"
|
|
9775
9862
|
}
|
|
9776
9863
|
],
|
|
9777
|
-
"humidity-sensor": [
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
},
|
|
9782
|
-
{
|
|
9783
|
-
"path": "unit",
|
|
9784
|
-
"valueType": "string"
|
|
9785
|
-
},
|
|
9786
|
-
{
|
|
9787
|
-
"path": "precision",
|
|
9788
|
-
"valueType": "number"
|
|
9789
|
-
}
|
|
9790
|
-
],
|
|
9864
|
+
"humidity-sensor": [{
|
|
9865
|
+
"path": "percent",
|
|
9866
|
+
"valueType": "number"
|
|
9867
|
+
}],
|
|
9791
9868
|
"image": [{
|
|
9792
9869
|
"path": "url",
|
|
9793
9870
|
"valueType": "string"
|
|
@@ -9995,6 +10072,10 @@ Object.freeze({
|
|
|
9995
10072
|
]
|
|
9996
10073
|
}
|
|
9997
10074
|
],
|
|
10075
|
+
"meter": [{
|
|
10076
|
+
"path": "value",
|
|
10077
|
+
"valueType": "number"
|
|
10078
|
+
}],
|
|
9998
10079
|
"motion": [
|
|
9999
10080
|
{
|
|
10000
10081
|
"path": "detected",
|
|
@@ -10126,20 +10207,10 @@ Object.freeze({
|
|
|
10126
10207
|
"valueType": "boolean"
|
|
10127
10208
|
}
|
|
10128
10209
|
],
|
|
10129
|
-
"numeric-sensor": [
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
},
|
|
10134
|
-
{
|
|
10135
|
-
"path": "unit",
|
|
10136
|
-
"valueType": "string"
|
|
10137
|
-
},
|
|
10138
|
-
{
|
|
10139
|
-
"path": "precision",
|
|
10140
|
-
"valueType": "number"
|
|
10141
|
-
}
|
|
10142
|
-
],
|
|
10210
|
+
"numeric-sensor": [{
|
|
10211
|
+
"path": "value",
|
|
10212
|
+
"valueType": "number"
|
|
10213
|
+
}],
|
|
10143
10214
|
"pet-feeder": [
|
|
10144
10215
|
{
|
|
10145
10216
|
"path": "foodLevel",
|
|
@@ -10231,14 +10302,6 @@ Object.freeze({
|
|
|
10231
10302
|
{
|
|
10232
10303
|
"path": "powerFactor",
|
|
10233
10304
|
"valueType": "number"
|
|
10234
|
-
},
|
|
10235
|
-
{
|
|
10236
|
-
"path": "unit",
|
|
10237
|
-
"valueType": "string"
|
|
10238
|
-
},
|
|
10239
|
-
{
|
|
10240
|
-
"path": "precision",
|
|
10241
|
-
"valueType": "number"
|
|
10242
10305
|
}
|
|
10243
10306
|
],
|
|
10244
10307
|
"presence": [
|
|
@@ -10267,20 +10330,10 @@ Object.freeze({
|
|
|
10267
10330
|
"valueType": "number"
|
|
10268
10331
|
}
|
|
10269
10332
|
],
|
|
10270
|
-
"pressure-sensor": [
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
},
|
|
10275
|
-
{
|
|
10276
|
-
"path": "unit",
|
|
10277
|
-
"valueType": "string"
|
|
10278
|
-
},
|
|
10279
|
-
{
|
|
10280
|
-
"path": "precision",
|
|
10281
|
-
"valueType": "number"
|
|
10282
|
-
}
|
|
10283
|
-
],
|
|
10333
|
+
"pressure-sensor": [{
|
|
10334
|
+
"path": "hpa",
|
|
10335
|
+
"valueType": "number"
|
|
10336
|
+
}],
|
|
10284
10337
|
"privacy-mask": [{
|
|
10285
10338
|
"path": "enabled",
|
|
10286
10339
|
"valueType": "boolean"
|
|
@@ -10591,20 +10644,10 @@ Object.freeze({
|
|
|
10591
10644
|
"path": "tampered",
|
|
10592
10645
|
"valueType": "boolean"
|
|
10593
10646
|
}],
|
|
10594
|
-
"temperature-sensor": [
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
},
|
|
10599
|
-
{
|
|
10600
|
-
"path": "unit",
|
|
10601
|
-
"valueType": "string"
|
|
10602
|
-
},
|
|
10603
|
-
{
|
|
10604
|
-
"path": "precision",
|
|
10605
|
-
"valueType": "number"
|
|
10606
|
-
}
|
|
10607
|
-
],
|
|
10647
|
+
"temperature-sensor": [{
|
|
10648
|
+
"path": "celsius",
|
|
10649
|
+
"valueType": "number"
|
|
10650
|
+
}],
|
|
10608
10651
|
"update": [
|
|
10609
10652
|
{
|
|
10610
10653
|
"path": "currentVersion",
|
|
@@ -10715,10 +10758,6 @@ Object.freeze({
|
|
|
10715
10758
|
"path": "temperature",
|
|
10716
10759
|
"valueType": "number"
|
|
10717
10760
|
},
|
|
10718
|
-
{
|
|
10719
|
-
"path": "temperatureUnit",
|
|
10720
|
-
"valueType": "string"
|
|
10721
|
-
},
|
|
10722
10761
|
{
|
|
10723
10762
|
"path": "humidity",
|
|
10724
10763
|
"valueType": "number"
|
|
@@ -10727,18 +10766,10 @@ Object.freeze({
|
|
|
10727
10766
|
"path": "pressure",
|
|
10728
10767
|
"valueType": "number"
|
|
10729
10768
|
},
|
|
10730
|
-
{
|
|
10731
|
-
"path": "pressureUnit",
|
|
10732
|
-
"valueType": "string"
|
|
10733
|
-
},
|
|
10734
10769
|
{
|
|
10735
10770
|
"path": "windSpeed",
|
|
10736
10771
|
"valueType": "number"
|
|
10737
10772
|
},
|
|
10738
|
-
{
|
|
10739
|
-
"path": "windSpeedUnit",
|
|
10740
|
-
"valueType": "string"
|
|
10741
|
-
},
|
|
10742
10773
|
{
|
|
10743
10774
|
"path": "windBearing",
|
|
10744
10775
|
"valueType": "number"
|
|
@@ -10788,7 +10819,7 @@ object({
|
|
|
10788
10819
|
params: record(string(), union([string(), number()])).optional()
|
|
10789
10820
|
});
|
|
10790
10821
|
//#endregion
|
|
10791
|
-
//#region ../types/dist/err-msg-
|
|
10822
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10792
10823
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10793
10824
|
DeviceType["Camera"] = "camera";
|
|
10794
10825
|
DeviceType["Hub"] = "hub";
|
|
@@ -10882,8 +10913,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10882
10913
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10883
10914
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10884
10915
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10885
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10916
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10917
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10886
10918
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10919
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10920
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10921
|
+
DeviceType["Washer"] = "washer";
|
|
10922
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10923
|
+
DeviceType["Dryer"] = "dryer";
|
|
10887
10924
|
return DeviceType;
|
|
10888
10925
|
}({});
|
|
10889
10926
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11131,7 +11168,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11131
11168
|
return DeviceRole;
|
|
11132
11169
|
}({});
|
|
11133
11170
|
//#endregion
|
|
11134
|
-
//#region ../types/dist/composition-
|
|
11171
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11135
11172
|
/**
|
|
11136
11173
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11137
11174
|
*
|
|
@@ -11446,6 +11483,13 @@ var table = {
|
|
|
11446
11483
|
apply: () => {
|
|
11447
11484
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11448
11485
|
}
|
|
11486
|
+
},
|
|
11487
|
+
schmitt: {
|
|
11488
|
+
minArgs: 3,
|
|
11489
|
+
maxArgs: 5,
|
|
11490
|
+
apply: () => {
|
|
11491
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11492
|
+
}
|
|
11449
11493
|
}
|
|
11450
11494
|
};
|
|
11451
11495
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11886,15 +11930,232 @@ function validateExpressionSource(src) {
|
|
|
11886
11930
|
}
|
|
11887
11931
|
return null;
|
|
11888
11932
|
}
|
|
11889
|
-
/**
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
11933
|
+
/**
|
|
11934
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11935
|
+
*
|
|
11936
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11937
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11938
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11939
|
+
*
|
|
11940
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11941
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11942
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11943
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11944
|
+
* can move later without moving the others.
|
|
11945
|
+
*/
|
|
11946
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11947
|
+
var APPLIANCE_KINDS = [
|
|
11948
|
+
"washer",
|
|
11949
|
+
"dryer",
|
|
11950
|
+
"dishwasher"
|
|
11951
|
+
];
|
|
11952
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11953
|
+
/**
|
|
11954
|
+
* Statistics and integrals over a history read (D944).
|
|
11955
|
+
*
|
|
11956
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11957
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11958
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11959
|
+
* as zero. A truncated read is not published.
|
|
11960
|
+
*/
|
|
11961
|
+
var STATISTIC_STATS = [
|
|
11962
|
+
"min",
|
|
11963
|
+
"max",
|
|
11964
|
+
"mean",
|
|
11965
|
+
"sum",
|
|
11966
|
+
"count",
|
|
11967
|
+
"change"
|
|
11968
|
+
];
|
|
11969
|
+
/**
|
|
11970
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11971
|
+
*
|
|
11972
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11973
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11974
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11975
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11976
|
+
*/
|
|
11977
|
+
var MINUTE_MS = 6e4;
|
|
11978
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11979
|
+
var DAY_MS$1 = 24 * HOUR_MS;
|
|
11980
|
+
var ROLLING_SPANS = [
|
|
11981
|
+
"1h",
|
|
11982
|
+
"24h",
|
|
11983
|
+
"2d",
|
|
11984
|
+
"7d",
|
|
11985
|
+
"30d",
|
|
11986
|
+
"custom"
|
|
11987
|
+
];
|
|
11988
|
+
var CALENDAR_PERIODS = [
|
|
11989
|
+
"today",
|
|
11990
|
+
"yesterday",
|
|
11991
|
+
"this-week",
|
|
11992
|
+
"this-month"
|
|
11993
|
+
];
|
|
11994
|
+
var RESET_PERIODS = [
|
|
11995
|
+
"never",
|
|
11996
|
+
"daily",
|
|
11997
|
+
"weekly",
|
|
11998
|
+
"monthly"
|
|
11999
|
+
];
|
|
12000
|
+
5 * MINUTE_MS;
|
|
12001
|
+
24 * HOUR_MS, 2 * DAY_MS$1, 7 * DAY_MS$1, 30 * DAY_MS$1;
|
|
12002
|
+
7 * DAY_MS$1, 30 * DAY_MS$1, 365 * DAY_MS$1;
|
|
12003
|
+
var rollingWindowObject = object({
|
|
12004
|
+
kind: literal("rolling"),
|
|
12005
|
+
span: _enum(ROLLING_SPANS),
|
|
12006
|
+
customMinutes: number().int().min(5).optional()
|
|
12007
|
+
}).check((payload) => {
|
|
12008
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
12009
|
+
code: "custom",
|
|
12010
|
+
message: "a custom range needs a duration in minutes",
|
|
12011
|
+
path: ["customMinutes"],
|
|
12012
|
+
input: payload.value
|
|
12013
|
+
});
|
|
12014
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
12015
|
+
code: "custom",
|
|
12016
|
+
message: "only a custom range carries a duration",
|
|
12017
|
+
path: ["customMinutes"],
|
|
12018
|
+
input: payload.value
|
|
12019
|
+
});
|
|
12020
|
+
});
|
|
12021
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12022
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12023
|
+
kind: literal("calendar"),
|
|
12024
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12025
|
+
})]);
|
|
12026
|
+
/**
|
|
12027
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
12028
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
12029
|
+
* `composition.ts` (D659).
|
|
12030
|
+
*/
|
|
11893
12031
|
var CompositionSourceRefSchema = object({
|
|
11894
12032
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11895
12033
|
addonId: string().min(1),
|
|
11896
12034
|
stableId: string().min(1)
|
|
11897
12035
|
});
|
|
12036
|
+
var GROUP_TEMPLATE_IDS = [
|
|
12037
|
+
"temperature",
|
|
12038
|
+
"humidity",
|
|
12039
|
+
"pressure",
|
|
12040
|
+
"illuminance",
|
|
12041
|
+
"power",
|
|
12042
|
+
"energy",
|
|
12043
|
+
"battery",
|
|
12044
|
+
"numeric",
|
|
12045
|
+
"motion",
|
|
12046
|
+
"contact",
|
|
12047
|
+
"leak",
|
|
12048
|
+
"smoke",
|
|
12049
|
+
"occupancy",
|
|
12050
|
+
"binary",
|
|
12051
|
+
"switch",
|
|
12052
|
+
"light",
|
|
12053
|
+
"fan",
|
|
12054
|
+
"cover",
|
|
12055
|
+
"valve",
|
|
12056
|
+
"lock",
|
|
12057
|
+
"media-player",
|
|
12058
|
+
"climate"
|
|
12059
|
+
];
|
|
12060
|
+
var NUMERIC_AGGREGATES = [
|
|
12061
|
+
"mean",
|
|
12062
|
+
"median",
|
|
12063
|
+
"min",
|
|
12064
|
+
"max",
|
|
12065
|
+
"sum"
|
|
12066
|
+
];
|
|
12067
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12068
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12069
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12070
|
+
var AGGREGATE_REDUCERS = [
|
|
12071
|
+
"mean",
|
|
12072
|
+
"median",
|
|
12073
|
+
"min",
|
|
12074
|
+
"max",
|
|
12075
|
+
"sum",
|
|
12076
|
+
"any",
|
|
12077
|
+
"all"
|
|
12078
|
+
];
|
|
12079
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12080
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12081
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12082
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12083
|
+
var HelperMemberSchema = object({
|
|
12084
|
+
source: CompositionSourceRefSchema,
|
|
12085
|
+
cap: string().min(1),
|
|
12086
|
+
fieldPath: string().min(1)
|
|
12087
|
+
});
|
|
12088
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12089
|
+
object({
|
|
12090
|
+
kind: literal("group"),
|
|
12091
|
+
templateId: GroupTemplateIdSchema,
|
|
12092
|
+
aggregate: AggregateReducerSchema,
|
|
12093
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12094
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12095
|
+
active: ActiveCriterionSchema.optional()
|
|
12096
|
+
}),
|
|
12097
|
+
object({
|
|
12098
|
+
kind: literal("appliance"),
|
|
12099
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12100
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12101
|
+
thresholdWatts: number().positive(),
|
|
12102
|
+
startDwellMs: number().int().nonnegative(),
|
|
12103
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12104
|
+
member: HelperMemberSchema
|
|
12105
|
+
}),
|
|
12106
|
+
object({
|
|
12107
|
+
kind: literal("statistic"),
|
|
12108
|
+
stat: _enum(STATISTIC_STATS),
|
|
12109
|
+
window: StatisticWindowSchema,
|
|
12110
|
+
source: HelperMemberSchema
|
|
12111
|
+
}),
|
|
12112
|
+
object({
|
|
12113
|
+
kind: literal("integral"),
|
|
12114
|
+
reset: _enum(RESET_PERIODS),
|
|
12115
|
+
output: _enum(["energy", "meter"]),
|
|
12116
|
+
source: HelperMemberSchema
|
|
12117
|
+
}),
|
|
12118
|
+
object({
|
|
12119
|
+
kind: literal("threshold"),
|
|
12120
|
+
source: HelperMemberSchema,
|
|
12121
|
+
high: number(),
|
|
12122
|
+
low: number(),
|
|
12123
|
+
onForMs: number().int().nonnegative(),
|
|
12124
|
+
offForMs: number().int().nonnegative()
|
|
12125
|
+
}),
|
|
12126
|
+
object({
|
|
12127
|
+
kind: literal("arithmetic"),
|
|
12128
|
+
op: _enum([
|
|
12129
|
+
"sum",
|
|
12130
|
+
"difference",
|
|
12131
|
+
"ratio"
|
|
12132
|
+
]),
|
|
12133
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12134
|
+
}),
|
|
12135
|
+
object({
|
|
12136
|
+
kind: literal("expression"),
|
|
12137
|
+
expr: string().min(1),
|
|
12138
|
+
inputs: array(object({
|
|
12139
|
+
name: string().min(1),
|
|
12140
|
+
member: HelperMemberSchema
|
|
12141
|
+
})).min(1).max(64),
|
|
12142
|
+
output: _enum(["number", "boolean"])
|
|
12143
|
+
}),
|
|
12144
|
+
object({
|
|
12145
|
+
kind: literal("derivative"),
|
|
12146
|
+
window: RollingWindowSchema,
|
|
12147
|
+
per: _enum([
|
|
12148
|
+
"second",
|
|
12149
|
+
"minute",
|
|
12150
|
+
"hour"
|
|
12151
|
+
]),
|
|
12152
|
+
source: HelperMemberSchema
|
|
12153
|
+
})
|
|
12154
|
+
]);
|
|
12155
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12156
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12157
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12158
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11898
12159
|
/** One field of one capability of one source device. */
|
|
11899
12160
|
var CompositionFieldReadSchema = object({
|
|
11900
12161
|
source: CompositionSourceRefSchema,
|
|
@@ -11938,7 +12199,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11938
12199
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11939
12200
|
CompositionFromSourceSchema,
|
|
11940
12201
|
CompositionExpressionSourceSchema,
|
|
11941
|
-
CompositionCodeSourceSchema
|
|
12202
|
+
CompositionCodeSourceSchema,
|
|
12203
|
+
object({
|
|
12204
|
+
kind: literal("aggregate"),
|
|
12205
|
+
reducer: _enum([
|
|
12206
|
+
"mean",
|
|
12207
|
+
"median",
|
|
12208
|
+
"min",
|
|
12209
|
+
"max",
|
|
12210
|
+
"sum",
|
|
12211
|
+
"any",
|
|
12212
|
+
"all"
|
|
12213
|
+
]),
|
|
12214
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12215
|
+
/**
|
|
12216
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12217
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12218
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12219
|
+
*/
|
|
12220
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12221
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12222
|
+
publish: _enum([
|
|
12223
|
+
"value",
|
|
12224
|
+
"included",
|
|
12225
|
+
"excluded",
|
|
12226
|
+
"total"
|
|
12227
|
+
]),
|
|
12228
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12229
|
+
empty: _enum([
|
|
12230
|
+
"null",
|
|
12231
|
+
"omit",
|
|
12232
|
+
"offline"
|
|
12233
|
+
])
|
|
12234
|
+
}),
|
|
12235
|
+
object({
|
|
12236
|
+
kind: literal("series"),
|
|
12237
|
+
read: CompositionFieldReadSchema,
|
|
12238
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12239
|
+
publish: _enum([
|
|
12240
|
+
"value",
|
|
12241
|
+
"included",
|
|
12242
|
+
"excluded",
|
|
12243
|
+
"total"
|
|
12244
|
+
]),
|
|
12245
|
+
/**
|
|
12246
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12247
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12248
|
+
*/
|
|
12249
|
+
empty: _enum([
|
|
12250
|
+
"null",
|
|
12251
|
+
"omit",
|
|
12252
|
+
"offline"
|
|
12253
|
+
])
|
|
12254
|
+
})
|
|
11942
12255
|
]);
|
|
11943
12256
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11944
12257
|
kind: literal("forward"),
|
|
@@ -11984,7 +12297,13 @@ var CompositionSchema = object({
|
|
|
11984
12297
|
kind: literal("existing"),
|
|
11985
12298
|
device: CompositionSourceRefSchema
|
|
11986
12299
|
})]),
|
|
11987
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12300
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12301
|
+
/**
|
|
12302
|
+
* Present when the block is a helper template. Absent on a free
|
|
12303
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12304
|
+
* never the compiled features.
|
|
12305
|
+
*/
|
|
12306
|
+
helper: HelperSpecSchema.optional()
|
|
11988
12307
|
}).superRefine((composition, ctx) => {
|
|
11989
12308
|
const seen = /* @__PURE__ */ new Set();
|
|
11990
12309
|
composition.features.forEach((feature, index) => {
|
|
@@ -17091,7 +17410,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17091
17410
|
*/
|
|
17092
17411
|
interactiveConnectPath: string().min(1).optional(),
|
|
17093
17412
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17094
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17413
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17414
|
+
/**
|
|
17415
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17416
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17417
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17418
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17419
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17420
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17421
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17422
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17423
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17424
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17425
|
+
* offers it as the default path; the fields the session fills are
|
|
17426
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17427
|
+
*/
|
|
17428
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17095
17429
|
}))
|
|
17096
17430
|
});
|
|
17097
17431
|
var ListInputSchema = object({
|
|
@@ -18086,7 +18420,12 @@ var CompositionProblemSchema = object({
|
|
|
18086
18420
|
"item-field-reserved",
|
|
18087
18421
|
"target-missing",
|
|
18088
18422
|
"target-unreadable",
|
|
18089
|
-
"not-replaceable"
|
|
18423
|
+
"not-replaceable",
|
|
18424
|
+
"native-capability-replace",
|
|
18425
|
+
"mixed-quantity",
|
|
18426
|
+
"helper-mismatch",
|
|
18427
|
+
"member-constraint",
|
|
18428
|
+
"retention"
|
|
18090
18429
|
]),
|
|
18091
18430
|
path: string(),
|
|
18092
18431
|
message: string()
|
|
@@ -18107,7 +18446,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18107
18446
|
"null",
|
|
18108
18447
|
"offline",
|
|
18109
18448
|
"unknown",
|
|
18110
|
-
"release"
|
|
18449
|
+
"release",
|
|
18450
|
+
"omit"
|
|
18111
18451
|
]);
|
|
18112
18452
|
/**
|
|
18113
18453
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18144,9 +18484,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18144
18484
|
reads: array(CompositionFieldReadSchema)
|
|
18145
18485
|
});
|
|
18146
18486
|
/**
|
|
18147
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18148
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18149
|
-
*
|
|
18487
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18488
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18489
|
+
* Replacing a capability the device already serves is refused
|
|
18490
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18491
|
+
* wire for a claim the hub already holds.
|
|
18150
18492
|
*/
|
|
18151
18493
|
var CompositionFeatureModeSchema = _enum([
|
|
18152
18494
|
"new",
|
|
@@ -18317,8 +18659,392 @@ Object.freeze({
|
|
|
18317
18659
|
latchedAt: {
|
|
18318
18660
|
kind: "fixed",
|
|
18319
18661
|
result: ["number", "null"]
|
|
18662
|
+
},
|
|
18663
|
+
schmitt: {
|
|
18664
|
+
kind: "fixed",
|
|
18665
|
+
result: ["boolean", "null"]
|
|
18320
18666
|
}
|
|
18321
18667
|
});
|
|
18668
|
+
/**
|
|
18669
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18670
|
+
* Data, not a form default written into the block.
|
|
18671
|
+
*/
|
|
18672
|
+
var NOW$2 = {
|
|
18673
|
+
fieldPath: "lastFetchedAt",
|
|
18674
|
+
expr: "now"
|
|
18675
|
+
};
|
|
18676
|
+
var CHANGED = {
|
|
18677
|
+
fieldPath: "lastChangedAt",
|
|
18678
|
+
expr: "now"
|
|
18679
|
+
};
|
|
18680
|
+
function numeric(input) {
|
|
18681
|
+
return {
|
|
18682
|
+
...input,
|
|
18683
|
+
family: "numeric",
|
|
18684
|
+
deviceType: DeviceType.Sensor,
|
|
18685
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18686
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18687
|
+
activeWhen: void 0,
|
|
18688
|
+
commandCaps: [],
|
|
18689
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18690
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18691
|
+
accept: [{
|
|
18692
|
+
cap: input.outputCap,
|
|
18693
|
+
fieldPath: input.outputField
|
|
18694
|
+
}]
|
|
18695
|
+
};
|
|
18696
|
+
}
|
|
18697
|
+
function binary(input) {
|
|
18698
|
+
return {
|
|
18699
|
+
...input,
|
|
18700
|
+
family: "binary",
|
|
18701
|
+
deviceType: DeviceType.Sensor,
|
|
18702
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18703
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18704
|
+
activeWhen: void 0,
|
|
18705
|
+
commandCaps: [],
|
|
18706
|
+
quantity: "none",
|
|
18707
|
+
baseUnit: void 0,
|
|
18708
|
+
aggregates: BINARY_AGGREGATES,
|
|
18709
|
+
empty: "offline"
|
|
18710
|
+
};
|
|
18711
|
+
}
|
|
18712
|
+
var GROUP_TEMPLATES = [
|
|
18713
|
+
numeric({
|
|
18714
|
+
id: "temperature",
|
|
18715
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18716
|
+
role: DeviceRole.TemperatureSensor,
|
|
18717
|
+
outputCap: "temperature-sensor",
|
|
18718
|
+
outputField: "celsius",
|
|
18719
|
+
quantity: "temperature",
|
|
18720
|
+
defaultAggregate: "mean",
|
|
18721
|
+
empty: "null",
|
|
18722
|
+
companions: [NOW$2]
|
|
18723
|
+
}),
|
|
18724
|
+
numeric({
|
|
18725
|
+
id: "humidity",
|
|
18726
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18727
|
+
role: DeviceRole.HumiditySensor,
|
|
18728
|
+
outputCap: "humidity-sensor",
|
|
18729
|
+
outputField: "percent",
|
|
18730
|
+
quantity: "humidity",
|
|
18731
|
+
defaultAggregate: "mean",
|
|
18732
|
+
empty: "null",
|
|
18733
|
+
companions: [NOW$2]
|
|
18734
|
+
}),
|
|
18735
|
+
numeric({
|
|
18736
|
+
id: "pressure",
|
|
18737
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18738
|
+
role: DeviceRole.PressureSensor,
|
|
18739
|
+
outputCap: "pressure-sensor",
|
|
18740
|
+
outputField: "hpa",
|
|
18741
|
+
quantity: "pressure",
|
|
18742
|
+
defaultAggregate: "mean",
|
|
18743
|
+
empty: "null",
|
|
18744
|
+
companions: [NOW$2]
|
|
18745
|
+
}),
|
|
18746
|
+
numeric({
|
|
18747
|
+
id: "illuminance",
|
|
18748
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18749
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18750
|
+
outputCap: "ambient-light-sensor",
|
|
18751
|
+
outputField: "lux",
|
|
18752
|
+
quantity: "illuminance",
|
|
18753
|
+
defaultAggregate: "mean",
|
|
18754
|
+
empty: "null",
|
|
18755
|
+
companions: [NOW$2]
|
|
18756
|
+
}),
|
|
18757
|
+
numeric({
|
|
18758
|
+
id: "power",
|
|
18759
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18760
|
+
role: DeviceRole.PowerSensor,
|
|
18761
|
+
outputCap: "power-meter",
|
|
18762
|
+
outputField: "watts",
|
|
18763
|
+
quantity: "power",
|
|
18764
|
+
defaultAggregate: "sum",
|
|
18765
|
+
empty: "omit",
|
|
18766
|
+
companions: [NOW$2]
|
|
18767
|
+
}),
|
|
18768
|
+
numeric({
|
|
18769
|
+
id: "energy",
|
|
18770
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18771
|
+
role: DeviceRole.EnergySensor,
|
|
18772
|
+
outputCap: "power-meter",
|
|
18773
|
+
outputField: "kwhTotal",
|
|
18774
|
+
quantity: "energy",
|
|
18775
|
+
defaultAggregate: "sum",
|
|
18776
|
+
empty: "omit",
|
|
18777
|
+
companions: [NOW$2]
|
|
18778
|
+
}),
|
|
18779
|
+
numeric({
|
|
18780
|
+
id: "battery",
|
|
18781
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18782
|
+
role: DeviceRole.BatterySensor,
|
|
18783
|
+
outputCap: "battery",
|
|
18784
|
+
outputField: "percentage",
|
|
18785
|
+
quantity: "percentage",
|
|
18786
|
+
defaultAggregate: "mean",
|
|
18787
|
+
empty: "null",
|
|
18788
|
+
companions: [
|
|
18789
|
+
{
|
|
18790
|
+
fieldPath: "charging",
|
|
18791
|
+
expr: "\"unknown\""
|
|
18792
|
+
},
|
|
18793
|
+
{
|
|
18794
|
+
fieldPath: "sleeping",
|
|
18795
|
+
expr: "false"
|
|
18796
|
+
},
|
|
18797
|
+
{
|
|
18798
|
+
fieldPath: "lastUpdated",
|
|
18799
|
+
expr: "now"
|
|
18800
|
+
}
|
|
18801
|
+
]
|
|
18802
|
+
}),
|
|
18803
|
+
numeric({
|
|
18804
|
+
id: "numeric",
|
|
18805
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18806
|
+
role: DeviceRole.NumericSensor,
|
|
18807
|
+
outputCap: "numeric-sensor",
|
|
18808
|
+
outputField: "value",
|
|
18809
|
+
quantity: "device",
|
|
18810
|
+
defaultAggregate: "mean",
|
|
18811
|
+
empty: "null",
|
|
18812
|
+
companions: [NOW$2]
|
|
18813
|
+
}),
|
|
18814
|
+
binary({
|
|
18815
|
+
id: "motion",
|
|
18816
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18817
|
+
role: DeviceRole.MotionSensor,
|
|
18818
|
+
outputCap: "motion",
|
|
18819
|
+
outputField: "detected",
|
|
18820
|
+
defaultAggregate: "any",
|
|
18821
|
+
accept: [{
|
|
18822
|
+
cap: "motion",
|
|
18823
|
+
fieldPath: "detected"
|
|
18824
|
+
}],
|
|
18825
|
+
companions: [{
|
|
18826
|
+
fieldPath: "lastDetectedAt",
|
|
18827
|
+
expr: "null"
|
|
18828
|
+
}, {
|
|
18829
|
+
fieldPath: "autoClearAfterMs",
|
|
18830
|
+
expr: "null"
|
|
18831
|
+
}]
|
|
18832
|
+
}),
|
|
18833
|
+
binary({
|
|
18834
|
+
id: "contact",
|
|
18835
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18836
|
+
role: DeviceRole.ContactSensor,
|
|
18837
|
+
outputCap: "contact",
|
|
18838
|
+
outputField: "entryOpen",
|
|
18839
|
+
defaultAggregate: "any",
|
|
18840
|
+
accept: [{
|
|
18841
|
+
cap: "contact",
|
|
18842
|
+
fieldPath: "entryOpen"
|
|
18843
|
+
}],
|
|
18844
|
+
companions: [CHANGED]
|
|
18845
|
+
}),
|
|
18846
|
+
binary({
|
|
18847
|
+
id: "leak",
|
|
18848
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18849
|
+
role: DeviceRole.LeakSensor,
|
|
18850
|
+
outputCap: "flood",
|
|
18851
|
+
outputField: "flooded",
|
|
18852
|
+
defaultAggregate: "any",
|
|
18853
|
+
accept: [{
|
|
18854
|
+
cap: "flood",
|
|
18855
|
+
fieldPath: "flooded"
|
|
18856
|
+
}],
|
|
18857
|
+
companions: [CHANGED]
|
|
18858
|
+
}),
|
|
18859
|
+
binary({
|
|
18860
|
+
id: "smoke",
|
|
18861
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18862
|
+
role: DeviceRole.SmokeSensor,
|
|
18863
|
+
outputCap: "smoke",
|
|
18864
|
+
outputField: "detected",
|
|
18865
|
+
defaultAggregate: "any",
|
|
18866
|
+
accept: [{
|
|
18867
|
+
cap: "smoke",
|
|
18868
|
+
fieldPath: "detected"
|
|
18869
|
+
}],
|
|
18870
|
+
companions: [CHANGED]
|
|
18871
|
+
}),
|
|
18872
|
+
binary({
|
|
18873
|
+
id: "occupancy",
|
|
18874
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18875
|
+
role: DeviceRole.BinarySensor,
|
|
18876
|
+
outputCap: "binary",
|
|
18877
|
+
outputField: "on",
|
|
18878
|
+
defaultAggregate: "any",
|
|
18879
|
+
accept: [{
|
|
18880
|
+
cap: "motion",
|
|
18881
|
+
fieldPath: "detected"
|
|
18882
|
+
}, {
|
|
18883
|
+
cap: "binary",
|
|
18884
|
+
fieldPath: "on"
|
|
18885
|
+
}],
|
|
18886
|
+
companions: [CHANGED]
|
|
18887
|
+
}),
|
|
18888
|
+
binary({
|
|
18889
|
+
id: "binary",
|
|
18890
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18891
|
+
role: DeviceRole.BinarySensor,
|
|
18892
|
+
outputCap: "binary",
|
|
18893
|
+
outputField: "on",
|
|
18894
|
+
defaultAggregate: "any",
|
|
18895
|
+
accept: [{
|
|
18896
|
+
cap: "binary",
|
|
18897
|
+
fieldPath: "on"
|
|
18898
|
+
}],
|
|
18899
|
+
companions: [CHANGED]
|
|
18900
|
+
}),
|
|
18901
|
+
actuator({
|
|
18902
|
+
id: "switch",
|
|
18903
|
+
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.",
|
|
18904
|
+
deviceType: DeviceType.Switch,
|
|
18905
|
+
outputCap: "switch",
|
|
18906
|
+
outputField: "on",
|
|
18907
|
+
member: {
|
|
18908
|
+
cap: "switch",
|
|
18909
|
+
fieldPath: "on"
|
|
18910
|
+
},
|
|
18911
|
+
commandCaps: ["switch"]
|
|
18912
|
+
}),
|
|
18913
|
+
actuator({
|
|
18914
|
+
id: "light",
|
|
18915
|
+
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.",
|
|
18916
|
+
deviceType: DeviceType.Light,
|
|
18917
|
+
outputCap: "switch",
|
|
18918
|
+
outputField: "on",
|
|
18919
|
+
member: {
|
|
18920
|
+
cap: "switch",
|
|
18921
|
+
fieldPath: "on"
|
|
18922
|
+
},
|
|
18923
|
+
commandCaps: [
|
|
18924
|
+
"switch",
|
|
18925
|
+
"brightness",
|
|
18926
|
+
"color"
|
|
18927
|
+
]
|
|
18928
|
+
}),
|
|
18929
|
+
actuator({
|
|
18930
|
+
id: "fan",
|
|
18931
|
+
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.",
|
|
18932
|
+
deviceType: DeviceType.Fan,
|
|
18933
|
+
outputCap: "switch",
|
|
18934
|
+
outputField: "on",
|
|
18935
|
+
member: {
|
|
18936
|
+
cap: "switch",
|
|
18937
|
+
fieldPath: "on"
|
|
18938
|
+
},
|
|
18939
|
+
commandCaps: ["switch", "fan-control"]
|
|
18940
|
+
}),
|
|
18941
|
+
actuator({
|
|
18942
|
+
id: "cover",
|
|
18943
|
+
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.",
|
|
18944
|
+
deviceType: DeviceType.Cover,
|
|
18945
|
+
outputCap: "group-active",
|
|
18946
|
+
outputField: "active",
|
|
18947
|
+
member: {
|
|
18948
|
+
cap: "cover",
|
|
18949
|
+
fieldPath: "state"
|
|
18950
|
+
},
|
|
18951
|
+
activeWhen: [
|
|
18952
|
+
"open",
|
|
18953
|
+
"opening",
|
|
18954
|
+
"stopped"
|
|
18955
|
+
],
|
|
18956
|
+
commandCaps: ["cover"]
|
|
18957
|
+
}),
|
|
18958
|
+
actuator({
|
|
18959
|
+
id: "valve",
|
|
18960
|
+
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.",
|
|
18961
|
+
deviceType: DeviceType.Valve,
|
|
18962
|
+
outputCap: "group-active",
|
|
18963
|
+
outputField: "active",
|
|
18964
|
+
member: {
|
|
18965
|
+
cap: "valve",
|
|
18966
|
+
fieldPath: "state"
|
|
18967
|
+
},
|
|
18968
|
+
activeWhen: [
|
|
18969
|
+
"open",
|
|
18970
|
+
"opening",
|
|
18971
|
+
"stopped"
|
|
18972
|
+
],
|
|
18973
|
+
commandCaps: ["valve"]
|
|
18974
|
+
}),
|
|
18975
|
+
actuator({
|
|
18976
|
+
id: "lock",
|
|
18977
|
+
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.",
|
|
18978
|
+
deviceType: DeviceType.Lock,
|
|
18979
|
+
outputCap: "group-active",
|
|
18980
|
+
outputField: "active",
|
|
18981
|
+
member: {
|
|
18982
|
+
cap: "lock-control",
|
|
18983
|
+
fieldPath: "state"
|
|
18984
|
+
},
|
|
18985
|
+
activeWhen: ["locked"],
|
|
18986
|
+
commandCaps: ["lock-control"]
|
|
18987
|
+
}),
|
|
18988
|
+
actuator({
|
|
18989
|
+
id: "media-player",
|
|
18990
|
+
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.",
|
|
18991
|
+
deviceType: DeviceType.MediaPlayer,
|
|
18992
|
+
outputCap: "group-active",
|
|
18993
|
+
outputField: "active",
|
|
18994
|
+
member: {
|
|
18995
|
+
cap: "media-player",
|
|
18996
|
+
fieldPath: "state"
|
|
18997
|
+
},
|
|
18998
|
+
activeWhen: ["playing", "buffering"],
|
|
18999
|
+
commandCaps: ["media-player"]
|
|
19000
|
+
}),
|
|
19001
|
+
actuator({
|
|
19002
|
+
id: "climate",
|
|
19003
|
+
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.",
|
|
19004
|
+
deviceType: DeviceType.Thermostat,
|
|
19005
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19006
|
+
outputCap: "group-active",
|
|
19007
|
+
outputField: "active",
|
|
19008
|
+
member: {
|
|
19009
|
+
cap: "climate-control",
|
|
19010
|
+
fieldPath: "mode"
|
|
19011
|
+
},
|
|
19012
|
+
activeWhen: [
|
|
19013
|
+
"heat",
|
|
19014
|
+
"cool",
|
|
19015
|
+
"auto",
|
|
19016
|
+
"heat_cool",
|
|
19017
|
+
"fan_only",
|
|
19018
|
+
"dry"
|
|
19019
|
+
],
|
|
19020
|
+
commandCaps: ["climate-control"]
|
|
19021
|
+
})
|
|
19022
|
+
];
|
|
19023
|
+
function actuator(input) {
|
|
19024
|
+
return {
|
|
19025
|
+
id: input.id,
|
|
19026
|
+
summary: input.summary,
|
|
19027
|
+
deviceType: input.deviceType,
|
|
19028
|
+
outputCap: input.outputCap,
|
|
19029
|
+
outputField: input.outputField,
|
|
19030
|
+
commandCaps: input.commandCaps,
|
|
19031
|
+
family: "actuator",
|
|
19032
|
+
role: void 0,
|
|
19033
|
+
memberDeviceType: input.deviceType,
|
|
19034
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19035
|
+
activeWhen: input.activeWhen,
|
|
19036
|
+
quantity: "none",
|
|
19037
|
+
baseUnit: void 0,
|
|
19038
|
+
aggregates: BINARY_AGGREGATES,
|
|
19039
|
+
defaultAggregate: "any",
|
|
19040
|
+
empty: "offline",
|
|
19041
|
+
accept: [input.member],
|
|
19042
|
+
companions: [CHANGED]
|
|
19043
|
+
};
|
|
19044
|
+
}
|
|
19045
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19046
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19047
|
+
DeviceType.Camera;
|
|
18322
19048
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18323
19049
|
/**
|
|
18324
19050
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20032,12 +20758,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
20032
20758
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20033
20759
|
* in-place so dispatch keeps working.
|
|
20034
20760
|
*
|
|
20035
|
-
* **
|
|
20036
|
-
*
|
|
20037
|
-
*
|
|
20038
|
-
*
|
|
20039
|
-
* (`ha-domain-mapping`)
|
|
20040
|
-
* stored after that point.
|
|
20761
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20762
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20763
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20764
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20765
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20766
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20041
20767
|
*
|
|
20042
20768
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20043
20769
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20051,6 +20777,14 @@ var SourceInfoSchema = object({
|
|
|
20051
20777
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20052
20778
|
* Used to detect rename when `id` changes. */
|
|
20053
20779
|
uniqueId: string().optional(),
|
|
20780
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20781
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20782
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20783
|
+
dateTimeShape: _enum([
|
|
20784
|
+
"date",
|
|
20785
|
+
"time",
|
|
20786
|
+
"datetime"
|
|
20787
|
+
]).optional(),
|
|
20054
20788
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20055
20789
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20056
20790
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -40963,7 +41697,8 @@ method(object({
|
|
|
40963
41697
|
"enum"
|
|
40964
41698
|
]),
|
|
40965
41699
|
enumValues: array(string()).optional(),
|
|
40966
|
-
item: boolean().optional()
|
|
41700
|
+
item: boolean().optional(),
|
|
41701
|
+
quantity: ReadingQuantitySchema.optional()
|
|
40967
41702
|
})).readonly(),
|
|
40968
41703
|
itemArray: object({
|
|
40969
41704
|
path: string(),
|
|
@@ -43324,7 +44059,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43324
44059
|
});
|
|
43325
44060
|
/**
|
|
43326
44061
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43327
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44062
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43328
44063
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43329
44064
|
* the originating provider config (mode + sourcePort) so the
|
|
43330
44065
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44763,8 +45498,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44763
45498
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44764
45499
|
var MaskGridShapeSchema = object({
|
|
44765
45500
|
kind: literal("grid"),
|
|
44766
|
-
gridWidth: number(),
|
|
44767
|
-
gridHeight: number(),
|
|
45501
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45502
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44768
45503
|
cells: array(boolean())
|
|
44769
45504
|
});
|
|
44770
45505
|
discriminatedUnion("kind", [
|
|
@@ -44876,6 +45611,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44876
45611
|
"detection-blind",
|
|
44877
45612
|
"motion-noisy",
|
|
44878
45613
|
"motion-calm",
|
|
45614
|
+
"package-llm-silent",
|
|
45615
|
+
"package-llm-answered",
|
|
44879
45616
|
"recording-stalled",
|
|
44880
45617
|
"recording-healthy",
|
|
44881
45618
|
"recording-degraded",
|
|
@@ -45965,7 +46702,20 @@ var NcRuleInputSchema = object({
|
|
|
45965
46702
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
45966
46703
|
* path does not run Zod defaults.
|
|
45967
46704
|
*/
|
|
45968
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46705
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46706
|
+
/**
|
|
46707
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46708
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46709
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46710
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46711
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46712
|
+
*
|
|
46713
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46714
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46715
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46716
|
+
* `false`, so it needs no `clear` key.
|
|
46717
|
+
*/
|
|
46718
|
+
askVerdict: boolean().optional()
|
|
45969
46719
|
});
|
|
45970
46720
|
/**
|
|
45971
46721
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -55890,6 +56640,28 @@ var PackageVersionInfoSchema = object({
|
|
|
55890
56640
|
deprecated: string().optional(),
|
|
55891
56641
|
distTags: array(string()).readonly()
|
|
55892
56642
|
});
|
|
56643
|
+
/**
|
|
56644
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56645
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56646
|
+
* tarball failure — never an empty string standing in for either.
|
|
56647
|
+
*/
|
|
56648
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56649
|
+
object({
|
|
56650
|
+
status: literal("ok"),
|
|
56651
|
+
markdown: string()
|
|
56652
|
+
}),
|
|
56653
|
+
object({ status: literal("missing") }),
|
|
56654
|
+
object({
|
|
56655
|
+
status: literal("error"),
|
|
56656
|
+
message: string()
|
|
56657
|
+
})
|
|
56658
|
+
]);
|
|
56659
|
+
var PackageDocsSchema = object({
|
|
56660
|
+
name: string(),
|
|
56661
|
+
version: string(),
|
|
56662
|
+
readme: PackageDocBodySchema,
|
|
56663
|
+
changelog: PackageDocBodySchema
|
|
56664
|
+
});
|
|
55893
56665
|
var SearchResultSchema = object({
|
|
55894
56666
|
name: string(),
|
|
55895
56667
|
version: string(),
|
|
@@ -56108,7 +56880,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56108
56880
|
}), object({ success: literal(true) }), {
|
|
56109
56881
|
kind: "mutation",
|
|
56110
56882
|
auth: "admin"
|
|
56111
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56883
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56884
|
+
name: string().min(1),
|
|
56885
|
+
version: string().min(1).optional()
|
|
56886
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56112
56887
|
kind: "mutation",
|
|
56113
56888
|
auth: "admin"
|
|
56114
56889
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56158,46 +56933,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56158
56933
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56159
56934
|
object({
|
|
56160
56935
|
/** Carbon dioxide concentration in ppm. */
|
|
56161
|
-
co2Ppm: number().min(0).optional(),
|
|
56936
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56162
56937
|
/** Total volatile organic compounds in ppb. */
|
|
56163
|
-
vocPpb: number().min(0).optional(),
|
|
56938
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56164
56939
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56165
|
-
pm25: number().min(0).optional(),
|
|
56940
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56166
56941
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56167
|
-
pm10: number().min(0).optional(),
|
|
56942
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56168
56943
|
/** Composite AQI value (typically 0..500). */
|
|
56169
|
-
aqi: number().optional(),
|
|
56944
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56170
56945
|
/** Ms epoch when the slice was last updated. */
|
|
56171
|
-
lastFetchedAt: number()
|
|
56172
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56173
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56174
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56175
|
-
* per slice is unambiguous. */
|
|
56176
|
-
unit: string().optional(),
|
|
56177
|
-
/** Suggested decimal places for numeric display.
|
|
56178
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56179
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56180
|
-
* auto-formatting when absent. */
|
|
56181
|
-
precision: number().int().min(0).max(10).optional()
|
|
56946
|
+
lastFetchedAt: number()
|
|
56182
56947
|
});
|
|
56183
56948
|
DeviceType.Sensor;
|
|
56184
56949
|
object({
|
|
56185
|
-
/** Current illuminance in lux (lx). */
|
|
56186
|
-
lux: number().min(0).meta({
|
|
56187
|
-
|
|
56950
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
56951
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
56952
|
+
precision: 0,
|
|
56188
56953
|
label: "Illuminance"
|
|
56189
|
-
}),
|
|
56954
|
+
})),
|
|
56190
56955
|
/** Ms epoch when the slice was last updated. */
|
|
56191
|
-
lastFetchedAt: number()
|
|
56192
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56193
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56194
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56195
|
-
unit: string().optional(),
|
|
56196
|
-
/** Suggested decimal places for numeric display.
|
|
56197
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56198
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56199
|
-
* auto-formatting when absent. */
|
|
56200
|
-
precision: number().int().min(0).max(10).optional()
|
|
56956
|
+
lastFetchedAt: number()
|
|
56201
56957
|
});
|
|
56202
56958
|
DeviceType.Sensor;
|
|
56203
56959
|
/**
|
|
@@ -56342,10 +57098,7 @@ var BatteryStatusSchema = object({
|
|
|
56342
57098
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56343
57099
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56344
57100
|
*/
|
|
56345
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56346
|
-
unit: "%",
|
|
56347
|
-
label: "Charge"
|
|
56348
|
-
}),
|
|
57101
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56349
57102
|
/**
|
|
56350
57103
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56351
57104
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56372,7 +57125,14 @@ var BatteryStatusSchema = object({
|
|
|
56372
57125
|
*/
|
|
56373
57126
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56374
57127
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56375
|
-
lastUpdated: number(),
|
|
57128
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57129
|
+
/**
|
|
57130
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57131
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57132
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57133
|
+
* `numeric-sensor` on the same device.
|
|
57134
|
+
*/
|
|
57135
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56376
57136
|
/**
|
|
56377
57137
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56378
57138
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56412,7 +57172,7 @@ var BatteryStatusSchema = object({
|
|
|
56412
57172
|
*/
|
|
56413
57173
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56414
57174
|
});
|
|
56415
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57175
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56416
57176
|
method(object({
|
|
56417
57177
|
deviceId: number(),
|
|
56418
57178
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56432,7 +57192,7 @@ object({
|
|
|
56432
57192
|
DeviceType.Sensor;
|
|
56433
57193
|
object({
|
|
56434
57194
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56435
|
-
percentage: number().min(0).max(100),
|
|
57195
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56436
57196
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56437
57197
|
lastChangedAt: number()
|
|
56438
57198
|
});
|
|
@@ -56827,21 +57587,21 @@ object({
|
|
|
56827
57587
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
56828
57588
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
56829
57589
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
56830
|
-
target: number().nullable(),
|
|
57590
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
56831
57591
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
56832
57592
|
* in `heat_cool` mode. */
|
|
56833
|
-
targetHigh: number().nullable(),
|
|
57593
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
56834
57594
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
56835
57595
|
* in `heat_cool` mode. */
|
|
56836
|
-
targetLow: number().nullable(),
|
|
57596
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
56837
57597
|
/** Target relative humidity (0..100). Null when the device has no
|
|
56838
57598
|
* humidity control. */
|
|
56839
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57599
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56840
57600
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
56841
57601
|
* the device's internal sensor. */
|
|
56842
|
-
currentTemp: number().nullable(),
|
|
57602
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
56843
57603
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
56844
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57604
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56845
57605
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
56846
57606
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
56847
57607
|
swingVertical: boolean().nullable(),
|
|
@@ -56849,11 +57609,11 @@ object({
|
|
|
56849
57609
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
56850
57610
|
swingHorizontal: boolean().nullable(),
|
|
56851
57611
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56852
|
-
minTemp: number().nullable().optional(),
|
|
57612
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56853
57613
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56854
|
-
maxTemp: number().nullable().optional(),
|
|
57614
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56855
57615
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
56856
|
-
tempStep: number().positive().nullable().optional(),
|
|
57616
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
56857
57617
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
56858
57618
|
lastFetchedAt: number()
|
|
56859
57619
|
});
|
|
@@ -56932,17 +57692,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
56932
57692
|
* modes to expose in the picker without a slice fetch.
|
|
56933
57693
|
*/
|
|
56934
57694
|
var RgbTripletSchema = object({
|
|
56935
|
-
r: number().int().min(0).max(255),
|
|
56936
|
-
g: number().int().min(0).max(255),
|
|
56937
|
-
b: number().int().min(0).max(255)
|
|
57695
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57696
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57697
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
56938
57698
|
});
|
|
56939
57699
|
var HsvTripletSchema = object({
|
|
56940
57700
|
/** Hue in degrees, 0..360. */
|
|
56941
|
-
h: number().min(0).max(360),
|
|
57701
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
56942
57702
|
/** Saturation as 0..100 inclusive. */
|
|
56943
|
-
s: number().min(0).max(100),
|
|
57703
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
56944
57704
|
/** Value/brightness as 0..100 inclusive. */
|
|
56945
|
-
v: number().min(0).max(100)
|
|
57705
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
56946
57706
|
});
|
|
56947
57707
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
56948
57708
|
object({
|
|
@@ -56971,7 +57731,7 @@ object({
|
|
|
56971
57731
|
/** Populated when `mode === 'hsv'`. */
|
|
56972
57732
|
hsv: HsvTripletSchema.optional(),
|
|
56973
57733
|
/** Populated when `mode === 'mired'`. */
|
|
56974
|
-
mireds: number().int().optional(),
|
|
57734
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
56975
57735
|
/** Ms epoch of the last operator-driven change. */
|
|
56976
57736
|
lastChangedAt: number()
|
|
56977
57737
|
});
|
|
@@ -57095,18 +57855,12 @@ _enum([
|
|
|
57095
57855
|
"empty",
|
|
57096
57856
|
"full"
|
|
57097
57857
|
]);
|
|
57098
|
-
/**
|
|
57099
|
-
|
|
57100
|
-
|
|
57101
|
-
"days",
|
|
57102
|
-
"hours",
|
|
57103
|
-
"cycles"
|
|
57104
|
-
]);
|
|
57105
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57106
|
-
* days). `value` null = unknown (D393). */
|
|
57858
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
57859
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
57860
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57107
57861
|
var ConsumableRemainingSchema = object({
|
|
57108
|
-
value: number().min(0).nullable(),
|
|
57109
|
-
|
|
57862
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
57863
|
+
kind: ConsumableRemainingKindSchema
|
|
57110
57864
|
});
|
|
57111
57865
|
var ConsumablesStatusSchema = object({
|
|
57112
57866
|
items: array(object({
|
|
@@ -57115,7 +57869,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57115
57869
|
/** Display name. */
|
|
57116
57870
|
label: string().min(1),
|
|
57117
57871
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57118
|
-
level: number().min(0).max(100).nullable(),
|
|
57872
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57119
57873
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57120
57874
|
status: ConsumableStatusSchema.nullable(),
|
|
57121
57875
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57132,7 +57886,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57132
57886
|
})),
|
|
57133
57887
|
lastChangedAt: number()
|
|
57134
57888
|
});
|
|
57135
|
-
Object.values(DeviceType), [...
|
|
57889
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57136
57890
|
Object.values(DeviceType), method(object({
|
|
57137
57891
|
deviceId: number().int().nonnegative(),
|
|
57138
57892
|
key: string().min(1)
|
|
@@ -57157,39 +57911,17 @@ object({
|
|
|
57157
57911
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57158
57912
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57159
57913
|
* or time-only — HA accepts all three forms). */
|
|
57160
|
-
value: union([number(), string()]),
|
|
57914
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57161
57915
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57162
57916
|
options: array(string()),
|
|
57163
57917
|
/** Ms epoch when the slice was last updated. */
|
|
57164
57918
|
lastChangedAt: number(),
|
|
57165
|
-
/**
|
|
57166
|
-
|
|
57167
|
-
|
|
57168
|
-
|
|
57169
|
-
/**
|
|
57170
|
-
|
|
57171
|
-
min: number().optional(),
|
|
57172
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57173
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57174
|
-
max: number().optional(),
|
|
57175
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57176
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57177
|
-
step: number().optional(),
|
|
57178
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57179
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57180
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57181
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57182
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57183
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57184
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57185
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57186
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57187
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57188
|
-
format: _enum([
|
|
57189
|
-
"date",
|
|
57190
|
-
"time",
|
|
57191
|
-
"datetime"
|
|
57192
|
-
]).optional()
|
|
57919
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
57920
|
+
min: number().optional().meta(readingMeta("device")),
|
|
57921
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
57922
|
+
max: number().optional().meta(readingMeta("device")),
|
|
57923
|
+
/** Step increment, in the device quantity's base unit. */
|
|
57924
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57193
57925
|
});
|
|
57194
57926
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57195
57927
|
object({
|
|
@@ -57227,9 +57959,9 @@ object({
|
|
|
57227
57959
|
]),
|
|
57228
57960
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57229
57961
|
* no intermediate position surface. */
|
|
57230
|
-
position: number().min(0).max(100).nullable(),
|
|
57962
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57231
57963
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57232
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
57964
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57233
57965
|
/** Ms epoch when the slice was last updated. */
|
|
57234
57966
|
lastChangedAt: number()
|
|
57235
57967
|
});
|
|
@@ -57287,9 +58019,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57287
58019
|
object({
|
|
57288
58020
|
mode: DayNightModeSchema,
|
|
57289
58021
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57290
|
-
sensitivity: number().optional(),
|
|
58022
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57291
58023
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57292
|
-
switchDelaySec: number().optional(),
|
|
58024
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57293
58025
|
lastFetchedAt: number()
|
|
57294
58026
|
});
|
|
57295
58027
|
/**
|
|
@@ -57444,11 +58176,11 @@ object({
|
|
|
57444
58176
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57445
58177
|
availablePrograms: array(string()),
|
|
57446
58178
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57447
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58179
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57448
58180
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57449
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58181
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57450
58182
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57451
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58183
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57452
58184
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57453
58185
|
doorOpen: boolean().nullable(),
|
|
57454
58186
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57472,7 +58204,7 @@ object({
|
|
|
57472
58204
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57473
58205
|
machineCareDue: boolean().nullable(),
|
|
57474
58206
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57475
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58207
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57476
58208
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57477
58209
|
halfLoad: boolean().nullable(),
|
|
57478
58210
|
hygienePlus: boolean().nullable(),
|
|
@@ -57487,7 +58219,7 @@ object({
|
|
|
57487
58219
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57488
58220
|
activeEvents: array(string()),
|
|
57489
58221
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57490
|
-
errorCode: number().nullable(),
|
|
58222
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57491
58223
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57492
58224
|
errorLabel: string().nullable(),
|
|
57493
58225
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -57633,24 +58365,14 @@ object({
|
|
|
57633
58365
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
57634
58366
|
lastPressedAt: number().nullable(),
|
|
57635
58367
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
57636
|
-
pressCountSinceStart: number()
|
|
58368
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
57637
58369
|
});
|
|
57638
58370
|
object({
|
|
57639
58371
|
deviceId: number(),
|
|
57640
58372
|
timestamp: number()
|
|
57641
58373
|
});
|
|
57642
58374
|
DeviceType.Button, DeviceType.Camera;
|
|
57643
|
-
|
|
57644
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
57645
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
57646
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
57647
|
-
* The option set is stable across observations; it is persisted in the
|
|
57648
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
57649
|
-
* stored in `sourceInfo`.
|
|
57650
|
-
*/
|
|
57651
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
57652
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
57653
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58375
|
+
_enum([
|
|
57654
58376
|
"date",
|
|
57655
58377
|
"time",
|
|
57656
58378
|
"datetime"
|
|
@@ -57658,12 +58380,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
57658
58380
|
object({
|
|
57659
58381
|
value: string(),
|
|
57660
58382
|
/**
|
|
57661
|
-
* Set
|
|
57662
|
-
* as
|
|
57663
|
-
*
|
|
57664
|
-
* a time-only sensor → `'time'`.
|
|
58383
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58384
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58385
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
57665
58386
|
*/
|
|
57666
|
-
|
|
58387
|
+
timestamp: boolean().optional(),
|
|
57667
58388
|
/** Ms epoch when the slice was last updated. */
|
|
57668
58389
|
lastFetchedAt: number()
|
|
57669
58390
|
});
|
|
@@ -57682,13 +58403,13 @@ var EventFireSchema = object({
|
|
|
57682
58403
|
deviceId: number(),
|
|
57683
58404
|
eventType: string(),
|
|
57684
58405
|
data: record(string(), unknown()).nullable(),
|
|
57685
|
-
timestamp: number(),
|
|
57686
|
-
seq: number()
|
|
58406
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58407
|
+
seq: number().meta(readingMeta("count"))
|
|
57687
58408
|
});
|
|
57688
58409
|
object({
|
|
57689
58410
|
eventTypes: array(string()),
|
|
57690
58411
|
lastEvent: EventFireSchema.nullable(),
|
|
57691
|
-
eventCountSinceStart: number()
|
|
58412
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
57692
58413
|
});
|
|
57693
58414
|
DeviceType.EventEmitter;
|
|
57694
58415
|
var IdentitySchema = object({
|
|
@@ -58077,10 +58798,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58077
58798
|
object({
|
|
58078
58799
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58079
58800
|
* speed surface (single-speed fan). */
|
|
58080
|
-
percentage: number().min(0).max(100).nullable(),
|
|
58801
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58081
58802
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58082
58803
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58083
|
-
percentageStep: number().positive().optional(),
|
|
58804
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
58084
58805
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
58085
58806
|
* — empty string when no preset is active or supported. */
|
|
58086
58807
|
preset: string(),
|
|
@@ -58162,7 +58883,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58162
58883
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58163
58884
|
model: string().nullable(),
|
|
58164
58885
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58165
|
-
channelCount: number().nullable(),
|
|
58886
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58166
58887
|
/**
|
|
58167
58888
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58168
58889
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58194,9 +58915,45 @@ object({
|
|
|
58194
58915
|
lastChangedAt: number()
|
|
58195
58916
|
});
|
|
58196
58917
|
DeviceType.Sensor;
|
|
58918
|
+
object({
|
|
58919
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
58920
|
+
results: array(object({
|
|
58921
|
+
deviceId: number().int().nonnegative(),
|
|
58922
|
+
cap: string().min(1),
|
|
58923
|
+
method: string().min(1),
|
|
58924
|
+
ok: boolean(),
|
|
58925
|
+
error: string().optional(),
|
|
58926
|
+
/** Ms epoch of the attempt. */
|
|
58927
|
+
at: number()
|
|
58928
|
+
})) });
|
|
58929
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58930
|
+
object({
|
|
58931
|
+
active: boolean().meta({ label: "Active" }),
|
|
58932
|
+
/** Ms epoch when the slice was last updated. */
|
|
58933
|
+
lastChangedAt: number()
|
|
58934
|
+
});
|
|
58935
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
58936
|
+
object({
|
|
58937
|
+
/** Members whose current value entered the aggregate. */
|
|
58938
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
58939
|
+
precision: 0,
|
|
58940
|
+
label: "Reporting"
|
|
58941
|
+
})),
|
|
58942
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
58943
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
58944
|
+
precision: 0,
|
|
58945
|
+
label: "Excluded"
|
|
58946
|
+
})),
|
|
58947
|
+
/** `included` + `excluded`. */
|
|
58948
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
58949
|
+
precision: 0,
|
|
58950
|
+
label: "Members"
|
|
58951
|
+
}))
|
|
58952
|
+
});
|
|
58953
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58197
58954
|
object({
|
|
58198
58955
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58199
|
-
position: number().min(0).max(100).nullable(),
|
|
58956
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58200
58957
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58201
58958
|
lastFetchedAt: number()
|
|
58202
58959
|
});
|
|
@@ -58205,9 +58962,9 @@ object({
|
|
|
58205
58962
|
/** Whether the humidifier is currently on. */
|
|
58206
58963
|
on: boolean(),
|
|
58207
58964
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58208
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58965
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58209
58966
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58210
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58967
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58211
58968
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58212
58969
|
* device has no mode surface. */
|
|
58213
58970
|
mode: string().nullable(),
|
|
@@ -58217,9 +58974,9 @@ object({
|
|
|
58217
58974
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58218
58975
|
action: string().nullable(),
|
|
58219
58976
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58220
|
-
minHumidity: number().nullable(),
|
|
58977
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58221
58978
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58222
|
-
maxHumidity: number().nullable(),
|
|
58979
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58223
58980
|
/** Ms epoch when the slice was last updated. */
|
|
58224
58981
|
lastChangedAt: number()
|
|
58225
58982
|
});
|
|
@@ -58243,22 +59000,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58243
59000
|
auth: "protected"
|
|
58244
59001
|
});
|
|
58245
59002
|
object({
|
|
58246
|
-
/** Current relative humidity, 0..100. */
|
|
58247
|
-
percent: number().min(0).max(100).meta({
|
|
58248
|
-
|
|
59003
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59004
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59005
|
+
precision: 0,
|
|
58249
59006
|
label: "Humidity"
|
|
58250
|
-
}),
|
|
59007
|
+
})),
|
|
58251
59008
|
/** Ms epoch when the slice was last updated. */
|
|
58252
|
-
lastFetchedAt: number()
|
|
58253
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58254
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58255
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58256
|
-
unit: string().optional(),
|
|
58257
|
-
/** Suggested decimal places for numeric display.
|
|
58258
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58259
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58260
|
-
* auto-formatting when absent. */
|
|
58261
|
-
precision: number().int().min(0).max(10).optional()
|
|
59009
|
+
lastFetchedAt: number()
|
|
58262
59010
|
});
|
|
58263
59011
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58264
59012
|
object({
|
|
@@ -58266,7 +59014,7 @@ object({
|
|
|
58266
59014
|
* entity exposes no `entity_picture` (yet). */
|
|
58267
59015
|
url: string().nullable(),
|
|
58268
59016
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58269
|
-
lastUpdated: number().nullable()
|
|
59017
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58270
59018
|
});
|
|
58271
59019
|
DeviceType.Image;
|
|
58272
59020
|
/**
|
|
@@ -58322,19 +59070,19 @@ var NormalizedRangeSchema = object({
|
|
|
58322
59070
|
});
|
|
58323
59071
|
object({
|
|
58324
59072
|
/** Normalized 0–100. */
|
|
58325
|
-
brightness: number().optional(),
|
|
59073
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58326
59074
|
/** Normalized 0–100. */
|
|
58327
|
-
contrast: number().optional(),
|
|
59075
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58328
59076
|
/** Normalized 0–100. */
|
|
58329
|
-
saturation: number().optional(),
|
|
59077
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58330
59078
|
/** Normalized 0–100. */
|
|
58331
|
-
sharpness: number().optional(),
|
|
59079
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58332
59080
|
mirror: boolean().optional(),
|
|
58333
59081
|
flip: boolean().optional(),
|
|
58334
59082
|
rotate: ImageRotateSchema.optional(),
|
|
58335
59083
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58336
59084
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58337
|
-
warmth: number().optional(),
|
|
59085
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58338
59086
|
exposureMode: ExposureModeSchema.optional(),
|
|
58339
59087
|
backlightMode: BacklightModeSchema.optional(),
|
|
58340
59088
|
lastFetchedAt: number()
|
|
@@ -58579,10 +59327,10 @@ var IntercomAbilitySchema = object({
|
|
|
58579
59327
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58580
59328
|
codecs: array(string()),
|
|
58581
59329
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58582
|
-
sampleRate: number(),
|
|
59330
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58583
59331
|
duplex: _enum(["half", "full"]),
|
|
58584
59332
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58585
|
-
maxBacklogMs: number()
|
|
59333
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58586
59334
|
});
|
|
58587
59335
|
var IntercomStatusSchema = object({
|
|
58588
59336
|
/** True while a talk session is open. */
|
|
@@ -58693,13 +59441,13 @@ object({
|
|
|
58693
59441
|
activity: LawnMowerActivitySchema,
|
|
58694
59442
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
58695
59443
|
* reading. */
|
|
58696
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59444
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58697
59445
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
58698
59446
|
* task is active / progress is unavailable. */
|
|
58699
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59447
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58700
59448
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
58701
59449
|
* or null when unknown. */
|
|
58702
|
-
currentCode: number().nullable(),
|
|
59450
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
58703
59451
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
58704
59452
|
currentCodeLabel: string().nullable(),
|
|
58705
59453
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -59109,7 +59857,14 @@ DeviceType.Lock, method(object({
|
|
|
59109
59857
|
auth: "protected"
|
|
59110
59858
|
}), method(object({
|
|
59111
59859
|
deviceId: number().int().nonnegative(),
|
|
59112
|
-
code: string().min(1).optional()
|
|
59860
|
+
code: string().min(1).optional(),
|
|
59861
|
+
/**
|
|
59862
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
59863
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
59864
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
59865
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
59866
|
+
*/
|
|
59867
|
+
confirm: boolean().optional()
|
|
59113
59868
|
}), _void(), {
|
|
59114
59869
|
kind: "mutation",
|
|
59115
59870
|
auth: "protected"
|
|
@@ -59117,6 +59872,11 @@ DeviceType.Lock, method(object({
|
|
|
59117
59872
|
kind: "mutation",
|
|
59118
59873
|
auth: "protected"
|
|
59119
59874
|
});
|
|
59875
|
+
object({
|
|
59876
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
59877
|
+
lastFetchedAt: number()
|
|
59878
|
+
});
|
|
59879
|
+
DeviceType.Sensor;
|
|
59120
59880
|
/**
|
|
59121
59881
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59122
59882
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59161,7 +59921,7 @@ object({
|
|
|
59161
59921
|
state: MediaPlayerStateSchema,
|
|
59162
59922
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59163
59923
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59164
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
59924
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59165
59925
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59166
59926
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59167
59927
|
isMuted: boolean().nullable(),
|
|
@@ -59174,10 +59934,10 @@ object({
|
|
|
59174
59934
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59175
59935
|
/** Current playback position in ms. Null when not seekable or
|
|
59176
59936
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59177
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
59937
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59178
59938
|
/** Total duration of the current media in ms. Null when unknown
|
|
59179
59939
|
* (live stream) or nothing is playing. */
|
|
59180
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
59940
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59181
59941
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59182
59942
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59183
59943
|
shuffle: boolean().nullable(),
|
|
@@ -59477,7 +60237,7 @@ object({
|
|
|
59477
60237
|
* it, every provider seeded it at boot, and every session left it
|
|
59478
60238
|
* `detected: true` after its detach.
|
|
59479
60239
|
*/
|
|
59480
|
-
autoClearAfterMs: number().nullable()
|
|
60240
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59481
60241
|
});
|
|
59482
60242
|
/**
|
|
59483
60243
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59527,7 +60287,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59527
60287
|
});
|
|
59528
60288
|
object({
|
|
59529
60289
|
enabled: boolean(),
|
|
59530
|
-
sensitivity: number(),
|
|
60290
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59531
60291
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59532
60292
|
regions: array(MotionZoneRegionSchema),
|
|
59533
60293
|
lastFetchedAt: number()
|
|
@@ -59831,7 +60591,7 @@ var NavigationStatusSchema = object({
|
|
|
59831
60591
|
following: boolean(),
|
|
59832
60592
|
flash: boolean(),
|
|
59833
60593
|
lightMode: NavigationLightModeSchema,
|
|
59834
|
-
lightLevel: number().min(40).max(100),
|
|
60594
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
59835
60595
|
/** Ms epoch when the slice was last updated. */
|
|
59836
60596
|
lastChangedAt: number()
|
|
59837
60597
|
});
|
|
@@ -59877,13 +60637,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
59877
60637
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
59878
60638
|
* SKIP a null rather than coerce it.
|
|
59879
60639
|
*/
|
|
59880
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
60640
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59881
60641
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
59882
|
-
rssiDbm: number().optional(),
|
|
60642
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
59883
60643
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
59884
60644
|
ssid: string().optional(),
|
|
59885
60645
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
59886
|
-
lastUpdated: number()
|
|
60646
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
59887
60647
|
});
|
|
59888
60648
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
59889
60649
|
deviceId: number(),
|
|
@@ -60202,7 +60962,7 @@ object({
|
|
|
60202
60962
|
lastError: string().nullable(),
|
|
60203
60963
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60204
60964
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60205
|
-
queueDepth: number().int().nonnegative(),
|
|
60965
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60206
60966
|
/** Per-feature capability matrix — authoritative source for the
|
|
60207
60967
|
* compose-form field gating. */
|
|
60208
60968
|
supports: NotifierSupportsSchema
|
|
@@ -60252,15 +61012,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60252
61012
|
acceptedAt: number()
|
|
60253
61013
|
});
|
|
60254
61014
|
object({
|
|
60255
|
-
|
|
60256
|
-
|
|
60257
|
-
* Populated live from the upstream source on each state push.
|
|
60258
|
-
* Absent for unitless sensors. */
|
|
60259
|
-
unit: string().optional(),
|
|
60260
|
-
/** Suggested decimal places for numeric display.
|
|
60261
|
-
* Populated live from the upstream source when provided.
|
|
60262
|
-
* Falls back to auto-formatting when absent. */
|
|
60263
|
-
precision: number().int().min(0).max(10).optional(),
|
|
61015
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
61016
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60264
61017
|
/** Ms epoch when the slice was last updated. */
|
|
60265
61018
|
lastFetchedAt: number()
|
|
60266
61019
|
});
|
|
@@ -60550,23 +61303,26 @@ object({
|
|
|
60550
61303
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60551
61304
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60552
61305
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60553
|
-
foodLevel: number().nullable(),
|
|
61306
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60554
61307
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60555
61308
|
* single-hopper models. */
|
|
60556
|
-
food1: number().nullable(),
|
|
61309
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60557
61310
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60558
61311
|
* single-hopper models. */
|
|
60559
|
-
food2: number().nullable(),
|
|
61312
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60560
61313
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60561
61314
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60562
61315
|
* below the feeder's low threshold. */
|
|
60563
61316
|
lowFood: boolean(),
|
|
60564
61317
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60565
61318
|
* device has no battery reading. */
|
|
60566
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60567
|
-
/**
|
|
60568
|
-
*
|
|
60569
|
-
|
|
61319
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61320
|
+
/**
|
|
61321
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61322
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61323
|
+
* model has no desiccant sensor.
|
|
61324
|
+
*/
|
|
61325
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60570
61326
|
/** True while a feed is in progress. */
|
|
60571
61327
|
feeding: boolean(),
|
|
60572
61328
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60577,7 +61333,7 @@ object({
|
|
|
60577
61333
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60578
61334
|
error: string().nullable(),
|
|
60579
61335
|
/** Raw device error code (0 / null = no error). */
|
|
60580
|
-
errorCode: number().nullable(),
|
|
61336
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60581
61337
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60582
61338
|
isDualHopper: boolean(),
|
|
60583
61339
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60587,7 +61343,7 @@ object({
|
|
|
60587
61343
|
/** Play a chime when dispensing. */
|
|
60588
61344
|
feedSound: boolean(),
|
|
60589
61345
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60590
|
-
volume: number(),
|
|
61346
|
+
volume: number().meta(readingMeta("none")),
|
|
60591
61347
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60592
61348
|
lastFetchedAt: number()
|
|
60593
61349
|
});
|
|
@@ -61024,38 +61780,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61024
61780
|
});
|
|
61025
61781
|
object({
|
|
61026
61782
|
/** Instantaneous power draw in watts. */
|
|
61027
|
-
watts: number().optional().meta({
|
|
61028
|
-
unit: "W",
|
|
61029
|
-
label: "Power"
|
|
61030
|
-
}),
|
|
61783
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61031
61784
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61032
|
-
kwhTotal: number().optional().meta({
|
|
61033
|
-
unit: "kWh",
|
|
61034
|
-
label: "Energy"
|
|
61035
|
-
}),
|
|
61785
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61036
61786
|
/** Voltage in volts. */
|
|
61037
|
-
volts: number().optional(),
|
|
61787
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61038
61788
|
/** Current in amperes. */
|
|
61039
|
-
amps: number().optional(),
|
|
61040
|
-
/** Apparent power in volt-amperes
|
|
61041
|
-
va: number().optional(),
|
|
61789
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61790
|
+
/** Apparent power in volt-amperes. */
|
|
61791
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61042
61792
|
/** Power factor (0..1) if reported. */
|
|
61043
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
61793
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61044
61794
|
/** Ms epoch when the slice was last updated. */
|
|
61045
|
-
lastFetchedAt: number()
|
|
61046
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
61047
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
61048
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
61049
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
61050
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
61051
|
-
unit: string().optional(),
|
|
61052
|
-
/** Suggested decimal places for numeric display.
|
|
61053
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61054
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61055
|
-
* auto-formatting when absent. */
|
|
61056
|
-
precision: number().int().min(0).max(10).optional()
|
|
61795
|
+
lastFetchedAt: number()
|
|
61057
61796
|
});
|
|
61058
|
-
|
|
61797
|
+
[
|
|
61798
|
+
DeviceType.Sensor,
|
|
61799
|
+
DeviceType.Switch,
|
|
61800
|
+
DeviceType.Light,
|
|
61801
|
+
DeviceType.Fan,
|
|
61802
|
+
DeviceType.Climate,
|
|
61803
|
+
DeviceType.Thermostat,
|
|
61804
|
+
DeviceType.Humidifier,
|
|
61805
|
+
DeviceType.WaterHeater,
|
|
61806
|
+
DeviceType.MediaPlayer,
|
|
61807
|
+
DeviceType.Washer,
|
|
61808
|
+
DeviceType.Dryer,
|
|
61809
|
+
DeviceType.Dishwasher,
|
|
61810
|
+
DeviceType.Vacuum,
|
|
61811
|
+
DeviceType.LawnMower,
|
|
61812
|
+
DeviceType.PetFeeder
|
|
61813
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61059
61814
|
/**
|
|
61060
61815
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61061
61816
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61074,11 +61829,11 @@ DeviceType.Sensor;
|
|
|
61074
61829
|
*/
|
|
61075
61830
|
var GpsLocationSchema = object({
|
|
61076
61831
|
/** Latitude in decimal degrees, -90..90. */
|
|
61077
|
-
latitude: number().min(-90).max(90),
|
|
61832
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
61078
61833
|
/** Longitude in decimal degrees, -180..180. */
|
|
61079
|
-
longitude: number().min(-180).max(180),
|
|
61834
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
61080
61835
|
/** Reported accuracy in meters (lower = better). */
|
|
61081
|
-
accuracyMeters: number().nonnegative()
|
|
61836
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
61082
61837
|
});
|
|
61083
61838
|
object({
|
|
61084
61839
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -61090,25 +61845,16 @@ object({
|
|
|
61090
61845
|
gps: GpsLocationSchema.nullable(),
|
|
61091
61846
|
/** Optional battery level of the tracking device (0..100). Null
|
|
61092
61847
|
* when not reported. */
|
|
61093
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
61848
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61094
61849
|
/** Ms epoch when the slice was last updated. */
|
|
61095
61850
|
lastChangedAt: number()
|
|
61096
61851
|
});
|
|
61097
61852
|
DeviceType.Presence;
|
|
61098
61853
|
object({
|
|
61099
|
-
/** Current pressure in hPa. */
|
|
61100
|
-
hpa: number(),
|
|
61854
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
61855
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61101
61856
|
/** Ms epoch when the slice was last updated. */
|
|
61102
|
-
lastFetchedAt: number()
|
|
61103
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61104
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61105
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61106
|
-
unit: string().optional(),
|
|
61107
|
-
/** Suggested decimal places for numeric display.
|
|
61108
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61109
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61110
|
-
* auto-formatting when absent. */
|
|
61111
|
-
precision: number().int().min(0).max(10).optional()
|
|
61857
|
+
lastFetchedAt: number()
|
|
61112
61858
|
});
|
|
61113
61859
|
DeviceType.Sensor;
|
|
61114
61860
|
/**
|
|
@@ -61441,8 +62187,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61441
62187
|
}), _void(), { kind: "mutation" });
|
|
61442
62188
|
var PtzAutotrackSettingsSchema = object({
|
|
61443
62189
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61444
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61445
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62190
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62191
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61446
62192
|
});
|
|
61447
62193
|
/**
|
|
61448
62194
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61499,7 +62245,7 @@ object({
|
|
|
61499
62245
|
/** null = unknown — never coerced to false (D393). */
|
|
61500
62246
|
running: boolean().nullable(),
|
|
61501
62247
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61502
|
-
since: number().nullable(),
|
|
62248
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61503
62249
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61504
62250
|
phase: string().nullable(),
|
|
61505
62251
|
/** null until a reading has been published (D393). */
|
|
@@ -61511,7 +62257,7 @@ object({
|
|
|
61511
62257
|
phase: string().nullable()
|
|
61512
62258
|
});
|
|
61513
62259
|
Object.values(DeviceType);
|
|
61514
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62260
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61515
62261
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61516
62262
|
kind: "mutation",
|
|
61517
62263
|
auth: "admin"
|
|
@@ -62697,9 +63443,9 @@ var RecordTriggerSchema = _enum([
|
|
|
62697
63443
|
*/
|
|
62698
63444
|
var RecordWindowSchema = object({
|
|
62699
63445
|
trigger: RecordTriggerSchema,
|
|
62700
|
-
day: number().int().min(0).max(6),
|
|
62701
|
-
startMinute: number().int().min(0).max(1439),
|
|
62702
|
-
endMinute: number().int().min(1).max(1440)
|
|
63446
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63447
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63448
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
62703
63449
|
});
|
|
62704
63450
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
62705
63451
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -62768,10 +63514,10 @@ object({
|
|
|
62768
63514
|
/** Master "record to the card at all" switch. */
|
|
62769
63515
|
enabled: boolean().nullable(),
|
|
62770
63516
|
overwriteWhenFull: boolean().nullable(),
|
|
62771
|
-
preRecordSec: number().nullable(),
|
|
62772
|
-
postRecordSec: number().nullable(),
|
|
63517
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63518
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
62773
63519
|
/** Length of one recorded file, in minutes. */
|
|
62774
|
-
segmentMinutes: number().nullable(),
|
|
63520
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
62775
63521
|
/** The primary track's weekly windows, flattened. */
|
|
62776
63522
|
windows: array(RecordWindowSchema),
|
|
62777
63523
|
/**
|
|
@@ -62787,7 +63533,7 @@ object({
|
|
|
62787
63533
|
* provider reporting a non-zero count also reports the schedule as not
|
|
62788
63534
|
* writable.
|
|
62789
63535
|
*/
|
|
62790
|
-
unreadableWindows: number(),
|
|
63536
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
62791
63537
|
/**
|
|
62792
63538
|
* The camera is scheduled to record and has NO usable storage.
|
|
62793
63539
|
*
|
|
@@ -63424,7 +64170,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63424
64170
|
url: string().optional(),
|
|
63425
64171
|
codec: string().optional(),
|
|
63426
64172
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63427
|
-
fps: number().positive().optional(),
|
|
64173
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63428
64174
|
label: string().optional(),
|
|
63429
64175
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63430
64176
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63454,18 +64200,18 @@ var StreamProfileSchema = _enum([
|
|
|
63454
64200
|
]);
|
|
63455
64201
|
/** The current encoding config of one stream profile. */
|
|
63456
64202
|
var StreamProfileConfigSchema = object({
|
|
63457
|
-
width: number(),
|
|
63458
|
-
height: number(),
|
|
64203
|
+
width: number().meta(readingMeta("none")),
|
|
64204
|
+
height: number().meta(readingMeta("none")),
|
|
63459
64205
|
codec: _enum(["h264", "h265"]),
|
|
63460
|
-
framerate: number(),
|
|
63461
|
-
bitrate: number(),
|
|
64206
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64207
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63462
64208
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63463
64209
|
encoderProfile: _enum([
|
|
63464
64210
|
"high",
|
|
63465
64211
|
"main",
|
|
63466
64212
|
"baseline"
|
|
63467
64213
|
]).optional(),
|
|
63468
|
-
gop: number().optional(),
|
|
64214
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63469
64215
|
/**
|
|
63470
64216
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63471
64217
|
*
|
|
@@ -63550,7 +64296,7 @@ object({
|
|
|
63550
64296
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63551
64297
|
lastChangedAt: number()
|
|
63552
64298
|
});
|
|
63553
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64299
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63554
64300
|
deviceId: number(),
|
|
63555
64301
|
on: boolean()
|
|
63556
64302
|
}), _void(), {
|
|
@@ -64108,23 +64854,13 @@ object({
|
|
|
64108
64854
|
});
|
|
64109
64855
|
DeviceType.Sensor;
|
|
64110
64856
|
object({
|
|
64111
|
-
/** Current temperature in Celsius. */
|
|
64112
|
-
celsius: number().meta({
|
|
64113
|
-
|
|
64857
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
64858
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
64859
|
+
precision: 1,
|
|
64114
64860
|
label: "Temperature"
|
|
64115
|
-
}),
|
|
64861
|
+
})),
|
|
64116
64862
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64117
|
-
lastFetchedAt: number()
|
|
64118
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64119
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64120
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64121
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64122
|
-
unit: string().optional(),
|
|
64123
|
-
/** Suggested decimal places for numeric display.
|
|
64124
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64125
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64126
|
-
* auto-formatting when absent. */
|
|
64127
|
-
precision: number().int().min(0).max(10).optional()
|
|
64863
|
+
lastFetchedAt: number()
|
|
64128
64864
|
});
|
|
64129
64865
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64130
64866
|
/**
|
|
@@ -64376,16 +65112,16 @@ object({
|
|
|
64376
65112
|
]),
|
|
64377
65113
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64378
65114
|
* reading. */
|
|
64379
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65115
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64380
65116
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64381
65117
|
* the vacuum has no speed control. */
|
|
64382
65118
|
fanSpeed: string().nullable(),
|
|
64383
65119
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64384
65120
|
availableFanSpeeds: array(string()),
|
|
64385
65121
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64386
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65122
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64387
65123
|
/** Current error code (0 / null = no error). */
|
|
64388
|
-
errorCode: number().nullable(),
|
|
65124
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64389
65125
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64390
65126
|
errorLabel: string().nullable(),
|
|
64391
65127
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64424,7 +65160,7 @@ object({
|
|
|
64424
65160
|
]),
|
|
64425
65161
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64426
65162
|
* intermediate position surface. */
|
|
64427
|
-
position: number().min(0).max(100).nullable(),
|
|
65163
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64428
65164
|
/** Ms epoch when the slice was last updated. */
|
|
64429
65165
|
lastChangedAt: number()
|
|
64430
65166
|
});
|
|
@@ -64452,9 +65188,9 @@ object({
|
|
|
64452
65188
|
DeviceType.Sensor;
|
|
64453
65189
|
object({
|
|
64454
65190
|
/** Current measured temperature. Null when not reported. */
|
|
64455
|
-
currentTemp: number().nullable(),
|
|
65191
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64456
65192
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64457
|
-
targetTemp: number().nullable(),
|
|
65193
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64458
65194
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64459
65195
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64460
65196
|
* device reports an unknown state. */
|
|
@@ -64465,9 +65201,9 @@ object({
|
|
|
64465
65201
|
* has no away surface. */
|
|
64466
65202
|
away: boolean().nullable(),
|
|
64467
65203
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64468
|
-
minTemp: number().nullable(),
|
|
65204
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64469
65205
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64470
|
-
maxTemp: number().nullable(),
|
|
65206
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64471
65207
|
/** Ms epoch when the slice was last updated. */
|
|
64472
65208
|
lastChangedAt: number()
|
|
64473
65209
|
});
|
|
@@ -64491,25 +65227,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64491
65227
|
auth: "protected"
|
|
64492
65228
|
});
|
|
64493
65229
|
object({
|
|
64494
|
-
/** Verbatim
|
|
64495
|
-
* when no condition has been reported yet. */
|
|
65230
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64496
65231
|
condition: string().nullable(),
|
|
64497
|
-
/** Current temperature in
|
|
64498
|
-
temperature: number().nullable(),
|
|
64499
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64500
|
-
temperatureUnit: string().nullable(),
|
|
65232
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65233
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64501
65234
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64502
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64503
|
-
/** Barometric pressure in
|
|
64504
|
-
pressure: number().nullable(),
|
|
64505
|
-
/**
|
|
64506
|
-
|
|
64507
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64508
|
-
windSpeed: number().nullable(),
|
|
64509
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64510
|
-
windSpeedUnit: string().nullable(),
|
|
65235
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65236
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65237
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65238
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65239
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64511
65240
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64512
|
-
windBearing: number().nullable(),
|
|
65241
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64513
65242
|
/** Ms epoch when the slice was last updated. */
|
|
64514
65243
|
lastFetchedAt: number()
|
|
64515
65244
|
});
|
|
@@ -65259,8 +65988,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65259
65988
|
kind: "mutation",
|
|
65260
65989
|
auth: "admin"
|
|
65261
65990
|
});
|
|
65991
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65262
65992
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65263
|
-
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;
|
|
65993
|
+
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;
|
|
65264
65994
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65265
65995
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65266
65996
|
new Set(CAP_NAMES);
|
|
@@ -65313,7 +66043,7 @@ var AccessoryKind = {
|
|
|
65313
66043
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65314
66044
|
};
|
|
65315
66045
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65316
|
-
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;
|
|
66046
|
+
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;
|
|
65317
66047
|
new Set(Object.values(DeviceType));
|
|
65318
66048
|
Object.freeze({
|
|
65319
66049
|
"accessories.getStatus": {
|
|
@@ -65421,6 +66151,13 @@ Object.freeze({
|
|
|
65421
66151
|
access: "view",
|
|
65422
66152
|
role: "admin"
|
|
65423
66153
|
},
|
|
66154
|
+
"addons.getPackageDocs": {
|
|
66155
|
+
capName: "addons",
|
|
66156
|
+
capScope: "system",
|
|
66157
|
+
addonId: null,
|
|
66158
|
+
access: "view",
|
|
66159
|
+
role: "admin"
|
|
66160
|
+
},
|
|
65424
66161
|
"addons.getVersions": {
|
|
65425
66162
|
capName: "addons",
|
|
65426
66163
|
capScope: "system",
|
|
@@ -68529,6 +69266,27 @@ Object.freeze({
|
|
|
68529
69266
|
access: "view",
|
|
68530
69267
|
role: "viewer"
|
|
68531
69268
|
},
|
|
69269
|
+
"groupActive.getStatus": {
|
|
69270
|
+
capName: "group-active",
|
|
69271
|
+
capScope: "device",
|
|
69272
|
+
addonId: null,
|
|
69273
|
+
access: "view",
|
|
69274
|
+
role: "viewer"
|
|
69275
|
+
},
|
|
69276
|
+
"groupCommands.getStatus": {
|
|
69277
|
+
capName: "group-commands",
|
|
69278
|
+
capScope: "device",
|
|
69279
|
+
addonId: null,
|
|
69280
|
+
access: "view",
|
|
69281
|
+
role: "viewer"
|
|
69282
|
+
},
|
|
69283
|
+
"groupStatus.getStatus": {
|
|
69284
|
+
capName: "group-status",
|
|
69285
|
+
capScope: "device",
|
|
69286
|
+
addonId: null,
|
|
69287
|
+
access: "view",
|
|
69288
|
+
role: "viewer"
|
|
69289
|
+
},
|
|
68532
69290
|
"heatingValve.getStatus": {
|
|
68533
69291
|
capName: "heating-valve",
|
|
68534
69292
|
capScope: "device",
|
|
@@ -69481,6 +70239,13 @@ Object.freeze({
|
|
|
69481
70239
|
access: "create",
|
|
69482
70240
|
role: "admin"
|
|
69483
70241
|
},
|
|
70242
|
+
"meter.getStatus": {
|
|
70243
|
+
capName: "meter",
|
|
70244
|
+
capScope: "device",
|
|
70245
|
+
addonId: null,
|
|
70246
|
+
access: "view",
|
|
70247
|
+
role: "viewer"
|
|
70248
|
+
},
|
|
69484
70249
|
"metricsProvider.collectSnapshot": {
|
|
69485
70250
|
capName: "metrics-provider",
|
|
69486
70251
|
capScope: "system",
|
|
@@ -77579,7 +78344,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77579
78344
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77580
78345
|
icon: "square"
|
|
77581
78346
|
}
|
|
77582
|
-
}
|
|
78347
|
+
},
|
|
78348
|
+
overrides: { byType: {
|
|
78349
|
+
[DeviceType.Washer]: {
|
|
78350
|
+
state: { running: {
|
|
78351
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78352
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78353
|
+
} },
|
|
78354
|
+
events: {
|
|
78355
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78356
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78357
|
+
}
|
|
78358
|
+
},
|
|
78359
|
+
[DeviceType.Dryer]: {
|
|
78360
|
+
state: { running: {
|
|
78361
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78362
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78363
|
+
} },
|
|
78364
|
+
events: {
|
|
78365
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78366
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78367
|
+
}
|
|
78368
|
+
},
|
|
78369
|
+
[DeviceType.Dishwasher]: {
|
|
78370
|
+
state: { running: {
|
|
78371
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78372
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78373
|
+
} },
|
|
78374
|
+
events: {
|
|
78375
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78376
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78377
|
+
}
|
|
78378
|
+
}
|
|
78379
|
+
} }
|
|
77583
78380
|
},
|
|
77584
78381
|
update: {
|
|
77585
78382
|
scope: "device",
|
|
@@ -78351,6 +79148,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78351
79148
|
icon: "flame"
|
|
78352
79149
|
}]
|
|
78353
79150
|
},
|
|
79151
|
+
"group-active": {
|
|
79152
|
+
scope: "device",
|
|
79153
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79154
|
+
},
|
|
79155
|
+
"group-commands": {
|
|
79156
|
+
scope: "device",
|
|
79157
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79158
|
+
},
|
|
79159
|
+
"group-status": {
|
|
79160
|
+
scope: "device",
|
|
79161
|
+
noun: t("Group", "Gruppo"),
|
|
79162
|
+
state: [
|
|
79163
|
+
{
|
|
79164
|
+
kind: "numeric",
|
|
79165
|
+
field: "included",
|
|
79166
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79167
|
+
label: t("Reporting", "Rispondono"),
|
|
79168
|
+
icon: "users"
|
|
79169
|
+
},
|
|
79170
|
+
{
|
|
79171
|
+
kind: "numeric",
|
|
79172
|
+
field: "excluded",
|
|
79173
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79174
|
+
label: t("Excluded", "Esclusi"),
|
|
79175
|
+
icon: "users"
|
|
79176
|
+
},
|
|
79177
|
+
{
|
|
79178
|
+
kind: "numeric",
|
|
79179
|
+
field: "total",
|
|
79180
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79181
|
+
label: t("Members", "Membri"),
|
|
79182
|
+
icon: "sigma"
|
|
79183
|
+
}
|
|
79184
|
+
]
|
|
79185
|
+
},
|
|
78354
79186
|
"humidity-sensor": {
|
|
78355
79187
|
scope: "device",
|
|
78356
79188
|
noun: t("Humidity", "Umidità"),
|
|
@@ -78376,6 +79208,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78376
79208
|
}],
|
|
78377
79209
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78378
79210
|
},
|
|
79211
|
+
meter: {
|
|
79212
|
+
scope: "device",
|
|
79213
|
+
noun: t("Meter", "Contatore"),
|
|
79214
|
+
state: [{
|
|
79215
|
+
kind: "numeric",
|
|
79216
|
+
field: "value",
|
|
79217
|
+
quantity: t("the total", "il totale"),
|
|
79218
|
+
label: t("Total", "Totale"),
|
|
79219
|
+
icon: "gauge"
|
|
79220
|
+
}]
|
|
79221
|
+
},
|
|
78379
79222
|
"numeric-sensor": {
|
|
78380
79223
|
scope: "device",
|
|
78381
79224
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78384,7 +79227,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78384
79227
|
field: "value",
|
|
78385
79228
|
quantity: t("the reading", "il valore"),
|
|
78386
79229
|
label: t("Reading", "Valore"),
|
|
78387
|
-
unitField: "unit",
|
|
78388
79230
|
icon: "gauge"
|
|
78389
79231
|
}]
|
|
78390
79232
|
},
|
|
@@ -78520,7 +79362,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78520
79362
|
field: "temperature",
|
|
78521
79363
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78522
79364
|
label: t("Temperature", "Temperatura"),
|
|
78523
|
-
|
|
79365
|
+
unit: "°C",
|
|
78524
79366
|
icon: "thermometer"
|
|
78525
79367
|
},
|
|
78526
79368
|
{
|
|
@@ -78536,7 +79378,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78536
79378
|
field: "windSpeed",
|
|
78537
79379
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78538
79380
|
label: t("Wind", "Vento"),
|
|
78539
|
-
|
|
79381
|
+
unit: "m/s",
|
|
78540
79382
|
icon: "wind"
|
|
78541
79383
|
},
|
|
78542
79384
|
{
|
|
@@ -78544,7 +79386,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78544
79386
|
field: "pressure",
|
|
78545
79387
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78546
79388
|
label: t("Pressure", "Pressione"),
|
|
78547
|
-
|
|
79389
|
+
unit: "hPa",
|
|
78548
79390
|
icon: "gauge"
|
|
78549
79391
|
}
|
|
78550
79392
|
]
|
|
@@ -78849,8 +79691,47 @@ function projectAction(cap, action) {
|
|
|
78849
79691
|
};
|
|
78850
79692
|
}
|
|
78851
79693
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
78852
|
-
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;
|
|
79694
|
+
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;
|
|
78853
79695
|
DeviceFeature.BatteryOperated;
|
|
79696
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79697
|
+
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.";
|
|
79698
|
+
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.";
|
|
79699
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79700
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79701
|
+
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.";
|
|
79702
|
+
function withheld(reason) {
|
|
79703
|
+
return {
|
|
79704
|
+
[DeviceType.Washer]: {
|
|
79705
|
+
exported: false,
|
|
79706
|
+
reason
|
|
79707
|
+
},
|
|
79708
|
+
[DeviceType.Dryer]: {
|
|
79709
|
+
exported: false,
|
|
79710
|
+
reason
|
|
79711
|
+
},
|
|
79712
|
+
[DeviceType.Dishwasher]: {
|
|
79713
|
+
exported: false,
|
|
79714
|
+
reason
|
|
79715
|
+
}
|
|
79716
|
+
};
|
|
79717
|
+
}
|
|
79718
|
+
function offered(received) {
|
|
79719
|
+
return {
|
|
79720
|
+
[DeviceType.Washer]: {
|
|
79721
|
+
exported: true,
|
|
79722
|
+
as: received
|
|
79723
|
+
},
|
|
79724
|
+
[DeviceType.Dryer]: {
|
|
79725
|
+
exported: true,
|
|
79726
|
+
as: received
|
|
79727
|
+
},
|
|
79728
|
+
[DeviceType.Dishwasher]: {
|
|
79729
|
+
exported: true,
|
|
79730
|
+
as: received
|
|
79731
|
+
}
|
|
79732
|
+
};
|
|
79733
|
+
}
|
|
79734
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
78854
79735
|
Object.freeze({
|
|
78855
79736
|
"accessories.getStatus": [{
|
|
78856
79737
|
name: "deviceId",
|
|
@@ -79817,6 +80698,21 @@ Object.freeze({
|
|
|
79817
80698
|
form: "single",
|
|
79818
80699
|
optional: false
|
|
79819
80700
|
}],
|
|
80701
|
+
"groupActive.getStatus": [{
|
|
80702
|
+
name: "deviceId",
|
|
80703
|
+
form: "single",
|
|
80704
|
+
optional: false
|
|
80705
|
+
}],
|
|
80706
|
+
"groupCommands.getStatus": [{
|
|
80707
|
+
name: "deviceId",
|
|
80708
|
+
form: "single",
|
|
80709
|
+
optional: false
|
|
80710
|
+
}],
|
|
80711
|
+
"groupStatus.getStatus": [{
|
|
80712
|
+
name: "deviceId",
|
|
80713
|
+
form: "single",
|
|
80714
|
+
optional: false
|
|
80715
|
+
}],
|
|
79820
80716
|
"heatingValve.getStatus": [{
|
|
79821
80717
|
name: "deviceId",
|
|
79822
80718
|
form: "single",
|
|
@@ -80017,6 +80913,11 @@ Object.freeze({
|
|
|
80017
80913
|
form: "single",
|
|
80018
80914
|
optional: false
|
|
80019
80915
|
}],
|
|
80916
|
+
"meter.getStatus": [{
|
|
80917
|
+
name: "deviceId",
|
|
80918
|
+
form: "single",
|
|
80919
|
+
optional: false
|
|
80920
|
+
}],
|
|
80020
80921
|
"motion.getStatus": [{
|
|
80021
80922
|
name: "deviceId",
|
|
80022
80923
|
form: "single",
|
|
@@ -81624,7 +82525,6 @@ Object.freeze({
|
|
|
81624
82525
|
"network-access": "ingress",
|
|
81625
82526
|
"smtp-provider": "email"
|
|
81626
82527
|
});
|
|
81627
|
-
DeviceType.Camera;
|
|
81628
82528
|
/**
|
|
81629
82529
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
81630
82530
|
* `z.infer`, they do not restate the shape.
|
|
@@ -81801,6 +82701,8 @@ new Map(Object.entries({
|
|
|
81801
82701
|
"detection-blind": "device-events",
|
|
81802
82702
|
"motion-noisy": "device-events",
|
|
81803
82703
|
"motion-calm": "device-events",
|
|
82704
|
+
"package-llm-silent": "device-events",
|
|
82705
|
+
"package-llm-answered": "device-events",
|
|
81804
82706
|
"recording-stalled": "device-events",
|
|
81805
82707
|
"recording-healthy": "device-events",
|
|
81806
82708
|
"recording-degraded": "device-events",
|
|
@@ -81884,6 +82786,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
81884
82786
|
label: "Motion without a subject",
|
|
81885
82787
|
kinds: ["motion-noisy", "motion-calm"]
|
|
81886
82788
|
},
|
|
82789
|
+
{
|
|
82790
|
+
id: "package-llm",
|
|
82791
|
+
family: "device-events",
|
|
82792
|
+
label: "Package confirm",
|
|
82793
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
82794
|
+
},
|
|
81887
82795
|
{
|
|
81888
82796
|
id: "recording",
|
|
81889
82797
|
family: "device-events",
|
|
@@ -82065,6 +82973,8 @@ var DEVICE_EVENTS = [
|
|
|
82065
82973
|
"detection-blind",
|
|
82066
82974
|
"motion-noisy",
|
|
82067
82975
|
"motion-calm",
|
|
82976
|
+
"package-llm-silent",
|
|
82977
|
+
"package-llm-answered",
|
|
82068
82978
|
"recording-stalled",
|
|
82069
82979
|
"recording-healthy",
|
|
82070
82980
|
"recording-degraded",
|
|
@@ -82333,6 +83243,15 @@ new Map([
|
|
|
82333
83243
|
snapshotLabel: "Cameras with constant motion now",
|
|
82334
83244
|
snapshotSection: null
|
|
82335
83245
|
},
|
|
83246
|
+
{
|
|
83247
|
+
id: "package-llm-confirm",
|
|
83248
|
+
family: "device-events",
|
|
83249
|
+
label: "Package confirm (not answering / answering again)",
|
|
83250
|
+
bad: ["package-llm-silent"],
|
|
83251
|
+
recovery: ["package-llm-answered"],
|
|
83252
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
83253
|
+
snapshotSection: null
|
|
83254
|
+
},
|
|
82336
83255
|
{
|
|
82337
83256
|
id: "recording-health",
|
|
82338
83257
|
family: "device-events",
|