@camstack/addon-mqtt-broker 1.2.145 → 1.2.147
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 +33 -0
- package/dist/mqtt-broker.addon.js +1366 -447
- package/dist/mqtt-broker.addon.mjs +1366 -447
- package/package.json +4 -2
|
@@ -39,7 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
39
39
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
40
40
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
41
41
|
//#endregion
|
|
42
|
-
//#region ../types/dist/event-category-
|
|
42
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
43
43
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
44
44
|
EventCategory["SystemBoot"] = "system.boot";
|
|
45
45
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -365,6 +365,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
365
365
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
366
366
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
367
367
|
/**
|
|
368
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
369
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
370
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
371
|
+
*/
|
|
372
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
373
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
374
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
375
|
+
/**
|
|
368
376
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
369
377
|
* (a settings change via `setAgentInferenceDevices` /
|
|
370
378
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5607,7 +5615,7 @@ var ZodIssueCode = {
|
|
|
5607
5615
|
var ZodFirstPartyTypeKind;
|
|
5608
5616
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5609
5617
|
//#endregion
|
|
5610
|
-
//#region ../types/dist/sleep
|
|
5618
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5611
5619
|
/**
|
|
5612
5620
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5613
5621
|
* window to float samples (D455).
|
|
@@ -8349,6 +8357,99 @@ function defineEntryKind(name, spec) {
|
|
|
8349
8357
|
if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
|
|
8350
8358
|
return defined;
|
|
8351
8359
|
}
|
|
8360
|
+
var READING_QUANTITIES = [
|
|
8361
|
+
"temperature",
|
|
8362
|
+
"pressure",
|
|
8363
|
+
"speed",
|
|
8364
|
+
"precipitation",
|
|
8365
|
+
"precipitation-rate",
|
|
8366
|
+
"length",
|
|
8367
|
+
"area",
|
|
8368
|
+
"illuminance",
|
|
8369
|
+
"irradiance",
|
|
8370
|
+
"power",
|
|
8371
|
+
"energy",
|
|
8372
|
+
"voltage",
|
|
8373
|
+
"current",
|
|
8374
|
+
"apparent-power",
|
|
8375
|
+
"humidity",
|
|
8376
|
+
"percentage",
|
|
8377
|
+
"concentration-volume",
|
|
8378
|
+
"concentration-mass",
|
|
8379
|
+
"concentration-ppb",
|
|
8380
|
+
"volume",
|
|
8381
|
+
"duration",
|
|
8382
|
+
"duration-ms",
|
|
8383
|
+
"information",
|
|
8384
|
+
"sound-level",
|
|
8385
|
+
"signal-level",
|
|
8386
|
+
"colour-temperature",
|
|
8387
|
+
"angle",
|
|
8388
|
+
"bitrate",
|
|
8389
|
+
"rate",
|
|
8390
|
+
"mass",
|
|
8391
|
+
"index",
|
|
8392
|
+
"ratio",
|
|
8393
|
+
"count",
|
|
8394
|
+
"none",
|
|
8395
|
+
"device"
|
|
8396
|
+
];
|
|
8397
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8398
|
+
new Set(READING_QUANTITIES);
|
|
8399
|
+
/**
|
|
8400
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8401
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8402
|
+
*/
|
|
8403
|
+
var QUANTITY_BASE = {
|
|
8404
|
+
temperature: "°C",
|
|
8405
|
+
pressure: "hPa",
|
|
8406
|
+
speed: "m/s",
|
|
8407
|
+
precipitation: "mm",
|
|
8408
|
+
"precipitation-rate": "mm/h",
|
|
8409
|
+
length: "m",
|
|
8410
|
+
area: "m²",
|
|
8411
|
+
illuminance: "lx",
|
|
8412
|
+
irradiance: "W/m²",
|
|
8413
|
+
power: "W",
|
|
8414
|
+
energy: "kWh",
|
|
8415
|
+
voltage: "V",
|
|
8416
|
+
current: "A",
|
|
8417
|
+
"apparent-power": "VA",
|
|
8418
|
+
humidity: "%",
|
|
8419
|
+
percentage: "%",
|
|
8420
|
+
"concentration-volume": "ppm",
|
|
8421
|
+
"concentration-mass": "µg/m³",
|
|
8422
|
+
"concentration-ppb": "ppb",
|
|
8423
|
+
volume: "L",
|
|
8424
|
+
duration: "s",
|
|
8425
|
+
"duration-ms": "ms",
|
|
8426
|
+
information: "B",
|
|
8427
|
+
"sound-level": "dBFS",
|
|
8428
|
+
"signal-level": "dBm",
|
|
8429
|
+
"colour-temperature": "mired",
|
|
8430
|
+
angle: "°",
|
|
8431
|
+
bitrate: "kbps",
|
|
8432
|
+
rate: "fps",
|
|
8433
|
+
mass: "kg",
|
|
8434
|
+
index: "none",
|
|
8435
|
+
ratio: "none",
|
|
8436
|
+
count: "none",
|
|
8437
|
+
none: "none",
|
|
8438
|
+
device: "device"
|
|
8439
|
+
};
|
|
8440
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8441
|
+
function baseUnitOf(quantity) {
|
|
8442
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8443
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8444
|
+
return symbol;
|
|
8445
|
+
}
|
|
8446
|
+
function readingMeta(quantity, extras) {
|
|
8447
|
+
return {
|
|
8448
|
+
quantity,
|
|
8449
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8450
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8451
|
+
};
|
|
8452
|
+
}
|
|
8352
8453
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8353
8454
|
var CamProfileSchema = _enum([
|
|
8354
8455
|
"high",
|
|
@@ -8376,8 +8477,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8376
8477
|
"derived"
|
|
8377
8478
|
]);
|
|
8378
8479
|
var CamStreamResolutionSchema = object({
|
|
8379
|
-
width: number().int().positive(),
|
|
8380
|
-
height: number().int().positive()
|
|
8480
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8481
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8381
8482
|
});
|
|
8382
8483
|
var CameraStreamSchema = object({
|
|
8383
8484
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8891,6 +8992,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8891
8992
|
"filesystem-browse",
|
|
8892
8993
|
"flood",
|
|
8893
8994
|
"gas",
|
|
8995
|
+
"group-active",
|
|
8996
|
+
"group-commands",
|
|
8997
|
+
"group-status",
|
|
8894
8998
|
"heating-valve",
|
|
8895
8999
|
"humidifier",
|
|
8896
9000
|
"humidity-sensor",
|
|
@@ -8911,6 +9015,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8911
9015
|
"login-method",
|
|
8912
9016
|
"media-player",
|
|
8913
9017
|
"mesh-network",
|
|
9018
|
+
"meter",
|
|
8914
9019
|
"metrics-provider",
|
|
8915
9020
|
"model-convert",
|
|
8916
9021
|
"model-distributor",
|
|
@@ -9020,14 +9125,6 @@ Object.freeze({
|
|
|
9020
9125
|
{
|
|
9021
9126
|
"path": "aqi",
|
|
9022
9127
|
"valueType": "number"
|
|
9023
|
-
},
|
|
9024
|
-
{
|
|
9025
|
-
"path": "unit",
|
|
9026
|
-
"valueType": "string"
|
|
9027
|
-
},
|
|
9028
|
-
{
|
|
9029
|
-
"path": "precision",
|
|
9030
|
-
"valueType": "number"
|
|
9031
9128
|
}
|
|
9032
9129
|
],
|
|
9033
9130
|
"alarm-panel": [
|
|
@@ -9063,20 +9160,10 @@ Object.freeze({
|
|
|
9063
9160
|
"valueType": "boolean"
|
|
9064
9161
|
}
|
|
9065
9162
|
],
|
|
9066
|
-
"ambient-light-sensor": [
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
},
|
|
9071
|
-
{
|
|
9072
|
-
"path": "unit",
|
|
9073
|
-
"valueType": "string"
|
|
9074
|
-
},
|
|
9075
|
-
{
|
|
9076
|
-
"path": "precision",
|
|
9077
|
-
"valueType": "number"
|
|
9078
|
-
}
|
|
9079
|
-
],
|
|
9163
|
+
"ambient-light-sensor": [{
|
|
9164
|
+
"path": "lux",
|
|
9165
|
+
"valueType": "number"
|
|
9166
|
+
}],
|
|
9080
9167
|
"audio-metrics": [
|
|
9081
9168
|
{
|
|
9082
9169
|
"path": "ts",
|
|
@@ -9156,6 +9243,10 @@ Object.freeze({
|
|
|
9156
9243
|
"path": "lastUpdated",
|
|
9157
9244
|
"valueType": "number"
|
|
9158
9245
|
},
|
|
9246
|
+
{
|
|
9247
|
+
"path": "volts",
|
|
9248
|
+
"valueType": "number"
|
|
9249
|
+
},
|
|
9159
9250
|
{
|
|
9160
9251
|
"path": "lastContactAt",
|
|
9161
9252
|
"valueType": "number"
|
|
@@ -9398,10 +9489,6 @@ Object.freeze({
|
|
|
9398
9489
|
"datetime"
|
|
9399
9490
|
]
|
|
9400
9491
|
},
|
|
9401
|
-
{
|
|
9402
|
-
"path": "unit",
|
|
9403
|
-
"valueType": "string"
|
|
9404
|
-
},
|
|
9405
9492
|
{
|
|
9406
9493
|
"path": "min",
|
|
9407
9494
|
"valueType": "number"
|
|
@@ -9413,19 +9500,6 @@ Object.freeze({
|
|
|
9413
9500
|
{
|
|
9414
9501
|
"path": "step",
|
|
9415
9502
|
"valueType": "number"
|
|
9416
|
-
},
|
|
9417
|
-
{
|
|
9418
|
-
"path": "precision",
|
|
9419
|
-
"valueType": "number"
|
|
9420
|
-
},
|
|
9421
|
-
{
|
|
9422
|
-
"path": "format",
|
|
9423
|
-
"valueType": "enum",
|
|
9424
|
-
"enumValues": [
|
|
9425
|
-
"date",
|
|
9426
|
-
"time",
|
|
9427
|
-
"datetime"
|
|
9428
|
-
]
|
|
9429
9503
|
}
|
|
9430
9504
|
],
|
|
9431
9505
|
"cover": [
|
|
@@ -9666,13 +9740,8 @@ Object.freeze({
|
|
|
9666
9740
|
"path": "value",
|
|
9667
9741
|
"valueType": "string"
|
|
9668
9742
|
}, {
|
|
9669
|
-
"path": "
|
|
9670
|
-
"valueType": "
|
|
9671
|
-
"enumValues": [
|
|
9672
|
-
"date",
|
|
9673
|
-
"time",
|
|
9674
|
-
"datetime"
|
|
9675
|
-
]
|
|
9743
|
+
"path": "timestamp",
|
|
9744
|
+
"valueType": "boolean"
|
|
9676
9745
|
}],
|
|
9677
9746
|
"event-emitter": [
|
|
9678
9747
|
{
|
|
@@ -9745,6 +9814,24 @@ Object.freeze({
|
|
|
9745
9814
|
"path": "detected",
|
|
9746
9815
|
"valueType": "boolean"
|
|
9747
9816
|
}],
|
|
9817
|
+
"group-active": [{
|
|
9818
|
+
"path": "active",
|
|
9819
|
+
"valueType": "boolean"
|
|
9820
|
+
}],
|
|
9821
|
+
"group-status": [
|
|
9822
|
+
{
|
|
9823
|
+
"path": "included",
|
|
9824
|
+
"valueType": "number"
|
|
9825
|
+
},
|
|
9826
|
+
{
|
|
9827
|
+
"path": "excluded",
|
|
9828
|
+
"valueType": "number"
|
|
9829
|
+
},
|
|
9830
|
+
{
|
|
9831
|
+
"path": "total",
|
|
9832
|
+
"valueType": "number"
|
|
9833
|
+
}
|
|
9834
|
+
],
|
|
9748
9835
|
"heating-valve": [{
|
|
9749
9836
|
"path": "position",
|
|
9750
9837
|
"valueType": "number"
|
|
@@ -9779,20 +9866,10 @@ Object.freeze({
|
|
|
9779
9866
|
"valueType": "number"
|
|
9780
9867
|
}
|
|
9781
9868
|
],
|
|
9782
|
-
"humidity-sensor": [
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9786
|
-
},
|
|
9787
|
-
{
|
|
9788
|
-
"path": "unit",
|
|
9789
|
-
"valueType": "string"
|
|
9790
|
-
},
|
|
9791
|
-
{
|
|
9792
|
-
"path": "precision",
|
|
9793
|
-
"valueType": "number"
|
|
9794
|
-
}
|
|
9795
|
-
],
|
|
9869
|
+
"humidity-sensor": [{
|
|
9870
|
+
"path": "percent",
|
|
9871
|
+
"valueType": "number"
|
|
9872
|
+
}],
|
|
9796
9873
|
"image": [{
|
|
9797
9874
|
"path": "url",
|
|
9798
9875
|
"valueType": "string"
|
|
@@ -10000,6 +10077,10 @@ Object.freeze({
|
|
|
10000
10077
|
]
|
|
10001
10078
|
}
|
|
10002
10079
|
],
|
|
10080
|
+
"meter": [{
|
|
10081
|
+
"path": "value",
|
|
10082
|
+
"valueType": "number"
|
|
10083
|
+
}],
|
|
10003
10084
|
"motion": [
|
|
10004
10085
|
{
|
|
10005
10086
|
"path": "detected",
|
|
@@ -10131,20 +10212,10 @@ Object.freeze({
|
|
|
10131
10212
|
"valueType": "boolean"
|
|
10132
10213
|
}
|
|
10133
10214
|
],
|
|
10134
|
-
"numeric-sensor": [
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
},
|
|
10139
|
-
{
|
|
10140
|
-
"path": "unit",
|
|
10141
|
-
"valueType": "string"
|
|
10142
|
-
},
|
|
10143
|
-
{
|
|
10144
|
-
"path": "precision",
|
|
10145
|
-
"valueType": "number"
|
|
10146
|
-
}
|
|
10147
|
-
],
|
|
10215
|
+
"numeric-sensor": [{
|
|
10216
|
+
"path": "value",
|
|
10217
|
+
"valueType": "number"
|
|
10218
|
+
}],
|
|
10148
10219
|
"pet-feeder": [
|
|
10149
10220
|
{
|
|
10150
10221
|
"path": "foodLevel",
|
|
@@ -10236,14 +10307,6 @@ Object.freeze({
|
|
|
10236
10307
|
{
|
|
10237
10308
|
"path": "powerFactor",
|
|
10238
10309
|
"valueType": "number"
|
|
10239
|
-
},
|
|
10240
|
-
{
|
|
10241
|
-
"path": "unit",
|
|
10242
|
-
"valueType": "string"
|
|
10243
|
-
},
|
|
10244
|
-
{
|
|
10245
|
-
"path": "precision",
|
|
10246
|
-
"valueType": "number"
|
|
10247
10310
|
}
|
|
10248
10311
|
],
|
|
10249
10312
|
"presence": [
|
|
@@ -10272,20 +10335,10 @@ Object.freeze({
|
|
|
10272
10335
|
"valueType": "number"
|
|
10273
10336
|
}
|
|
10274
10337
|
],
|
|
10275
|
-
"pressure-sensor": [
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
},
|
|
10280
|
-
{
|
|
10281
|
-
"path": "unit",
|
|
10282
|
-
"valueType": "string"
|
|
10283
|
-
},
|
|
10284
|
-
{
|
|
10285
|
-
"path": "precision",
|
|
10286
|
-
"valueType": "number"
|
|
10287
|
-
}
|
|
10288
|
-
],
|
|
10338
|
+
"pressure-sensor": [{
|
|
10339
|
+
"path": "hpa",
|
|
10340
|
+
"valueType": "number"
|
|
10341
|
+
}],
|
|
10289
10342
|
"privacy-mask": [{
|
|
10290
10343
|
"path": "enabled",
|
|
10291
10344
|
"valueType": "boolean"
|
|
@@ -10596,20 +10649,10 @@ Object.freeze({
|
|
|
10596
10649
|
"path": "tampered",
|
|
10597
10650
|
"valueType": "boolean"
|
|
10598
10651
|
}],
|
|
10599
|
-
"temperature-sensor": [
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
|
|
10603
|
-
},
|
|
10604
|
-
{
|
|
10605
|
-
"path": "unit",
|
|
10606
|
-
"valueType": "string"
|
|
10607
|
-
},
|
|
10608
|
-
{
|
|
10609
|
-
"path": "precision",
|
|
10610
|
-
"valueType": "number"
|
|
10611
|
-
}
|
|
10612
|
-
],
|
|
10652
|
+
"temperature-sensor": [{
|
|
10653
|
+
"path": "celsius",
|
|
10654
|
+
"valueType": "number"
|
|
10655
|
+
}],
|
|
10613
10656
|
"update": [
|
|
10614
10657
|
{
|
|
10615
10658
|
"path": "currentVersion",
|
|
@@ -10720,10 +10763,6 @@ Object.freeze({
|
|
|
10720
10763
|
"path": "temperature",
|
|
10721
10764
|
"valueType": "number"
|
|
10722
10765
|
},
|
|
10723
|
-
{
|
|
10724
|
-
"path": "temperatureUnit",
|
|
10725
|
-
"valueType": "string"
|
|
10726
|
-
},
|
|
10727
10766
|
{
|
|
10728
10767
|
"path": "humidity",
|
|
10729
10768
|
"valueType": "number"
|
|
@@ -10732,18 +10771,10 @@ Object.freeze({
|
|
|
10732
10771
|
"path": "pressure",
|
|
10733
10772
|
"valueType": "number"
|
|
10734
10773
|
},
|
|
10735
|
-
{
|
|
10736
|
-
"path": "pressureUnit",
|
|
10737
|
-
"valueType": "string"
|
|
10738
|
-
},
|
|
10739
10774
|
{
|
|
10740
10775
|
"path": "windSpeed",
|
|
10741
10776
|
"valueType": "number"
|
|
10742
10777
|
},
|
|
10743
|
-
{
|
|
10744
|
-
"path": "windSpeedUnit",
|
|
10745
|
-
"valueType": "string"
|
|
10746
|
-
},
|
|
10747
10778
|
{
|
|
10748
10779
|
"path": "windBearing",
|
|
10749
10780
|
"valueType": "number"
|
|
@@ -10793,7 +10824,7 @@ object({
|
|
|
10793
10824
|
params: record(string(), union([string(), number()])).optional()
|
|
10794
10825
|
});
|
|
10795
10826
|
//#endregion
|
|
10796
|
-
//#region ../types/dist/err-msg-
|
|
10827
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10797
10828
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10798
10829
|
DeviceType["Camera"] = "camera";
|
|
10799
10830
|
DeviceType["Hub"] = "hub";
|
|
@@ -10887,8 +10918,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10887
10918
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10888
10919
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10889
10920
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10890
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10921
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10922
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10891
10923
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10924
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10925
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10926
|
+
DeviceType["Washer"] = "washer";
|
|
10927
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10928
|
+
DeviceType["Dryer"] = "dryer";
|
|
10892
10929
|
return DeviceType;
|
|
10893
10930
|
}({});
|
|
10894
10931
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11136,7 +11173,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11136
11173
|
return DeviceRole;
|
|
11137
11174
|
}({});
|
|
11138
11175
|
//#endregion
|
|
11139
|
-
//#region ../types/dist/composition-
|
|
11176
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11140
11177
|
/**
|
|
11141
11178
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11142
11179
|
*
|
|
@@ -11451,6 +11488,13 @@ var table = {
|
|
|
11451
11488
|
apply: () => {
|
|
11452
11489
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11453
11490
|
}
|
|
11491
|
+
},
|
|
11492
|
+
schmitt: {
|
|
11493
|
+
minArgs: 3,
|
|
11494
|
+
maxArgs: 5,
|
|
11495
|
+
apply: () => {
|
|
11496
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11497
|
+
}
|
|
11454
11498
|
}
|
|
11455
11499
|
};
|
|
11456
11500
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11891,15 +11935,232 @@ function validateExpressionSource(src) {
|
|
|
11891
11935
|
}
|
|
11892
11936
|
return null;
|
|
11893
11937
|
}
|
|
11894
|
-
/**
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11938
|
+
/**
|
|
11939
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11940
|
+
*
|
|
11941
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11942
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11943
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11944
|
+
*
|
|
11945
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11946
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11947
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11948
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11949
|
+
* can move later without moving the others.
|
|
11950
|
+
*/
|
|
11951
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11952
|
+
var APPLIANCE_KINDS = [
|
|
11953
|
+
"washer",
|
|
11954
|
+
"dryer",
|
|
11955
|
+
"dishwasher"
|
|
11956
|
+
];
|
|
11957
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11958
|
+
/**
|
|
11959
|
+
* Statistics and integrals over a history read (D944).
|
|
11960
|
+
*
|
|
11961
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11962
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11963
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11964
|
+
* as zero. A truncated read is not published.
|
|
11965
|
+
*/
|
|
11966
|
+
var STATISTIC_STATS = [
|
|
11967
|
+
"min",
|
|
11968
|
+
"max",
|
|
11969
|
+
"mean",
|
|
11970
|
+
"sum",
|
|
11971
|
+
"count",
|
|
11972
|
+
"change"
|
|
11973
|
+
];
|
|
11974
|
+
/**
|
|
11975
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11976
|
+
*
|
|
11977
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11978
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11979
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11980
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11981
|
+
*/
|
|
11982
|
+
var MINUTE_MS = 6e4;
|
|
11983
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11984
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11985
|
+
var ROLLING_SPANS = [
|
|
11986
|
+
"1h",
|
|
11987
|
+
"24h",
|
|
11988
|
+
"2d",
|
|
11989
|
+
"7d",
|
|
11990
|
+
"30d",
|
|
11991
|
+
"custom"
|
|
11992
|
+
];
|
|
11993
|
+
var CALENDAR_PERIODS = [
|
|
11994
|
+
"today",
|
|
11995
|
+
"yesterday",
|
|
11996
|
+
"this-week",
|
|
11997
|
+
"this-month"
|
|
11998
|
+
];
|
|
11999
|
+
var RESET_PERIODS = [
|
|
12000
|
+
"never",
|
|
12001
|
+
"daily",
|
|
12002
|
+
"weekly",
|
|
12003
|
+
"monthly"
|
|
12004
|
+
];
|
|
12005
|
+
5 * MINUTE_MS;
|
|
12006
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
12007
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
12008
|
+
var rollingWindowObject = object({
|
|
12009
|
+
kind: literal("rolling"),
|
|
12010
|
+
span: _enum(ROLLING_SPANS),
|
|
12011
|
+
customMinutes: number().int().min(5).optional()
|
|
12012
|
+
}).check((payload) => {
|
|
12013
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
12014
|
+
code: "custom",
|
|
12015
|
+
message: "a custom range needs a duration in minutes",
|
|
12016
|
+
path: ["customMinutes"],
|
|
12017
|
+
input: payload.value
|
|
12018
|
+
});
|
|
12019
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
12020
|
+
code: "custom",
|
|
12021
|
+
message: "only a custom range carries a duration",
|
|
12022
|
+
path: ["customMinutes"],
|
|
12023
|
+
input: payload.value
|
|
12024
|
+
});
|
|
12025
|
+
});
|
|
12026
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12027
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12028
|
+
kind: literal("calendar"),
|
|
12029
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12030
|
+
})]);
|
|
12031
|
+
/**
|
|
12032
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
12033
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
12034
|
+
* `composition.ts` (D659).
|
|
12035
|
+
*/
|
|
11898
12036
|
var CompositionSourceRefSchema = object({
|
|
11899
12037
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11900
12038
|
addonId: string().min(1),
|
|
11901
12039
|
stableId: string().min(1)
|
|
11902
12040
|
});
|
|
12041
|
+
var GROUP_TEMPLATE_IDS = [
|
|
12042
|
+
"temperature",
|
|
12043
|
+
"humidity",
|
|
12044
|
+
"pressure",
|
|
12045
|
+
"illuminance",
|
|
12046
|
+
"power",
|
|
12047
|
+
"energy",
|
|
12048
|
+
"battery",
|
|
12049
|
+
"numeric",
|
|
12050
|
+
"motion",
|
|
12051
|
+
"contact",
|
|
12052
|
+
"leak",
|
|
12053
|
+
"smoke",
|
|
12054
|
+
"occupancy",
|
|
12055
|
+
"binary",
|
|
12056
|
+
"switch",
|
|
12057
|
+
"light",
|
|
12058
|
+
"fan",
|
|
12059
|
+
"cover",
|
|
12060
|
+
"valve",
|
|
12061
|
+
"lock",
|
|
12062
|
+
"media-player",
|
|
12063
|
+
"climate"
|
|
12064
|
+
];
|
|
12065
|
+
var NUMERIC_AGGREGATES = [
|
|
12066
|
+
"mean",
|
|
12067
|
+
"median",
|
|
12068
|
+
"min",
|
|
12069
|
+
"max",
|
|
12070
|
+
"sum"
|
|
12071
|
+
];
|
|
12072
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12073
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12074
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12075
|
+
var AGGREGATE_REDUCERS = [
|
|
12076
|
+
"mean",
|
|
12077
|
+
"median",
|
|
12078
|
+
"min",
|
|
12079
|
+
"max",
|
|
12080
|
+
"sum",
|
|
12081
|
+
"any",
|
|
12082
|
+
"all"
|
|
12083
|
+
];
|
|
12084
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12085
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12086
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12087
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12088
|
+
var HelperMemberSchema = object({
|
|
12089
|
+
source: CompositionSourceRefSchema,
|
|
12090
|
+
cap: string().min(1),
|
|
12091
|
+
fieldPath: string().min(1)
|
|
12092
|
+
});
|
|
12093
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12094
|
+
object({
|
|
12095
|
+
kind: literal("group"),
|
|
12096
|
+
templateId: GroupTemplateIdSchema,
|
|
12097
|
+
aggregate: AggregateReducerSchema,
|
|
12098
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12099
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12100
|
+
active: ActiveCriterionSchema.optional()
|
|
12101
|
+
}),
|
|
12102
|
+
object({
|
|
12103
|
+
kind: literal("appliance"),
|
|
12104
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12105
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12106
|
+
thresholdWatts: number().positive(),
|
|
12107
|
+
startDwellMs: number().int().nonnegative(),
|
|
12108
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12109
|
+
member: HelperMemberSchema
|
|
12110
|
+
}),
|
|
12111
|
+
object({
|
|
12112
|
+
kind: literal("statistic"),
|
|
12113
|
+
stat: _enum(STATISTIC_STATS),
|
|
12114
|
+
window: StatisticWindowSchema,
|
|
12115
|
+
source: HelperMemberSchema
|
|
12116
|
+
}),
|
|
12117
|
+
object({
|
|
12118
|
+
kind: literal("integral"),
|
|
12119
|
+
reset: _enum(RESET_PERIODS),
|
|
12120
|
+
output: _enum(["energy", "meter"]),
|
|
12121
|
+
source: HelperMemberSchema
|
|
12122
|
+
}),
|
|
12123
|
+
object({
|
|
12124
|
+
kind: literal("threshold"),
|
|
12125
|
+
source: HelperMemberSchema,
|
|
12126
|
+
high: number(),
|
|
12127
|
+
low: number(),
|
|
12128
|
+
onForMs: number().int().nonnegative(),
|
|
12129
|
+
offForMs: number().int().nonnegative()
|
|
12130
|
+
}),
|
|
12131
|
+
object({
|
|
12132
|
+
kind: literal("arithmetic"),
|
|
12133
|
+
op: _enum([
|
|
12134
|
+
"sum",
|
|
12135
|
+
"difference",
|
|
12136
|
+
"ratio"
|
|
12137
|
+
]),
|
|
12138
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12139
|
+
}),
|
|
12140
|
+
object({
|
|
12141
|
+
kind: literal("expression"),
|
|
12142
|
+
expr: string().min(1),
|
|
12143
|
+
inputs: array(object({
|
|
12144
|
+
name: string().min(1),
|
|
12145
|
+
member: HelperMemberSchema
|
|
12146
|
+
})).min(1).max(64),
|
|
12147
|
+
output: _enum(["number", "boolean"])
|
|
12148
|
+
}),
|
|
12149
|
+
object({
|
|
12150
|
+
kind: literal("derivative"),
|
|
12151
|
+
window: RollingWindowSchema,
|
|
12152
|
+
per: _enum([
|
|
12153
|
+
"second",
|
|
12154
|
+
"minute",
|
|
12155
|
+
"hour"
|
|
12156
|
+
]),
|
|
12157
|
+
source: HelperMemberSchema
|
|
12158
|
+
})
|
|
12159
|
+
]);
|
|
12160
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12161
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12162
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12163
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11903
12164
|
/** One field of one capability of one source device. */
|
|
11904
12165
|
var CompositionFieldReadSchema = object({
|
|
11905
12166
|
source: CompositionSourceRefSchema,
|
|
@@ -11943,7 +12204,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11943
12204
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11944
12205
|
CompositionFromSourceSchema,
|
|
11945
12206
|
CompositionExpressionSourceSchema,
|
|
11946
|
-
CompositionCodeSourceSchema
|
|
12207
|
+
CompositionCodeSourceSchema,
|
|
12208
|
+
object({
|
|
12209
|
+
kind: literal("aggregate"),
|
|
12210
|
+
reducer: _enum([
|
|
12211
|
+
"mean",
|
|
12212
|
+
"median",
|
|
12213
|
+
"min",
|
|
12214
|
+
"max",
|
|
12215
|
+
"sum",
|
|
12216
|
+
"any",
|
|
12217
|
+
"all"
|
|
12218
|
+
]),
|
|
12219
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12220
|
+
/**
|
|
12221
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12222
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12223
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12224
|
+
*/
|
|
12225
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12226
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12227
|
+
publish: _enum([
|
|
12228
|
+
"value",
|
|
12229
|
+
"included",
|
|
12230
|
+
"excluded",
|
|
12231
|
+
"total"
|
|
12232
|
+
]),
|
|
12233
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12234
|
+
empty: _enum([
|
|
12235
|
+
"null",
|
|
12236
|
+
"omit",
|
|
12237
|
+
"offline"
|
|
12238
|
+
])
|
|
12239
|
+
}),
|
|
12240
|
+
object({
|
|
12241
|
+
kind: literal("series"),
|
|
12242
|
+
read: CompositionFieldReadSchema,
|
|
12243
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12244
|
+
publish: _enum([
|
|
12245
|
+
"value",
|
|
12246
|
+
"included",
|
|
12247
|
+
"excluded",
|
|
12248
|
+
"total"
|
|
12249
|
+
]),
|
|
12250
|
+
/**
|
|
12251
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12252
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12253
|
+
*/
|
|
12254
|
+
empty: _enum([
|
|
12255
|
+
"null",
|
|
12256
|
+
"omit",
|
|
12257
|
+
"offline"
|
|
12258
|
+
])
|
|
12259
|
+
})
|
|
11947
12260
|
]);
|
|
11948
12261
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11949
12262
|
kind: literal("forward"),
|
|
@@ -11989,7 +12302,13 @@ var CompositionSchema = object({
|
|
|
11989
12302
|
kind: literal("existing"),
|
|
11990
12303
|
device: CompositionSourceRefSchema
|
|
11991
12304
|
})]),
|
|
11992
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12305
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12306
|
+
/**
|
|
12307
|
+
* Present when the block is a helper template. Absent on a free
|
|
12308
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12309
|
+
* never the compiled features.
|
|
12310
|
+
*/
|
|
12311
|
+
helper: HelperSpecSchema.optional()
|
|
11993
12312
|
}).superRefine((composition, ctx) => {
|
|
11994
12313
|
const seen = /* @__PURE__ */ new Set();
|
|
11995
12314
|
composition.features.forEach((feature, index) => {
|
|
@@ -17096,7 +17415,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17096
17415
|
*/
|
|
17097
17416
|
interactiveConnectPath: string().min(1).optional(),
|
|
17098
17417
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17099
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17418
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17419
|
+
/**
|
|
17420
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17421
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17422
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17423
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17424
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17425
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17426
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17427
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17428
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17429
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17430
|
+
* offers it as the default path; the fields the session fills are
|
|
17431
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17432
|
+
*/
|
|
17433
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17100
17434
|
}))
|
|
17101
17435
|
});
|
|
17102
17436
|
var ListInputSchema = object({
|
|
@@ -18140,7 +18474,12 @@ var CompositionProblemSchema = object({
|
|
|
18140
18474
|
"item-field-reserved",
|
|
18141
18475
|
"target-missing",
|
|
18142
18476
|
"target-unreadable",
|
|
18143
|
-
"not-replaceable"
|
|
18477
|
+
"not-replaceable",
|
|
18478
|
+
"native-capability-replace",
|
|
18479
|
+
"mixed-quantity",
|
|
18480
|
+
"helper-mismatch",
|
|
18481
|
+
"member-constraint",
|
|
18482
|
+
"retention"
|
|
18144
18483
|
]),
|
|
18145
18484
|
path: string(),
|
|
18146
18485
|
message: string()
|
|
@@ -18161,7 +18500,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18161
18500
|
"null",
|
|
18162
18501
|
"offline",
|
|
18163
18502
|
"unknown",
|
|
18164
|
-
"release"
|
|
18503
|
+
"release",
|
|
18504
|
+
"omit"
|
|
18165
18505
|
]);
|
|
18166
18506
|
/**
|
|
18167
18507
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18198,9 +18538,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18198
18538
|
reads: array(CompositionFieldReadSchema)
|
|
18199
18539
|
});
|
|
18200
18540
|
/**
|
|
18201
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18202
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18203
|
-
*
|
|
18541
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18542
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18543
|
+
* Replacing a capability the device already serves is refused
|
|
18544
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18545
|
+
* wire for a claim the hub already holds.
|
|
18204
18546
|
*/
|
|
18205
18547
|
var CompositionFeatureModeSchema = _enum([
|
|
18206
18548
|
"new",
|
|
@@ -18371,8 +18713,392 @@ Object.freeze({
|
|
|
18371
18713
|
latchedAt: {
|
|
18372
18714
|
kind: "fixed",
|
|
18373
18715
|
result: ["number", "null"]
|
|
18716
|
+
},
|
|
18717
|
+
schmitt: {
|
|
18718
|
+
kind: "fixed",
|
|
18719
|
+
result: ["boolean", "null"]
|
|
18374
18720
|
}
|
|
18375
18721
|
});
|
|
18722
|
+
/**
|
|
18723
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18724
|
+
* Data, not a form default written into the block.
|
|
18725
|
+
*/
|
|
18726
|
+
var NOW$2 = {
|
|
18727
|
+
fieldPath: "lastFetchedAt",
|
|
18728
|
+
expr: "now"
|
|
18729
|
+
};
|
|
18730
|
+
var CHANGED = {
|
|
18731
|
+
fieldPath: "lastChangedAt",
|
|
18732
|
+
expr: "now"
|
|
18733
|
+
};
|
|
18734
|
+
function numeric(input) {
|
|
18735
|
+
return {
|
|
18736
|
+
...input,
|
|
18737
|
+
family: "numeric",
|
|
18738
|
+
deviceType: DeviceType.Sensor,
|
|
18739
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18740
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18741
|
+
activeWhen: void 0,
|
|
18742
|
+
commandCaps: [],
|
|
18743
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18744
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18745
|
+
accept: [{
|
|
18746
|
+
cap: input.outputCap,
|
|
18747
|
+
fieldPath: input.outputField
|
|
18748
|
+
}]
|
|
18749
|
+
};
|
|
18750
|
+
}
|
|
18751
|
+
function binary(input) {
|
|
18752
|
+
return {
|
|
18753
|
+
...input,
|
|
18754
|
+
family: "binary",
|
|
18755
|
+
deviceType: DeviceType.Sensor,
|
|
18756
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18757
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18758
|
+
activeWhen: void 0,
|
|
18759
|
+
commandCaps: [],
|
|
18760
|
+
quantity: "none",
|
|
18761
|
+
baseUnit: void 0,
|
|
18762
|
+
aggregates: BINARY_AGGREGATES,
|
|
18763
|
+
empty: "offline"
|
|
18764
|
+
};
|
|
18765
|
+
}
|
|
18766
|
+
var GROUP_TEMPLATES = [
|
|
18767
|
+
numeric({
|
|
18768
|
+
id: "temperature",
|
|
18769
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18770
|
+
role: DeviceRole.TemperatureSensor,
|
|
18771
|
+
outputCap: "temperature-sensor",
|
|
18772
|
+
outputField: "celsius",
|
|
18773
|
+
quantity: "temperature",
|
|
18774
|
+
defaultAggregate: "mean",
|
|
18775
|
+
empty: "null",
|
|
18776
|
+
companions: [NOW$2]
|
|
18777
|
+
}),
|
|
18778
|
+
numeric({
|
|
18779
|
+
id: "humidity",
|
|
18780
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18781
|
+
role: DeviceRole.HumiditySensor,
|
|
18782
|
+
outputCap: "humidity-sensor",
|
|
18783
|
+
outputField: "percent",
|
|
18784
|
+
quantity: "humidity",
|
|
18785
|
+
defaultAggregate: "mean",
|
|
18786
|
+
empty: "null",
|
|
18787
|
+
companions: [NOW$2]
|
|
18788
|
+
}),
|
|
18789
|
+
numeric({
|
|
18790
|
+
id: "pressure",
|
|
18791
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18792
|
+
role: DeviceRole.PressureSensor,
|
|
18793
|
+
outputCap: "pressure-sensor",
|
|
18794
|
+
outputField: "hpa",
|
|
18795
|
+
quantity: "pressure",
|
|
18796
|
+
defaultAggregate: "mean",
|
|
18797
|
+
empty: "null",
|
|
18798
|
+
companions: [NOW$2]
|
|
18799
|
+
}),
|
|
18800
|
+
numeric({
|
|
18801
|
+
id: "illuminance",
|
|
18802
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18803
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18804
|
+
outputCap: "ambient-light-sensor",
|
|
18805
|
+
outputField: "lux",
|
|
18806
|
+
quantity: "illuminance",
|
|
18807
|
+
defaultAggregate: "mean",
|
|
18808
|
+
empty: "null",
|
|
18809
|
+
companions: [NOW$2]
|
|
18810
|
+
}),
|
|
18811
|
+
numeric({
|
|
18812
|
+
id: "power",
|
|
18813
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18814
|
+
role: DeviceRole.PowerSensor,
|
|
18815
|
+
outputCap: "power-meter",
|
|
18816
|
+
outputField: "watts",
|
|
18817
|
+
quantity: "power",
|
|
18818
|
+
defaultAggregate: "sum",
|
|
18819
|
+
empty: "omit",
|
|
18820
|
+
companions: [NOW$2]
|
|
18821
|
+
}),
|
|
18822
|
+
numeric({
|
|
18823
|
+
id: "energy",
|
|
18824
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18825
|
+
role: DeviceRole.EnergySensor,
|
|
18826
|
+
outputCap: "power-meter",
|
|
18827
|
+
outputField: "kwhTotal",
|
|
18828
|
+
quantity: "energy",
|
|
18829
|
+
defaultAggregate: "sum",
|
|
18830
|
+
empty: "omit",
|
|
18831
|
+
companions: [NOW$2]
|
|
18832
|
+
}),
|
|
18833
|
+
numeric({
|
|
18834
|
+
id: "battery",
|
|
18835
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18836
|
+
role: DeviceRole.BatterySensor,
|
|
18837
|
+
outputCap: "battery",
|
|
18838
|
+
outputField: "percentage",
|
|
18839
|
+
quantity: "percentage",
|
|
18840
|
+
defaultAggregate: "mean",
|
|
18841
|
+
empty: "null",
|
|
18842
|
+
companions: [
|
|
18843
|
+
{
|
|
18844
|
+
fieldPath: "charging",
|
|
18845
|
+
expr: "\"unknown\""
|
|
18846
|
+
},
|
|
18847
|
+
{
|
|
18848
|
+
fieldPath: "sleeping",
|
|
18849
|
+
expr: "false"
|
|
18850
|
+
},
|
|
18851
|
+
{
|
|
18852
|
+
fieldPath: "lastUpdated",
|
|
18853
|
+
expr: "now"
|
|
18854
|
+
}
|
|
18855
|
+
]
|
|
18856
|
+
}),
|
|
18857
|
+
numeric({
|
|
18858
|
+
id: "numeric",
|
|
18859
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18860
|
+
role: DeviceRole.NumericSensor,
|
|
18861
|
+
outputCap: "numeric-sensor",
|
|
18862
|
+
outputField: "value",
|
|
18863
|
+
quantity: "device",
|
|
18864
|
+
defaultAggregate: "mean",
|
|
18865
|
+
empty: "null",
|
|
18866
|
+
companions: [NOW$2]
|
|
18867
|
+
}),
|
|
18868
|
+
binary({
|
|
18869
|
+
id: "motion",
|
|
18870
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18871
|
+
role: DeviceRole.MotionSensor,
|
|
18872
|
+
outputCap: "motion",
|
|
18873
|
+
outputField: "detected",
|
|
18874
|
+
defaultAggregate: "any",
|
|
18875
|
+
accept: [{
|
|
18876
|
+
cap: "motion",
|
|
18877
|
+
fieldPath: "detected"
|
|
18878
|
+
}],
|
|
18879
|
+
companions: [{
|
|
18880
|
+
fieldPath: "lastDetectedAt",
|
|
18881
|
+
expr: "null"
|
|
18882
|
+
}, {
|
|
18883
|
+
fieldPath: "autoClearAfterMs",
|
|
18884
|
+
expr: "null"
|
|
18885
|
+
}]
|
|
18886
|
+
}),
|
|
18887
|
+
binary({
|
|
18888
|
+
id: "contact",
|
|
18889
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18890
|
+
role: DeviceRole.ContactSensor,
|
|
18891
|
+
outputCap: "contact",
|
|
18892
|
+
outputField: "entryOpen",
|
|
18893
|
+
defaultAggregate: "any",
|
|
18894
|
+
accept: [{
|
|
18895
|
+
cap: "contact",
|
|
18896
|
+
fieldPath: "entryOpen"
|
|
18897
|
+
}],
|
|
18898
|
+
companions: [CHANGED]
|
|
18899
|
+
}),
|
|
18900
|
+
binary({
|
|
18901
|
+
id: "leak",
|
|
18902
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18903
|
+
role: DeviceRole.LeakSensor,
|
|
18904
|
+
outputCap: "flood",
|
|
18905
|
+
outputField: "flooded",
|
|
18906
|
+
defaultAggregate: "any",
|
|
18907
|
+
accept: [{
|
|
18908
|
+
cap: "flood",
|
|
18909
|
+
fieldPath: "flooded"
|
|
18910
|
+
}],
|
|
18911
|
+
companions: [CHANGED]
|
|
18912
|
+
}),
|
|
18913
|
+
binary({
|
|
18914
|
+
id: "smoke",
|
|
18915
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18916
|
+
role: DeviceRole.SmokeSensor,
|
|
18917
|
+
outputCap: "smoke",
|
|
18918
|
+
outputField: "detected",
|
|
18919
|
+
defaultAggregate: "any",
|
|
18920
|
+
accept: [{
|
|
18921
|
+
cap: "smoke",
|
|
18922
|
+
fieldPath: "detected"
|
|
18923
|
+
}],
|
|
18924
|
+
companions: [CHANGED]
|
|
18925
|
+
}),
|
|
18926
|
+
binary({
|
|
18927
|
+
id: "occupancy",
|
|
18928
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18929
|
+
role: DeviceRole.BinarySensor,
|
|
18930
|
+
outputCap: "binary",
|
|
18931
|
+
outputField: "on",
|
|
18932
|
+
defaultAggregate: "any",
|
|
18933
|
+
accept: [{
|
|
18934
|
+
cap: "motion",
|
|
18935
|
+
fieldPath: "detected"
|
|
18936
|
+
}, {
|
|
18937
|
+
cap: "binary",
|
|
18938
|
+
fieldPath: "on"
|
|
18939
|
+
}],
|
|
18940
|
+
companions: [CHANGED]
|
|
18941
|
+
}),
|
|
18942
|
+
binary({
|
|
18943
|
+
id: "binary",
|
|
18944
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18945
|
+
role: DeviceRole.BinarySensor,
|
|
18946
|
+
outputCap: "binary",
|
|
18947
|
+
outputField: "on",
|
|
18948
|
+
defaultAggregate: "any",
|
|
18949
|
+
accept: [{
|
|
18950
|
+
cap: "binary",
|
|
18951
|
+
fieldPath: "on"
|
|
18952
|
+
}],
|
|
18953
|
+
companions: [CHANGED]
|
|
18954
|
+
}),
|
|
18955
|
+
actuator({
|
|
18956
|
+
id: "switch",
|
|
18957
|
+
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.",
|
|
18958
|
+
deviceType: DeviceType.Switch,
|
|
18959
|
+
outputCap: "switch",
|
|
18960
|
+
outputField: "on",
|
|
18961
|
+
member: {
|
|
18962
|
+
cap: "switch",
|
|
18963
|
+
fieldPath: "on"
|
|
18964
|
+
},
|
|
18965
|
+
commandCaps: ["switch"]
|
|
18966
|
+
}),
|
|
18967
|
+
actuator({
|
|
18968
|
+
id: "light",
|
|
18969
|
+
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.",
|
|
18970
|
+
deviceType: DeviceType.Light,
|
|
18971
|
+
outputCap: "switch",
|
|
18972
|
+
outputField: "on",
|
|
18973
|
+
member: {
|
|
18974
|
+
cap: "switch",
|
|
18975
|
+
fieldPath: "on"
|
|
18976
|
+
},
|
|
18977
|
+
commandCaps: [
|
|
18978
|
+
"switch",
|
|
18979
|
+
"brightness",
|
|
18980
|
+
"color"
|
|
18981
|
+
]
|
|
18982
|
+
}),
|
|
18983
|
+
actuator({
|
|
18984
|
+
id: "fan",
|
|
18985
|
+
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.",
|
|
18986
|
+
deviceType: DeviceType.Fan,
|
|
18987
|
+
outputCap: "switch",
|
|
18988
|
+
outputField: "on",
|
|
18989
|
+
member: {
|
|
18990
|
+
cap: "switch",
|
|
18991
|
+
fieldPath: "on"
|
|
18992
|
+
},
|
|
18993
|
+
commandCaps: ["switch", "fan-control"]
|
|
18994
|
+
}),
|
|
18995
|
+
actuator({
|
|
18996
|
+
id: "cover",
|
|
18997
|
+
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.",
|
|
18998
|
+
deviceType: DeviceType.Cover,
|
|
18999
|
+
outputCap: "group-active",
|
|
19000
|
+
outputField: "active",
|
|
19001
|
+
member: {
|
|
19002
|
+
cap: "cover",
|
|
19003
|
+
fieldPath: "state"
|
|
19004
|
+
},
|
|
19005
|
+
activeWhen: [
|
|
19006
|
+
"open",
|
|
19007
|
+
"opening",
|
|
19008
|
+
"stopped"
|
|
19009
|
+
],
|
|
19010
|
+
commandCaps: ["cover"]
|
|
19011
|
+
}),
|
|
19012
|
+
actuator({
|
|
19013
|
+
id: "valve",
|
|
19014
|
+
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.",
|
|
19015
|
+
deviceType: DeviceType.Valve,
|
|
19016
|
+
outputCap: "group-active",
|
|
19017
|
+
outputField: "active",
|
|
19018
|
+
member: {
|
|
19019
|
+
cap: "valve",
|
|
19020
|
+
fieldPath: "state"
|
|
19021
|
+
},
|
|
19022
|
+
activeWhen: [
|
|
19023
|
+
"open",
|
|
19024
|
+
"opening",
|
|
19025
|
+
"stopped"
|
|
19026
|
+
],
|
|
19027
|
+
commandCaps: ["valve"]
|
|
19028
|
+
}),
|
|
19029
|
+
actuator({
|
|
19030
|
+
id: "lock",
|
|
19031
|
+
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.",
|
|
19032
|
+
deviceType: DeviceType.Lock,
|
|
19033
|
+
outputCap: "group-active",
|
|
19034
|
+
outputField: "active",
|
|
19035
|
+
member: {
|
|
19036
|
+
cap: "lock-control",
|
|
19037
|
+
fieldPath: "state"
|
|
19038
|
+
},
|
|
19039
|
+
activeWhen: ["locked"],
|
|
19040
|
+
commandCaps: ["lock-control"]
|
|
19041
|
+
}),
|
|
19042
|
+
actuator({
|
|
19043
|
+
id: "media-player",
|
|
19044
|
+
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.",
|
|
19045
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19046
|
+
outputCap: "group-active",
|
|
19047
|
+
outputField: "active",
|
|
19048
|
+
member: {
|
|
19049
|
+
cap: "media-player",
|
|
19050
|
+
fieldPath: "state"
|
|
19051
|
+
},
|
|
19052
|
+
activeWhen: ["playing", "buffering"],
|
|
19053
|
+
commandCaps: ["media-player"]
|
|
19054
|
+
}),
|
|
19055
|
+
actuator({
|
|
19056
|
+
id: "climate",
|
|
19057
|
+
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.",
|
|
19058
|
+
deviceType: DeviceType.Thermostat,
|
|
19059
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19060
|
+
outputCap: "group-active",
|
|
19061
|
+
outputField: "active",
|
|
19062
|
+
member: {
|
|
19063
|
+
cap: "climate-control",
|
|
19064
|
+
fieldPath: "mode"
|
|
19065
|
+
},
|
|
19066
|
+
activeWhen: [
|
|
19067
|
+
"heat",
|
|
19068
|
+
"cool",
|
|
19069
|
+
"auto",
|
|
19070
|
+
"heat_cool",
|
|
19071
|
+
"fan_only",
|
|
19072
|
+
"dry"
|
|
19073
|
+
],
|
|
19074
|
+
commandCaps: ["climate-control"]
|
|
19075
|
+
})
|
|
19076
|
+
];
|
|
19077
|
+
function actuator(input) {
|
|
19078
|
+
return {
|
|
19079
|
+
id: input.id,
|
|
19080
|
+
summary: input.summary,
|
|
19081
|
+
deviceType: input.deviceType,
|
|
19082
|
+
outputCap: input.outputCap,
|
|
19083
|
+
outputField: input.outputField,
|
|
19084
|
+
commandCaps: input.commandCaps,
|
|
19085
|
+
family: "actuator",
|
|
19086
|
+
role: void 0,
|
|
19087
|
+
memberDeviceType: input.deviceType,
|
|
19088
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19089
|
+
activeWhen: input.activeWhen,
|
|
19090
|
+
quantity: "none",
|
|
19091
|
+
baseUnit: void 0,
|
|
19092
|
+
aggregates: BINARY_AGGREGATES,
|
|
19093
|
+
defaultAggregate: "any",
|
|
19094
|
+
empty: "offline",
|
|
19095
|
+
accept: [input.member],
|
|
19096
|
+
companions: [CHANGED]
|
|
19097
|
+
};
|
|
19098
|
+
}
|
|
19099
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19100
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19101
|
+
DeviceType.Camera;
|
|
18376
19102
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18377
19103
|
/**
|
|
18378
19104
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20086,12 +20812,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
20086
20812
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20087
20813
|
* in-place so dispatch keeps working.
|
|
20088
20814
|
*
|
|
20089
|
-
* **
|
|
20090
|
-
*
|
|
20091
|
-
*
|
|
20092
|
-
*
|
|
20093
|
-
* (`ha-domain-mapping`)
|
|
20094
|
-
* stored after that point.
|
|
20815
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20816
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20817
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20818
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20819
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20820
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20095
20821
|
*
|
|
20096
20822
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20097
20823
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20105,6 +20831,14 @@ var SourceInfoSchema = object({
|
|
|
20105
20831
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20106
20832
|
* Used to detect rename when `id` changes. */
|
|
20107
20833
|
uniqueId: string().optional(),
|
|
20834
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20835
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20836
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20837
|
+
dateTimeShape: _enum([
|
|
20838
|
+
"date",
|
|
20839
|
+
"time",
|
|
20840
|
+
"datetime"
|
|
20841
|
+
]).optional(),
|
|
20108
20842
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20109
20843
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20110
20844
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41017,7 +41751,8 @@ method(object({
|
|
|
41017
41751
|
"enum"
|
|
41018
41752
|
]),
|
|
41019
41753
|
enumValues: array(string()).optional(),
|
|
41020
|
-
item: boolean().optional()
|
|
41754
|
+
item: boolean().optional(),
|
|
41755
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41021
41756
|
})).readonly(),
|
|
41022
41757
|
itemArray: object({
|
|
41023
41758
|
path: string(),
|
|
@@ -43397,7 +44132,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43397
44132
|
});
|
|
43398
44133
|
/**
|
|
43399
44134
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43400
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44135
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43401
44136
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43402
44137
|
* the originating provider config (mode + sourcePort) so the
|
|
43403
44138
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44836,8 +45571,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44836
45571
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44837
45572
|
var MaskGridShapeSchema = object({
|
|
44838
45573
|
kind: literal("grid"),
|
|
44839
|
-
gridWidth: number(),
|
|
44840
|
-
gridHeight: number(),
|
|
45574
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45575
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44841
45576
|
cells: array(boolean())
|
|
44842
45577
|
});
|
|
44843
45578
|
discriminatedUnion("kind", [
|
|
@@ -44949,6 +45684,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44949
45684
|
"detection-blind",
|
|
44950
45685
|
"motion-noisy",
|
|
44951
45686
|
"motion-calm",
|
|
45687
|
+
"package-llm-silent",
|
|
45688
|
+
"package-llm-answered",
|
|
44952
45689
|
"recording-stalled",
|
|
44953
45690
|
"recording-healthy",
|
|
44954
45691
|
"recording-degraded",
|
|
@@ -46038,7 +46775,20 @@ var NcRuleInputSchema = object({
|
|
|
46038
46775
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46039
46776
|
* path does not run Zod defaults.
|
|
46040
46777
|
*/
|
|
46041
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46778
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46779
|
+
/**
|
|
46780
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46781
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46782
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46783
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46784
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46785
|
+
*
|
|
46786
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46787
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46788
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46789
|
+
* `false`, so it needs no `clear` key.
|
|
46790
|
+
*/
|
|
46791
|
+
askVerdict: boolean().optional()
|
|
46042
46792
|
});
|
|
46043
46793
|
/**
|
|
46044
46794
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -55963,6 +56713,28 @@ var PackageVersionInfoSchema = object({
|
|
|
55963
56713
|
deprecated: string().optional(),
|
|
55964
56714
|
distTags: array(string()).readonly()
|
|
55965
56715
|
});
|
|
56716
|
+
/**
|
|
56717
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56718
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56719
|
+
* tarball failure — never an empty string standing in for either.
|
|
56720
|
+
*/
|
|
56721
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56722
|
+
object({
|
|
56723
|
+
status: literal("ok"),
|
|
56724
|
+
markdown: string()
|
|
56725
|
+
}),
|
|
56726
|
+
object({ status: literal("missing") }),
|
|
56727
|
+
object({
|
|
56728
|
+
status: literal("error"),
|
|
56729
|
+
message: string()
|
|
56730
|
+
})
|
|
56731
|
+
]);
|
|
56732
|
+
var PackageDocsSchema = object({
|
|
56733
|
+
name: string(),
|
|
56734
|
+
version: string(),
|
|
56735
|
+
readme: PackageDocBodySchema,
|
|
56736
|
+
changelog: PackageDocBodySchema
|
|
56737
|
+
});
|
|
55966
56738
|
var SearchResultSchema = object({
|
|
55967
56739
|
name: string(),
|
|
55968
56740
|
version: string(),
|
|
@@ -56181,7 +56953,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56181
56953
|
}), object({ success: literal(true) }), {
|
|
56182
56954
|
kind: "mutation",
|
|
56183
56955
|
auth: "admin"
|
|
56184
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56956
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56957
|
+
name: string().min(1),
|
|
56958
|
+
version: string().min(1).optional()
|
|
56959
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56185
56960
|
kind: "mutation",
|
|
56186
56961
|
auth: "admin"
|
|
56187
56962
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56231,46 +57006,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56231
57006
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56232
57007
|
object({
|
|
56233
57008
|
/** Carbon dioxide concentration in ppm. */
|
|
56234
|
-
co2Ppm: number().min(0).optional(),
|
|
57009
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56235
57010
|
/** Total volatile organic compounds in ppb. */
|
|
56236
|
-
vocPpb: number().min(0).optional(),
|
|
57011
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56237
57012
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56238
|
-
pm25: number().min(0).optional(),
|
|
57013
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56239
57014
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56240
|
-
pm10: number().min(0).optional(),
|
|
57015
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56241
57016
|
/** Composite AQI value (typically 0..500). */
|
|
56242
|
-
aqi: number().optional(),
|
|
57017
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56243
57018
|
/** Ms epoch when the slice was last updated. */
|
|
56244
|
-
lastFetchedAt: number()
|
|
56245
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56246
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56247
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56248
|
-
* per slice is unambiguous. */
|
|
56249
|
-
unit: string().optional(),
|
|
56250
|
-
/** Suggested decimal places for numeric display.
|
|
56251
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56252
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56253
|
-
* auto-formatting when absent. */
|
|
56254
|
-
precision: number().int().min(0).max(10).optional()
|
|
57019
|
+
lastFetchedAt: number()
|
|
56255
57020
|
});
|
|
56256
57021
|
DeviceType.Sensor;
|
|
56257
57022
|
object({
|
|
56258
|
-
/** Current illuminance in lux (lx). */
|
|
56259
|
-
lux: number().min(0).meta({
|
|
56260
|
-
|
|
57023
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57024
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57025
|
+
precision: 0,
|
|
56261
57026
|
label: "Illuminance"
|
|
56262
|
-
}),
|
|
57027
|
+
})),
|
|
56263
57028
|
/** Ms epoch when the slice was last updated. */
|
|
56264
|
-
lastFetchedAt: number()
|
|
56265
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56266
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56267
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56268
|
-
unit: string().optional(),
|
|
56269
|
-
/** Suggested decimal places for numeric display.
|
|
56270
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56271
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56272
|
-
* auto-formatting when absent. */
|
|
56273
|
-
precision: number().int().min(0).max(10).optional()
|
|
57029
|
+
lastFetchedAt: number()
|
|
56274
57030
|
});
|
|
56275
57031
|
DeviceType.Sensor;
|
|
56276
57032
|
/**
|
|
@@ -56415,10 +57171,7 @@ var BatteryStatusSchema = object({
|
|
|
56415
57171
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56416
57172
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56417
57173
|
*/
|
|
56418
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56419
|
-
unit: "%",
|
|
56420
|
-
label: "Charge"
|
|
56421
|
-
}),
|
|
57174
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56422
57175
|
/**
|
|
56423
57176
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56424
57177
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56445,7 +57198,14 @@ var BatteryStatusSchema = object({
|
|
|
56445
57198
|
*/
|
|
56446
57199
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56447
57200
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56448
|
-
lastUpdated: number(),
|
|
57201
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57202
|
+
/**
|
|
57203
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57204
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57205
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57206
|
+
* `numeric-sensor` on the same device.
|
|
57207
|
+
*/
|
|
57208
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56449
57209
|
/**
|
|
56450
57210
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56451
57211
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56485,7 +57245,7 @@ var BatteryStatusSchema = object({
|
|
|
56485
57245
|
*/
|
|
56486
57246
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56487
57247
|
});
|
|
56488
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57248
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56489
57249
|
method(object({
|
|
56490
57250
|
deviceId: number(),
|
|
56491
57251
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56505,7 +57265,7 @@ object({
|
|
|
56505
57265
|
DeviceType.Sensor;
|
|
56506
57266
|
object({
|
|
56507
57267
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56508
|
-
percentage: number().min(0).max(100),
|
|
57268
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56509
57269
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56510
57270
|
lastChangedAt: number()
|
|
56511
57271
|
});
|
|
@@ -56890,21 +57650,21 @@ object({
|
|
|
56890
57650
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
56891
57651
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
56892
57652
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
56893
|
-
target: number().nullable(),
|
|
57653
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
56894
57654
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
56895
57655
|
* in `heat_cool` mode. */
|
|
56896
|
-
targetHigh: number().nullable(),
|
|
57656
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
56897
57657
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
56898
57658
|
* in `heat_cool` mode. */
|
|
56899
|
-
targetLow: number().nullable(),
|
|
57659
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
56900
57660
|
/** Target relative humidity (0..100). Null when the device has no
|
|
56901
57661
|
* humidity control. */
|
|
56902
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57662
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56903
57663
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
56904
57664
|
* the device's internal sensor. */
|
|
56905
|
-
currentTemp: number().nullable(),
|
|
57665
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
56906
57666
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
56907
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57667
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
56908
57668
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
56909
57669
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
56910
57670
|
swingVertical: boolean().nullable(),
|
|
@@ -56912,11 +57672,11 @@ object({
|
|
|
56912
57672
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
56913
57673
|
swingHorizontal: boolean().nullable(),
|
|
56914
57674
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56915
|
-
minTemp: number().nullable().optional(),
|
|
57675
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56916
57676
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
56917
|
-
maxTemp: number().nullable().optional(),
|
|
57677
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
56918
57678
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
56919
|
-
tempStep: number().positive().nullable().optional(),
|
|
57679
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
56920
57680
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
56921
57681
|
lastFetchedAt: number()
|
|
56922
57682
|
});
|
|
@@ -56995,17 +57755,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
56995
57755
|
* modes to expose in the picker without a slice fetch.
|
|
56996
57756
|
*/
|
|
56997
57757
|
var RgbTripletSchema = object({
|
|
56998
|
-
r: number().int().min(0).max(255),
|
|
56999
|
-
g: number().int().min(0).max(255),
|
|
57000
|
-
b: number().int().min(0).max(255)
|
|
57758
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57759
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57760
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57001
57761
|
});
|
|
57002
57762
|
var HsvTripletSchema = object({
|
|
57003
57763
|
/** Hue in degrees, 0..360. */
|
|
57004
|
-
h: number().min(0).max(360),
|
|
57764
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57005
57765
|
/** Saturation as 0..100 inclusive. */
|
|
57006
|
-
s: number().min(0).max(100),
|
|
57766
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57007
57767
|
/** Value/brightness as 0..100 inclusive. */
|
|
57008
|
-
v: number().min(0).max(100)
|
|
57768
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57009
57769
|
});
|
|
57010
57770
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57011
57771
|
object({
|
|
@@ -57034,7 +57794,7 @@ object({
|
|
|
57034
57794
|
/** Populated when `mode === 'hsv'`. */
|
|
57035
57795
|
hsv: HsvTripletSchema.optional(),
|
|
57036
57796
|
/** Populated when `mode === 'mired'`. */
|
|
57037
|
-
mireds: number().int().optional(),
|
|
57797
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57038
57798
|
/** Ms epoch of the last operator-driven change. */
|
|
57039
57799
|
lastChangedAt: number()
|
|
57040
57800
|
});
|
|
@@ -57158,18 +57918,12 @@ _enum([
|
|
|
57158
57918
|
"empty",
|
|
57159
57919
|
"full"
|
|
57160
57920
|
]);
|
|
57161
|
-
/**
|
|
57162
|
-
|
|
57163
|
-
|
|
57164
|
-
"days",
|
|
57165
|
-
"hours",
|
|
57166
|
-
"cycles"
|
|
57167
|
-
]);
|
|
57168
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57169
|
-
* days). `value` null = unknown (D393). */
|
|
57921
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
57922
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
57923
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57170
57924
|
var ConsumableRemainingSchema = object({
|
|
57171
|
-
value: number().min(0).nullable(),
|
|
57172
|
-
|
|
57925
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
57926
|
+
kind: ConsumableRemainingKindSchema
|
|
57173
57927
|
});
|
|
57174
57928
|
var ConsumablesStatusSchema = object({
|
|
57175
57929
|
items: array(object({
|
|
@@ -57178,7 +57932,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57178
57932
|
/** Display name. */
|
|
57179
57933
|
label: string().min(1),
|
|
57180
57934
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57181
|
-
level: number().min(0).max(100).nullable(),
|
|
57935
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57182
57936
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57183
57937
|
status: ConsumableStatusSchema.nullable(),
|
|
57184
57938
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57195,7 +57949,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57195
57949
|
})),
|
|
57196
57950
|
lastChangedAt: number()
|
|
57197
57951
|
});
|
|
57198
|
-
Object.values(DeviceType), [...
|
|
57952
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57199
57953
|
Object.values(DeviceType), method(object({
|
|
57200
57954
|
deviceId: number().int().nonnegative(),
|
|
57201
57955
|
key: string().min(1)
|
|
@@ -57220,39 +57974,17 @@ object({
|
|
|
57220
57974
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57221
57975
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57222
57976
|
* or time-only — HA accepts all three forms). */
|
|
57223
|
-
value: union([number(), string()]),
|
|
57977
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57224
57978
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57225
57979
|
options: array(string()),
|
|
57226
57980
|
/** Ms epoch when the slice was last updated. */
|
|
57227
57981
|
lastChangedAt: number(),
|
|
57228
|
-
/**
|
|
57229
|
-
|
|
57230
|
-
|
|
57231
|
-
|
|
57232
|
-
/**
|
|
57233
|
-
|
|
57234
|
-
min: number().optional(),
|
|
57235
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57236
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57237
|
-
max: number().optional(),
|
|
57238
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57239
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57240
|
-
step: number().optional(),
|
|
57241
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57242
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57243
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57244
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57245
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57246
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57247
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57248
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57249
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57250
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57251
|
-
format: _enum([
|
|
57252
|
-
"date",
|
|
57253
|
-
"time",
|
|
57254
|
-
"datetime"
|
|
57255
|
-
]).optional()
|
|
57982
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
57983
|
+
min: number().optional().meta(readingMeta("device")),
|
|
57984
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
57985
|
+
max: number().optional().meta(readingMeta("device")),
|
|
57986
|
+
/** Step increment, in the device quantity's base unit. */
|
|
57987
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57256
57988
|
});
|
|
57257
57989
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57258
57990
|
object({
|
|
@@ -57290,9 +58022,9 @@ object({
|
|
|
57290
58022
|
]),
|
|
57291
58023
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57292
58024
|
* no intermediate position surface. */
|
|
57293
|
-
position: number().min(0).max(100).nullable(),
|
|
58025
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57294
58026
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57295
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58027
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57296
58028
|
/** Ms epoch when the slice was last updated. */
|
|
57297
58029
|
lastChangedAt: number()
|
|
57298
58030
|
});
|
|
@@ -57350,9 +58082,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57350
58082
|
object({
|
|
57351
58083
|
mode: DayNightModeSchema,
|
|
57352
58084
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57353
|
-
sensitivity: number().optional(),
|
|
58085
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57354
58086
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57355
|
-
switchDelaySec: number().optional(),
|
|
58087
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57356
58088
|
lastFetchedAt: number()
|
|
57357
58089
|
});
|
|
57358
58090
|
/**
|
|
@@ -57507,11 +58239,11 @@ object({
|
|
|
57507
58239
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57508
58240
|
availablePrograms: array(string()),
|
|
57509
58241
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57510
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58242
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57511
58243
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57512
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58244
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57513
58245
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57514
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58246
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57515
58247
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57516
58248
|
doorOpen: boolean().nullable(),
|
|
57517
58249
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57535,7 +58267,7 @@ object({
|
|
|
57535
58267
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57536
58268
|
machineCareDue: boolean().nullable(),
|
|
57537
58269
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57538
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58270
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57539
58271
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57540
58272
|
halfLoad: boolean().nullable(),
|
|
57541
58273
|
hygienePlus: boolean().nullable(),
|
|
@@ -57550,7 +58282,7 @@ object({
|
|
|
57550
58282
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57551
58283
|
activeEvents: array(string()),
|
|
57552
58284
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57553
|
-
errorCode: number().nullable(),
|
|
58285
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57554
58286
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57555
58287
|
errorLabel: string().nullable(),
|
|
57556
58288
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -57696,24 +58428,14 @@ object({
|
|
|
57696
58428
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
57697
58429
|
lastPressedAt: number().nullable(),
|
|
57698
58430
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
57699
|
-
pressCountSinceStart: number()
|
|
58431
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
57700
58432
|
});
|
|
57701
58433
|
object({
|
|
57702
58434
|
deviceId: number(),
|
|
57703
58435
|
timestamp: number()
|
|
57704
58436
|
});
|
|
57705
58437
|
DeviceType.Button, DeviceType.Camera;
|
|
57706
|
-
|
|
57707
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
57708
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
57709
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
57710
|
-
* The option set is stable across observations; it is persisted in the
|
|
57711
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
57712
|
-
* stored in `sourceInfo`.
|
|
57713
|
-
*/
|
|
57714
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
57715
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
57716
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58438
|
+
_enum([
|
|
57717
58439
|
"date",
|
|
57718
58440
|
"time",
|
|
57719
58441
|
"datetime"
|
|
@@ -57721,12 +58443,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
57721
58443
|
object({
|
|
57722
58444
|
value: string(),
|
|
57723
58445
|
/**
|
|
57724
|
-
* Set
|
|
57725
|
-
* as
|
|
57726
|
-
*
|
|
57727
|
-
* a time-only sensor → `'time'`.
|
|
58446
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58447
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58448
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
57728
58449
|
*/
|
|
57729
|
-
|
|
58450
|
+
timestamp: boolean().optional(),
|
|
57730
58451
|
/** Ms epoch when the slice was last updated. */
|
|
57731
58452
|
lastFetchedAt: number()
|
|
57732
58453
|
});
|
|
@@ -57745,13 +58466,13 @@ var EventFireSchema = object({
|
|
|
57745
58466
|
deviceId: number(),
|
|
57746
58467
|
eventType: string(),
|
|
57747
58468
|
data: record(string(), unknown()).nullable(),
|
|
57748
|
-
timestamp: number(),
|
|
57749
|
-
seq: number()
|
|
58469
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58470
|
+
seq: number().meta(readingMeta("count"))
|
|
57750
58471
|
});
|
|
57751
58472
|
object({
|
|
57752
58473
|
eventTypes: array(string()),
|
|
57753
58474
|
lastEvent: EventFireSchema.nullable(),
|
|
57754
|
-
eventCountSinceStart: number()
|
|
58475
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
57755
58476
|
});
|
|
57756
58477
|
DeviceType.EventEmitter;
|
|
57757
58478
|
var IdentitySchema = object({
|
|
@@ -58140,10 +58861,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58140
58861
|
object({
|
|
58141
58862
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58142
58863
|
* speed surface (single-speed fan). */
|
|
58143
|
-
percentage: number().min(0).max(100).nullable(),
|
|
58864
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58144
58865
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58145
58866
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58146
|
-
percentageStep: number().positive().optional(),
|
|
58867
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
58147
58868
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
58148
58869
|
* — empty string when no preset is active or supported. */
|
|
58149
58870
|
preset: string(),
|
|
@@ -58225,7 +58946,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58225
58946
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58226
58947
|
model: string().nullable(),
|
|
58227
58948
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58228
|
-
channelCount: number().nullable(),
|
|
58949
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58229
58950
|
/**
|
|
58230
58951
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58231
58952
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58257,9 +58978,45 @@ object({
|
|
|
58257
58978
|
lastChangedAt: number()
|
|
58258
58979
|
});
|
|
58259
58980
|
DeviceType.Sensor;
|
|
58981
|
+
object({
|
|
58982
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
58983
|
+
results: array(object({
|
|
58984
|
+
deviceId: number().int().nonnegative(),
|
|
58985
|
+
cap: string().min(1),
|
|
58986
|
+
method: string().min(1),
|
|
58987
|
+
ok: boolean(),
|
|
58988
|
+
error: string().optional(),
|
|
58989
|
+
/** Ms epoch of the attempt. */
|
|
58990
|
+
at: number()
|
|
58991
|
+
})) });
|
|
58992
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58993
|
+
object({
|
|
58994
|
+
active: boolean().meta({ label: "Active" }),
|
|
58995
|
+
/** Ms epoch when the slice was last updated. */
|
|
58996
|
+
lastChangedAt: number()
|
|
58997
|
+
});
|
|
58998
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
58999
|
+
object({
|
|
59000
|
+
/** Members whose current value entered the aggregate. */
|
|
59001
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
59002
|
+
precision: 0,
|
|
59003
|
+
label: "Reporting"
|
|
59004
|
+
})),
|
|
59005
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
59006
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
59007
|
+
precision: 0,
|
|
59008
|
+
label: "Excluded"
|
|
59009
|
+
})),
|
|
59010
|
+
/** `included` + `excluded`. */
|
|
59011
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
59012
|
+
precision: 0,
|
|
59013
|
+
label: "Members"
|
|
59014
|
+
}))
|
|
59015
|
+
});
|
|
59016
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58260
59017
|
object({
|
|
58261
59018
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58262
|
-
position: number().min(0).max(100).nullable(),
|
|
59019
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58263
59020
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58264
59021
|
lastFetchedAt: number()
|
|
58265
59022
|
});
|
|
@@ -58268,9 +59025,9 @@ object({
|
|
|
58268
59025
|
/** Whether the humidifier is currently on. */
|
|
58269
59026
|
on: boolean(),
|
|
58270
59027
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58271
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59028
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58272
59029
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58273
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59030
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58274
59031
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58275
59032
|
* device has no mode surface. */
|
|
58276
59033
|
mode: string().nullable(),
|
|
@@ -58280,9 +59037,9 @@ object({
|
|
|
58280
59037
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58281
59038
|
action: string().nullable(),
|
|
58282
59039
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58283
|
-
minHumidity: number().nullable(),
|
|
59040
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58284
59041
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58285
|
-
maxHumidity: number().nullable(),
|
|
59042
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58286
59043
|
/** Ms epoch when the slice was last updated. */
|
|
58287
59044
|
lastChangedAt: number()
|
|
58288
59045
|
});
|
|
@@ -58306,22 +59063,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58306
59063
|
auth: "protected"
|
|
58307
59064
|
});
|
|
58308
59065
|
object({
|
|
58309
|
-
/** Current relative humidity, 0..100. */
|
|
58310
|
-
percent: number().min(0).max(100).meta({
|
|
58311
|
-
|
|
59066
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59067
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59068
|
+
precision: 0,
|
|
58312
59069
|
label: "Humidity"
|
|
58313
|
-
}),
|
|
59070
|
+
})),
|
|
58314
59071
|
/** Ms epoch when the slice was last updated. */
|
|
58315
|
-
lastFetchedAt: number()
|
|
58316
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58317
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58318
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58319
|
-
unit: string().optional(),
|
|
58320
|
-
/** Suggested decimal places for numeric display.
|
|
58321
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58322
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58323
|
-
* auto-formatting when absent. */
|
|
58324
|
-
precision: number().int().min(0).max(10).optional()
|
|
59072
|
+
lastFetchedAt: number()
|
|
58325
59073
|
});
|
|
58326
59074
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58327
59075
|
object({
|
|
@@ -58329,7 +59077,7 @@ object({
|
|
|
58329
59077
|
* entity exposes no `entity_picture` (yet). */
|
|
58330
59078
|
url: string().nullable(),
|
|
58331
59079
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58332
|
-
lastUpdated: number().nullable()
|
|
59080
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58333
59081
|
});
|
|
58334
59082
|
DeviceType.Image;
|
|
58335
59083
|
/**
|
|
@@ -58385,19 +59133,19 @@ var NormalizedRangeSchema = object({
|
|
|
58385
59133
|
});
|
|
58386
59134
|
object({
|
|
58387
59135
|
/** Normalized 0–100. */
|
|
58388
|
-
brightness: number().optional(),
|
|
59136
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58389
59137
|
/** Normalized 0–100. */
|
|
58390
|
-
contrast: number().optional(),
|
|
59138
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58391
59139
|
/** Normalized 0–100. */
|
|
58392
|
-
saturation: number().optional(),
|
|
59140
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58393
59141
|
/** Normalized 0–100. */
|
|
58394
|
-
sharpness: number().optional(),
|
|
59142
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58395
59143
|
mirror: boolean().optional(),
|
|
58396
59144
|
flip: boolean().optional(),
|
|
58397
59145
|
rotate: ImageRotateSchema.optional(),
|
|
58398
59146
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58399
59147
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58400
|
-
warmth: number().optional(),
|
|
59148
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58401
59149
|
exposureMode: ExposureModeSchema.optional(),
|
|
58402
59150
|
backlightMode: BacklightModeSchema.optional(),
|
|
58403
59151
|
lastFetchedAt: number()
|
|
@@ -58642,10 +59390,10 @@ var IntercomAbilitySchema = object({
|
|
|
58642
59390
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58643
59391
|
codecs: array(string()),
|
|
58644
59392
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58645
|
-
sampleRate: number(),
|
|
59393
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58646
59394
|
duplex: _enum(["half", "full"]),
|
|
58647
59395
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58648
|
-
maxBacklogMs: number()
|
|
59396
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58649
59397
|
});
|
|
58650
59398
|
var IntercomStatusSchema = object({
|
|
58651
59399
|
/** True while a talk session is open. */
|
|
@@ -58756,13 +59504,13 @@ object({
|
|
|
58756
59504
|
activity: LawnMowerActivitySchema,
|
|
58757
59505
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
58758
59506
|
* reading. */
|
|
58759
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59507
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58760
59508
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
58761
59509
|
* task is active / progress is unavailable. */
|
|
58762
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59510
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58763
59511
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
58764
59512
|
* or null when unknown. */
|
|
58765
|
-
currentCode: number().nullable(),
|
|
59513
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
58766
59514
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
58767
59515
|
currentCodeLabel: string().nullable(),
|
|
58768
59516
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -59172,7 +59920,14 @@ DeviceType.Lock, method(object({
|
|
|
59172
59920
|
auth: "protected"
|
|
59173
59921
|
}), method(object({
|
|
59174
59922
|
deviceId: number().int().nonnegative(),
|
|
59175
|
-
code: string().min(1).optional()
|
|
59923
|
+
code: string().min(1).optional(),
|
|
59924
|
+
/**
|
|
59925
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
59926
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
59927
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
59928
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
59929
|
+
*/
|
|
59930
|
+
confirm: boolean().optional()
|
|
59176
59931
|
}), _void(), {
|
|
59177
59932
|
kind: "mutation",
|
|
59178
59933
|
auth: "protected"
|
|
@@ -59180,6 +59935,11 @@ DeviceType.Lock, method(object({
|
|
|
59180
59935
|
kind: "mutation",
|
|
59181
59936
|
auth: "protected"
|
|
59182
59937
|
});
|
|
59938
|
+
object({
|
|
59939
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
59940
|
+
lastFetchedAt: number()
|
|
59941
|
+
});
|
|
59942
|
+
DeviceType.Sensor;
|
|
59183
59943
|
/**
|
|
59184
59944
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59185
59945
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59224,7 +59984,7 @@ object({
|
|
|
59224
59984
|
state: MediaPlayerStateSchema,
|
|
59225
59985
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59226
59986
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59227
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
59987
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59228
59988
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59229
59989
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59230
59990
|
isMuted: boolean().nullable(),
|
|
@@ -59237,10 +59997,10 @@ object({
|
|
|
59237
59997
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59238
59998
|
/** Current playback position in ms. Null when not seekable or
|
|
59239
59999
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59240
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
60000
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59241
60001
|
/** Total duration of the current media in ms. Null when unknown
|
|
59242
60002
|
* (live stream) or nothing is playing. */
|
|
59243
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
60003
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59244
60004
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59245
60005
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59246
60006
|
shuffle: boolean().nullable(),
|
|
@@ -59540,7 +60300,7 @@ object({
|
|
|
59540
60300
|
* it, every provider seeded it at boot, and every session left it
|
|
59541
60301
|
* `detected: true` after its detach.
|
|
59542
60302
|
*/
|
|
59543
|
-
autoClearAfterMs: number().nullable()
|
|
60303
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59544
60304
|
});
|
|
59545
60305
|
/**
|
|
59546
60306
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59590,7 +60350,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59590
60350
|
});
|
|
59591
60351
|
object({
|
|
59592
60352
|
enabled: boolean(),
|
|
59593
|
-
sensitivity: number(),
|
|
60353
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59594
60354
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59595
60355
|
regions: array(MotionZoneRegionSchema),
|
|
59596
60356
|
lastFetchedAt: number()
|
|
@@ -59894,7 +60654,7 @@ var NavigationStatusSchema = object({
|
|
|
59894
60654
|
following: boolean(),
|
|
59895
60655
|
flash: boolean(),
|
|
59896
60656
|
lightMode: NavigationLightModeSchema,
|
|
59897
|
-
lightLevel: number().min(40).max(100),
|
|
60657
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
59898
60658
|
/** Ms epoch when the slice was last updated. */
|
|
59899
60659
|
lastChangedAt: number()
|
|
59900
60660
|
});
|
|
@@ -59940,13 +60700,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
59940
60700
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
59941
60701
|
* SKIP a null rather than coerce it.
|
|
59942
60702
|
*/
|
|
59943
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
60703
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59944
60704
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
59945
|
-
rssiDbm: number().optional(),
|
|
60705
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
59946
60706
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
59947
60707
|
ssid: string().optional(),
|
|
59948
60708
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
59949
|
-
lastUpdated: number()
|
|
60709
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
59950
60710
|
});
|
|
59951
60711
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
59952
60712
|
deviceId: number(),
|
|
@@ -60265,7 +61025,7 @@ object({
|
|
|
60265
61025
|
lastError: string().nullable(),
|
|
60266
61026
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60267
61027
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60268
|
-
queueDepth: number().int().nonnegative(),
|
|
61028
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60269
61029
|
/** Per-feature capability matrix — authoritative source for the
|
|
60270
61030
|
* compose-form field gating. */
|
|
60271
61031
|
supports: NotifierSupportsSchema
|
|
@@ -60315,15 +61075,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60315
61075
|
acceptedAt: number()
|
|
60316
61076
|
});
|
|
60317
61077
|
object({
|
|
60318
|
-
|
|
60319
|
-
|
|
60320
|
-
* Populated live from the upstream source on each state push.
|
|
60321
|
-
* Absent for unitless sensors. */
|
|
60322
|
-
unit: string().optional(),
|
|
60323
|
-
/** Suggested decimal places for numeric display.
|
|
60324
|
-
* Populated live from the upstream source when provided.
|
|
60325
|
-
* Falls back to auto-formatting when absent. */
|
|
60326
|
-
precision: number().int().min(0).max(10).optional(),
|
|
61078
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
61079
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60327
61080
|
/** Ms epoch when the slice was last updated. */
|
|
60328
61081
|
lastFetchedAt: number()
|
|
60329
61082
|
});
|
|
@@ -60613,23 +61366,26 @@ object({
|
|
|
60613
61366
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60614
61367
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60615
61368
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60616
|
-
foodLevel: number().nullable(),
|
|
61369
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60617
61370
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60618
61371
|
* single-hopper models. */
|
|
60619
|
-
food1: number().nullable(),
|
|
61372
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60620
61373
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60621
61374
|
* single-hopper models. */
|
|
60622
|
-
food2: number().nullable(),
|
|
61375
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60623
61376
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60624
61377
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60625
61378
|
* below the feeder's low threshold. */
|
|
60626
61379
|
lowFood: boolean(),
|
|
60627
61380
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60628
61381
|
* device has no battery reading. */
|
|
60629
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60630
|
-
/**
|
|
60631
|
-
*
|
|
60632
|
-
|
|
61382
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61383
|
+
/**
|
|
61384
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61385
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61386
|
+
* model has no desiccant sensor.
|
|
61387
|
+
*/
|
|
61388
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60633
61389
|
/** True while a feed is in progress. */
|
|
60634
61390
|
feeding: boolean(),
|
|
60635
61391
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60640,7 +61396,7 @@ object({
|
|
|
60640
61396
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60641
61397
|
error: string().nullable(),
|
|
60642
61398
|
/** Raw device error code (0 / null = no error). */
|
|
60643
|
-
errorCode: number().nullable(),
|
|
61399
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60644
61400
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60645
61401
|
isDualHopper: boolean(),
|
|
60646
61402
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60650,7 +61406,7 @@ object({
|
|
|
60650
61406
|
/** Play a chime when dispensing. */
|
|
60651
61407
|
feedSound: boolean(),
|
|
60652
61408
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60653
|
-
volume: number(),
|
|
61409
|
+
volume: number().meta(readingMeta("none")),
|
|
60654
61410
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60655
61411
|
lastFetchedAt: number()
|
|
60656
61412
|
});
|
|
@@ -61087,38 +61843,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61087
61843
|
});
|
|
61088
61844
|
object({
|
|
61089
61845
|
/** Instantaneous power draw in watts. */
|
|
61090
|
-
watts: number().optional().meta({
|
|
61091
|
-
unit: "W",
|
|
61092
|
-
label: "Power"
|
|
61093
|
-
}),
|
|
61846
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61094
61847
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61095
|
-
kwhTotal: number().optional().meta({
|
|
61096
|
-
unit: "kWh",
|
|
61097
|
-
label: "Energy"
|
|
61098
|
-
}),
|
|
61848
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61099
61849
|
/** Voltage in volts. */
|
|
61100
|
-
volts: number().optional(),
|
|
61850
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61101
61851
|
/** Current in amperes. */
|
|
61102
|
-
amps: number().optional(),
|
|
61103
|
-
/** Apparent power in volt-amperes
|
|
61104
|
-
va: number().optional(),
|
|
61852
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61853
|
+
/** Apparent power in volt-amperes. */
|
|
61854
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61105
61855
|
/** Power factor (0..1) if reported. */
|
|
61106
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
61856
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61107
61857
|
/** Ms epoch when the slice was last updated. */
|
|
61108
|
-
lastFetchedAt: number()
|
|
61109
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
61110
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
61111
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
61112
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
61113
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
61114
|
-
unit: string().optional(),
|
|
61115
|
-
/** Suggested decimal places for numeric display.
|
|
61116
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61117
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61118
|
-
* auto-formatting when absent. */
|
|
61119
|
-
precision: number().int().min(0).max(10).optional()
|
|
61858
|
+
lastFetchedAt: number()
|
|
61120
61859
|
});
|
|
61121
|
-
|
|
61860
|
+
[
|
|
61861
|
+
DeviceType.Sensor,
|
|
61862
|
+
DeviceType.Switch,
|
|
61863
|
+
DeviceType.Light,
|
|
61864
|
+
DeviceType.Fan,
|
|
61865
|
+
DeviceType.Climate,
|
|
61866
|
+
DeviceType.Thermostat,
|
|
61867
|
+
DeviceType.Humidifier,
|
|
61868
|
+
DeviceType.WaterHeater,
|
|
61869
|
+
DeviceType.MediaPlayer,
|
|
61870
|
+
DeviceType.Washer,
|
|
61871
|
+
DeviceType.Dryer,
|
|
61872
|
+
DeviceType.Dishwasher,
|
|
61873
|
+
DeviceType.Vacuum,
|
|
61874
|
+
DeviceType.LawnMower,
|
|
61875
|
+
DeviceType.PetFeeder
|
|
61876
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61122
61877
|
/**
|
|
61123
61878
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61124
61879
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61137,11 +61892,11 @@ DeviceType.Sensor;
|
|
|
61137
61892
|
*/
|
|
61138
61893
|
var GpsLocationSchema = object({
|
|
61139
61894
|
/** Latitude in decimal degrees, -90..90. */
|
|
61140
|
-
latitude: number().min(-90).max(90),
|
|
61895
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
61141
61896
|
/** Longitude in decimal degrees, -180..180. */
|
|
61142
|
-
longitude: number().min(-180).max(180),
|
|
61897
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
61143
61898
|
/** Reported accuracy in meters (lower = better). */
|
|
61144
|
-
accuracyMeters: number().nonnegative()
|
|
61899
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
61145
61900
|
});
|
|
61146
61901
|
object({
|
|
61147
61902
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -61153,25 +61908,16 @@ object({
|
|
|
61153
61908
|
gps: GpsLocationSchema.nullable(),
|
|
61154
61909
|
/** Optional battery level of the tracking device (0..100). Null
|
|
61155
61910
|
* when not reported. */
|
|
61156
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
61911
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61157
61912
|
/** Ms epoch when the slice was last updated. */
|
|
61158
61913
|
lastChangedAt: number()
|
|
61159
61914
|
});
|
|
61160
61915
|
DeviceType.Presence;
|
|
61161
61916
|
object({
|
|
61162
|
-
/** Current pressure in hPa. */
|
|
61163
|
-
hpa: number(),
|
|
61917
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
61918
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61164
61919
|
/** Ms epoch when the slice was last updated. */
|
|
61165
|
-
lastFetchedAt: number()
|
|
61166
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61167
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61168
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61169
|
-
unit: string().optional(),
|
|
61170
|
-
/** Suggested decimal places for numeric display.
|
|
61171
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61172
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61173
|
-
* auto-formatting when absent. */
|
|
61174
|
-
precision: number().int().min(0).max(10).optional()
|
|
61920
|
+
lastFetchedAt: number()
|
|
61175
61921
|
});
|
|
61176
61922
|
DeviceType.Sensor;
|
|
61177
61923
|
/**
|
|
@@ -61504,8 +62250,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61504
62250
|
}), _void(), { kind: "mutation" });
|
|
61505
62251
|
var PtzAutotrackSettingsSchema = object({
|
|
61506
62252
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61507
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61508
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62253
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62254
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61509
62255
|
});
|
|
61510
62256
|
/**
|
|
61511
62257
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61562,7 +62308,7 @@ object({
|
|
|
61562
62308
|
/** null = unknown — never coerced to false (D393). */
|
|
61563
62309
|
running: boolean().nullable(),
|
|
61564
62310
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61565
|
-
since: number().nullable(),
|
|
62311
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61566
62312
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61567
62313
|
phase: string().nullable(),
|
|
61568
62314
|
/** null until a reading has been published (D393). */
|
|
@@ -61574,7 +62320,7 @@ object({
|
|
|
61574
62320
|
phase: string().nullable()
|
|
61575
62321
|
});
|
|
61576
62322
|
Object.values(DeviceType);
|
|
61577
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62323
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61578
62324
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61579
62325
|
kind: "mutation",
|
|
61580
62326
|
auth: "admin"
|
|
@@ -62760,9 +63506,9 @@ var RecordTriggerSchema = _enum([
|
|
|
62760
63506
|
*/
|
|
62761
63507
|
var RecordWindowSchema = object({
|
|
62762
63508
|
trigger: RecordTriggerSchema,
|
|
62763
|
-
day: number().int().min(0).max(6),
|
|
62764
|
-
startMinute: number().int().min(0).max(1439),
|
|
62765
|
-
endMinute: number().int().min(1).max(1440)
|
|
63509
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63510
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63511
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
62766
63512
|
});
|
|
62767
63513
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
62768
63514
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -62831,10 +63577,10 @@ object({
|
|
|
62831
63577
|
/** Master "record to the card at all" switch. */
|
|
62832
63578
|
enabled: boolean().nullable(),
|
|
62833
63579
|
overwriteWhenFull: boolean().nullable(),
|
|
62834
|
-
preRecordSec: number().nullable(),
|
|
62835
|
-
postRecordSec: number().nullable(),
|
|
63580
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63581
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
62836
63582
|
/** Length of one recorded file, in minutes. */
|
|
62837
|
-
segmentMinutes: number().nullable(),
|
|
63583
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
62838
63584
|
/** The primary track's weekly windows, flattened. */
|
|
62839
63585
|
windows: array(RecordWindowSchema),
|
|
62840
63586
|
/**
|
|
@@ -62850,7 +63596,7 @@ object({
|
|
|
62850
63596
|
* provider reporting a non-zero count also reports the schedule as not
|
|
62851
63597
|
* writable.
|
|
62852
63598
|
*/
|
|
62853
|
-
unreadableWindows: number(),
|
|
63599
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
62854
63600
|
/**
|
|
62855
63601
|
* The camera is scheduled to record and has NO usable storage.
|
|
62856
63602
|
*
|
|
@@ -63487,7 +64233,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63487
64233
|
url: string().optional(),
|
|
63488
64234
|
codec: string().optional(),
|
|
63489
64235
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63490
|
-
fps: number().positive().optional(),
|
|
64236
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63491
64237
|
label: string().optional(),
|
|
63492
64238
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63493
64239
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63517,18 +64263,18 @@ var StreamProfileSchema = _enum([
|
|
|
63517
64263
|
]);
|
|
63518
64264
|
/** The current encoding config of one stream profile. */
|
|
63519
64265
|
var StreamProfileConfigSchema = object({
|
|
63520
|
-
width: number(),
|
|
63521
|
-
height: number(),
|
|
64266
|
+
width: number().meta(readingMeta("none")),
|
|
64267
|
+
height: number().meta(readingMeta("none")),
|
|
63522
64268
|
codec: _enum(["h264", "h265"]),
|
|
63523
|
-
framerate: number(),
|
|
63524
|
-
bitrate: number(),
|
|
64269
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64270
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63525
64271
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63526
64272
|
encoderProfile: _enum([
|
|
63527
64273
|
"high",
|
|
63528
64274
|
"main",
|
|
63529
64275
|
"baseline"
|
|
63530
64276
|
]).optional(),
|
|
63531
|
-
gop: number().optional(),
|
|
64277
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63532
64278
|
/**
|
|
63533
64279
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63534
64280
|
*
|
|
@@ -63613,7 +64359,7 @@ object({
|
|
|
63613
64359
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63614
64360
|
lastChangedAt: number()
|
|
63615
64361
|
});
|
|
63616
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64362
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63617
64363
|
deviceId: number(),
|
|
63618
64364
|
on: boolean()
|
|
63619
64365
|
}), _void(), {
|
|
@@ -64171,23 +64917,13 @@ object({
|
|
|
64171
64917
|
});
|
|
64172
64918
|
DeviceType.Sensor;
|
|
64173
64919
|
object({
|
|
64174
|
-
/** Current temperature in Celsius. */
|
|
64175
|
-
celsius: number().meta({
|
|
64176
|
-
|
|
64920
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
64921
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
64922
|
+
precision: 1,
|
|
64177
64923
|
label: "Temperature"
|
|
64178
|
-
}),
|
|
64924
|
+
})),
|
|
64179
64925
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64180
|
-
lastFetchedAt: number()
|
|
64181
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64182
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64183
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64184
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64185
|
-
unit: string().optional(),
|
|
64186
|
-
/** Suggested decimal places for numeric display.
|
|
64187
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64188
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64189
|
-
* auto-formatting when absent. */
|
|
64190
|
-
precision: number().int().min(0).max(10).optional()
|
|
64926
|
+
lastFetchedAt: number()
|
|
64191
64927
|
});
|
|
64192
64928
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64193
64929
|
/**
|
|
@@ -64439,16 +65175,16 @@ object({
|
|
|
64439
65175
|
]),
|
|
64440
65176
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64441
65177
|
* reading. */
|
|
64442
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65178
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64443
65179
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64444
65180
|
* the vacuum has no speed control. */
|
|
64445
65181
|
fanSpeed: string().nullable(),
|
|
64446
65182
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64447
65183
|
availableFanSpeeds: array(string()),
|
|
64448
65184
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64449
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65185
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64450
65186
|
/** Current error code (0 / null = no error). */
|
|
64451
|
-
errorCode: number().nullable(),
|
|
65187
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64452
65188
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64453
65189
|
errorLabel: string().nullable(),
|
|
64454
65190
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64487,7 +65223,7 @@ object({
|
|
|
64487
65223
|
]),
|
|
64488
65224
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64489
65225
|
* intermediate position surface. */
|
|
64490
|
-
position: number().min(0).max(100).nullable(),
|
|
65226
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64491
65227
|
/** Ms epoch when the slice was last updated. */
|
|
64492
65228
|
lastChangedAt: number()
|
|
64493
65229
|
});
|
|
@@ -64515,9 +65251,9 @@ object({
|
|
|
64515
65251
|
DeviceType.Sensor;
|
|
64516
65252
|
object({
|
|
64517
65253
|
/** Current measured temperature. Null when not reported. */
|
|
64518
|
-
currentTemp: number().nullable(),
|
|
65254
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64519
65255
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64520
|
-
targetTemp: number().nullable(),
|
|
65256
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64521
65257
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64522
65258
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64523
65259
|
* device reports an unknown state. */
|
|
@@ -64528,9 +65264,9 @@ object({
|
|
|
64528
65264
|
* has no away surface. */
|
|
64529
65265
|
away: boolean().nullable(),
|
|
64530
65266
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64531
|
-
minTemp: number().nullable(),
|
|
65267
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64532
65268
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64533
|
-
maxTemp: number().nullable(),
|
|
65269
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64534
65270
|
/** Ms epoch when the slice was last updated. */
|
|
64535
65271
|
lastChangedAt: number()
|
|
64536
65272
|
});
|
|
@@ -64554,25 +65290,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64554
65290
|
auth: "protected"
|
|
64555
65291
|
});
|
|
64556
65292
|
object({
|
|
64557
|
-
/** Verbatim
|
|
64558
|
-
* when no condition has been reported yet. */
|
|
65293
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64559
65294
|
condition: string().nullable(),
|
|
64560
|
-
/** Current temperature in
|
|
64561
|
-
temperature: number().nullable(),
|
|
64562
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64563
|
-
temperatureUnit: string().nullable(),
|
|
65295
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65296
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64564
65297
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64565
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64566
|
-
/** Barometric pressure in
|
|
64567
|
-
pressure: number().nullable(),
|
|
64568
|
-
/**
|
|
64569
|
-
|
|
64570
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64571
|
-
windSpeed: number().nullable(),
|
|
64572
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64573
|
-
windSpeedUnit: string().nullable(),
|
|
65298
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65299
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65300
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65301
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65302
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64574
65303
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64575
|
-
windBearing: number().nullable(),
|
|
65304
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64576
65305
|
/** Ms epoch when the slice was last updated. */
|
|
64577
65306
|
lastFetchedAt: number()
|
|
64578
65307
|
});
|
|
@@ -65322,8 +66051,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65322
66051
|
kind: "mutation",
|
|
65323
66052
|
auth: "admin"
|
|
65324
66053
|
});
|
|
66054
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65325
66055
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65326
|
-
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;
|
|
66056
|
+
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;
|
|
65327
66057
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65328
66058
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65329
66059
|
new Set(CAP_NAMES);
|
|
@@ -65376,7 +66106,7 @@ var AccessoryKind = {
|
|
|
65376
66106
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65377
66107
|
};
|
|
65378
66108
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65379
|
-
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;
|
|
66109
|
+
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;
|
|
65380
66110
|
new Set(Object.values(DeviceType));
|
|
65381
66111
|
Object.freeze({
|
|
65382
66112
|
"accessories.getStatus": {
|
|
@@ -65484,6 +66214,13 @@ Object.freeze({
|
|
|
65484
66214
|
access: "view",
|
|
65485
66215
|
role: "admin"
|
|
65486
66216
|
},
|
|
66217
|
+
"addons.getPackageDocs": {
|
|
66218
|
+
capName: "addons",
|
|
66219
|
+
capScope: "system",
|
|
66220
|
+
addonId: null,
|
|
66221
|
+
access: "view",
|
|
66222
|
+
role: "admin"
|
|
66223
|
+
},
|
|
65487
66224
|
"addons.getVersions": {
|
|
65488
66225
|
capName: "addons",
|
|
65489
66226
|
capScope: "system",
|
|
@@ -68592,6 +69329,27 @@ Object.freeze({
|
|
|
68592
69329
|
access: "view",
|
|
68593
69330
|
role: "viewer"
|
|
68594
69331
|
},
|
|
69332
|
+
"groupActive.getStatus": {
|
|
69333
|
+
capName: "group-active",
|
|
69334
|
+
capScope: "device",
|
|
69335
|
+
addonId: null,
|
|
69336
|
+
access: "view",
|
|
69337
|
+
role: "viewer"
|
|
69338
|
+
},
|
|
69339
|
+
"groupCommands.getStatus": {
|
|
69340
|
+
capName: "group-commands",
|
|
69341
|
+
capScope: "device",
|
|
69342
|
+
addonId: null,
|
|
69343
|
+
access: "view",
|
|
69344
|
+
role: "viewer"
|
|
69345
|
+
},
|
|
69346
|
+
"groupStatus.getStatus": {
|
|
69347
|
+
capName: "group-status",
|
|
69348
|
+
capScope: "device",
|
|
69349
|
+
addonId: null,
|
|
69350
|
+
access: "view",
|
|
69351
|
+
role: "viewer"
|
|
69352
|
+
},
|
|
68595
69353
|
"heatingValve.getStatus": {
|
|
68596
69354
|
capName: "heating-valve",
|
|
68597
69355
|
capScope: "device",
|
|
@@ -69544,6 +70302,13 @@ Object.freeze({
|
|
|
69544
70302
|
access: "create",
|
|
69545
70303
|
role: "admin"
|
|
69546
70304
|
},
|
|
70305
|
+
"meter.getStatus": {
|
|
70306
|
+
capName: "meter",
|
|
70307
|
+
capScope: "device",
|
|
70308
|
+
addonId: null,
|
|
70309
|
+
access: "view",
|
|
70310
|
+
role: "viewer"
|
|
70311
|
+
},
|
|
69547
70312
|
"metricsProvider.collectSnapshot": {
|
|
69548
70313
|
capName: "metrics-provider",
|
|
69549
70314
|
capScope: "system",
|
|
@@ -77642,7 +78407,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77642
78407
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77643
78408
|
icon: "square"
|
|
77644
78409
|
}
|
|
77645
|
-
}
|
|
78410
|
+
},
|
|
78411
|
+
overrides: { byType: {
|
|
78412
|
+
[DeviceType.Washer]: {
|
|
78413
|
+
state: { running: {
|
|
78414
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78415
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78416
|
+
} },
|
|
78417
|
+
events: {
|
|
78418
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78419
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78420
|
+
}
|
|
78421
|
+
},
|
|
78422
|
+
[DeviceType.Dryer]: {
|
|
78423
|
+
state: { running: {
|
|
78424
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78425
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78426
|
+
} },
|
|
78427
|
+
events: {
|
|
78428
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78429
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78430
|
+
}
|
|
78431
|
+
},
|
|
78432
|
+
[DeviceType.Dishwasher]: {
|
|
78433
|
+
state: { running: {
|
|
78434
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78435
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78436
|
+
} },
|
|
78437
|
+
events: {
|
|
78438
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78439
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78440
|
+
}
|
|
78441
|
+
}
|
|
78442
|
+
} }
|
|
77646
78443
|
},
|
|
77647
78444
|
update: {
|
|
77648
78445
|
scope: "device",
|
|
@@ -78414,6 +79211,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78414
79211
|
icon: "flame"
|
|
78415
79212
|
}]
|
|
78416
79213
|
},
|
|
79214
|
+
"group-active": {
|
|
79215
|
+
scope: "device",
|
|
79216
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79217
|
+
},
|
|
79218
|
+
"group-commands": {
|
|
79219
|
+
scope: "device",
|
|
79220
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79221
|
+
},
|
|
79222
|
+
"group-status": {
|
|
79223
|
+
scope: "device",
|
|
79224
|
+
noun: t("Group", "Gruppo"),
|
|
79225
|
+
state: [
|
|
79226
|
+
{
|
|
79227
|
+
kind: "numeric",
|
|
79228
|
+
field: "included",
|
|
79229
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79230
|
+
label: t("Reporting", "Rispondono"),
|
|
79231
|
+
icon: "users"
|
|
79232
|
+
},
|
|
79233
|
+
{
|
|
79234
|
+
kind: "numeric",
|
|
79235
|
+
field: "excluded",
|
|
79236
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79237
|
+
label: t("Excluded", "Esclusi"),
|
|
79238
|
+
icon: "users"
|
|
79239
|
+
},
|
|
79240
|
+
{
|
|
79241
|
+
kind: "numeric",
|
|
79242
|
+
field: "total",
|
|
79243
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79244
|
+
label: t("Members", "Membri"),
|
|
79245
|
+
icon: "sigma"
|
|
79246
|
+
}
|
|
79247
|
+
]
|
|
79248
|
+
},
|
|
78417
79249
|
"humidity-sensor": {
|
|
78418
79250
|
scope: "device",
|
|
78419
79251
|
noun: t("Humidity", "Umidità"),
|
|
@@ -78439,6 +79271,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78439
79271
|
}],
|
|
78440
79272
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78441
79273
|
},
|
|
79274
|
+
meter: {
|
|
79275
|
+
scope: "device",
|
|
79276
|
+
noun: t("Meter", "Contatore"),
|
|
79277
|
+
state: [{
|
|
79278
|
+
kind: "numeric",
|
|
79279
|
+
field: "value",
|
|
79280
|
+
quantity: t("the total", "il totale"),
|
|
79281
|
+
label: t("Total", "Totale"),
|
|
79282
|
+
icon: "gauge"
|
|
79283
|
+
}]
|
|
79284
|
+
},
|
|
78442
79285
|
"numeric-sensor": {
|
|
78443
79286
|
scope: "device",
|
|
78444
79287
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78447,7 +79290,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78447
79290
|
field: "value",
|
|
78448
79291
|
quantity: t("the reading", "il valore"),
|
|
78449
79292
|
label: t("Reading", "Valore"),
|
|
78450
|
-
unitField: "unit",
|
|
78451
79293
|
icon: "gauge"
|
|
78452
79294
|
}]
|
|
78453
79295
|
},
|
|
@@ -78583,7 +79425,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78583
79425
|
field: "temperature",
|
|
78584
79426
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78585
79427
|
label: t("Temperature", "Temperatura"),
|
|
78586
|
-
|
|
79428
|
+
unit: "°C",
|
|
78587
79429
|
icon: "thermometer"
|
|
78588
79430
|
},
|
|
78589
79431
|
{
|
|
@@ -78599,7 +79441,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78599
79441
|
field: "windSpeed",
|
|
78600
79442
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78601
79443
|
label: t("Wind", "Vento"),
|
|
78602
|
-
|
|
79444
|
+
unit: "m/s",
|
|
78603
79445
|
icon: "wind"
|
|
78604
79446
|
},
|
|
78605
79447
|
{
|
|
@@ -78607,7 +79449,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78607
79449
|
field: "pressure",
|
|
78608
79450
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78609
79451
|
label: t("Pressure", "Pressione"),
|
|
78610
|
-
|
|
79452
|
+
unit: "hPa",
|
|
78611
79453
|
icon: "gauge"
|
|
78612
79454
|
}
|
|
78613
79455
|
]
|
|
@@ -78912,8 +79754,47 @@ function projectAction(cap, action) {
|
|
|
78912
79754
|
};
|
|
78913
79755
|
}
|
|
78914
79756
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
78915
|
-
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;
|
|
79757
|
+
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;
|
|
78916
79758
|
DeviceFeature.BatteryOperated;
|
|
79759
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79760
|
+
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.";
|
|
79761
|
+
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.";
|
|
79762
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79763
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79764
|
+
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.";
|
|
79765
|
+
function withheld(reason) {
|
|
79766
|
+
return {
|
|
79767
|
+
[DeviceType.Washer]: {
|
|
79768
|
+
exported: false,
|
|
79769
|
+
reason
|
|
79770
|
+
},
|
|
79771
|
+
[DeviceType.Dryer]: {
|
|
79772
|
+
exported: false,
|
|
79773
|
+
reason
|
|
79774
|
+
},
|
|
79775
|
+
[DeviceType.Dishwasher]: {
|
|
79776
|
+
exported: false,
|
|
79777
|
+
reason
|
|
79778
|
+
}
|
|
79779
|
+
};
|
|
79780
|
+
}
|
|
79781
|
+
function offered(received) {
|
|
79782
|
+
return {
|
|
79783
|
+
[DeviceType.Washer]: {
|
|
79784
|
+
exported: true,
|
|
79785
|
+
as: received
|
|
79786
|
+
},
|
|
79787
|
+
[DeviceType.Dryer]: {
|
|
79788
|
+
exported: true,
|
|
79789
|
+
as: received
|
|
79790
|
+
},
|
|
79791
|
+
[DeviceType.Dishwasher]: {
|
|
79792
|
+
exported: true,
|
|
79793
|
+
as: received
|
|
79794
|
+
}
|
|
79795
|
+
};
|
|
79796
|
+
}
|
|
79797
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
78917
79798
|
Object.freeze({
|
|
78918
79799
|
"accessories.getStatus": [{
|
|
78919
79800
|
name: "deviceId",
|
|
@@ -79880,6 +80761,21 @@ Object.freeze({
|
|
|
79880
80761
|
form: "single",
|
|
79881
80762
|
optional: false
|
|
79882
80763
|
}],
|
|
80764
|
+
"groupActive.getStatus": [{
|
|
80765
|
+
name: "deviceId",
|
|
80766
|
+
form: "single",
|
|
80767
|
+
optional: false
|
|
80768
|
+
}],
|
|
80769
|
+
"groupCommands.getStatus": [{
|
|
80770
|
+
name: "deviceId",
|
|
80771
|
+
form: "single",
|
|
80772
|
+
optional: false
|
|
80773
|
+
}],
|
|
80774
|
+
"groupStatus.getStatus": [{
|
|
80775
|
+
name: "deviceId",
|
|
80776
|
+
form: "single",
|
|
80777
|
+
optional: false
|
|
80778
|
+
}],
|
|
79883
80779
|
"heatingValve.getStatus": [{
|
|
79884
80780
|
name: "deviceId",
|
|
79885
80781
|
form: "single",
|
|
@@ -80080,6 +80976,11 @@ Object.freeze({
|
|
|
80080
80976
|
form: "single",
|
|
80081
80977
|
optional: false
|
|
80082
80978
|
}],
|
|
80979
|
+
"meter.getStatus": [{
|
|
80980
|
+
name: "deviceId",
|
|
80981
|
+
form: "single",
|
|
80982
|
+
optional: false
|
|
80983
|
+
}],
|
|
80083
80984
|
"motion.getStatus": [{
|
|
80084
80985
|
name: "deviceId",
|
|
80085
80986
|
form: "single",
|
|
@@ -81687,7 +82588,6 @@ Object.freeze({
|
|
|
81687
82588
|
"network-access": "ingress",
|
|
81688
82589
|
"smtp-provider": "email"
|
|
81689
82590
|
});
|
|
81690
|
-
DeviceType.Camera;
|
|
81691
82591
|
/**
|
|
81692
82592
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
81693
82593
|
* `z.infer`, they do not restate the shape.
|
|
@@ -81864,6 +82764,8 @@ new Map(Object.entries({
|
|
|
81864
82764
|
"detection-blind": "device-events",
|
|
81865
82765
|
"motion-noisy": "device-events",
|
|
81866
82766
|
"motion-calm": "device-events",
|
|
82767
|
+
"package-llm-silent": "device-events",
|
|
82768
|
+
"package-llm-answered": "device-events",
|
|
81867
82769
|
"recording-stalled": "device-events",
|
|
81868
82770
|
"recording-healthy": "device-events",
|
|
81869
82771
|
"recording-degraded": "device-events",
|
|
@@ -81947,6 +82849,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
81947
82849
|
label: "Motion without a subject",
|
|
81948
82850
|
kinds: ["motion-noisy", "motion-calm"]
|
|
81949
82851
|
},
|
|
82852
|
+
{
|
|
82853
|
+
id: "package-llm",
|
|
82854
|
+
family: "device-events",
|
|
82855
|
+
label: "Package confirm",
|
|
82856
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
82857
|
+
},
|
|
81950
82858
|
{
|
|
81951
82859
|
id: "recording",
|
|
81952
82860
|
family: "device-events",
|
|
@@ -82128,6 +83036,8 @@ var DEVICE_EVENTS = [
|
|
|
82128
83036
|
"detection-blind",
|
|
82129
83037
|
"motion-noisy",
|
|
82130
83038
|
"motion-calm",
|
|
83039
|
+
"package-llm-silent",
|
|
83040
|
+
"package-llm-answered",
|
|
82131
83041
|
"recording-stalled",
|
|
82132
83042
|
"recording-healthy",
|
|
82133
83043
|
"recording-degraded",
|
|
@@ -82396,6 +83306,15 @@ new Map([
|
|
|
82396
83306
|
snapshotLabel: "Cameras with constant motion now",
|
|
82397
83307
|
snapshotSection: null
|
|
82398
83308
|
},
|
|
83309
|
+
{
|
|
83310
|
+
id: "package-llm-confirm",
|
|
83311
|
+
family: "device-events",
|
|
83312
|
+
label: "Package confirm (not answering / answering again)",
|
|
83313
|
+
bad: ["package-llm-silent"],
|
|
83314
|
+
recovery: ["package-llm-answered"],
|
|
83315
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
83316
|
+
snapshotSection: null
|
|
83317
|
+
},
|
|
82399
83318
|
{
|
|
82400
83319
|
id: "recording-health",
|
|
82401
83320
|
family: "device-events",
|