@camstack/addon-notifiers 1.2.621 → 1.2.623
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +35 -0
- package/dist/addon.js +1369 -450
- package/dist/addon.mjs +1369 -450
- package/i18n/en.json +1 -1
- package/i18n/it.json +1 -1
- package/package.json +6 -4
package/dist/addon.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
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).
|
|
@@ -8270,6 +8278,99 @@ function defineRecordKinds(specs) {
|
|
|
8270
8278
|
}
|
|
8271
8279
|
return out;
|
|
8272
8280
|
}
|
|
8281
|
+
var READING_QUANTITIES = [
|
|
8282
|
+
"temperature",
|
|
8283
|
+
"pressure",
|
|
8284
|
+
"speed",
|
|
8285
|
+
"precipitation",
|
|
8286
|
+
"precipitation-rate",
|
|
8287
|
+
"length",
|
|
8288
|
+
"area",
|
|
8289
|
+
"illuminance",
|
|
8290
|
+
"irradiance",
|
|
8291
|
+
"power",
|
|
8292
|
+
"energy",
|
|
8293
|
+
"voltage",
|
|
8294
|
+
"current",
|
|
8295
|
+
"apparent-power",
|
|
8296
|
+
"humidity",
|
|
8297
|
+
"percentage",
|
|
8298
|
+
"concentration-volume",
|
|
8299
|
+
"concentration-mass",
|
|
8300
|
+
"concentration-ppb",
|
|
8301
|
+
"volume",
|
|
8302
|
+
"duration",
|
|
8303
|
+
"duration-ms",
|
|
8304
|
+
"information",
|
|
8305
|
+
"sound-level",
|
|
8306
|
+
"signal-level",
|
|
8307
|
+
"colour-temperature",
|
|
8308
|
+
"angle",
|
|
8309
|
+
"bitrate",
|
|
8310
|
+
"rate",
|
|
8311
|
+
"mass",
|
|
8312
|
+
"index",
|
|
8313
|
+
"ratio",
|
|
8314
|
+
"count",
|
|
8315
|
+
"none",
|
|
8316
|
+
"device"
|
|
8317
|
+
];
|
|
8318
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8319
|
+
new Set(READING_QUANTITIES);
|
|
8320
|
+
/**
|
|
8321
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8322
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8323
|
+
*/
|
|
8324
|
+
var QUANTITY_BASE = {
|
|
8325
|
+
temperature: "°C",
|
|
8326
|
+
pressure: "hPa",
|
|
8327
|
+
speed: "m/s",
|
|
8328
|
+
precipitation: "mm",
|
|
8329
|
+
"precipitation-rate": "mm/h",
|
|
8330
|
+
length: "m",
|
|
8331
|
+
area: "m²",
|
|
8332
|
+
illuminance: "lx",
|
|
8333
|
+
irradiance: "W/m²",
|
|
8334
|
+
power: "W",
|
|
8335
|
+
energy: "kWh",
|
|
8336
|
+
voltage: "V",
|
|
8337
|
+
current: "A",
|
|
8338
|
+
"apparent-power": "VA",
|
|
8339
|
+
humidity: "%",
|
|
8340
|
+
percentage: "%",
|
|
8341
|
+
"concentration-volume": "ppm",
|
|
8342
|
+
"concentration-mass": "µg/m³",
|
|
8343
|
+
"concentration-ppb": "ppb",
|
|
8344
|
+
volume: "L",
|
|
8345
|
+
duration: "s",
|
|
8346
|
+
"duration-ms": "ms",
|
|
8347
|
+
information: "B",
|
|
8348
|
+
"sound-level": "dBFS",
|
|
8349
|
+
"signal-level": "dBm",
|
|
8350
|
+
"colour-temperature": "mired",
|
|
8351
|
+
angle: "°",
|
|
8352
|
+
bitrate: "kbps",
|
|
8353
|
+
rate: "fps",
|
|
8354
|
+
mass: "kg",
|
|
8355
|
+
index: "none",
|
|
8356
|
+
ratio: "none",
|
|
8357
|
+
count: "none",
|
|
8358
|
+
none: "none",
|
|
8359
|
+
device: "device"
|
|
8360
|
+
};
|
|
8361
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8362
|
+
function baseUnitOf(quantity) {
|
|
8363
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8364
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8365
|
+
return symbol;
|
|
8366
|
+
}
|
|
8367
|
+
function readingMeta(quantity, extras) {
|
|
8368
|
+
return {
|
|
8369
|
+
quantity,
|
|
8370
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8371
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8372
|
+
};
|
|
8373
|
+
}
|
|
8273
8374
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8274
8375
|
var CamProfileSchema = _enum([
|
|
8275
8376
|
"high",
|
|
@@ -8297,8 +8398,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8297
8398
|
"derived"
|
|
8298
8399
|
]);
|
|
8299
8400
|
var CamStreamResolutionSchema = object({
|
|
8300
|
-
width: number().int().positive(),
|
|
8301
|
-
height: number().int().positive()
|
|
8401
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8402
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8302
8403
|
});
|
|
8303
8404
|
var CameraStreamSchema = object({
|
|
8304
8405
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8834,6 +8935,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8834
8935
|
"filesystem-browse",
|
|
8835
8936
|
"flood",
|
|
8836
8937
|
"gas",
|
|
8938
|
+
"group-active",
|
|
8939
|
+
"group-commands",
|
|
8940
|
+
"group-status",
|
|
8837
8941
|
"heating-valve",
|
|
8838
8942
|
"humidifier",
|
|
8839
8943
|
"humidity-sensor",
|
|
@@ -8854,6 +8958,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8854
8958
|
"login-method",
|
|
8855
8959
|
"media-player",
|
|
8856
8960
|
"mesh-network",
|
|
8961
|
+
"meter",
|
|
8857
8962
|
"metrics-provider",
|
|
8858
8963
|
"model-convert",
|
|
8859
8964
|
"model-distributor",
|
|
@@ -8963,14 +9068,6 @@ Object.freeze({
|
|
|
8963
9068
|
{
|
|
8964
9069
|
"path": "aqi",
|
|
8965
9070
|
"valueType": "number"
|
|
8966
|
-
},
|
|
8967
|
-
{
|
|
8968
|
-
"path": "unit",
|
|
8969
|
-
"valueType": "string"
|
|
8970
|
-
},
|
|
8971
|
-
{
|
|
8972
|
-
"path": "precision",
|
|
8973
|
-
"valueType": "number"
|
|
8974
9071
|
}
|
|
8975
9072
|
],
|
|
8976
9073
|
"alarm-panel": [
|
|
@@ -9006,20 +9103,10 @@ Object.freeze({
|
|
|
9006
9103
|
"valueType": "boolean"
|
|
9007
9104
|
}
|
|
9008
9105
|
],
|
|
9009
|
-
"ambient-light-sensor": [
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
|
|
9013
|
-
},
|
|
9014
|
-
{
|
|
9015
|
-
"path": "unit",
|
|
9016
|
-
"valueType": "string"
|
|
9017
|
-
},
|
|
9018
|
-
{
|
|
9019
|
-
"path": "precision",
|
|
9020
|
-
"valueType": "number"
|
|
9021
|
-
}
|
|
9022
|
-
],
|
|
9106
|
+
"ambient-light-sensor": [{
|
|
9107
|
+
"path": "lux",
|
|
9108
|
+
"valueType": "number"
|
|
9109
|
+
}],
|
|
9023
9110
|
"audio-metrics": [
|
|
9024
9111
|
{
|
|
9025
9112
|
"path": "ts",
|
|
@@ -9099,6 +9186,10 @@ Object.freeze({
|
|
|
9099
9186
|
"path": "lastUpdated",
|
|
9100
9187
|
"valueType": "number"
|
|
9101
9188
|
},
|
|
9189
|
+
{
|
|
9190
|
+
"path": "volts",
|
|
9191
|
+
"valueType": "number"
|
|
9192
|
+
},
|
|
9102
9193
|
{
|
|
9103
9194
|
"path": "lastContactAt",
|
|
9104
9195
|
"valueType": "number"
|
|
@@ -9341,10 +9432,6 @@ Object.freeze({
|
|
|
9341
9432
|
"datetime"
|
|
9342
9433
|
]
|
|
9343
9434
|
},
|
|
9344
|
-
{
|
|
9345
|
-
"path": "unit",
|
|
9346
|
-
"valueType": "string"
|
|
9347
|
-
},
|
|
9348
9435
|
{
|
|
9349
9436
|
"path": "min",
|
|
9350
9437
|
"valueType": "number"
|
|
@@ -9356,19 +9443,6 @@ Object.freeze({
|
|
|
9356
9443
|
{
|
|
9357
9444
|
"path": "step",
|
|
9358
9445
|
"valueType": "number"
|
|
9359
|
-
},
|
|
9360
|
-
{
|
|
9361
|
-
"path": "precision",
|
|
9362
|
-
"valueType": "number"
|
|
9363
|
-
},
|
|
9364
|
-
{
|
|
9365
|
-
"path": "format",
|
|
9366
|
-
"valueType": "enum",
|
|
9367
|
-
"enumValues": [
|
|
9368
|
-
"date",
|
|
9369
|
-
"time",
|
|
9370
|
-
"datetime"
|
|
9371
|
-
]
|
|
9372
9446
|
}
|
|
9373
9447
|
],
|
|
9374
9448
|
"cover": [
|
|
@@ -9609,13 +9683,8 @@ Object.freeze({
|
|
|
9609
9683
|
"path": "value",
|
|
9610
9684
|
"valueType": "string"
|
|
9611
9685
|
}, {
|
|
9612
|
-
"path": "
|
|
9613
|
-
"valueType": "
|
|
9614
|
-
"enumValues": [
|
|
9615
|
-
"date",
|
|
9616
|
-
"time",
|
|
9617
|
-
"datetime"
|
|
9618
|
-
]
|
|
9686
|
+
"path": "timestamp",
|
|
9687
|
+
"valueType": "boolean"
|
|
9619
9688
|
}],
|
|
9620
9689
|
"event-emitter": [
|
|
9621
9690
|
{
|
|
@@ -9688,6 +9757,24 @@ Object.freeze({
|
|
|
9688
9757
|
"path": "detected",
|
|
9689
9758
|
"valueType": "boolean"
|
|
9690
9759
|
}],
|
|
9760
|
+
"group-active": [{
|
|
9761
|
+
"path": "active",
|
|
9762
|
+
"valueType": "boolean"
|
|
9763
|
+
}],
|
|
9764
|
+
"group-status": [
|
|
9765
|
+
{
|
|
9766
|
+
"path": "included",
|
|
9767
|
+
"valueType": "number"
|
|
9768
|
+
},
|
|
9769
|
+
{
|
|
9770
|
+
"path": "excluded",
|
|
9771
|
+
"valueType": "number"
|
|
9772
|
+
},
|
|
9773
|
+
{
|
|
9774
|
+
"path": "total",
|
|
9775
|
+
"valueType": "number"
|
|
9776
|
+
}
|
|
9777
|
+
],
|
|
9691
9778
|
"heating-valve": [{
|
|
9692
9779
|
"path": "position",
|
|
9693
9780
|
"valueType": "number"
|
|
@@ -9722,20 +9809,10 @@ Object.freeze({
|
|
|
9722
9809
|
"valueType": "number"
|
|
9723
9810
|
}
|
|
9724
9811
|
],
|
|
9725
|
-
"humidity-sensor": [
|
|
9726
|
-
|
|
9727
|
-
|
|
9728
|
-
|
|
9729
|
-
},
|
|
9730
|
-
{
|
|
9731
|
-
"path": "unit",
|
|
9732
|
-
"valueType": "string"
|
|
9733
|
-
},
|
|
9734
|
-
{
|
|
9735
|
-
"path": "precision",
|
|
9736
|
-
"valueType": "number"
|
|
9737
|
-
}
|
|
9738
|
-
],
|
|
9812
|
+
"humidity-sensor": [{
|
|
9813
|
+
"path": "percent",
|
|
9814
|
+
"valueType": "number"
|
|
9815
|
+
}],
|
|
9739
9816
|
"image": [{
|
|
9740
9817
|
"path": "url",
|
|
9741
9818
|
"valueType": "string"
|
|
@@ -9943,6 +10020,10 @@ Object.freeze({
|
|
|
9943
10020
|
]
|
|
9944
10021
|
}
|
|
9945
10022
|
],
|
|
10023
|
+
"meter": [{
|
|
10024
|
+
"path": "value",
|
|
10025
|
+
"valueType": "number"
|
|
10026
|
+
}],
|
|
9946
10027
|
"motion": [
|
|
9947
10028
|
{
|
|
9948
10029
|
"path": "detected",
|
|
@@ -10074,20 +10155,10 @@ Object.freeze({
|
|
|
10074
10155
|
"valueType": "boolean"
|
|
10075
10156
|
}
|
|
10076
10157
|
],
|
|
10077
|
-
"numeric-sensor": [
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
},
|
|
10082
|
-
{
|
|
10083
|
-
"path": "unit",
|
|
10084
|
-
"valueType": "string"
|
|
10085
|
-
},
|
|
10086
|
-
{
|
|
10087
|
-
"path": "precision",
|
|
10088
|
-
"valueType": "number"
|
|
10089
|
-
}
|
|
10090
|
-
],
|
|
10158
|
+
"numeric-sensor": [{
|
|
10159
|
+
"path": "value",
|
|
10160
|
+
"valueType": "number"
|
|
10161
|
+
}],
|
|
10091
10162
|
"pet-feeder": [
|
|
10092
10163
|
{
|
|
10093
10164
|
"path": "foodLevel",
|
|
@@ -10179,14 +10250,6 @@ Object.freeze({
|
|
|
10179
10250
|
{
|
|
10180
10251
|
"path": "powerFactor",
|
|
10181
10252
|
"valueType": "number"
|
|
10182
|
-
},
|
|
10183
|
-
{
|
|
10184
|
-
"path": "unit",
|
|
10185
|
-
"valueType": "string"
|
|
10186
|
-
},
|
|
10187
|
-
{
|
|
10188
|
-
"path": "precision",
|
|
10189
|
-
"valueType": "number"
|
|
10190
10253
|
}
|
|
10191
10254
|
],
|
|
10192
10255
|
"presence": [
|
|
@@ -10215,20 +10278,10 @@ Object.freeze({
|
|
|
10215
10278
|
"valueType": "number"
|
|
10216
10279
|
}
|
|
10217
10280
|
],
|
|
10218
|
-
"pressure-sensor": [
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
},
|
|
10223
|
-
{
|
|
10224
|
-
"path": "unit",
|
|
10225
|
-
"valueType": "string"
|
|
10226
|
-
},
|
|
10227
|
-
{
|
|
10228
|
-
"path": "precision",
|
|
10229
|
-
"valueType": "number"
|
|
10230
|
-
}
|
|
10231
|
-
],
|
|
10281
|
+
"pressure-sensor": [{
|
|
10282
|
+
"path": "hpa",
|
|
10283
|
+
"valueType": "number"
|
|
10284
|
+
}],
|
|
10232
10285
|
"privacy-mask": [{
|
|
10233
10286
|
"path": "enabled",
|
|
10234
10287
|
"valueType": "boolean"
|
|
@@ -10539,20 +10592,10 @@ Object.freeze({
|
|
|
10539
10592
|
"path": "tampered",
|
|
10540
10593
|
"valueType": "boolean"
|
|
10541
10594
|
}],
|
|
10542
|
-
"temperature-sensor": [
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
},
|
|
10547
|
-
{
|
|
10548
|
-
"path": "unit",
|
|
10549
|
-
"valueType": "string"
|
|
10550
|
-
},
|
|
10551
|
-
{
|
|
10552
|
-
"path": "precision",
|
|
10553
|
-
"valueType": "number"
|
|
10554
|
-
}
|
|
10555
|
-
],
|
|
10595
|
+
"temperature-sensor": [{
|
|
10596
|
+
"path": "celsius",
|
|
10597
|
+
"valueType": "number"
|
|
10598
|
+
}],
|
|
10556
10599
|
"update": [
|
|
10557
10600
|
{
|
|
10558
10601
|
"path": "currentVersion",
|
|
@@ -10663,10 +10706,6 @@ Object.freeze({
|
|
|
10663
10706
|
"path": "temperature",
|
|
10664
10707
|
"valueType": "number"
|
|
10665
10708
|
},
|
|
10666
|
-
{
|
|
10667
|
-
"path": "temperatureUnit",
|
|
10668
|
-
"valueType": "string"
|
|
10669
|
-
},
|
|
10670
10709
|
{
|
|
10671
10710
|
"path": "humidity",
|
|
10672
10711
|
"valueType": "number"
|
|
@@ -10675,18 +10714,10 @@ Object.freeze({
|
|
|
10675
10714
|
"path": "pressure",
|
|
10676
10715
|
"valueType": "number"
|
|
10677
10716
|
},
|
|
10678
|
-
{
|
|
10679
|
-
"path": "pressureUnit",
|
|
10680
|
-
"valueType": "string"
|
|
10681
|
-
},
|
|
10682
10717
|
{
|
|
10683
10718
|
"path": "windSpeed",
|
|
10684
10719
|
"valueType": "number"
|
|
10685
10720
|
},
|
|
10686
|
-
{
|
|
10687
|
-
"path": "windSpeedUnit",
|
|
10688
|
-
"valueType": "string"
|
|
10689
|
-
},
|
|
10690
10721
|
{
|
|
10691
10722
|
"path": "windBearing",
|
|
10692
10723
|
"valueType": "number"
|
|
@@ -10750,7 +10781,7 @@ function userError(code, params, englishFallback) {
|
|
|
10750
10781
|
return new CamstackError(code, params, englishFallback);
|
|
10751
10782
|
}
|
|
10752
10783
|
//#endregion
|
|
10753
|
-
//#region ../types/dist/err-msg-
|
|
10784
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10754
10785
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10755
10786
|
DeviceType["Camera"] = "camera";
|
|
10756
10787
|
DeviceType["Hub"] = "hub";
|
|
@@ -10844,8 +10875,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10844
10875
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10845
10876
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10846
10877
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10847
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10878
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10879
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10848
10880
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10881
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10882
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10883
|
+
DeviceType["Washer"] = "washer";
|
|
10884
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10885
|
+
DeviceType["Dryer"] = "dryer";
|
|
10849
10886
|
return DeviceType;
|
|
10850
10887
|
}({});
|
|
10851
10888
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11093,7 +11130,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11093
11130
|
return DeviceRole;
|
|
11094
11131
|
}({});
|
|
11095
11132
|
//#endregion
|
|
11096
|
-
//#region ../types/dist/composition-
|
|
11133
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11097
11134
|
/**
|
|
11098
11135
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11099
11136
|
*
|
|
@@ -11408,6 +11445,13 @@ var table = {
|
|
|
11408
11445
|
apply: () => {
|
|
11409
11446
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11410
11447
|
}
|
|
11448
|
+
},
|
|
11449
|
+
schmitt: {
|
|
11450
|
+
minArgs: 3,
|
|
11451
|
+
maxArgs: 5,
|
|
11452
|
+
apply: () => {
|
|
11453
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11454
|
+
}
|
|
11411
11455
|
}
|
|
11412
11456
|
};
|
|
11413
11457
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11848,15 +11892,232 @@ function validateExpressionSource(src) {
|
|
|
11848
11892
|
}
|
|
11849
11893
|
return null;
|
|
11850
11894
|
}
|
|
11851
|
-
/**
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11895
|
+
/**
|
|
11896
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11897
|
+
*
|
|
11898
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11899
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11900
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11901
|
+
*
|
|
11902
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11903
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11904
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11905
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11906
|
+
* can move later without moving the others.
|
|
11907
|
+
*/
|
|
11908
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11909
|
+
var APPLIANCE_KINDS = [
|
|
11910
|
+
"washer",
|
|
11911
|
+
"dryer",
|
|
11912
|
+
"dishwasher"
|
|
11913
|
+
];
|
|
11914
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11915
|
+
/**
|
|
11916
|
+
* Statistics and integrals over a history read (D944).
|
|
11917
|
+
*
|
|
11918
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11919
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11920
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11921
|
+
* as zero. A truncated read is not published.
|
|
11922
|
+
*/
|
|
11923
|
+
var STATISTIC_STATS = [
|
|
11924
|
+
"min",
|
|
11925
|
+
"max",
|
|
11926
|
+
"mean",
|
|
11927
|
+
"sum",
|
|
11928
|
+
"count",
|
|
11929
|
+
"change"
|
|
11930
|
+
];
|
|
11931
|
+
/**
|
|
11932
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11933
|
+
*
|
|
11934
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11935
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11936
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11937
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11938
|
+
*/
|
|
11939
|
+
var MINUTE_MS = 6e4;
|
|
11940
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11941
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11942
|
+
var ROLLING_SPANS = [
|
|
11943
|
+
"1h",
|
|
11944
|
+
"24h",
|
|
11945
|
+
"2d",
|
|
11946
|
+
"7d",
|
|
11947
|
+
"30d",
|
|
11948
|
+
"custom"
|
|
11949
|
+
];
|
|
11950
|
+
var CALENDAR_PERIODS = [
|
|
11951
|
+
"today",
|
|
11952
|
+
"yesterday",
|
|
11953
|
+
"this-week",
|
|
11954
|
+
"this-month"
|
|
11955
|
+
];
|
|
11956
|
+
var RESET_PERIODS = [
|
|
11957
|
+
"never",
|
|
11958
|
+
"daily",
|
|
11959
|
+
"weekly",
|
|
11960
|
+
"monthly"
|
|
11961
|
+
];
|
|
11962
|
+
5 * MINUTE_MS;
|
|
11963
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11964
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11965
|
+
var rollingWindowObject = object({
|
|
11966
|
+
kind: literal("rolling"),
|
|
11967
|
+
span: _enum(ROLLING_SPANS),
|
|
11968
|
+
customMinutes: number().int().min(5).optional()
|
|
11969
|
+
}).check((payload) => {
|
|
11970
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11971
|
+
code: "custom",
|
|
11972
|
+
message: "a custom range needs a duration in minutes",
|
|
11973
|
+
path: ["customMinutes"],
|
|
11974
|
+
input: payload.value
|
|
11975
|
+
});
|
|
11976
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11977
|
+
code: "custom",
|
|
11978
|
+
message: "only a custom range carries a duration",
|
|
11979
|
+
path: ["customMinutes"],
|
|
11980
|
+
input: payload.value
|
|
11981
|
+
});
|
|
11982
|
+
});
|
|
11983
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
11984
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
11985
|
+
kind: literal("calendar"),
|
|
11986
|
+
period: _enum(CALENDAR_PERIODS)
|
|
11987
|
+
})]);
|
|
11988
|
+
/**
|
|
11989
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11990
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11991
|
+
* `composition.ts` (D659).
|
|
11992
|
+
*/
|
|
11855
11993
|
var CompositionSourceRefSchema = object({
|
|
11856
11994
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11857
11995
|
addonId: string().min(1),
|
|
11858
11996
|
stableId: string().min(1)
|
|
11859
11997
|
});
|
|
11998
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11999
|
+
"temperature",
|
|
12000
|
+
"humidity",
|
|
12001
|
+
"pressure",
|
|
12002
|
+
"illuminance",
|
|
12003
|
+
"power",
|
|
12004
|
+
"energy",
|
|
12005
|
+
"battery",
|
|
12006
|
+
"numeric",
|
|
12007
|
+
"motion",
|
|
12008
|
+
"contact",
|
|
12009
|
+
"leak",
|
|
12010
|
+
"smoke",
|
|
12011
|
+
"occupancy",
|
|
12012
|
+
"binary",
|
|
12013
|
+
"switch",
|
|
12014
|
+
"light",
|
|
12015
|
+
"fan",
|
|
12016
|
+
"cover",
|
|
12017
|
+
"valve",
|
|
12018
|
+
"lock",
|
|
12019
|
+
"media-player",
|
|
12020
|
+
"climate"
|
|
12021
|
+
];
|
|
12022
|
+
var NUMERIC_AGGREGATES = [
|
|
12023
|
+
"mean",
|
|
12024
|
+
"median",
|
|
12025
|
+
"min",
|
|
12026
|
+
"max",
|
|
12027
|
+
"sum"
|
|
12028
|
+
];
|
|
12029
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12030
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12031
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12032
|
+
var AGGREGATE_REDUCERS = [
|
|
12033
|
+
"mean",
|
|
12034
|
+
"median",
|
|
12035
|
+
"min",
|
|
12036
|
+
"max",
|
|
12037
|
+
"sum",
|
|
12038
|
+
"any",
|
|
12039
|
+
"all"
|
|
12040
|
+
];
|
|
12041
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12042
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12043
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12044
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12045
|
+
var HelperMemberSchema = object({
|
|
12046
|
+
source: CompositionSourceRefSchema,
|
|
12047
|
+
cap: string().min(1),
|
|
12048
|
+
fieldPath: string().min(1)
|
|
12049
|
+
});
|
|
12050
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12051
|
+
object({
|
|
12052
|
+
kind: literal("group"),
|
|
12053
|
+
templateId: GroupTemplateIdSchema,
|
|
12054
|
+
aggregate: AggregateReducerSchema,
|
|
12055
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12056
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12057
|
+
active: ActiveCriterionSchema.optional()
|
|
12058
|
+
}),
|
|
12059
|
+
object({
|
|
12060
|
+
kind: literal("appliance"),
|
|
12061
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12062
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12063
|
+
thresholdWatts: number().positive(),
|
|
12064
|
+
startDwellMs: number().int().nonnegative(),
|
|
12065
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12066
|
+
member: HelperMemberSchema
|
|
12067
|
+
}),
|
|
12068
|
+
object({
|
|
12069
|
+
kind: literal("statistic"),
|
|
12070
|
+
stat: _enum(STATISTIC_STATS),
|
|
12071
|
+
window: StatisticWindowSchema,
|
|
12072
|
+
source: HelperMemberSchema
|
|
12073
|
+
}),
|
|
12074
|
+
object({
|
|
12075
|
+
kind: literal("integral"),
|
|
12076
|
+
reset: _enum(RESET_PERIODS),
|
|
12077
|
+
output: _enum(["energy", "meter"]),
|
|
12078
|
+
source: HelperMemberSchema
|
|
12079
|
+
}),
|
|
12080
|
+
object({
|
|
12081
|
+
kind: literal("threshold"),
|
|
12082
|
+
source: HelperMemberSchema,
|
|
12083
|
+
high: number(),
|
|
12084
|
+
low: number(),
|
|
12085
|
+
onForMs: number().int().nonnegative(),
|
|
12086
|
+
offForMs: number().int().nonnegative()
|
|
12087
|
+
}),
|
|
12088
|
+
object({
|
|
12089
|
+
kind: literal("arithmetic"),
|
|
12090
|
+
op: _enum([
|
|
12091
|
+
"sum",
|
|
12092
|
+
"difference",
|
|
12093
|
+
"ratio"
|
|
12094
|
+
]),
|
|
12095
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12096
|
+
}),
|
|
12097
|
+
object({
|
|
12098
|
+
kind: literal("expression"),
|
|
12099
|
+
expr: string().min(1),
|
|
12100
|
+
inputs: array(object({
|
|
12101
|
+
name: string().min(1),
|
|
12102
|
+
member: HelperMemberSchema
|
|
12103
|
+
})).min(1).max(64),
|
|
12104
|
+
output: _enum(["number", "boolean"])
|
|
12105
|
+
}),
|
|
12106
|
+
object({
|
|
12107
|
+
kind: literal("derivative"),
|
|
12108
|
+
window: RollingWindowSchema,
|
|
12109
|
+
per: _enum([
|
|
12110
|
+
"second",
|
|
12111
|
+
"minute",
|
|
12112
|
+
"hour"
|
|
12113
|
+
]),
|
|
12114
|
+
source: HelperMemberSchema
|
|
12115
|
+
})
|
|
12116
|
+
]);
|
|
12117
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12118
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12119
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12120
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11860
12121
|
/** One field of one capability of one source device. */
|
|
11861
12122
|
var CompositionFieldReadSchema = object({
|
|
11862
12123
|
source: CompositionSourceRefSchema,
|
|
@@ -11900,7 +12161,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11900
12161
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11901
12162
|
CompositionFromSourceSchema,
|
|
11902
12163
|
CompositionExpressionSourceSchema,
|
|
11903
|
-
CompositionCodeSourceSchema
|
|
12164
|
+
CompositionCodeSourceSchema,
|
|
12165
|
+
object({
|
|
12166
|
+
kind: literal("aggregate"),
|
|
12167
|
+
reducer: _enum([
|
|
12168
|
+
"mean",
|
|
12169
|
+
"median",
|
|
12170
|
+
"min",
|
|
12171
|
+
"max",
|
|
12172
|
+
"sum",
|
|
12173
|
+
"any",
|
|
12174
|
+
"all"
|
|
12175
|
+
]),
|
|
12176
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12177
|
+
/**
|
|
12178
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12179
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12180
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12181
|
+
*/
|
|
12182
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12183
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12184
|
+
publish: _enum([
|
|
12185
|
+
"value",
|
|
12186
|
+
"included",
|
|
12187
|
+
"excluded",
|
|
12188
|
+
"total"
|
|
12189
|
+
]),
|
|
12190
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12191
|
+
empty: _enum([
|
|
12192
|
+
"null",
|
|
12193
|
+
"omit",
|
|
12194
|
+
"offline"
|
|
12195
|
+
])
|
|
12196
|
+
}),
|
|
12197
|
+
object({
|
|
12198
|
+
kind: literal("series"),
|
|
12199
|
+
read: CompositionFieldReadSchema,
|
|
12200
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12201
|
+
publish: _enum([
|
|
12202
|
+
"value",
|
|
12203
|
+
"included",
|
|
12204
|
+
"excluded",
|
|
12205
|
+
"total"
|
|
12206
|
+
]),
|
|
12207
|
+
/**
|
|
12208
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12209
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12210
|
+
*/
|
|
12211
|
+
empty: _enum([
|
|
12212
|
+
"null",
|
|
12213
|
+
"omit",
|
|
12214
|
+
"offline"
|
|
12215
|
+
])
|
|
12216
|
+
})
|
|
11904
12217
|
]);
|
|
11905
12218
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11906
12219
|
kind: literal("forward"),
|
|
@@ -11946,7 +12259,13 @@ var CompositionSchema = object({
|
|
|
11946
12259
|
kind: literal("existing"),
|
|
11947
12260
|
device: CompositionSourceRefSchema
|
|
11948
12261
|
})]),
|
|
11949
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12262
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12263
|
+
/**
|
|
12264
|
+
* Present when the block is a helper template. Absent on a free
|
|
12265
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12266
|
+
* never the compiled features.
|
|
12267
|
+
*/
|
|
12268
|
+
helper: HelperSpecSchema.optional()
|
|
11950
12269
|
}).superRefine((composition, ctx) => {
|
|
11951
12270
|
const seen = /* @__PURE__ */ new Set();
|
|
11952
12271
|
composition.features.forEach((feature, index) => {
|
|
@@ -17189,7 +17508,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17189
17508
|
*/
|
|
17190
17509
|
interactiveConnectPath: string().min(1).optional(),
|
|
17191
17510
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17192
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17511
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17512
|
+
/**
|
|
17513
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17514
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17515
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17516
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17517
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17518
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17519
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17520
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17521
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17522
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17523
|
+
* offers it as the default path; the fields the session fills are
|
|
17524
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17525
|
+
*/
|
|
17526
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17193
17527
|
}))
|
|
17194
17528
|
});
|
|
17195
17529
|
var ListInputSchema = object({
|
|
@@ -18184,7 +18518,12 @@ var CompositionProblemSchema = object({
|
|
|
18184
18518
|
"item-field-reserved",
|
|
18185
18519
|
"target-missing",
|
|
18186
18520
|
"target-unreadable",
|
|
18187
|
-
"not-replaceable"
|
|
18521
|
+
"not-replaceable",
|
|
18522
|
+
"native-capability-replace",
|
|
18523
|
+
"mixed-quantity",
|
|
18524
|
+
"helper-mismatch",
|
|
18525
|
+
"member-constraint",
|
|
18526
|
+
"retention"
|
|
18188
18527
|
]),
|
|
18189
18528
|
path: string(),
|
|
18190
18529
|
message: string()
|
|
@@ -18205,7 +18544,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18205
18544
|
"null",
|
|
18206
18545
|
"offline",
|
|
18207
18546
|
"unknown",
|
|
18208
|
-
"release"
|
|
18547
|
+
"release",
|
|
18548
|
+
"omit"
|
|
18209
18549
|
]);
|
|
18210
18550
|
/**
|
|
18211
18551
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18242,9 +18582,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18242
18582
|
reads: array(CompositionFieldReadSchema)
|
|
18243
18583
|
});
|
|
18244
18584
|
/**
|
|
18245
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18246
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18247
|
-
*
|
|
18585
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18586
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18587
|
+
* Replacing a capability the device already serves is refused
|
|
18588
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18589
|
+
* wire for a claim the hub already holds.
|
|
18248
18590
|
*/
|
|
18249
18591
|
var CompositionFeatureModeSchema = _enum([
|
|
18250
18592
|
"new",
|
|
@@ -18415,8 +18757,392 @@ Object.freeze({
|
|
|
18415
18757
|
latchedAt: {
|
|
18416
18758
|
kind: "fixed",
|
|
18417
18759
|
result: ["number", "null"]
|
|
18760
|
+
},
|
|
18761
|
+
schmitt: {
|
|
18762
|
+
kind: "fixed",
|
|
18763
|
+
result: ["boolean", "null"]
|
|
18418
18764
|
}
|
|
18419
18765
|
});
|
|
18766
|
+
/**
|
|
18767
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18768
|
+
* Data, not a form default written into the block.
|
|
18769
|
+
*/
|
|
18770
|
+
var NOW$2 = {
|
|
18771
|
+
fieldPath: "lastFetchedAt",
|
|
18772
|
+
expr: "now"
|
|
18773
|
+
};
|
|
18774
|
+
var CHANGED = {
|
|
18775
|
+
fieldPath: "lastChangedAt",
|
|
18776
|
+
expr: "now"
|
|
18777
|
+
};
|
|
18778
|
+
function numeric(input) {
|
|
18779
|
+
return {
|
|
18780
|
+
...input,
|
|
18781
|
+
family: "numeric",
|
|
18782
|
+
deviceType: DeviceType.Sensor,
|
|
18783
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18784
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18785
|
+
activeWhen: void 0,
|
|
18786
|
+
commandCaps: [],
|
|
18787
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18788
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18789
|
+
accept: [{
|
|
18790
|
+
cap: input.outputCap,
|
|
18791
|
+
fieldPath: input.outputField
|
|
18792
|
+
}]
|
|
18793
|
+
};
|
|
18794
|
+
}
|
|
18795
|
+
function binary(input) {
|
|
18796
|
+
return {
|
|
18797
|
+
...input,
|
|
18798
|
+
family: "binary",
|
|
18799
|
+
deviceType: DeviceType.Sensor,
|
|
18800
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18801
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18802
|
+
activeWhen: void 0,
|
|
18803
|
+
commandCaps: [],
|
|
18804
|
+
quantity: "none",
|
|
18805
|
+
baseUnit: void 0,
|
|
18806
|
+
aggregates: BINARY_AGGREGATES,
|
|
18807
|
+
empty: "offline"
|
|
18808
|
+
};
|
|
18809
|
+
}
|
|
18810
|
+
var GROUP_TEMPLATES = [
|
|
18811
|
+
numeric({
|
|
18812
|
+
id: "temperature",
|
|
18813
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18814
|
+
role: DeviceRole.TemperatureSensor,
|
|
18815
|
+
outputCap: "temperature-sensor",
|
|
18816
|
+
outputField: "celsius",
|
|
18817
|
+
quantity: "temperature",
|
|
18818
|
+
defaultAggregate: "mean",
|
|
18819
|
+
empty: "null",
|
|
18820
|
+
companions: [NOW$2]
|
|
18821
|
+
}),
|
|
18822
|
+
numeric({
|
|
18823
|
+
id: "humidity",
|
|
18824
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18825
|
+
role: DeviceRole.HumiditySensor,
|
|
18826
|
+
outputCap: "humidity-sensor",
|
|
18827
|
+
outputField: "percent",
|
|
18828
|
+
quantity: "humidity",
|
|
18829
|
+
defaultAggregate: "mean",
|
|
18830
|
+
empty: "null",
|
|
18831
|
+
companions: [NOW$2]
|
|
18832
|
+
}),
|
|
18833
|
+
numeric({
|
|
18834
|
+
id: "pressure",
|
|
18835
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18836
|
+
role: DeviceRole.PressureSensor,
|
|
18837
|
+
outputCap: "pressure-sensor",
|
|
18838
|
+
outputField: "hpa",
|
|
18839
|
+
quantity: "pressure",
|
|
18840
|
+
defaultAggregate: "mean",
|
|
18841
|
+
empty: "null",
|
|
18842
|
+
companions: [NOW$2]
|
|
18843
|
+
}),
|
|
18844
|
+
numeric({
|
|
18845
|
+
id: "illuminance",
|
|
18846
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18847
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18848
|
+
outputCap: "ambient-light-sensor",
|
|
18849
|
+
outputField: "lux",
|
|
18850
|
+
quantity: "illuminance",
|
|
18851
|
+
defaultAggregate: "mean",
|
|
18852
|
+
empty: "null",
|
|
18853
|
+
companions: [NOW$2]
|
|
18854
|
+
}),
|
|
18855
|
+
numeric({
|
|
18856
|
+
id: "power",
|
|
18857
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18858
|
+
role: DeviceRole.PowerSensor,
|
|
18859
|
+
outputCap: "power-meter",
|
|
18860
|
+
outputField: "watts",
|
|
18861
|
+
quantity: "power",
|
|
18862
|
+
defaultAggregate: "sum",
|
|
18863
|
+
empty: "omit",
|
|
18864
|
+
companions: [NOW$2]
|
|
18865
|
+
}),
|
|
18866
|
+
numeric({
|
|
18867
|
+
id: "energy",
|
|
18868
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18869
|
+
role: DeviceRole.EnergySensor,
|
|
18870
|
+
outputCap: "power-meter",
|
|
18871
|
+
outputField: "kwhTotal",
|
|
18872
|
+
quantity: "energy",
|
|
18873
|
+
defaultAggregate: "sum",
|
|
18874
|
+
empty: "omit",
|
|
18875
|
+
companions: [NOW$2]
|
|
18876
|
+
}),
|
|
18877
|
+
numeric({
|
|
18878
|
+
id: "battery",
|
|
18879
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18880
|
+
role: DeviceRole.BatterySensor,
|
|
18881
|
+
outputCap: "battery",
|
|
18882
|
+
outputField: "percentage",
|
|
18883
|
+
quantity: "percentage",
|
|
18884
|
+
defaultAggregate: "mean",
|
|
18885
|
+
empty: "null",
|
|
18886
|
+
companions: [
|
|
18887
|
+
{
|
|
18888
|
+
fieldPath: "charging",
|
|
18889
|
+
expr: "\"unknown\""
|
|
18890
|
+
},
|
|
18891
|
+
{
|
|
18892
|
+
fieldPath: "sleeping",
|
|
18893
|
+
expr: "false"
|
|
18894
|
+
},
|
|
18895
|
+
{
|
|
18896
|
+
fieldPath: "lastUpdated",
|
|
18897
|
+
expr: "now"
|
|
18898
|
+
}
|
|
18899
|
+
]
|
|
18900
|
+
}),
|
|
18901
|
+
numeric({
|
|
18902
|
+
id: "numeric",
|
|
18903
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18904
|
+
role: DeviceRole.NumericSensor,
|
|
18905
|
+
outputCap: "numeric-sensor",
|
|
18906
|
+
outputField: "value",
|
|
18907
|
+
quantity: "device",
|
|
18908
|
+
defaultAggregate: "mean",
|
|
18909
|
+
empty: "null",
|
|
18910
|
+
companions: [NOW$2]
|
|
18911
|
+
}),
|
|
18912
|
+
binary({
|
|
18913
|
+
id: "motion",
|
|
18914
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18915
|
+
role: DeviceRole.MotionSensor,
|
|
18916
|
+
outputCap: "motion",
|
|
18917
|
+
outputField: "detected",
|
|
18918
|
+
defaultAggregate: "any",
|
|
18919
|
+
accept: [{
|
|
18920
|
+
cap: "motion",
|
|
18921
|
+
fieldPath: "detected"
|
|
18922
|
+
}],
|
|
18923
|
+
companions: [{
|
|
18924
|
+
fieldPath: "lastDetectedAt",
|
|
18925
|
+
expr: "null"
|
|
18926
|
+
}, {
|
|
18927
|
+
fieldPath: "autoClearAfterMs",
|
|
18928
|
+
expr: "null"
|
|
18929
|
+
}]
|
|
18930
|
+
}),
|
|
18931
|
+
binary({
|
|
18932
|
+
id: "contact",
|
|
18933
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18934
|
+
role: DeviceRole.ContactSensor,
|
|
18935
|
+
outputCap: "contact",
|
|
18936
|
+
outputField: "entryOpen",
|
|
18937
|
+
defaultAggregate: "any",
|
|
18938
|
+
accept: [{
|
|
18939
|
+
cap: "contact",
|
|
18940
|
+
fieldPath: "entryOpen"
|
|
18941
|
+
}],
|
|
18942
|
+
companions: [CHANGED]
|
|
18943
|
+
}),
|
|
18944
|
+
binary({
|
|
18945
|
+
id: "leak",
|
|
18946
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18947
|
+
role: DeviceRole.LeakSensor,
|
|
18948
|
+
outputCap: "flood",
|
|
18949
|
+
outputField: "flooded",
|
|
18950
|
+
defaultAggregate: "any",
|
|
18951
|
+
accept: [{
|
|
18952
|
+
cap: "flood",
|
|
18953
|
+
fieldPath: "flooded"
|
|
18954
|
+
}],
|
|
18955
|
+
companions: [CHANGED]
|
|
18956
|
+
}),
|
|
18957
|
+
binary({
|
|
18958
|
+
id: "smoke",
|
|
18959
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18960
|
+
role: DeviceRole.SmokeSensor,
|
|
18961
|
+
outputCap: "smoke",
|
|
18962
|
+
outputField: "detected",
|
|
18963
|
+
defaultAggregate: "any",
|
|
18964
|
+
accept: [{
|
|
18965
|
+
cap: "smoke",
|
|
18966
|
+
fieldPath: "detected"
|
|
18967
|
+
}],
|
|
18968
|
+
companions: [CHANGED]
|
|
18969
|
+
}),
|
|
18970
|
+
binary({
|
|
18971
|
+
id: "occupancy",
|
|
18972
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18973
|
+
role: DeviceRole.BinarySensor,
|
|
18974
|
+
outputCap: "binary",
|
|
18975
|
+
outputField: "on",
|
|
18976
|
+
defaultAggregate: "any",
|
|
18977
|
+
accept: [{
|
|
18978
|
+
cap: "motion",
|
|
18979
|
+
fieldPath: "detected"
|
|
18980
|
+
}, {
|
|
18981
|
+
cap: "binary",
|
|
18982
|
+
fieldPath: "on"
|
|
18983
|
+
}],
|
|
18984
|
+
companions: [CHANGED]
|
|
18985
|
+
}),
|
|
18986
|
+
binary({
|
|
18987
|
+
id: "binary",
|
|
18988
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18989
|
+
role: DeviceRole.BinarySensor,
|
|
18990
|
+
outputCap: "binary",
|
|
18991
|
+
outputField: "on",
|
|
18992
|
+
defaultAggregate: "any",
|
|
18993
|
+
accept: [{
|
|
18994
|
+
cap: "binary",
|
|
18995
|
+
fieldPath: "on"
|
|
18996
|
+
}],
|
|
18997
|
+
companions: [CHANGED]
|
|
18998
|
+
}),
|
|
18999
|
+
actuator({
|
|
19000
|
+
id: "switch",
|
|
19001
|
+
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.",
|
|
19002
|
+
deviceType: DeviceType.Switch,
|
|
19003
|
+
outputCap: "switch",
|
|
19004
|
+
outputField: "on",
|
|
19005
|
+
member: {
|
|
19006
|
+
cap: "switch",
|
|
19007
|
+
fieldPath: "on"
|
|
19008
|
+
},
|
|
19009
|
+
commandCaps: ["switch"]
|
|
19010
|
+
}),
|
|
19011
|
+
actuator({
|
|
19012
|
+
id: "light",
|
|
19013
|
+
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.",
|
|
19014
|
+
deviceType: DeviceType.Light,
|
|
19015
|
+
outputCap: "switch",
|
|
19016
|
+
outputField: "on",
|
|
19017
|
+
member: {
|
|
19018
|
+
cap: "switch",
|
|
19019
|
+
fieldPath: "on"
|
|
19020
|
+
},
|
|
19021
|
+
commandCaps: [
|
|
19022
|
+
"switch",
|
|
19023
|
+
"brightness",
|
|
19024
|
+
"color"
|
|
19025
|
+
]
|
|
19026
|
+
}),
|
|
19027
|
+
actuator({
|
|
19028
|
+
id: "fan",
|
|
19029
|
+
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.",
|
|
19030
|
+
deviceType: DeviceType.Fan,
|
|
19031
|
+
outputCap: "switch",
|
|
19032
|
+
outputField: "on",
|
|
19033
|
+
member: {
|
|
19034
|
+
cap: "switch",
|
|
19035
|
+
fieldPath: "on"
|
|
19036
|
+
},
|
|
19037
|
+
commandCaps: ["switch", "fan-control"]
|
|
19038
|
+
}),
|
|
19039
|
+
actuator({
|
|
19040
|
+
id: "cover",
|
|
19041
|
+
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.",
|
|
19042
|
+
deviceType: DeviceType.Cover,
|
|
19043
|
+
outputCap: "group-active",
|
|
19044
|
+
outputField: "active",
|
|
19045
|
+
member: {
|
|
19046
|
+
cap: "cover",
|
|
19047
|
+
fieldPath: "state"
|
|
19048
|
+
},
|
|
19049
|
+
activeWhen: [
|
|
19050
|
+
"open",
|
|
19051
|
+
"opening",
|
|
19052
|
+
"stopped"
|
|
19053
|
+
],
|
|
19054
|
+
commandCaps: ["cover"]
|
|
19055
|
+
}),
|
|
19056
|
+
actuator({
|
|
19057
|
+
id: "valve",
|
|
19058
|
+
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.",
|
|
19059
|
+
deviceType: DeviceType.Valve,
|
|
19060
|
+
outputCap: "group-active",
|
|
19061
|
+
outputField: "active",
|
|
19062
|
+
member: {
|
|
19063
|
+
cap: "valve",
|
|
19064
|
+
fieldPath: "state"
|
|
19065
|
+
},
|
|
19066
|
+
activeWhen: [
|
|
19067
|
+
"open",
|
|
19068
|
+
"opening",
|
|
19069
|
+
"stopped"
|
|
19070
|
+
],
|
|
19071
|
+
commandCaps: ["valve"]
|
|
19072
|
+
}),
|
|
19073
|
+
actuator({
|
|
19074
|
+
id: "lock",
|
|
19075
|
+
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.",
|
|
19076
|
+
deviceType: DeviceType.Lock,
|
|
19077
|
+
outputCap: "group-active",
|
|
19078
|
+
outputField: "active",
|
|
19079
|
+
member: {
|
|
19080
|
+
cap: "lock-control",
|
|
19081
|
+
fieldPath: "state"
|
|
19082
|
+
},
|
|
19083
|
+
activeWhen: ["locked"],
|
|
19084
|
+
commandCaps: ["lock-control"]
|
|
19085
|
+
}),
|
|
19086
|
+
actuator({
|
|
19087
|
+
id: "media-player",
|
|
19088
|
+
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.",
|
|
19089
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19090
|
+
outputCap: "group-active",
|
|
19091
|
+
outputField: "active",
|
|
19092
|
+
member: {
|
|
19093
|
+
cap: "media-player",
|
|
19094
|
+
fieldPath: "state"
|
|
19095
|
+
},
|
|
19096
|
+
activeWhen: ["playing", "buffering"],
|
|
19097
|
+
commandCaps: ["media-player"]
|
|
19098
|
+
}),
|
|
19099
|
+
actuator({
|
|
19100
|
+
id: "climate",
|
|
19101
|
+
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.",
|
|
19102
|
+
deviceType: DeviceType.Thermostat,
|
|
19103
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19104
|
+
outputCap: "group-active",
|
|
19105
|
+
outputField: "active",
|
|
19106
|
+
member: {
|
|
19107
|
+
cap: "climate-control",
|
|
19108
|
+
fieldPath: "mode"
|
|
19109
|
+
},
|
|
19110
|
+
activeWhen: [
|
|
19111
|
+
"heat",
|
|
19112
|
+
"cool",
|
|
19113
|
+
"auto",
|
|
19114
|
+
"heat_cool",
|
|
19115
|
+
"fan_only",
|
|
19116
|
+
"dry"
|
|
19117
|
+
],
|
|
19118
|
+
commandCaps: ["climate-control"]
|
|
19119
|
+
})
|
|
19120
|
+
];
|
|
19121
|
+
function actuator(input) {
|
|
19122
|
+
return {
|
|
19123
|
+
id: input.id,
|
|
19124
|
+
summary: input.summary,
|
|
19125
|
+
deviceType: input.deviceType,
|
|
19126
|
+
outputCap: input.outputCap,
|
|
19127
|
+
outputField: input.outputField,
|
|
19128
|
+
commandCaps: input.commandCaps,
|
|
19129
|
+
family: "actuator",
|
|
19130
|
+
role: void 0,
|
|
19131
|
+
memberDeviceType: input.deviceType,
|
|
19132
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19133
|
+
activeWhen: input.activeWhen,
|
|
19134
|
+
quantity: "none",
|
|
19135
|
+
baseUnit: void 0,
|
|
19136
|
+
aggregates: BINARY_AGGREGATES,
|
|
19137
|
+
defaultAggregate: "any",
|
|
19138
|
+
empty: "offline",
|
|
19139
|
+
accept: [input.member],
|
|
19140
|
+
companions: [CHANGED]
|
|
19141
|
+
};
|
|
19142
|
+
}
|
|
19143
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19144
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19145
|
+
DeviceType.Camera;
|
|
18420
19146
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18421
19147
|
/**
|
|
18422
19148
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20130,12 +20856,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
20130
20856
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20131
20857
|
* in-place so dispatch keeps working.
|
|
20132
20858
|
*
|
|
20133
|
-
* **
|
|
20134
|
-
*
|
|
20135
|
-
*
|
|
20136
|
-
*
|
|
20137
|
-
* (`ha-domain-mapping`)
|
|
20138
|
-
* stored after that point.
|
|
20859
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20860
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20861
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20862
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20863
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20864
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20139
20865
|
*
|
|
20140
20866
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20141
20867
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20149,6 +20875,14 @@ var SourceInfoSchema = object({
|
|
|
20149
20875
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20150
20876
|
* Used to detect rename when `id` changes. */
|
|
20151
20877
|
uniqueId: string().optional(),
|
|
20878
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20879
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20880
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20881
|
+
dateTimeShape: _enum([
|
|
20882
|
+
"date",
|
|
20883
|
+
"time",
|
|
20884
|
+
"datetime"
|
|
20885
|
+
]).optional(),
|
|
20152
20886
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20153
20887
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20154
20888
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41061,7 +41795,8 @@ method(object({
|
|
|
41061
41795
|
"enum"
|
|
41062
41796
|
]),
|
|
41063
41797
|
enumValues: array(string()).optional(),
|
|
41064
|
-
item: boolean().optional()
|
|
41798
|
+
item: boolean().optional(),
|
|
41799
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41065
41800
|
})).readonly(),
|
|
41066
41801
|
itemArray: object({
|
|
41067
41802
|
path: string(),
|
|
@@ -43422,7 +44157,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43422
44157
|
});
|
|
43423
44158
|
/**
|
|
43424
44159
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43425
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44160
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43426
44161
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43427
44162
|
* the originating provider config (mode + sourcePort) so the
|
|
43428
44163
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44883,8 +45618,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44883
45618
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44884
45619
|
var MaskGridShapeSchema = object({
|
|
44885
45620
|
kind: literal("grid"),
|
|
44886
|
-
gridWidth: number(),
|
|
44887
|
-
gridHeight: number(),
|
|
45621
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45622
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44888
45623
|
cells: array(boolean())
|
|
44889
45624
|
});
|
|
44890
45625
|
discriminatedUnion("kind", [
|
|
@@ -44996,6 +45731,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44996
45731
|
"detection-blind",
|
|
44997
45732
|
"motion-noisy",
|
|
44998
45733
|
"motion-calm",
|
|
45734
|
+
"package-llm-silent",
|
|
45735
|
+
"package-llm-answered",
|
|
44999
45736
|
"recording-stalled",
|
|
45000
45737
|
"recording-healthy",
|
|
45001
45738
|
"recording-degraded",
|
|
@@ -46085,7 +46822,20 @@ var NcRuleInputSchema = object({
|
|
|
46085
46822
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46086
46823
|
* path does not run Zod defaults.
|
|
46087
46824
|
*/
|
|
46088
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46825
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46826
|
+
/**
|
|
46827
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46828
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46829
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46830
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46831
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46832
|
+
*
|
|
46833
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46834
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46835
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46836
|
+
* `false`, so it needs no `clear` key.
|
|
46837
|
+
*/
|
|
46838
|
+
askVerdict: boolean().optional()
|
|
46089
46839
|
});
|
|
46090
46840
|
/**
|
|
46091
46841
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56010,6 +56760,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56010
56760
|
deprecated: string().optional(),
|
|
56011
56761
|
distTags: array(string()).readonly()
|
|
56012
56762
|
});
|
|
56763
|
+
/**
|
|
56764
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56765
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56766
|
+
* tarball failure — never an empty string standing in for either.
|
|
56767
|
+
*/
|
|
56768
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56769
|
+
object({
|
|
56770
|
+
status: literal("ok"),
|
|
56771
|
+
markdown: string()
|
|
56772
|
+
}),
|
|
56773
|
+
object({ status: literal("missing") }),
|
|
56774
|
+
object({
|
|
56775
|
+
status: literal("error"),
|
|
56776
|
+
message: string()
|
|
56777
|
+
})
|
|
56778
|
+
]);
|
|
56779
|
+
var PackageDocsSchema = object({
|
|
56780
|
+
name: string(),
|
|
56781
|
+
version: string(),
|
|
56782
|
+
readme: PackageDocBodySchema,
|
|
56783
|
+
changelog: PackageDocBodySchema
|
|
56784
|
+
});
|
|
56013
56785
|
var SearchResultSchema = object({
|
|
56014
56786
|
name: string(),
|
|
56015
56787
|
version: string(),
|
|
@@ -56228,7 +57000,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56228
57000
|
}), object({ success: literal(true) }), {
|
|
56229
57001
|
kind: "mutation",
|
|
56230
57002
|
auth: "admin"
|
|
56231
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57003
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57004
|
+
name: string().min(1),
|
|
57005
|
+
version: string().min(1).optional()
|
|
57006
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56232
57007
|
kind: "mutation",
|
|
56233
57008
|
auth: "admin"
|
|
56234
57009
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56278,46 +57053,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56278
57053
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56279
57054
|
object({
|
|
56280
57055
|
/** Carbon dioxide concentration in ppm. */
|
|
56281
|
-
co2Ppm: number().min(0).optional(),
|
|
57056
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56282
57057
|
/** Total volatile organic compounds in ppb. */
|
|
56283
|
-
vocPpb: number().min(0).optional(),
|
|
57058
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56284
57059
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56285
|
-
pm25: number().min(0).optional(),
|
|
57060
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56286
57061
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56287
|
-
pm10: number().min(0).optional(),
|
|
57062
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56288
57063
|
/** Composite AQI value (typically 0..500). */
|
|
56289
|
-
aqi: number().optional(),
|
|
57064
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56290
57065
|
/** Ms epoch when the slice was last updated. */
|
|
56291
|
-
lastFetchedAt: number()
|
|
56292
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56293
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56294
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56295
|
-
* per slice is unambiguous. */
|
|
56296
|
-
unit: string().optional(),
|
|
56297
|
-
/** Suggested decimal places for numeric display.
|
|
56298
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56299
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56300
|
-
* auto-formatting when absent. */
|
|
56301
|
-
precision: number().int().min(0).max(10).optional()
|
|
57066
|
+
lastFetchedAt: number()
|
|
56302
57067
|
});
|
|
56303
57068
|
DeviceType.Sensor;
|
|
56304
57069
|
object({
|
|
56305
|
-
/** Current illuminance in lux (lx). */
|
|
56306
|
-
lux: number().min(0).meta({
|
|
56307
|
-
|
|
57070
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57071
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57072
|
+
precision: 0,
|
|
56308
57073
|
label: "Illuminance"
|
|
56309
|
-
}),
|
|
57074
|
+
})),
|
|
56310
57075
|
/** Ms epoch when the slice was last updated. */
|
|
56311
|
-
lastFetchedAt: number()
|
|
56312
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56313
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56314
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56315
|
-
unit: string().optional(),
|
|
56316
|
-
/** Suggested decimal places for numeric display.
|
|
56317
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56318
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56319
|
-
* auto-formatting when absent. */
|
|
56320
|
-
precision: number().int().min(0).max(10).optional()
|
|
57076
|
+
lastFetchedAt: number()
|
|
56321
57077
|
});
|
|
56322
57078
|
DeviceType.Sensor;
|
|
56323
57079
|
/**
|
|
@@ -56462,10 +57218,7 @@ var BatteryStatusSchema = object({
|
|
|
56462
57218
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56463
57219
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56464
57220
|
*/
|
|
56465
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56466
|
-
unit: "%",
|
|
56467
|
-
label: "Charge"
|
|
56468
|
-
}),
|
|
57221
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56469
57222
|
/**
|
|
56470
57223
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56471
57224
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56492,7 +57245,14 @@ var BatteryStatusSchema = object({
|
|
|
56492
57245
|
*/
|
|
56493
57246
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56494
57247
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56495
|
-
lastUpdated: number(),
|
|
57248
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57249
|
+
/**
|
|
57250
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57251
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57252
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57253
|
+
* `numeric-sensor` on the same device.
|
|
57254
|
+
*/
|
|
57255
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56496
57256
|
/**
|
|
56497
57257
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56498
57258
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56532,7 +57292,7 @@ var BatteryStatusSchema = object({
|
|
|
56532
57292
|
*/
|
|
56533
57293
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56534
57294
|
});
|
|
56535
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57295
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56536
57296
|
method(object({
|
|
56537
57297
|
deviceId: number(),
|
|
56538
57298
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56552,7 +57312,7 @@ object({
|
|
|
56552
57312
|
DeviceType.Sensor;
|
|
56553
57313
|
object({
|
|
56554
57314
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56555
|
-
percentage: number().min(0).max(100),
|
|
57315
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56556
57316
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56557
57317
|
lastChangedAt: number()
|
|
56558
57318
|
});
|
|
@@ -56937,21 +57697,21 @@ object({
|
|
|
56937
57697
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
56938
57698
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
56939
57699
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
56940
|
-
target: number().nullable(),
|
|
57700
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
56941
57701
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
56942
57702
|
* in `heat_cool` mode. */
|
|
56943
|
-
targetHigh: number().nullable(),
|
|
57703
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
56944
57704
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
56945
57705
|
* in `heat_cool` mode. */
|
|
56946
|
-
targetLow: number().nullable(),
|
|
57706
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
56947
57707
|
/** Target relative humidity (0..100). Null when the device has no
|
|
56948
57708
|
* humidity control. */
|
|
56949
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57709
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56950
57710
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
56951
57711
|
* the device's internal sensor. */
|
|
56952
|
-
currentTemp: number().nullable(),
|
|
57712
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
56953
57713
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
56954
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57714
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56955
57715
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
56956
57716
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
56957
57717
|
swingVertical: boolean().nullable(),
|
|
@@ -56959,11 +57719,11 @@ object({
|
|
|
56959
57719
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
56960
57720
|
swingHorizontal: boolean().nullable(),
|
|
56961
57721
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56962
|
-
minTemp: number().nullable().optional(),
|
|
57722
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56963
57723
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56964
|
-
maxTemp: number().nullable().optional(),
|
|
57724
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56965
57725
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
56966
|
-
tempStep: number().positive().nullable().optional(),
|
|
57726
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
56967
57727
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
56968
57728
|
lastFetchedAt: number()
|
|
56969
57729
|
});
|
|
@@ -57042,17 +57802,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
57042
57802
|
* modes to expose in the picker without a slice fetch.
|
|
57043
57803
|
*/
|
|
57044
57804
|
var RgbTripletSchema = object({
|
|
57045
|
-
r: number().int().min(0).max(255),
|
|
57046
|
-
g: number().int().min(0).max(255),
|
|
57047
|
-
b: number().int().min(0).max(255)
|
|
57805
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57806
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57807
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57048
57808
|
});
|
|
57049
57809
|
var HsvTripletSchema = object({
|
|
57050
57810
|
/** Hue in degrees, 0..360. */
|
|
57051
|
-
h: number().min(0).max(360),
|
|
57811
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57052
57812
|
/** Saturation as 0..100 inclusive. */
|
|
57053
|
-
s: number().min(0).max(100),
|
|
57813
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57054
57814
|
/** Value/brightness as 0..100 inclusive. */
|
|
57055
|
-
v: number().min(0).max(100)
|
|
57815
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57056
57816
|
});
|
|
57057
57817
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57058
57818
|
object({
|
|
@@ -57081,7 +57841,7 @@ object({
|
|
|
57081
57841
|
/** Populated when `mode === 'hsv'`. */
|
|
57082
57842
|
hsv: HsvTripletSchema.optional(),
|
|
57083
57843
|
/** Populated when `mode === 'mired'`. */
|
|
57084
|
-
mireds: number().int().optional(),
|
|
57844
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57085
57845
|
/** Ms epoch of the last operator-driven change. */
|
|
57086
57846
|
lastChangedAt: number()
|
|
57087
57847
|
});
|
|
@@ -57205,18 +57965,12 @@ _enum([
|
|
|
57205
57965
|
"empty",
|
|
57206
57966
|
"full"
|
|
57207
57967
|
]);
|
|
57208
|
-
/**
|
|
57209
|
-
|
|
57210
|
-
|
|
57211
|
-
"days",
|
|
57212
|
-
"hours",
|
|
57213
|
-
"cycles"
|
|
57214
|
-
]);
|
|
57215
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57216
|
-
* days). `value` null = unknown (D393). */
|
|
57968
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
57969
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
57970
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57217
57971
|
var ConsumableRemainingSchema = object({
|
|
57218
|
-
value: number().min(0).nullable(),
|
|
57219
|
-
|
|
57972
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
57973
|
+
kind: ConsumableRemainingKindSchema
|
|
57220
57974
|
});
|
|
57221
57975
|
var ConsumablesStatusSchema = object({
|
|
57222
57976
|
items: array(object({
|
|
@@ -57225,7 +57979,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57225
57979
|
/** Display name. */
|
|
57226
57980
|
label: string().min(1),
|
|
57227
57981
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57228
|
-
level: number().min(0).max(100).nullable(),
|
|
57982
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57229
57983
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57230
57984
|
status: ConsumableStatusSchema.nullable(),
|
|
57231
57985
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57242,7 +57996,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57242
57996
|
})),
|
|
57243
57997
|
lastChangedAt: number()
|
|
57244
57998
|
});
|
|
57245
|
-
Object.values(DeviceType), [...
|
|
57999
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57246
58000
|
Object.values(DeviceType), method(object({
|
|
57247
58001
|
deviceId: number().int().nonnegative(),
|
|
57248
58002
|
key: string().min(1)
|
|
@@ -57267,39 +58021,17 @@ object({
|
|
|
57267
58021
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57268
58022
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57269
58023
|
* or time-only — HA accepts all three forms). */
|
|
57270
|
-
value: union([number(), string()]),
|
|
58024
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57271
58025
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57272
58026
|
options: array(string()),
|
|
57273
58027
|
/** Ms epoch when the slice was last updated. */
|
|
57274
58028
|
lastChangedAt: number(),
|
|
57275
|
-
/**
|
|
57276
|
-
|
|
57277
|
-
|
|
57278
|
-
|
|
57279
|
-
/**
|
|
57280
|
-
|
|
57281
|
-
min: number().optional(),
|
|
57282
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57283
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57284
|
-
max: number().optional(),
|
|
57285
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57286
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57287
|
-
step: number().optional(),
|
|
57288
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57289
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57290
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57291
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57292
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57293
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57294
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57295
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57296
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57297
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57298
|
-
format: _enum([
|
|
57299
|
-
"date",
|
|
57300
|
-
"time",
|
|
57301
|
-
"datetime"
|
|
57302
|
-
]).optional()
|
|
58029
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58030
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58031
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58032
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58033
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58034
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57303
58035
|
});
|
|
57304
58036
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57305
58037
|
object({
|
|
@@ -57337,9 +58069,9 @@ object({
|
|
|
57337
58069
|
]),
|
|
57338
58070
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57339
58071
|
* no intermediate position surface. */
|
|
57340
|
-
position: number().min(0).max(100).nullable(),
|
|
58072
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57341
58073
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57342
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58074
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57343
58075
|
/** Ms epoch when the slice was last updated. */
|
|
57344
58076
|
lastChangedAt: number()
|
|
57345
58077
|
});
|
|
@@ -57397,9 +58129,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57397
58129
|
object({
|
|
57398
58130
|
mode: DayNightModeSchema,
|
|
57399
58131
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57400
|
-
sensitivity: number().optional(),
|
|
58132
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57401
58133
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57402
|
-
switchDelaySec: number().optional(),
|
|
58134
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57403
58135
|
lastFetchedAt: number()
|
|
57404
58136
|
});
|
|
57405
58137
|
/**
|
|
@@ -57554,11 +58286,11 @@ object({
|
|
|
57554
58286
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57555
58287
|
availablePrograms: array(string()),
|
|
57556
58288
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57557
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58289
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57558
58290
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57559
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58291
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57560
58292
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57561
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58293
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57562
58294
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57563
58295
|
doorOpen: boolean().nullable(),
|
|
57564
58296
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57582,7 +58314,7 @@ object({
|
|
|
57582
58314
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57583
58315
|
machineCareDue: boolean().nullable(),
|
|
57584
58316
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57585
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58317
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57586
58318
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57587
58319
|
halfLoad: boolean().nullable(),
|
|
57588
58320
|
hygienePlus: boolean().nullable(),
|
|
@@ -57597,7 +58329,7 @@ object({
|
|
|
57597
58329
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57598
58330
|
activeEvents: array(string()),
|
|
57599
58331
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57600
|
-
errorCode: number().nullable(),
|
|
58332
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57601
58333
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57602
58334
|
errorLabel: string().nullable(),
|
|
57603
58335
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -57743,24 +58475,14 @@ object({
|
|
|
57743
58475
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
57744
58476
|
lastPressedAt: number().nullable(),
|
|
57745
58477
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
57746
|
-
pressCountSinceStart: number()
|
|
58478
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
57747
58479
|
});
|
|
57748
58480
|
object({
|
|
57749
58481
|
deviceId: number(),
|
|
57750
58482
|
timestamp: number()
|
|
57751
58483
|
});
|
|
57752
58484
|
DeviceType.Button, DeviceType.Camera;
|
|
57753
|
-
|
|
57754
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
57755
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
57756
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
57757
|
-
* The option set is stable across observations; it is persisted in the
|
|
57758
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
57759
|
-
* stored in `sourceInfo`.
|
|
57760
|
-
*/
|
|
57761
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
57762
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
57763
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58485
|
+
_enum([
|
|
57764
58486
|
"date",
|
|
57765
58487
|
"time",
|
|
57766
58488
|
"datetime"
|
|
@@ -57768,12 +58490,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
57768
58490
|
object({
|
|
57769
58491
|
value: string(),
|
|
57770
58492
|
/**
|
|
57771
|
-
* Set
|
|
57772
|
-
* as
|
|
57773
|
-
*
|
|
57774
|
-
* a time-only sensor → `'time'`.
|
|
58493
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58494
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58495
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
57775
58496
|
*/
|
|
57776
|
-
|
|
58497
|
+
timestamp: boolean().optional(),
|
|
57777
58498
|
/** Ms epoch when the slice was last updated. */
|
|
57778
58499
|
lastFetchedAt: number()
|
|
57779
58500
|
});
|
|
@@ -57792,13 +58513,13 @@ var EventFireSchema = object({
|
|
|
57792
58513
|
deviceId: number(),
|
|
57793
58514
|
eventType: string(),
|
|
57794
58515
|
data: record(string(), unknown()).nullable(),
|
|
57795
|
-
timestamp: number(),
|
|
57796
|
-
seq: number()
|
|
58516
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58517
|
+
seq: number().meta(readingMeta("count"))
|
|
57797
58518
|
});
|
|
57798
58519
|
object({
|
|
57799
58520
|
eventTypes: array(string()),
|
|
57800
58521
|
lastEvent: EventFireSchema.nullable(),
|
|
57801
|
-
eventCountSinceStart: number()
|
|
58522
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
57802
58523
|
});
|
|
57803
58524
|
DeviceType.EventEmitter;
|
|
57804
58525
|
var IdentitySchema = object({
|
|
@@ -58187,10 +58908,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58187
58908
|
object({
|
|
58188
58909
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58189
58910
|
* speed surface (single-speed fan). */
|
|
58190
|
-
percentage: number().min(0).max(100).nullable(),
|
|
58911
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58191
58912
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58192
58913
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58193
|
-
percentageStep: number().positive().optional(),
|
|
58914
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
58194
58915
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
58195
58916
|
* — empty string when no preset is active or supported. */
|
|
58196
58917
|
preset: string(),
|
|
@@ -58272,7 +58993,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58272
58993
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58273
58994
|
model: string().nullable(),
|
|
58274
58995
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58275
|
-
channelCount: number().nullable(),
|
|
58996
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58276
58997
|
/**
|
|
58277
58998
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58278
58999
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58304,9 +59025,45 @@ object({
|
|
|
58304
59025
|
lastChangedAt: number()
|
|
58305
59026
|
});
|
|
58306
59027
|
DeviceType.Sensor;
|
|
59028
|
+
object({
|
|
59029
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
59030
|
+
results: array(object({
|
|
59031
|
+
deviceId: number().int().nonnegative(),
|
|
59032
|
+
cap: string().min(1),
|
|
59033
|
+
method: string().min(1),
|
|
59034
|
+
ok: boolean(),
|
|
59035
|
+
error: string().optional(),
|
|
59036
|
+
/** Ms epoch of the attempt. */
|
|
59037
|
+
at: number()
|
|
59038
|
+
})) });
|
|
59039
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
59040
|
+
object({
|
|
59041
|
+
active: boolean().meta({ label: "Active" }),
|
|
59042
|
+
/** Ms epoch when the slice was last updated. */
|
|
59043
|
+
lastChangedAt: number()
|
|
59044
|
+
});
|
|
59045
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
59046
|
+
object({
|
|
59047
|
+
/** Members whose current value entered the aggregate. */
|
|
59048
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
59049
|
+
precision: 0,
|
|
59050
|
+
label: "Reporting"
|
|
59051
|
+
})),
|
|
59052
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
59053
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
59054
|
+
precision: 0,
|
|
59055
|
+
label: "Excluded"
|
|
59056
|
+
})),
|
|
59057
|
+
/** `included` + `excluded`. */
|
|
59058
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
59059
|
+
precision: 0,
|
|
59060
|
+
label: "Members"
|
|
59061
|
+
}))
|
|
59062
|
+
});
|
|
59063
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58307
59064
|
object({
|
|
58308
59065
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58309
|
-
position: number().min(0).max(100).nullable(),
|
|
59066
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58310
59067
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58311
59068
|
lastFetchedAt: number()
|
|
58312
59069
|
});
|
|
@@ -58315,9 +59072,9 @@ object({
|
|
|
58315
59072
|
/** Whether the humidifier is currently on. */
|
|
58316
59073
|
on: boolean(),
|
|
58317
59074
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58318
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59075
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58319
59076
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58320
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59077
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58321
59078
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58322
59079
|
* device has no mode surface. */
|
|
58323
59080
|
mode: string().nullable(),
|
|
@@ -58327,9 +59084,9 @@ object({
|
|
|
58327
59084
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58328
59085
|
action: string().nullable(),
|
|
58329
59086
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58330
|
-
minHumidity: number().nullable(),
|
|
59087
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58331
59088
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58332
|
-
maxHumidity: number().nullable(),
|
|
59089
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58333
59090
|
/** Ms epoch when the slice was last updated. */
|
|
58334
59091
|
lastChangedAt: number()
|
|
58335
59092
|
});
|
|
@@ -58353,22 +59110,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58353
59110
|
auth: "protected"
|
|
58354
59111
|
});
|
|
58355
59112
|
object({
|
|
58356
|
-
/** Current relative humidity, 0..100. */
|
|
58357
|
-
percent: number().min(0).max(100).meta({
|
|
58358
|
-
|
|
59113
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59114
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59115
|
+
precision: 0,
|
|
58359
59116
|
label: "Humidity"
|
|
58360
|
-
}),
|
|
59117
|
+
})),
|
|
58361
59118
|
/** Ms epoch when the slice was last updated. */
|
|
58362
|
-
lastFetchedAt: number()
|
|
58363
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58364
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58365
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58366
|
-
unit: string().optional(),
|
|
58367
|
-
/** Suggested decimal places for numeric display.
|
|
58368
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58369
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58370
|
-
* auto-formatting when absent. */
|
|
58371
|
-
precision: number().int().min(0).max(10).optional()
|
|
59119
|
+
lastFetchedAt: number()
|
|
58372
59120
|
});
|
|
58373
59121
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58374
59122
|
object({
|
|
@@ -58376,7 +59124,7 @@ object({
|
|
|
58376
59124
|
* entity exposes no `entity_picture` (yet). */
|
|
58377
59125
|
url: string().nullable(),
|
|
58378
59126
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58379
|
-
lastUpdated: number().nullable()
|
|
59127
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58380
59128
|
});
|
|
58381
59129
|
DeviceType.Image;
|
|
58382
59130
|
/**
|
|
@@ -58432,19 +59180,19 @@ var NormalizedRangeSchema = object({
|
|
|
58432
59180
|
});
|
|
58433
59181
|
object({
|
|
58434
59182
|
/** Normalized 0–100. */
|
|
58435
|
-
brightness: number().optional(),
|
|
59183
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58436
59184
|
/** Normalized 0–100. */
|
|
58437
|
-
contrast: number().optional(),
|
|
59185
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58438
59186
|
/** Normalized 0–100. */
|
|
58439
|
-
saturation: number().optional(),
|
|
59187
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58440
59188
|
/** Normalized 0–100. */
|
|
58441
|
-
sharpness: number().optional(),
|
|
59189
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58442
59190
|
mirror: boolean().optional(),
|
|
58443
59191
|
flip: boolean().optional(),
|
|
58444
59192
|
rotate: ImageRotateSchema.optional(),
|
|
58445
59193
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58446
59194
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58447
|
-
warmth: number().optional(),
|
|
59195
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58448
59196
|
exposureMode: ExposureModeSchema.optional(),
|
|
58449
59197
|
backlightMode: BacklightModeSchema.optional(),
|
|
58450
59198
|
lastFetchedAt: number()
|
|
@@ -58689,10 +59437,10 @@ var IntercomAbilitySchema = object({
|
|
|
58689
59437
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58690
59438
|
codecs: array(string()),
|
|
58691
59439
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58692
|
-
sampleRate: number(),
|
|
59440
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58693
59441
|
duplex: _enum(["half", "full"]),
|
|
58694
59442
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58695
|
-
maxBacklogMs: number()
|
|
59443
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58696
59444
|
});
|
|
58697
59445
|
var IntercomStatusSchema = object({
|
|
58698
59446
|
/** True while a talk session is open. */
|
|
@@ -58803,13 +59551,13 @@ object({
|
|
|
58803
59551
|
activity: LawnMowerActivitySchema,
|
|
58804
59552
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
58805
59553
|
* reading. */
|
|
58806
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59554
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58807
59555
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
58808
59556
|
* task is active / progress is unavailable. */
|
|
58809
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59557
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58810
59558
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
58811
59559
|
* or null when unknown. */
|
|
58812
|
-
currentCode: number().nullable(),
|
|
59560
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
58813
59561
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
58814
59562
|
currentCodeLabel: string().nullable(),
|
|
58815
59563
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -59219,7 +59967,14 @@ DeviceType.Lock, method(object({
|
|
|
59219
59967
|
auth: "protected"
|
|
59220
59968
|
}), method(object({
|
|
59221
59969
|
deviceId: number().int().nonnegative(),
|
|
59222
|
-
code: string().min(1).optional()
|
|
59970
|
+
code: string().min(1).optional(),
|
|
59971
|
+
/**
|
|
59972
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
59973
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
59974
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
59975
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
59976
|
+
*/
|
|
59977
|
+
confirm: boolean().optional()
|
|
59223
59978
|
}), _void(), {
|
|
59224
59979
|
kind: "mutation",
|
|
59225
59980
|
auth: "protected"
|
|
@@ -59227,6 +59982,11 @@ DeviceType.Lock, method(object({
|
|
|
59227
59982
|
kind: "mutation",
|
|
59228
59983
|
auth: "protected"
|
|
59229
59984
|
});
|
|
59985
|
+
object({
|
|
59986
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
59987
|
+
lastFetchedAt: number()
|
|
59988
|
+
});
|
|
59989
|
+
DeviceType.Sensor;
|
|
59230
59990
|
/**
|
|
59231
59991
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59232
59992
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59271,7 +60031,7 @@ object({
|
|
|
59271
60031
|
state: MediaPlayerStateSchema,
|
|
59272
60032
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59273
60033
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59274
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
60034
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59275
60035
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59276
60036
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59277
60037
|
isMuted: boolean().nullable(),
|
|
@@ -59284,10 +60044,10 @@ object({
|
|
|
59284
60044
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59285
60045
|
/** Current playback position in ms. Null when not seekable or
|
|
59286
60046
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59287
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
60047
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59288
60048
|
/** Total duration of the current media in ms. Null when unknown
|
|
59289
60049
|
* (live stream) or nothing is playing. */
|
|
59290
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
60050
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59291
60051
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59292
60052
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59293
60053
|
shuffle: boolean().nullable(),
|
|
@@ -59587,7 +60347,7 @@ object({
|
|
|
59587
60347
|
* it, every provider seeded it at boot, and every session left it
|
|
59588
60348
|
* `detected: true` after its detach.
|
|
59589
60349
|
*/
|
|
59590
|
-
autoClearAfterMs: number().nullable()
|
|
60350
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59591
60351
|
});
|
|
59592
60352
|
/**
|
|
59593
60353
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59637,7 +60397,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59637
60397
|
});
|
|
59638
60398
|
object({
|
|
59639
60399
|
enabled: boolean(),
|
|
59640
|
-
sensitivity: number(),
|
|
60400
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59641
60401
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59642
60402
|
regions: array(MotionZoneRegionSchema),
|
|
59643
60403
|
lastFetchedAt: number()
|
|
@@ -59941,7 +60701,7 @@ var NavigationStatusSchema = object({
|
|
|
59941
60701
|
following: boolean(),
|
|
59942
60702
|
flash: boolean(),
|
|
59943
60703
|
lightMode: NavigationLightModeSchema,
|
|
59944
|
-
lightLevel: number().min(40).max(100),
|
|
60704
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
59945
60705
|
/** Ms epoch when the slice was last updated. */
|
|
59946
60706
|
lastChangedAt: number()
|
|
59947
60707
|
});
|
|
@@ -59987,13 +60747,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
59987
60747
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
59988
60748
|
* SKIP a null rather than coerce it.
|
|
59989
60749
|
*/
|
|
59990
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
60750
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59991
60751
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
59992
|
-
rssiDbm: number().optional(),
|
|
60752
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
59993
60753
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
59994
60754
|
ssid: string().optional(),
|
|
59995
60755
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
59996
|
-
lastUpdated: number()
|
|
60756
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
59997
60757
|
});
|
|
59998
60758
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
59999
60759
|
deviceId: number(),
|
|
@@ -60312,7 +61072,7 @@ object({
|
|
|
60312
61072
|
lastError: string().nullable(),
|
|
60313
61073
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60314
61074
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60315
|
-
queueDepth: number().int().nonnegative(),
|
|
61075
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60316
61076
|
/** Per-feature capability matrix — authoritative source for the
|
|
60317
61077
|
* compose-form field gating. */
|
|
60318
61078
|
supports: NotifierSupportsSchema
|
|
@@ -60362,15 +61122,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60362
61122
|
acceptedAt: number()
|
|
60363
61123
|
});
|
|
60364
61124
|
object({
|
|
60365
|
-
|
|
60366
|
-
|
|
60367
|
-
* Populated live from the upstream source on each state push.
|
|
60368
|
-
* Absent for unitless sensors. */
|
|
60369
|
-
unit: string().optional(),
|
|
60370
|
-
/** Suggested decimal places for numeric display.
|
|
60371
|
-
* Populated live from the upstream source when provided.
|
|
60372
|
-
* Falls back to auto-formatting when absent. */
|
|
60373
|
-
precision: number().int().min(0).max(10).optional(),
|
|
61125
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
61126
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60374
61127
|
/** Ms epoch when the slice was last updated. */
|
|
60375
61128
|
lastFetchedAt: number()
|
|
60376
61129
|
});
|
|
@@ -60660,23 +61413,26 @@ object({
|
|
|
60660
61413
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60661
61414
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60662
61415
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60663
|
-
foodLevel: number().nullable(),
|
|
61416
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60664
61417
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60665
61418
|
* single-hopper models. */
|
|
60666
|
-
food1: number().nullable(),
|
|
61419
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60667
61420
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60668
61421
|
* single-hopper models. */
|
|
60669
|
-
food2: number().nullable(),
|
|
61422
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60670
61423
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60671
61424
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60672
61425
|
* below the feeder's low threshold. */
|
|
60673
61426
|
lowFood: boolean(),
|
|
60674
61427
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60675
61428
|
* device has no battery reading. */
|
|
60676
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60677
|
-
/**
|
|
60678
|
-
*
|
|
60679
|
-
|
|
61429
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61430
|
+
/**
|
|
61431
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61432
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61433
|
+
* model has no desiccant sensor.
|
|
61434
|
+
*/
|
|
61435
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60680
61436
|
/** True while a feed is in progress. */
|
|
60681
61437
|
feeding: boolean(),
|
|
60682
61438
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60687,7 +61443,7 @@ object({
|
|
|
60687
61443
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60688
61444
|
error: string().nullable(),
|
|
60689
61445
|
/** Raw device error code (0 / null = no error). */
|
|
60690
|
-
errorCode: number().nullable(),
|
|
61446
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60691
61447
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60692
61448
|
isDualHopper: boolean(),
|
|
60693
61449
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60697,7 +61453,7 @@ object({
|
|
|
60697
61453
|
/** Play a chime when dispensing. */
|
|
60698
61454
|
feedSound: boolean(),
|
|
60699
61455
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60700
|
-
volume: number(),
|
|
61456
|
+
volume: number().meta(readingMeta("none")),
|
|
60701
61457
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60702
61458
|
lastFetchedAt: number()
|
|
60703
61459
|
});
|
|
@@ -61134,38 +61890,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61134
61890
|
});
|
|
61135
61891
|
object({
|
|
61136
61892
|
/** Instantaneous power draw in watts. */
|
|
61137
|
-
watts: number().optional().meta({
|
|
61138
|
-
unit: "W",
|
|
61139
|
-
label: "Power"
|
|
61140
|
-
}),
|
|
61893
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61141
61894
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61142
|
-
kwhTotal: number().optional().meta({
|
|
61143
|
-
unit: "kWh",
|
|
61144
|
-
label: "Energy"
|
|
61145
|
-
}),
|
|
61895
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61146
61896
|
/** Voltage in volts. */
|
|
61147
|
-
volts: number().optional(),
|
|
61897
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61148
61898
|
/** Current in amperes. */
|
|
61149
|
-
amps: number().optional(),
|
|
61150
|
-
/** Apparent power in volt-amperes
|
|
61151
|
-
va: number().optional(),
|
|
61899
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61900
|
+
/** Apparent power in volt-amperes. */
|
|
61901
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61152
61902
|
/** Power factor (0..1) if reported. */
|
|
61153
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
61903
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61154
61904
|
/** Ms epoch when the slice was last updated. */
|
|
61155
|
-
lastFetchedAt: number()
|
|
61156
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
61157
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
61158
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
61159
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
61160
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
61161
|
-
unit: string().optional(),
|
|
61162
|
-
/** Suggested decimal places for numeric display.
|
|
61163
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61164
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61165
|
-
* auto-formatting when absent. */
|
|
61166
|
-
precision: number().int().min(0).max(10).optional()
|
|
61905
|
+
lastFetchedAt: number()
|
|
61167
61906
|
});
|
|
61168
|
-
|
|
61907
|
+
[
|
|
61908
|
+
DeviceType.Sensor,
|
|
61909
|
+
DeviceType.Switch,
|
|
61910
|
+
DeviceType.Light,
|
|
61911
|
+
DeviceType.Fan,
|
|
61912
|
+
DeviceType.Climate,
|
|
61913
|
+
DeviceType.Thermostat,
|
|
61914
|
+
DeviceType.Humidifier,
|
|
61915
|
+
DeviceType.WaterHeater,
|
|
61916
|
+
DeviceType.MediaPlayer,
|
|
61917
|
+
DeviceType.Washer,
|
|
61918
|
+
DeviceType.Dryer,
|
|
61919
|
+
DeviceType.Dishwasher,
|
|
61920
|
+
DeviceType.Vacuum,
|
|
61921
|
+
DeviceType.LawnMower,
|
|
61922
|
+
DeviceType.PetFeeder
|
|
61923
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61169
61924
|
/**
|
|
61170
61925
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61171
61926
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61184,11 +61939,11 @@ DeviceType.Sensor;
|
|
|
61184
61939
|
*/
|
|
61185
61940
|
var GpsLocationSchema = object({
|
|
61186
61941
|
/** Latitude in decimal degrees, -90..90. */
|
|
61187
|
-
latitude: number().min(-90).max(90),
|
|
61942
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
61188
61943
|
/** Longitude in decimal degrees, -180..180. */
|
|
61189
|
-
longitude: number().min(-180).max(180),
|
|
61944
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
61190
61945
|
/** Reported accuracy in meters (lower = better). */
|
|
61191
|
-
accuracyMeters: number().nonnegative()
|
|
61946
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
61192
61947
|
});
|
|
61193
61948
|
object({
|
|
61194
61949
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -61200,25 +61955,16 @@ object({
|
|
|
61200
61955
|
gps: GpsLocationSchema.nullable(),
|
|
61201
61956
|
/** Optional battery level of the tracking device (0..100). Null
|
|
61202
61957
|
* when not reported. */
|
|
61203
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
61958
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61204
61959
|
/** Ms epoch when the slice was last updated. */
|
|
61205
61960
|
lastChangedAt: number()
|
|
61206
61961
|
});
|
|
61207
61962
|
DeviceType.Presence;
|
|
61208
61963
|
object({
|
|
61209
|
-
/** Current pressure in hPa. */
|
|
61210
|
-
hpa: number(),
|
|
61964
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
61965
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61211
61966
|
/** Ms epoch when the slice was last updated. */
|
|
61212
|
-
lastFetchedAt: number()
|
|
61213
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61214
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61215
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61216
|
-
unit: string().optional(),
|
|
61217
|
-
/** Suggested decimal places for numeric display.
|
|
61218
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61219
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61220
|
-
* auto-formatting when absent. */
|
|
61221
|
-
precision: number().int().min(0).max(10).optional()
|
|
61967
|
+
lastFetchedAt: number()
|
|
61222
61968
|
});
|
|
61223
61969
|
DeviceType.Sensor;
|
|
61224
61970
|
/**
|
|
@@ -61551,8 +62297,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61551
62297
|
}), _void(), { kind: "mutation" });
|
|
61552
62298
|
var PtzAutotrackSettingsSchema = object({
|
|
61553
62299
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61554
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61555
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62300
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62301
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61556
62302
|
});
|
|
61557
62303
|
/**
|
|
61558
62304
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61609,7 +62355,7 @@ object({
|
|
|
61609
62355
|
/** null = unknown — never coerced to false (D393). */
|
|
61610
62356
|
running: boolean().nullable(),
|
|
61611
62357
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61612
|
-
since: number().nullable(),
|
|
62358
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61613
62359
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61614
62360
|
phase: string().nullable(),
|
|
61615
62361
|
/** null until a reading has been published (D393). */
|
|
@@ -61621,7 +62367,7 @@ object({
|
|
|
61621
62367
|
phase: string().nullable()
|
|
61622
62368
|
});
|
|
61623
62369
|
Object.values(DeviceType);
|
|
61624
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62370
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61625
62371
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61626
62372
|
kind: "mutation",
|
|
61627
62373
|
auth: "admin"
|
|
@@ -62807,9 +63553,9 @@ var RecordTriggerSchema = _enum([
|
|
|
62807
63553
|
*/
|
|
62808
63554
|
var RecordWindowSchema = object({
|
|
62809
63555
|
trigger: RecordTriggerSchema,
|
|
62810
|
-
day: number().int().min(0).max(6),
|
|
62811
|
-
startMinute: number().int().min(0).max(1439),
|
|
62812
|
-
endMinute: number().int().min(1).max(1440)
|
|
63556
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63557
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63558
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
62813
63559
|
});
|
|
62814
63560
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
62815
63561
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -62878,10 +63624,10 @@ object({
|
|
|
62878
63624
|
/** Master "record to the card at all" switch. */
|
|
62879
63625
|
enabled: boolean().nullable(),
|
|
62880
63626
|
overwriteWhenFull: boolean().nullable(),
|
|
62881
|
-
preRecordSec: number().nullable(),
|
|
62882
|
-
postRecordSec: number().nullable(),
|
|
63627
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63628
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
62883
63629
|
/** Length of one recorded file, in minutes. */
|
|
62884
|
-
segmentMinutes: number().nullable(),
|
|
63630
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
62885
63631
|
/** The primary track's weekly windows, flattened. */
|
|
62886
63632
|
windows: array(RecordWindowSchema),
|
|
62887
63633
|
/**
|
|
@@ -62897,7 +63643,7 @@ object({
|
|
|
62897
63643
|
* provider reporting a non-zero count also reports the schedule as not
|
|
62898
63644
|
* writable.
|
|
62899
63645
|
*/
|
|
62900
|
-
unreadableWindows: number(),
|
|
63646
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
62901
63647
|
/**
|
|
62902
63648
|
* The camera is scheduled to record and has NO usable storage.
|
|
62903
63649
|
*
|
|
@@ -63534,7 +64280,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63534
64280
|
url: string().optional(),
|
|
63535
64281
|
codec: string().optional(),
|
|
63536
64282
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63537
|
-
fps: number().positive().optional(),
|
|
64283
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63538
64284
|
label: string().optional(),
|
|
63539
64285
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63540
64286
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63564,18 +64310,18 @@ var StreamProfileSchema = _enum([
|
|
|
63564
64310
|
]);
|
|
63565
64311
|
/** The current encoding config of one stream profile. */
|
|
63566
64312
|
var StreamProfileConfigSchema = object({
|
|
63567
|
-
width: number(),
|
|
63568
|
-
height: number(),
|
|
64313
|
+
width: number().meta(readingMeta("none")),
|
|
64314
|
+
height: number().meta(readingMeta("none")),
|
|
63569
64315
|
codec: _enum(["h264", "h265"]),
|
|
63570
|
-
framerate: number(),
|
|
63571
|
-
bitrate: number(),
|
|
64316
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64317
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63572
64318
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63573
64319
|
encoderProfile: _enum([
|
|
63574
64320
|
"high",
|
|
63575
64321
|
"main",
|
|
63576
64322
|
"baseline"
|
|
63577
64323
|
]).optional(),
|
|
63578
|
-
gop: number().optional(),
|
|
64324
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63579
64325
|
/**
|
|
63580
64326
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63581
64327
|
*
|
|
@@ -63660,7 +64406,7 @@ object({
|
|
|
63660
64406
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63661
64407
|
lastChangedAt: number()
|
|
63662
64408
|
});
|
|
63663
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64409
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63664
64410
|
deviceId: number(),
|
|
63665
64411
|
on: boolean()
|
|
63666
64412
|
}), _void(), {
|
|
@@ -64218,23 +64964,13 @@ object({
|
|
|
64218
64964
|
});
|
|
64219
64965
|
DeviceType.Sensor;
|
|
64220
64966
|
object({
|
|
64221
|
-
/** Current temperature in Celsius. */
|
|
64222
|
-
celsius: number().meta({
|
|
64223
|
-
|
|
64967
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
64968
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
64969
|
+
precision: 1,
|
|
64224
64970
|
label: "Temperature"
|
|
64225
|
-
}),
|
|
64971
|
+
})),
|
|
64226
64972
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64227
|
-
lastFetchedAt: number()
|
|
64228
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64229
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64230
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64231
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64232
|
-
unit: string().optional(),
|
|
64233
|
-
/** Suggested decimal places for numeric display.
|
|
64234
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64235
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64236
|
-
* auto-formatting when absent. */
|
|
64237
|
-
precision: number().int().min(0).max(10).optional()
|
|
64973
|
+
lastFetchedAt: number()
|
|
64238
64974
|
});
|
|
64239
64975
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64240
64976
|
/**
|
|
@@ -64486,16 +65222,16 @@ object({
|
|
|
64486
65222
|
]),
|
|
64487
65223
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64488
65224
|
* reading. */
|
|
64489
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65225
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64490
65226
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64491
65227
|
* the vacuum has no speed control. */
|
|
64492
65228
|
fanSpeed: string().nullable(),
|
|
64493
65229
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64494
65230
|
availableFanSpeeds: array(string()),
|
|
64495
65231
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64496
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65232
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64497
65233
|
/** Current error code (0 / null = no error). */
|
|
64498
|
-
errorCode: number().nullable(),
|
|
65234
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64499
65235
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64500
65236
|
errorLabel: string().nullable(),
|
|
64501
65237
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64534,7 +65270,7 @@ object({
|
|
|
64534
65270
|
]),
|
|
64535
65271
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64536
65272
|
* intermediate position surface. */
|
|
64537
|
-
position: number().min(0).max(100).nullable(),
|
|
65273
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64538
65274
|
/** Ms epoch when the slice was last updated. */
|
|
64539
65275
|
lastChangedAt: number()
|
|
64540
65276
|
});
|
|
@@ -64562,9 +65298,9 @@ object({
|
|
|
64562
65298
|
DeviceType.Sensor;
|
|
64563
65299
|
object({
|
|
64564
65300
|
/** Current measured temperature. Null when not reported. */
|
|
64565
|
-
currentTemp: number().nullable(),
|
|
65301
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64566
65302
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64567
|
-
targetTemp: number().nullable(),
|
|
65303
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64568
65304
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64569
65305
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64570
65306
|
* device reports an unknown state. */
|
|
@@ -64575,9 +65311,9 @@ object({
|
|
|
64575
65311
|
* has no away surface. */
|
|
64576
65312
|
away: boolean().nullable(),
|
|
64577
65313
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64578
|
-
minTemp: number().nullable(),
|
|
65314
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64579
65315
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64580
|
-
maxTemp: number().nullable(),
|
|
65316
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64581
65317
|
/** Ms epoch when the slice was last updated. */
|
|
64582
65318
|
lastChangedAt: number()
|
|
64583
65319
|
});
|
|
@@ -64601,25 +65337,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64601
65337
|
auth: "protected"
|
|
64602
65338
|
});
|
|
64603
65339
|
object({
|
|
64604
|
-
/** Verbatim
|
|
64605
|
-
* when no condition has been reported yet. */
|
|
65340
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64606
65341
|
condition: string().nullable(),
|
|
64607
|
-
/** Current temperature in
|
|
64608
|
-
temperature: number().nullable(),
|
|
64609
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64610
|
-
temperatureUnit: string().nullable(),
|
|
65342
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65343
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64611
65344
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64612
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64613
|
-
/** Barometric pressure in
|
|
64614
|
-
pressure: number().nullable(),
|
|
64615
|
-
/**
|
|
64616
|
-
|
|
64617
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64618
|
-
windSpeed: number().nullable(),
|
|
64619
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64620
|
-
windSpeedUnit: string().nullable(),
|
|
65345
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65346
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65347
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65348
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65349
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64621
65350
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64622
|
-
windBearing: number().nullable(),
|
|
65351
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64623
65352
|
/** Ms epoch when the slice was last updated. */
|
|
64624
65353
|
lastFetchedAt: number()
|
|
64625
65354
|
});
|
|
@@ -65369,8 +66098,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65369
66098
|
kind: "mutation",
|
|
65370
66099
|
auth: "admin"
|
|
65371
66100
|
});
|
|
66101
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65372
66102
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65373
|
-
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;
|
|
66103
|
+
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;
|
|
65374
66104
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65375
66105
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65376
66106
|
new Set(CAP_NAMES);
|
|
@@ -65423,7 +66153,7 @@ var AccessoryKind = {
|
|
|
65423
66153
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65424
66154
|
};
|
|
65425
66155
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65426
|
-
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;
|
|
66156
|
+
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;
|
|
65427
66157
|
new Set(Object.values(DeviceType));
|
|
65428
66158
|
Object.freeze({
|
|
65429
66159
|
"accessories.getStatus": {
|
|
@@ -65531,6 +66261,13 @@ Object.freeze({
|
|
|
65531
66261
|
access: "view",
|
|
65532
66262
|
role: "admin"
|
|
65533
66263
|
},
|
|
66264
|
+
"addons.getPackageDocs": {
|
|
66265
|
+
capName: "addons",
|
|
66266
|
+
capScope: "system",
|
|
66267
|
+
addonId: null,
|
|
66268
|
+
access: "view",
|
|
66269
|
+
role: "admin"
|
|
66270
|
+
},
|
|
65534
66271
|
"addons.getVersions": {
|
|
65535
66272
|
capName: "addons",
|
|
65536
66273
|
capScope: "system",
|
|
@@ -68639,6 +69376,27 @@ Object.freeze({
|
|
|
68639
69376
|
access: "view",
|
|
68640
69377
|
role: "viewer"
|
|
68641
69378
|
},
|
|
69379
|
+
"groupActive.getStatus": {
|
|
69380
|
+
capName: "group-active",
|
|
69381
|
+
capScope: "device",
|
|
69382
|
+
addonId: null,
|
|
69383
|
+
access: "view",
|
|
69384
|
+
role: "viewer"
|
|
69385
|
+
},
|
|
69386
|
+
"groupCommands.getStatus": {
|
|
69387
|
+
capName: "group-commands",
|
|
69388
|
+
capScope: "device",
|
|
69389
|
+
addonId: null,
|
|
69390
|
+
access: "view",
|
|
69391
|
+
role: "viewer"
|
|
69392
|
+
},
|
|
69393
|
+
"groupStatus.getStatus": {
|
|
69394
|
+
capName: "group-status",
|
|
69395
|
+
capScope: "device",
|
|
69396
|
+
addonId: null,
|
|
69397
|
+
access: "view",
|
|
69398
|
+
role: "viewer"
|
|
69399
|
+
},
|
|
68642
69400
|
"heatingValve.getStatus": {
|
|
68643
69401
|
capName: "heating-valve",
|
|
68644
69402
|
capScope: "device",
|
|
@@ -69591,6 +70349,13 @@ Object.freeze({
|
|
|
69591
70349
|
access: "create",
|
|
69592
70350
|
role: "admin"
|
|
69593
70351
|
},
|
|
70352
|
+
"meter.getStatus": {
|
|
70353
|
+
capName: "meter",
|
|
70354
|
+
capScope: "device",
|
|
70355
|
+
addonId: null,
|
|
70356
|
+
access: "view",
|
|
70357
|
+
role: "viewer"
|
|
70358
|
+
},
|
|
69594
70359
|
"metricsProvider.collectSnapshot": {
|
|
69595
70360
|
capName: "metrics-provider",
|
|
69596
70361
|
capScope: "system",
|
|
@@ -77689,7 +78454,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77689
78454
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77690
78455
|
icon: "square"
|
|
77691
78456
|
}
|
|
77692
|
-
}
|
|
78457
|
+
},
|
|
78458
|
+
overrides: { byType: {
|
|
78459
|
+
[DeviceType.Washer]: {
|
|
78460
|
+
state: { running: {
|
|
78461
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78462
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78463
|
+
} },
|
|
78464
|
+
events: {
|
|
78465
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78466
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78467
|
+
}
|
|
78468
|
+
},
|
|
78469
|
+
[DeviceType.Dryer]: {
|
|
78470
|
+
state: { running: {
|
|
78471
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78472
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78473
|
+
} },
|
|
78474
|
+
events: {
|
|
78475
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78476
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78477
|
+
}
|
|
78478
|
+
},
|
|
78479
|
+
[DeviceType.Dishwasher]: {
|
|
78480
|
+
state: { running: {
|
|
78481
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78482
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78483
|
+
} },
|
|
78484
|
+
events: {
|
|
78485
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78486
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78487
|
+
}
|
|
78488
|
+
}
|
|
78489
|
+
} }
|
|
77693
78490
|
},
|
|
77694
78491
|
update: {
|
|
77695
78492
|
scope: "device",
|
|
@@ -78461,6 +79258,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78461
79258
|
icon: "flame"
|
|
78462
79259
|
}]
|
|
78463
79260
|
},
|
|
79261
|
+
"group-active": {
|
|
79262
|
+
scope: "device",
|
|
79263
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79264
|
+
},
|
|
79265
|
+
"group-commands": {
|
|
79266
|
+
scope: "device",
|
|
79267
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79268
|
+
},
|
|
79269
|
+
"group-status": {
|
|
79270
|
+
scope: "device",
|
|
79271
|
+
noun: t("Group", "Gruppo"),
|
|
79272
|
+
state: [
|
|
79273
|
+
{
|
|
79274
|
+
kind: "numeric",
|
|
79275
|
+
field: "included",
|
|
79276
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79277
|
+
label: t("Reporting", "Rispondono"),
|
|
79278
|
+
icon: "users"
|
|
79279
|
+
},
|
|
79280
|
+
{
|
|
79281
|
+
kind: "numeric",
|
|
79282
|
+
field: "excluded",
|
|
79283
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79284
|
+
label: t("Excluded", "Esclusi"),
|
|
79285
|
+
icon: "users"
|
|
79286
|
+
},
|
|
79287
|
+
{
|
|
79288
|
+
kind: "numeric",
|
|
79289
|
+
field: "total",
|
|
79290
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79291
|
+
label: t("Members", "Membri"),
|
|
79292
|
+
icon: "sigma"
|
|
79293
|
+
}
|
|
79294
|
+
]
|
|
79295
|
+
},
|
|
78464
79296
|
"humidity-sensor": {
|
|
78465
79297
|
scope: "device",
|
|
78466
79298
|
noun: t("Humidity", "Umidità"),
|
|
@@ -78486,6 +79318,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78486
79318
|
}],
|
|
78487
79319
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78488
79320
|
},
|
|
79321
|
+
meter: {
|
|
79322
|
+
scope: "device",
|
|
79323
|
+
noun: t("Meter", "Contatore"),
|
|
79324
|
+
state: [{
|
|
79325
|
+
kind: "numeric",
|
|
79326
|
+
field: "value",
|
|
79327
|
+
quantity: t("the total", "il totale"),
|
|
79328
|
+
label: t("Total", "Totale"),
|
|
79329
|
+
icon: "gauge"
|
|
79330
|
+
}]
|
|
79331
|
+
},
|
|
78489
79332
|
"numeric-sensor": {
|
|
78490
79333
|
scope: "device",
|
|
78491
79334
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78494,7 +79337,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78494
79337
|
field: "value",
|
|
78495
79338
|
quantity: t("the reading", "il valore"),
|
|
78496
79339
|
label: t("Reading", "Valore"),
|
|
78497
|
-
unitField: "unit",
|
|
78498
79340
|
icon: "gauge"
|
|
78499
79341
|
}]
|
|
78500
79342
|
},
|
|
@@ -78630,7 +79472,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78630
79472
|
field: "temperature",
|
|
78631
79473
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78632
79474
|
label: t("Temperature", "Temperatura"),
|
|
78633
|
-
|
|
79475
|
+
unit: "°C",
|
|
78634
79476
|
icon: "thermometer"
|
|
78635
79477
|
},
|
|
78636
79478
|
{
|
|
@@ -78646,7 +79488,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78646
79488
|
field: "windSpeed",
|
|
78647
79489
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78648
79490
|
label: t("Wind", "Vento"),
|
|
78649
|
-
|
|
79491
|
+
unit: "m/s",
|
|
78650
79492
|
icon: "wind"
|
|
78651
79493
|
},
|
|
78652
79494
|
{
|
|
@@ -78654,7 +79496,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78654
79496
|
field: "pressure",
|
|
78655
79497
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78656
79498
|
label: t("Pressure", "Pressione"),
|
|
78657
|
-
|
|
79499
|
+
unit: "hPa",
|
|
78658
79500
|
icon: "gauge"
|
|
78659
79501
|
}
|
|
78660
79502
|
]
|
|
@@ -78959,8 +79801,47 @@ function projectAction(cap, action) {
|
|
|
78959
79801
|
};
|
|
78960
79802
|
}
|
|
78961
79803
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
78962
|
-
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;
|
|
79804
|
+
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;
|
|
78963
79805
|
DeviceFeature.BatteryOperated;
|
|
79806
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79807
|
+
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.";
|
|
79808
|
+
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.";
|
|
79809
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79810
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79811
|
+
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.";
|
|
79812
|
+
function withheld(reason) {
|
|
79813
|
+
return {
|
|
79814
|
+
[DeviceType.Washer]: {
|
|
79815
|
+
exported: false,
|
|
79816
|
+
reason
|
|
79817
|
+
},
|
|
79818
|
+
[DeviceType.Dryer]: {
|
|
79819
|
+
exported: false,
|
|
79820
|
+
reason
|
|
79821
|
+
},
|
|
79822
|
+
[DeviceType.Dishwasher]: {
|
|
79823
|
+
exported: false,
|
|
79824
|
+
reason
|
|
79825
|
+
}
|
|
79826
|
+
};
|
|
79827
|
+
}
|
|
79828
|
+
function offered(received) {
|
|
79829
|
+
return {
|
|
79830
|
+
[DeviceType.Washer]: {
|
|
79831
|
+
exported: true,
|
|
79832
|
+
as: received
|
|
79833
|
+
},
|
|
79834
|
+
[DeviceType.Dryer]: {
|
|
79835
|
+
exported: true,
|
|
79836
|
+
as: received
|
|
79837
|
+
},
|
|
79838
|
+
[DeviceType.Dishwasher]: {
|
|
79839
|
+
exported: true,
|
|
79840
|
+
as: received
|
|
79841
|
+
}
|
|
79842
|
+
};
|
|
79843
|
+
}
|
|
79844
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
78964
79845
|
Object.freeze({
|
|
78965
79846
|
"accessories.getStatus": [{
|
|
78966
79847
|
name: "deviceId",
|
|
@@ -79927,6 +80808,21 @@ Object.freeze({
|
|
|
79927
80808
|
form: "single",
|
|
79928
80809
|
optional: false
|
|
79929
80810
|
}],
|
|
80811
|
+
"groupActive.getStatus": [{
|
|
80812
|
+
name: "deviceId",
|
|
80813
|
+
form: "single",
|
|
80814
|
+
optional: false
|
|
80815
|
+
}],
|
|
80816
|
+
"groupCommands.getStatus": [{
|
|
80817
|
+
name: "deviceId",
|
|
80818
|
+
form: "single",
|
|
80819
|
+
optional: false
|
|
80820
|
+
}],
|
|
80821
|
+
"groupStatus.getStatus": [{
|
|
80822
|
+
name: "deviceId",
|
|
80823
|
+
form: "single",
|
|
80824
|
+
optional: false
|
|
80825
|
+
}],
|
|
79930
80826
|
"heatingValve.getStatus": [{
|
|
79931
80827
|
name: "deviceId",
|
|
79932
80828
|
form: "single",
|
|
@@ -80127,6 +81023,11 @@ Object.freeze({
|
|
|
80127
81023
|
form: "single",
|
|
80128
81024
|
optional: false
|
|
80129
81025
|
}],
|
|
81026
|
+
"meter.getStatus": [{
|
|
81027
|
+
name: "deviceId",
|
|
81028
|
+
form: "single",
|
|
81029
|
+
optional: false
|
|
81030
|
+
}],
|
|
80130
81031
|
"motion.getStatus": [{
|
|
80131
81032
|
name: "deviceId",
|
|
80132
81033
|
form: "single",
|
|
@@ -81734,7 +82635,6 @@ Object.freeze({
|
|
|
81734
82635
|
"network-access": "ingress",
|
|
81735
82636
|
"smtp-provider": "email"
|
|
81736
82637
|
});
|
|
81737
|
-
DeviceType.Camera;
|
|
81738
82638
|
/**
|
|
81739
82639
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
81740
82640
|
* `z.infer`, they do not restate the shape.
|
|
@@ -82118,6 +83018,8 @@ new Map(Object.entries({
|
|
|
82118
83018
|
"detection-blind": "device-events",
|
|
82119
83019
|
"motion-noisy": "device-events",
|
|
82120
83020
|
"motion-calm": "device-events",
|
|
83021
|
+
"package-llm-silent": "device-events",
|
|
83022
|
+
"package-llm-answered": "device-events",
|
|
82121
83023
|
"recording-stalled": "device-events",
|
|
82122
83024
|
"recording-healthy": "device-events",
|
|
82123
83025
|
"recording-degraded": "device-events",
|
|
@@ -82201,6 +83103,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
82201
83103
|
label: "Motion without a subject",
|
|
82202
83104
|
kinds: ["motion-noisy", "motion-calm"]
|
|
82203
83105
|
},
|
|
83106
|
+
{
|
|
83107
|
+
id: "package-llm",
|
|
83108
|
+
family: "device-events",
|
|
83109
|
+
label: "Package confirm",
|
|
83110
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
83111
|
+
},
|
|
82204
83112
|
{
|
|
82205
83113
|
id: "recording",
|
|
82206
83114
|
family: "device-events",
|
|
@@ -82382,6 +83290,8 @@ var DEVICE_EVENTS = [
|
|
|
82382
83290
|
"detection-blind",
|
|
82383
83291
|
"motion-noisy",
|
|
82384
83292
|
"motion-calm",
|
|
83293
|
+
"package-llm-silent",
|
|
83294
|
+
"package-llm-answered",
|
|
82385
83295
|
"recording-stalled",
|
|
82386
83296
|
"recording-healthy",
|
|
82387
83297
|
"recording-degraded",
|
|
@@ -82650,6 +83560,15 @@ new Map([
|
|
|
82650
83560
|
snapshotLabel: "Cameras with constant motion now",
|
|
82651
83561
|
snapshotSection: null
|
|
82652
83562
|
},
|
|
83563
|
+
{
|
|
83564
|
+
id: "package-llm-confirm",
|
|
83565
|
+
family: "device-events",
|
|
83566
|
+
label: "Package confirm (not answering / answering again)",
|
|
83567
|
+
bad: ["package-llm-silent"],
|
|
83568
|
+
recovery: ["package-llm-answered"],
|
|
83569
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
83570
|
+
snapshotSection: null
|
|
83571
|
+
},
|
|
82653
83572
|
{
|
|
82654
83573
|
id: "recording-health",
|
|
82655
83574
|
family: "device-events",
|
|
@@ -83464,7 +84383,7 @@ function buildEmailDescriptor(providers = []) {
|
|
|
83464
84383
|
id: "email",
|
|
83465
84384
|
title: "Email",
|
|
83466
84385
|
titleKey: "notifiers:emailDescriptor.s_email.title",
|
|
83467
|
-
description: "Send via a Connectivity → Email provider (Google
|
|
84386
|
+
description: "Send via a Connectivity → Email provider (Google or Email (SMTP)). Install and Verify a provider first.",
|
|
83468
84387
|
descriptionKey: "notifiers:emailDescriptor.s_email.description",
|
|
83469
84388
|
fields: [
|
|
83470
84389
|
{
|
|
@@ -83481,7 +84400,7 @@ function buildEmailDescriptor(providers = []) {
|
|
|
83481
84400
|
key: "smtpAddonId",
|
|
83482
84401
|
label: "Email provider",
|
|
83483
84402
|
labelKey: "notifiers:emailDescriptor.s_email.smtpAddonId.label",
|
|
83484
|
-
description: options.length === 0 ? "No Email provider installed. Open Connectivity → Email, install Google
|
|
84403
|
+
description: options.length === 0 ? "No Email provider installed. Open Connectivity → Email, install Google or Email (SMTP), then Verify." : "Which Connectivity → Email entry delivers this target. Verify it under Connectivity → Email if the label says not verified.",
|
|
83485
84404
|
required: true,
|
|
83486
84405
|
options
|
|
83487
84406
|
},
|
|
@@ -85781,7 +86700,7 @@ var HTTP_NOTIFIER_ADAPTERS = [
|
|
|
85781
86700
|
*/
|
|
85782
86701
|
function buildNotifierAdapters(smtp) {
|
|
85783
86702
|
const emailSmtp = smtp ?? { async sendEmail() {
|
|
85784
|
-
throw new Error("email: no smtp-provider client — install Google
|
|
86703
|
+
throw new Error("email: no smtp-provider client — install Google or Email (SMTP) under Connectivity → Email and Verify it");
|
|
85785
86704
|
} };
|
|
85786
86705
|
return [...HTTP_NOTIFIER_ADAPTERS, createEmailAdapter(emailSmtp)];
|
|
85787
86706
|
}
|