@camstack/addon-google-services 0.2.31 → 0.2.33
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 +37 -0
- package/dist/google-services.addon.js +1368 -449
- package/dist/google-services.addon.mjs +1368 -449
- package/package.json +7 -5
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
let node_crypto = require("node:crypto");
|
|
6
|
-
//#region ../types/dist/event-category-
|
|
6
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
7
7
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
8
8
|
EventCategory["SystemBoot"] = "system.boot";
|
|
9
9
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -329,6 +329,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
329
329
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
330
330
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
331
331
|
/**
|
|
332
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
333
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
334
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
335
|
+
*/
|
|
336
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
337
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
338
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
339
|
+
/**
|
|
332
340
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
333
341
|
* (a settings change via `setAgentInferenceDevices` /
|
|
334
342
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5571,7 +5579,7 @@ var ZodIssueCode = {
|
|
|
5571
5579
|
var ZodFirstPartyTypeKind;
|
|
5572
5580
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5573
5581
|
//#endregion
|
|
5574
|
-
//#region ../types/dist/sleep
|
|
5582
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5575
5583
|
/**
|
|
5576
5584
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5577
5585
|
* window to float samples (D455).
|
|
@@ -8313,6 +8321,99 @@ function defineEntryKind(name, spec) {
|
|
|
8313
8321
|
if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
|
|
8314
8322
|
return defined;
|
|
8315
8323
|
}
|
|
8324
|
+
var READING_QUANTITIES = [
|
|
8325
|
+
"temperature",
|
|
8326
|
+
"pressure",
|
|
8327
|
+
"speed",
|
|
8328
|
+
"precipitation",
|
|
8329
|
+
"precipitation-rate",
|
|
8330
|
+
"length",
|
|
8331
|
+
"area",
|
|
8332
|
+
"illuminance",
|
|
8333
|
+
"irradiance",
|
|
8334
|
+
"power",
|
|
8335
|
+
"energy",
|
|
8336
|
+
"voltage",
|
|
8337
|
+
"current",
|
|
8338
|
+
"apparent-power",
|
|
8339
|
+
"humidity",
|
|
8340
|
+
"percentage",
|
|
8341
|
+
"concentration-volume",
|
|
8342
|
+
"concentration-mass",
|
|
8343
|
+
"concentration-ppb",
|
|
8344
|
+
"volume",
|
|
8345
|
+
"duration",
|
|
8346
|
+
"duration-ms",
|
|
8347
|
+
"information",
|
|
8348
|
+
"sound-level",
|
|
8349
|
+
"signal-level",
|
|
8350
|
+
"colour-temperature",
|
|
8351
|
+
"angle",
|
|
8352
|
+
"bitrate",
|
|
8353
|
+
"rate",
|
|
8354
|
+
"mass",
|
|
8355
|
+
"index",
|
|
8356
|
+
"ratio",
|
|
8357
|
+
"count",
|
|
8358
|
+
"none",
|
|
8359
|
+
"device"
|
|
8360
|
+
];
|
|
8361
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8362
|
+
new Set(READING_QUANTITIES);
|
|
8363
|
+
/**
|
|
8364
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8365
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8366
|
+
*/
|
|
8367
|
+
var QUANTITY_BASE = {
|
|
8368
|
+
temperature: "°C",
|
|
8369
|
+
pressure: "hPa",
|
|
8370
|
+
speed: "m/s",
|
|
8371
|
+
precipitation: "mm",
|
|
8372
|
+
"precipitation-rate": "mm/h",
|
|
8373
|
+
length: "m",
|
|
8374
|
+
area: "m²",
|
|
8375
|
+
illuminance: "lx",
|
|
8376
|
+
irradiance: "W/m²",
|
|
8377
|
+
power: "W",
|
|
8378
|
+
energy: "kWh",
|
|
8379
|
+
voltage: "V",
|
|
8380
|
+
current: "A",
|
|
8381
|
+
"apparent-power": "VA",
|
|
8382
|
+
humidity: "%",
|
|
8383
|
+
percentage: "%",
|
|
8384
|
+
"concentration-volume": "ppm",
|
|
8385
|
+
"concentration-mass": "µg/m³",
|
|
8386
|
+
"concentration-ppb": "ppb",
|
|
8387
|
+
volume: "L",
|
|
8388
|
+
duration: "s",
|
|
8389
|
+
"duration-ms": "ms",
|
|
8390
|
+
information: "B",
|
|
8391
|
+
"sound-level": "dBFS",
|
|
8392
|
+
"signal-level": "dBm",
|
|
8393
|
+
"colour-temperature": "mired",
|
|
8394
|
+
angle: "°",
|
|
8395
|
+
bitrate: "kbps",
|
|
8396
|
+
rate: "fps",
|
|
8397
|
+
mass: "kg",
|
|
8398
|
+
index: "none",
|
|
8399
|
+
ratio: "none",
|
|
8400
|
+
count: "none",
|
|
8401
|
+
none: "none",
|
|
8402
|
+
device: "device"
|
|
8403
|
+
};
|
|
8404
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8405
|
+
function baseUnitOf(quantity) {
|
|
8406
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8407
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8408
|
+
return symbol;
|
|
8409
|
+
}
|
|
8410
|
+
function readingMeta(quantity, extras) {
|
|
8411
|
+
return {
|
|
8412
|
+
quantity,
|
|
8413
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8414
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8415
|
+
};
|
|
8416
|
+
}
|
|
8316
8417
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8317
8418
|
var CamProfileSchema = _enum([
|
|
8318
8419
|
"high",
|
|
@@ -8340,8 +8441,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8340
8441
|
"derived"
|
|
8341
8442
|
]);
|
|
8342
8443
|
var CamStreamResolutionSchema = object({
|
|
8343
|
-
width: number().int().positive(),
|
|
8344
|
-
height: number().int().positive()
|
|
8444
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8445
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8345
8446
|
});
|
|
8346
8447
|
var CameraStreamSchema = object({
|
|
8347
8448
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8855,6 +8956,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8855
8956
|
"filesystem-browse",
|
|
8856
8957
|
"flood",
|
|
8857
8958
|
"gas",
|
|
8959
|
+
"group-active",
|
|
8960
|
+
"group-commands",
|
|
8961
|
+
"group-status",
|
|
8858
8962
|
"heating-valve",
|
|
8859
8963
|
"humidifier",
|
|
8860
8964
|
"humidity-sensor",
|
|
@@ -8875,6 +8979,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8875
8979
|
"login-method",
|
|
8876
8980
|
"media-player",
|
|
8877
8981
|
"mesh-network",
|
|
8982
|
+
"meter",
|
|
8878
8983
|
"metrics-provider",
|
|
8879
8984
|
"model-convert",
|
|
8880
8985
|
"model-distributor",
|
|
@@ -8984,14 +9089,6 @@ Object.freeze({
|
|
|
8984
9089
|
{
|
|
8985
9090
|
"path": "aqi",
|
|
8986
9091
|
"valueType": "number"
|
|
8987
|
-
},
|
|
8988
|
-
{
|
|
8989
|
-
"path": "unit",
|
|
8990
|
-
"valueType": "string"
|
|
8991
|
-
},
|
|
8992
|
-
{
|
|
8993
|
-
"path": "precision",
|
|
8994
|
-
"valueType": "number"
|
|
8995
9092
|
}
|
|
8996
9093
|
],
|
|
8997
9094
|
"alarm-panel": [
|
|
@@ -9027,20 +9124,10 @@ Object.freeze({
|
|
|
9027
9124
|
"valueType": "boolean"
|
|
9028
9125
|
}
|
|
9029
9126
|
],
|
|
9030
|
-
"ambient-light-sensor": [
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
},
|
|
9035
|
-
{
|
|
9036
|
-
"path": "unit",
|
|
9037
|
-
"valueType": "string"
|
|
9038
|
-
},
|
|
9039
|
-
{
|
|
9040
|
-
"path": "precision",
|
|
9041
|
-
"valueType": "number"
|
|
9042
|
-
}
|
|
9043
|
-
],
|
|
9127
|
+
"ambient-light-sensor": [{
|
|
9128
|
+
"path": "lux",
|
|
9129
|
+
"valueType": "number"
|
|
9130
|
+
}],
|
|
9044
9131
|
"audio-metrics": [
|
|
9045
9132
|
{
|
|
9046
9133
|
"path": "ts",
|
|
@@ -9120,6 +9207,10 @@ Object.freeze({
|
|
|
9120
9207
|
"path": "lastUpdated",
|
|
9121
9208
|
"valueType": "number"
|
|
9122
9209
|
},
|
|
9210
|
+
{
|
|
9211
|
+
"path": "volts",
|
|
9212
|
+
"valueType": "number"
|
|
9213
|
+
},
|
|
9123
9214
|
{
|
|
9124
9215
|
"path": "lastContactAt",
|
|
9125
9216
|
"valueType": "number"
|
|
@@ -9362,10 +9453,6 @@ Object.freeze({
|
|
|
9362
9453
|
"datetime"
|
|
9363
9454
|
]
|
|
9364
9455
|
},
|
|
9365
|
-
{
|
|
9366
|
-
"path": "unit",
|
|
9367
|
-
"valueType": "string"
|
|
9368
|
-
},
|
|
9369
9456
|
{
|
|
9370
9457
|
"path": "min",
|
|
9371
9458
|
"valueType": "number"
|
|
@@ -9377,19 +9464,6 @@ Object.freeze({
|
|
|
9377
9464
|
{
|
|
9378
9465
|
"path": "step",
|
|
9379
9466
|
"valueType": "number"
|
|
9380
|
-
},
|
|
9381
|
-
{
|
|
9382
|
-
"path": "precision",
|
|
9383
|
-
"valueType": "number"
|
|
9384
|
-
},
|
|
9385
|
-
{
|
|
9386
|
-
"path": "format",
|
|
9387
|
-
"valueType": "enum",
|
|
9388
|
-
"enumValues": [
|
|
9389
|
-
"date",
|
|
9390
|
-
"time",
|
|
9391
|
-
"datetime"
|
|
9392
|
-
]
|
|
9393
9467
|
}
|
|
9394
9468
|
],
|
|
9395
9469
|
"cover": [
|
|
@@ -9630,13 +9704,8 @@ Object.freeze({
|
|
|
9630
9704
|
"path": "value",
|
|
9631
9705
|
"valueType": "string"
|
|
9632
9706
|
}, {
|
|
9633
|
-
"path": "
|
|
9634
|
-
"valueType": "
|
|
9635
|
-
"enumValues": [
|
|
9636
|
-
"date",
|
|
9637
|
-
"time",
|
|
9638
|
-
"datetime"
|
|
9639
|
-
]
|
|
9707
|
+
"path": "timestamp",
|
|
9708
|
+
"valueType": "boolean"
|
|
9640
9709
|
}],
|
|
9641
9710
|
"event-emitter": [
|
|
9642
9711
|
{
|
|
@@ -9709,6 +9778,24 @@ Object.freeze({
|
|
|
9709
9778
|
"path": "detected",
|
|
9710
9779
|
"valueType": "boolean"
|
|
9711
9780
|
}],
|
|
9781
|
+
"group-active": [{
|
|
9782
|
+
"path": "active",
|
|
9783
|
+
"valueType": "boolean"
|
|
9784
|
+
}],
|
|
9785
|
+
"group-status": [
|
|
9786
|
+
{
|
|
9787
|
+
"path": "included",
|
|
9788
|
+
"valueType": "number"
|
|
9789
|
+
},
|
|
9790
|
+
{
|
|
9791
|
+
"path": "excluded",
|
|
9792
|
+
"valueType": "number"
|
|
9793
|
+
},
|
|
9794
|
+
{
|
|
9795
|
+
"path": "total",
|
|
9796
|
+
"valueType": "number"
|
|
9797
|
+
}
|
|
9798
|
+
],
|
|
9712
9799
|
"heating-valve": [{
|
|
9713
9800
|
"path": "position",
|
|
9714
9801
|
"valueType": "number"
|
|
@@ -9743,20 +9830,10 @@ Object.freeze({
|
|
|
9743
9830
|
"valueType": "number"
|
|
9744
9831
|
}
|
|
9745
9832
|
],
|
|
9746
|
-
"humidity-sensor": [
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
},
|
|
9751
|
-
{
|
|
9752
|
-
"path": "unit",
|
|
9753
|
-
"valueType": "string"
|
|
9754
|
-
},
|
|
9755
|
-
{
|
|
9756
|
-
"path": "precision",
|
|
9757
|
-
"valueType": "number"
|
|
9758
|
-
}
|
|
9759
|
-
],
|
|
9833
|
+
"humidity-sensor": [{
|
|
9834
|
+
"path": "percent",
|
|
9835
|
+
"valueType": "number"
|
|
9836
|
+
}],
|
|
9760
9837
|
"image": [{
|
|
9761
9838
|
"path": "url",
|
|
9762
9839
|
"valueType": "string"
|
|
@@ -9964,6 +10041,10 @@ Object.freeze({
|
|
|
9964
10041
|
]
|
|
9965
10042
|
}
|
|
9966
10043
|
],
|
|
10044
|
+
"meter": [{
|
|
10045
|
+
"path": "value",
|
|
10046
|
+
"valueType": "number"
|
|
10047
|
+
}],
|
|
9967
10048
|
"motion": [
|
|
9968
10049
|
{
|
|
9969
10050
|
"path": "detected",
|
|
@@ -10095,20 +10176,10 @@ Object.freeze({
|
|
|
10095
10176
|
"valueType": "boolean"
|
|
10096
10177
|
}
|
|
10097
10178
|
],
|
|
10098
|
-
"numeric-sensor": [
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
},
|
|
10103
|
-
{
|
|
10104
|
-
"path": "unit",
|
|
10105
|
-
"valueType": "string"
|
|
10106
|
-
},
|
|
10107
|
-
{
|
|
10108
|
-
"path": "precision",
|
|
10109
|
-
"valueType": "number"
|
|
10110
|
-
}
|
|
10111
|
-
],
|
|
10179
|
+
"numeric-sensor": [{
|
|
10180
|
+
"path": "value",
|
|
10181
|
+
"valueType": "number"
|
|
10182
|
+
}],
|
|
10112
10183
|
"pet-feeder": [
|
|
10113
10184
|
{
|
|
10114
10185
|
"path": "foodLevel",
|
|
@@ -10200,14 +10271,6 @@ Object.freeze({
|
|
|
10200
10271
|
{
|
|
10201
10272
|
"path": "powerFactor",
|
|
10202
10273
|
"valueType": "number"
|
|
10203
|
-
},
|
|
10204
|
-
{
|
|
10205
|
-
"path": "unit",
|
|
10206
|
-
"valueType": "string"
|
|
10207
|
-
},
|
|
10208
|
-
{
|
|
10209
|
-
"path": "precision",
|
|
10210
|
-
"valueType": "number"
|
|
10211
10274
|
}
|
|
10212
10275
|
],
|
|
10213
10276
|
"presence": [
|
|
@@ -10236,20 +10299,10 @@ Object.freeze({
|
|
|
10236
10299
|
"valueType": "number"
|
|
10237
10300
|
}
|
|
10238
10301
|
],
|
|
10239
|
-
"pressure-sensor": [
|
|
10240
|
-
|
|
10241
|
-
|
|
10242
|
-
|
|
10243
|
-
},
|
|
10244
|
-
{
|
|
10245
|
-
"path": "unit",
|
|
10246
|
-
"valueType": "string"
|
|
10247
|
-
},
|
|
10248
|
-
{
|
|
10249
|
-
"path": "precision",
|
|
10250
|
-
"valueType": "number"
|
|
10251
|
-
}
|
|
10252
|
-
],
|
|
10302
|
+
"pressure-sensor": [{
|
|
10303
|
+
"path": "hpa",
|
|
10304
|
+
"valueType": "number"
|
|
10305
|
+
}],
|
|
10253
10306
|
"privacy-mask": [{
|
|
10254
10307
|
"path": "enabled",
|
|
10255
10308
|
"valueType": "boolean"
|
|
@@ -10560,20 +10613,10 @@ Object.freeze({
|
|
|
10560
10613
|
"path": "tampered",
|
|
10561
10614
|
"valueType": "boolean"
|
|
10562
10615
|
}],
|
|
10563
|
-
"temperature-sensor": [
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
},
|
|
10568
|
-
{
|
|
10569
|
-
"path": "unit",
|
|
10570
|
-
"valueType": "string"
|
|
10571
|
-
},
|
|
10572
|
-
{
|
|
10573
|
-
"path": "precision",
|
|
10574
|
-
"valueType": "number"
|
|
10575
|
-
}
|
|
10576
|
-
],
|
|
10616
|
+
"temperature-sensor": [{
|
|
10617
|
+
"path": "celsius",
|
|
10618
|
+
"valueType": "number"
|
|
10619
|
+
}],
|
|
10577
10620
|
"update": [
|
|
10578
10621
|
{
|
|
10579
10622
|
"path": "currentVersion",
|
|
@@ -10684,10 +10727,6 @@ Object.freeze({
|
|
|
10684
10727
|
"path": "temperature",
|
|
10685
10728
|
"valueType": "number"
|
|
10686
10729
|
},
|
|
10687
|
-
{
|
|
10688
|
-
"path": "temperatureUnit",
|
|
10689
|
-
"valueType": "string"
|
|
10690
|
-
},
|
|
10691
10730
|
{
|
|
10692
10731
|
"path": "humidity",
|
|
10693
10732
|
"valueType": "number"
|
|
@@ -10696,18 +10735,10 @@ Object.freeze({
|
|
|
10696
10735
|
"path": "pressure",
|
|
10697
10736
|
"valueType": "number"
|
|
10698
10737
|
},
|
|
10699
|
-
{
|
|
10700
|
-
"path": "pressureUnit",
|
|
10701
|
-
"valueType": "string"
|
|
10702
|
-
},
|
|
10703
10738
|
{
|
|
10704
10739
|
"path": "windSpeed",
|
|
10705
10740
|
"valueType": "number"
|
|
10706
10741
|
},
|
|
10707
|
-
{
|
|
10708
|
-
"path": "windSpeedUnit",
|
|
10709
|
-
"valueType": "string"
|
|
10710
|
-
},
|
|
10711
10742
|
{
|
|
10712
10743
|
"path": "windBearing",
|
|
10713
10744
|
"valueType": "number"
|
|
@@ -10771,7 +10802,7 @@ function userError(code, params, englishFallback) {
|
|
|
10771
10802
|
return new CamstackError(code, params, englishFallback);
|
|
10772
10803
|
}
|
|
10773
10804
|
//#endregion
|
|
10774
|
-
//#region ../types/dist/err-msg-
|
|
10805
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10775
10806
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10776
10807
|
DeviceType["Camera"] = "camera";
|
|
10777
10808
|
DeviceType["Hub"] = "hub";
|
|
@@ -10865,8 +10896,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10865
10896
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10866
10897
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10867
10898
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10868
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10899
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10900
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10869
10901
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10902
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10903
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10904
|
+
DeviceType["Washer"] = "washer";
|
|
10905
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10906
|
+
DeviceType["Dryer"] = "dryer";
|
|
10870
10907
|
return DeviceType;
|
|
10871
10908
|
}({});
|
|
10872
10909
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11114,7 +11151,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11114
11151
|
return DeviceRole;
|
|
11115
11152
|
}({});
|
|
11116
11153
|
//#endregion
|
|
11117
|
-
//#region ../types/dist/composition-
|
|
11154
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11118
11155
|
/**
|
|
11119
11156
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11120
11157
|
*
|
|
@@ -11429,6 +11466,13 @@ var table = {
|
|
|
11429
11466
|
apply: () => {
|
|
11430
11467
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11431
11468
|
}
|
|
11469
|
+
},
|
|
11470
|
+
schmitt: {
|
|
11471
|
+
minArgs: 3,
|
|
11472
|
+
maxArgs: 5,
|
|
11473
|
+
apply: () => {
|
|
11474
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11475
|
+
}
|
|
11432
11476
|
}
|
|
11433
11477
|
};
|
|
11434
11478
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11869,15 +11913,232 @@ function validateExpressionSource(src) {
|
|
|
11869
11913
|
}
|
|
11870
11914
|
return null;
|
|
11871
11915
|
}
|
|
11872
|
-
/**
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11916
|
+
/**
|
|
11917
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11918
|
+
*
|
|
11919
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11920
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11921
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11922
|
+
*
|
|
11923
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11924
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11925
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11926
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11927
|
+
* can move later without moving the others.
|
|
11928
|
+
*/
|
|
11929
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11930
|
+
var APPLIANCE_KINDS = [
|
|
11931
|
+
"washer",
|
|
11932
|
+
"dryer",
|
|
11933
|
+
"dishwasher"
|
|
11934
|
+
];
|
|
11935
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11936
|
+
/**
|
|
11937
|
+
* Statistics and integrals over a history read (D944).
|
|
11938
|
+
*
|
|
11939
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11940
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11941
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11942
|
+
* as zero. A truncated read is not published.
|
|
11943
|
+
*/
|
|
11944
|
+
var STATISTIC_STATS = [
|
|
11945
|
+
"min",
|
|
11946
|
+
"max",
|
|
11947
|
+
"mean",
|
|
11948
|
+
"sum",
|
|
11949
|
+
"count",
|
|
11950
|
+
"change"
|
|
11951
|
+
];
|
|
11952
|
+
/**
|
|
11953
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11954
|
+
*
|
|
11955
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11956
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11957
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11958
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11959
|
+
*/
|
|
11960
|
+
var MINUTE_MS = 6e4;
|
|
11961
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11962
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11963
|
+
var ROLLING_SPANS = [
|
|
11964
|
+
"1h",
|
|
11965
|
+
"24h",
|
|
11966
|
+
"2d",
|
|
11967
|
+
"7d",
|
|
11968
|
+
"30d",
|
|
11969
|
+
"custom"
|
|
11970
|
+
];
|
|
11971
|
+
var CALENDAR_PERIODS = [
|
|
11972
|
+
"today",
|
|
11973
|
+
"yesterday",
|
|
11974
|
+
"this-week",
|
|
11975
|
+
"this-month"
|
|
11976
|
+
];
|
|
11977
|
+
var RESET_PERIODS = [
|
|
11978
|
+
"never",
|
|
11979
|
+
"daily",
|
|
11980
|
+
"weekly",
|
|
11981
|
+
"monthly"
|
|
11982
|
+
];
|
|
11983
|
+
5 * MINUTE_MS;
|
|
11984
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11985
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11986
|
+
var rollingWindowObject = object({
|
|
11987
|
+
kind: literal("rolling"),
|
|
11988
|
+
span: _enum(ROLLING_SPANS),
|
|
11989
|
+
customMinutes: number().int().min(5).optional()
|
|
11990
|
+
}).check((payload) => {
|
|
11991
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11992
|
+
code: "custom",
|
|
11993
|
+
message: "a custom range needs a duration in minutes",
|
|
11994
|
+
path: ["customMinutes"],
|
|
11995
|
+
input: payload.value
|
|
11996
|
+
});
|
|
11997
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11998
|
+
code: "custom",
|
|
11999
|
+
message: "only a custom range carries a duration",
|
|
12000
|
+
path: ["customMinutes"],
|
|
12001
|
+
input: payload.value
|
|
12002
|
+
});
|
|
12003
|
+
});
|
|
12004
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12005
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12006
|
+
kind: literal("calendar"),
|
|
12007
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12008
|
+
})]);
|
|
12009
|
+
/**
|
|
12010
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
12011
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
12012
|
+
* `composition.ts` (D659).
|
|
12013
|
+
*/
|
|
11876
12014
|
var CompositionSourceRefSchema = object({
|
|
11877
12015
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11878
12016
|
addonId: string().min(1),
|
|
11879
12017
|
stableId: string().min(1)
|
|
11880
12018
|
});
|
|
12019
|
+
var GROUP_TEMPLATE_IDS = [
|
|
12020
|
+
"temperature",
|
|
12021
|
+
"humidity",
|
|
12022
|
+
"pressure",
|
|
12023
|
+
"illuminance",
|
|
12024
|
+
"power",
|
|
12025
|
+
"energy",
|
|
12026
|
+
"battery",
|
|
12027
|
+
"numeric",
|
|
12028
|
+
"motion",
|
|
12029
|
+
"contact",
|
|
12030
|
+
"leak",
|
|
12031
|
+
"smoke",
|
|
12032
|
+
"occupancy",
|
|
12033
|
+
"binary",
|
|
12034
|
+
"switch",
|
|
12035
|
+
"light",
|
|
12036
|
+
"fan",
|
|
12037
|
+
"cover",
|
|
12038
|
+
"valve",
|
|
12039
|
+
"lock",
|
|
12040
|
+
"media-player",
|
|
12041
|
+
"climate"
|
|
12042
|
+
];
|
|
12043
|
+
var NUMERIC_AGGREGATES = [
|
|
12044
|
+
"mean",
|
|
12045
|
+
"median",
|
|
12046
|
+
"min",
|
|
12047
|
+
"max",
|
|
12048
|
+
"sum"
|
|
12049
|
+
];
|
|
12050
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12051
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12052
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12053
|
+
var AGGREGATE_REDUCERS = [
|
|
12054
|
+
"mean",
|
|
12055
|
+
"median",
|
|
12056
|
+
"min",
|
|
12057
|
+
"max",
|
|
12058
|
+
"sum",
|
|
12059
|
+
"any",
|
|
12060
|
+
"all"
|
|
12061
|
+
];
|
|
12062
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12063
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12064
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12065
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12066
|
+
var HelperMemberSchema = object({
|
|
12067
|
+
source: CompositionSourceRefSchema,
|
|
12068
|
+
cap: string().min(1),
|
|
12069
|
+
fieldPath: string().min(1)
|
|
12070
|
+
});
|
|
12071
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12072
|
+
object({
|
|
12073
|
+
kind: literal("group"),
|
|
12074
|
+
templateId: GroupTemplateIdSchema,
|
|
12075
|
+
aggregate: AggregateReducerSchema,
|
|
12076
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12077
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12078
|
+
active: ActiveCriterionSchema.optional()
|
|
12079
|
+
}),
|
|
12080
|
+
object({
|
|
12081
|
+
kind: literal("appliance"),
|
|
12082
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12083
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12084
|
+
thresholdWatts: number().positive(),
|
|
12085
|
+
startDwellMs: number().int().nonnegative(),
|
|
12086
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12087
|
+
member: HelperMemberSchema
|
|
12088
|
+
}),
|
|
12089
|
+
object({
|
|
12090
|
+
kind: literal("statistic"),
|
|
12091
|
+
stat: _enum(STATISTIC_STATS),
|
|
12092
|
+
window: StatisticWindowSchema,
|
|
12093
|
+
source: HelperMemberSchema
|
|
12094
|
+
}),
|
|
12095
|
+
object({
|
|
12096
|
+
kind: literal("integral"),
|
|
12097
|
+
reset: _enum(RESET_PERIODS),
|
|
12098
|
+
output: _enum(["energy", "meter"]),
|
|
12099
|
+
source: HelperMemberSchema
|
|
12100
|
+
}),
|
|
12101
|
+
object({
|
|
12102
|
+
kind: literal("threshold"),
|
|
12103
|
+
source: HelperMemberSchema,
|
|
12104
|
+
high: number(),
|
|
12105
|
+
low: number(),
|
|
12106
|
+
onForMs: number().int().nonnegative(),
|
|
12107
|
+
offForMs: number().int().nonnegative()
|
|
12108
|
+
}),
|
|
12109
|
+
object({
|
|
12110
|
+
kind: literal("arithmetic"),
|
|
12111
|
+
op: _enum([
|
|
12112
|
+
"sum",
|
|
12113
|
+
"difference",
|
|
12114
|
+
"ratio"
|
|
12115
|
+
]),
|
|
12116
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12117
|
+
}),
|
|
12118
|
+
object({
|
|
12119
|
+
kind: literal("expression"),
|
|
12120
|
+
expr: string().min(1),
|
|
12121
|
+
inputs: array(object({
|
|
12122
|
+
name: string().min(1),
|
|
12123
|
+
member: HelperMemberSchema
|
|
12124
|
+
})).min(1).max(64),
|
|
12125
|
+
output: _enum(["number", "boolean"])
|
|
12126
|
+
}),
|
|
12127
|
+
object({
|
|
12128
|
+
kind: literal("derivative"),
|
|
12129
|
+
window: RollingWindowSchema,
|
|
12130
|
+
per: _enum([
|
|
12131
|
+
"second",
|
|
12132
|
+
"minute",
|
|
12133
|
+
"hour"
|
|
12134
|
+
]),
|
|
12135
|
+
source: HelperMemberSchema
|
|
12136
|
+
})
|
|
12137
|
+
]);
|
|
12138
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12139
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12140
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12141
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11881
12142
|
/** One field of one capability of one source device. */
|
|
11882
12143
|
var CompositionFieldReadSchema = object({
|
|
11883
12144
|
source: CompositionSourceRefSchema,
|
|
@@ -11921,7 +12182,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11921
12182
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11922
12183
|
CompositionFromSourceSchema,
|
|
11923
12184
|
CompositionExpressionSourceSchema,
|
|
11924
|
-
CompositionCodeSourceSchema
|
|
12185
|
+
CompositionCodeSourceSchema,
|
|
12186
|
+
object({
|
|
12187
|
+
kind: literal("aggregate"),
|
|
12188
|
+
reducer: _enum([
|
|
12189
|
+
"mean",
|
|
12190
|
+
"median",
|
|
12191
|
+
"min",
|
|
12192
|
+
"max",
|
|
12193
|
+
"sum",
|
|
12194
|
+
"any",
|
|
12195
|
+
"all"
|
|
12196
|
+
]),
|
|
12197
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12198
|
+
/**
|
|
12199
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12200
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12201
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12202
|
+
*/
|
|
12203
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12204
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12205
|
+
publish: _enum([
|
|
12206
|
+
"value",
|
|
12207
|
+
"included",
|
|
12208
|
+
"excluded",
|
|
12209
|
+
"total"
|
|
12210
|
+
]),
|
|
12211
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12212
|
+
empty: _enum([
|
|
12213
|
+
"null",
|
|
12214
|
+
"omit",
|
|
12215
|
+
"offline"
|
|
12216
|
+
])
|
|
12217
|
+
}),
|
|
12218
|
+
object({
|
|
12219
|
+
kind: literal("series"),
|
|
12220
|
+
read: CompositionFieldReadSchema,
|
|
12221
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12222
|
+
publish: _enum([
|
|
12223
|
+
"value",
|
|
12224
|
+
"included",
|
|
12225
|
+
"excluded",
|
|
12226
|
+
"total"
|
|
12227
|
+
]),
|
|
12228
|
+
/**
|
|
12229
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12230
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12231
|
+
*/
|
|
12232
|
+
empty: _enum([
|
|
12233
|
+
"null",
|
|
12234
|
+
"omit",
|
|
12235
|
+
"offline"
|
|
12236
|
+
])
|
|
12237
|
+
})
|
|
11925
12238
|
]);
|
|
11926
12239
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11927
12240
|
kind: literal("forward"),
|
|
@@ -11967,7 +12280,13 @@ var CompositionSchema = object({
|
|
|
11967
12280
|
kind: literal("existing"),
|
|
11968
12281
|
device: CompositionSourceRefSchema
|
|
11969
12282
|
})]),
|
|
11970
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12283
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12284
|
+
/**
|
|
12285
|
+
* Present when the block is a helper template. Absent on a free
|
|
12286
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12287
|
+
* never the compiled features.
|
|
12288
|
+
*/
|
|
12289
|
+
helper: HelperSpecSchema.optional()
|
|
11971
12290
|
}).superRefine((composition, ctx) => {
|
|
11972
12291
|
const seen = /* @__PURE__ */ new Set();
|
|
11973
12292
|
composition.features.forEach((feature, index) => {
|
|
@@ -17210,7 +17529,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17210
17529
|
*/
|
|
17211
17530
|
interactiveConnectPath: string().min(1).optional(),
|
|
17212
17531
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17213
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17532
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17533
|
+
/**
|
|
17534
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17535
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17536
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17537
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17538
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17539
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17540
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17541
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17542
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17543
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17544
|
+
* offers it as the default path; the fields the session fills are
|
|
17545
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17546
|
+
*/
|
|
17547
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17214
17548
|
}))
|
|
17215
17549
|
});
|
|
17216
17550
|
var ListInputSchema = object({
|
|
@@ -18254,7 +18588,12 @@ var CompositionProblemSchema = object({
|
|
|
18254
18588
|
"item-field-reserved",
|
|
18255
18589
|
"target-missing",
|
|
18256
18590
|
"target-unreadable",
|
|
18257
|
-
"not-replaceable"
|
|
18591
|
+
"not-replaceable",
|
|
18592
|
+
"native-capability-replace",
|
|
18593
|
+
"mixed-quantity",
|
|
18594
|
+
"helper-mismatch",
|
|
18595
|
+
"member-constraint",
|
|
18596
|
+
"retention"
|
|
18258
18597
|
]),
|
|
18259
18598
|
path: string(),
|
|
18260
18599
|
message: string()
|
|
@@ -18275,7 +18614,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18275
18614
|
"null",
|
|
18276
18615
|
"offline",
|
|
18277
18616
|
"unknown",
|
|
18278
|
-
"release"
|
|
18617
|
+
"release",
|
|
18618
|
+
"omit"
|
|
18279
18619
|
]);
|
|
18280
18620
|
/**
|
|
18281
18621
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18312,9 +18652,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18312
18652
|
reads: array(CompositionFieldReadSchema)
|
|
18313
18653
|
});
|
|
18314
18654
|
/**
|
|
18315
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18316
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18317
|
-
*
|
|
18655
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18656
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18657
|
+
* Replacing a capability the device already serves is refused
|
|
18658
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18659
|
+
* wire for a claim the hub already holds.
|
|
18318
18660
|
*/
|
|
18319
18661
|
var CompositionFeatureModeSchema = _enum([
|
|
18320
18662
|
"new",
|
|
@@ -18485,8 +18827,392 @@ Object.freeze({
|
|
|
18485
18827
|
latchedAt: {
|
|
18486
18828
|
kind: "fixed",
|
|
18487
18829
|
result: ["number", "null"]
|
|
18830
|
+
},
|
|
18831
|
+
schmitt: {
|
|
18832
|
+
kind: "fixed",
|
|
18833
|
+
result: ["boolean", "null"]
|
|
18488
18834
|
}
|
|
18489
18835
|
});
|
|
18836
|
+
/**
|
|
18837
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18838
|
+
* Data, not a form default written into the block.
|
|
18839
|
+
*/
|
|
18840
|
+
var NOW$2 = {
|
|
18841
|
+
fieldPath: "lastFetchedAt",
|
|
18842
|
+
expr: "now"
|
|
18843
|
+
};
|
|
18844
|
+
var CHANGED = {
|
|
18845
|
+
fieldPath: "lastChangedAt",
|
|
18846
|
+
expr: "now"
|
|
18847
|
+
};
|
|
18848
|
+
function numeric(input) {
|
|
18849
|
+
return {
|
|
18850
|
+
...input,
|
|
18851
|
+
family: "numeric",
|
|
18852
|
+
deviceType: DeviceType.Sensor,
|
|
18853
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18854
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18855
|
+
activeWhen: void 0,
|
|
18856
|
+
commandCaps: [],
|
|
18857
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18858
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18859
|
+
accept: [{
|
|
18860
|
+
cap: input.outputCap,
|
|
18861
|
+
fieldPath: input.outputField
|
|
18862
|
+
}]
|
|
18863
|
+
};
|
|
18864
|
+
}
|
|
18865
|
+
function binary(input) {
|
|
18866
|
+
return {
|
|
18867
|
+
...input,
|
|
18868
|
+
family: "binary",
|
|
18869
|
+
deviceType: DeviceType.Sensor,
|
|
18870
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18871
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18872
|
+
activeWhen: void 0,
|
|
18873
|
+
commandCaps: [],
|
|
18874
|
+
quantity: "none",
|
|
18875
|
+
baseUnit: void 0,
|
|
18876
|
+
aggregates: BINARY_AGGREGATES,
|
|
18877
|
+
empty: "offline"
|
|
18878
|
+
};
|
|
18879
|
+
}
|
|
18880
|
+
var GROUP_TEMPLATES = [
|
|
18881
|
+
numeric({
|
|
18882
|
+
id: "temperature",
|
|
18883
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18884
|
+
role: DeviceRole.TemperatureSensor,
|
|
18885
|
+
outputCap: "temperature-sensor",
|
|
18886
|
+
outputField: "celsius",
|
|
18887
|
+
quantity: "temperature",
|
|
18888
|
+
defaultAggregate: "mean",
|
|
18889
|
+
empty: "null",
|
|
18890
|
+
companions: [NOW$2]
|
|
18891
|
+
}),
|
|
18892
|
+
numeric({
|
|
18893
|
+
id: "humidity",
|
|
18894
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18895
|
+
role: DeviceRole.HumiditySensor,
|
|
18896
|
+
outputCap: "humidity-sensor",
|
|
18897
|
+
outputField: "percent",
|
|
18898
|
+
quantity: "humidity",
|
|
18899
|
+
defaultAggregate: "mean",
|
|
18900
|
+
empty: "null",
|
|
18901
|
+
companions: [NOW$2]
|
|
18902
|
+
}),
|
|
18903
|
+
numeric({
|
|
18904
|
+
id: "pressure",
|
|
18905
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18906
|
+
role: DeviceRole.PressureSensor,
|
|
18907
|
+
outputCap: "pressure-sensor",
|
|
18908
|
+
outputField: "hpa",
|
|
18909
|
+
quantity: "pressure",
|
|
18910
|
+
defaultAggregate: "mean",
|
|
18911
|
+
empty: "null",
|
|
18912
|
+
companions: [NOW$2]
|
|
18913
|
+
}),
|
|
18914
|
+
numeric({
|
|
18915
|
+
id: "illuminance",
|
|
18916
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18917
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18918
|
+
outputCap: "ambient-light-sensor",
|
|
18919
|
+
outputField: "lux",
|
|
18920
|
+
quantity: "illuminance",
|
|
18921
|
+
defaultAggregate: "mean",
|
|
18922
|
+
empty: "null",
|
|
18923
|
+
companions: [NOW$2]
|
|
18924
|
+
}),
|
|
18925
|
+
numeric({
|
|
18926
|
+
id: "power",
|
|
18927
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18928
|
+
role: DeviceRole.PowerSensor,
|
|
18929
|
+
outputCap: "power-meter",
|
|
18930
|
+
outputField: "watts",
|
|
18931
|
+
quantity: "power",
|
|
18932
|
+
defaultAggregate: "sum",
|
|
18933
|
+
empty: "omit",
|
|
18934
|
+
companions: [NOW$2]
|
|
18935
|
+
}),
|
|
18936
|
+
numeric({
|
|
18937
|
+
id: "energy",
|
|
18938
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18939
|
+
role: DeviceRole.EnergySensor,
|
|
18940
|
+
outputCap: "power-meter",
|
|
18941
|
+
outputField: "kwhTotal",
|
|
18942
|
+
quantity: "energy",
|
|
18943
|
+
defaultAggregate: "sum",
|
|
18944
|
+
empty: "omit",
|
|
18945
|
+
companions: [NOW$2]
|
|
18946
|
+
}),
|
|
18947
|
+
numeric({
|
|
18948
|
+
id: "battery",
|
|
18949
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18950
|
+
role: DeviceRole.BatterySensor,
|
|
18951
|
+
outputCap: "battery",
|
|
18952
|
+
outputField: "percentage",
|
|
18953
|
+
quantity: "percentage",
|
|
18954
|
+
defaultAggregate: "mean",
|
|
18955
|
+
empty: "null",
|
|
18956
|
+
companions: [
|
|
18957
|
+
{
|
|
18958
|
+
fieldPath: "charging",
|
|
18959
|
+
expr: "\"unknown\""
|
|
18960
|
+
},
|
|
18961
|
+
{
|
|
18962
|
+
fieldPath: "sleeping",
|
|
18963
|
+
expr: "false"
|
|
18964
|
+
},
|
|
18965
|
+
{
|
|
18966
|
+
fieldPath: "lastUpdated",
|
|
18967
|
+
expr: "now"
|
|
18968
|
+
}
|
|
18969
|
+
]
|
|
18970
|
+
}),
|
|
18971
|
+
numeric({
|
|
18972
|
+
id: "numeric",
|
|
18973
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18974
|
+
role: DeviceRole.NumericSensor,
|
|
18975
|
+
outputCap: "numeric-sensor",
|
|
18976
|
+
outputField: "value",
|
|
18977
|
+
quantity: "device",
|
|
18978
|
+
defaultAggregate: "mean",
|
|
18979
|
+
empty: "null",
|
|
18980
|
+
companions: [NOW$2]
|
|
18981
|
+
}),
|
|
18982
|
+
binary({
|
|
18983
|
+
id: "motion",
|
|
18984
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18985
|
+
role: DeviceRole.MotionSensor,
|
|
18986
|
+
outputCap: "motion",
|
|
18987
|
+
outputField: "detected",
|
|
18988
|
+
defaultAggregate: "any",
|
|
18989
|
+
accept: [{
|
|
18990
|
+
cap: "motion",
|
|
18991
|
+
fieldPath: "detected"
|
|
18992
|
+
}],
|
|
18993
|
+
companions: [{
|
|
18994
|
+
fieldPath: "lastDetectedAt",
|
|
18995
|
+
expr: "null"
|
|
18996
|
+
}, {
|
|
18997
|
+
fieldPath: "autoClearAfterMs",
|
|
18998
|
+
expr: "null"
|
|
18999
|
+
}]
|
|
19000
|
+
}),
|
|
19001
|
+
binary({
|
|
19002
|
+
id: "contact",
|
|
19003
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
19004
|
+
role: DeviceRole.ContactSensor,
|
|
19005
|
+
outputCap: "contact",
|
|
19006
|
+
outputField: "entryOpen",
|
|
19007
|
+
defaultAggregate: "any",
|
|
19008
|
+
accept: [{
|
|
19009
|
+
cap: "contact",
|
|
19010
|
+
fieldPath: "entryOpen"
|
|
19011
|
+
}],
|
|
19012
|
+
companions: [CHANGED]
|
|
19013
|
+
}),
|
|
19014
|
+
binary({
|
|
19015
|
+
id: "leak",
|
|
19016
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
19017
|
+
role: DeviceRole.LeakSensor,
|
|
19018
|
+
outputCap: "flood",
|
|
19019
|
+
outputField: "flooded",
|
|
19020
|
+
defaultAggregate: "any",
|
|
19021
|
+
accept: [{
|
|
19022
|
+
cap: "flood",
|
|
19023
|
+
fieldPath: "flooded"
|
|
19024
|
+
}],
|
|
19025
|
+
companions: [CHANGED]
|
|
19026
|
+
}),
|
|
19027
|
+
binary({
|
|
19028
|
+
id: "smoke",
|
|
19029
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
19030
|
+
role: DeviceRole.SmokeSensor,
|
|
19031
|
+
outputCap: "smoke",
|
|
19032
|
+
outputField: "detected",
|
|
19033
|
+
defaultAggregate: "any",
|
|
19034
|
+
accept: [{
|
|
19035
|
+
cap: "smoke",
|
|
19036
|
+
fieldPath: "detected"
|
|
19037
|
+
}],
|
|
19038
|
+
companions: [CHANGED]
|
|
19039
|
+
}),
|
|
19040
|
+
binary({
|
|
19041
|
+
id: "occupancy",
|
|
19042
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
19043
|
+
role: DeviceRole.BinarySensor,
|
|
19044
|
+
outputCap: "binary",
|
|
19045
|
+
outputField: "on",
|
|
19046
|
+
defaultAggregate: "any",
|
|
19047
|
+
accept: [{
|
|
19048
|
+
cap: "motion",
|
|
19049
|
+
fieldPath: "detected"
|
|
19050
|
+
}, {
|
|
19051
|
+
cap: "binary",
|
|
19052
|
+
fieldPath: "on"
|
|
19053
|
+
}],
|
|
19054
|
+
companions: [CHANGED]
|
|
19055
|
+
}),
|
|
19056
|
+
binary({
|
|
19057
|
+
id: "binary",
|
|
19058
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
19059
|
+
role: DeviceRole.BinarySensor,
|
|
19060
|
+
outputCap: "binary",
|
|
19061
|
+
outputField: "on",
|
|
19062
|
+
defaultAggregate: "any",
|
|
19063
|
+
accept: [{
|
|
19064
|
+
cap: "binary",
|
|
19065
|
+
fieldPath: "on"
|
|
19066
|
+
}],
|
|
19067
|
+
companions: [CHANGED]
|
|
19068
|
+
}),
|
|
19069
|
+
actuator({
|
|
19070
|
+
id: "switch",
|
|
19071
|
+
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.",
|
|
19072
|
+
deviceType: DeviceType.Switch,
|
|
19073
|
+
outputCap: "switch",
|
|
19074
|
+
outputField: "on",
|
|
19075
|
+
member: {
|
|
19076
|
+
cap: "switch",
|
|
19077
|
+
fieldPath: "on"
|
|
19078
|
+
},
|
|
19079
|
+
commandCaps: ["switch"]
|
|
19080
|
+
}),
|
|
19081
|
+
actuator({
|
|
19082
|
+
id: "light",
|
|
19083
|
+
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.",
|
|
19084
|
+
deviceType: DeviceType.Light,
|
|
19085
|
+
outputCap: "switch",
|
|
19086
|
+
outputField: "on",
|
|
19087
|
+
member: {
|
|
19088
|
+
cap: "switch",
|
|
19089
|
+
fieldPath: "on"
|
|
19090
|
+
},
|
|
19091
|
+
commandCaps: [
|
|
19092
|
+
"switch",
|
|
19093
|
+
"brightness",
|
|
19094
|
+
"color"
|
|
19095
|
+
]
|
|
19096
|
+
}),
|
|
19097
|
+
actuator({
|
|
19098
|
+
id: "fan",
|
|
19099
|
+
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.",
|
|
19100
|
+
deviceType: DeviceType.Fan,
|
|
19101
|
+
outputCap: "switch",
|
|
19102
|
+
outputField: "on",
|
|
19103
|
+
member: {
|
|
19104
|
+
cap: "switch",
|
|
19105
|
+
fieldPath: "on"
|
|
19106
|
+
},
|
|
19107
|
+
commandCaps: ["switch", "fan-control"]
|
|
19108
|
+
}),
|
|
19109
|
+
actuator({
|
|
19110
|
+
id: "cover",
|
|
19111
|
+
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.",
|
|
19112
|
+
deviceType: DeviceType.Cover,
|
|
19113
|
+
outputCap: "group-active",
|
|
19114
|
+
outputField: "active",
|
|
19115
|
+
member: {
|
|
19116
|
+
cap: "cover",
|
|
19117
|
+
fieldPath: "state"
|
|
19118
|
+
},
|
|
19119
|
+
activeWhen: [
|
|
19120
|
+
"open",
|
|
19121
|
+
"opening",
|
|
19122
|
+
"stopped"
|
|
19123
|
+
],
|
|
19124
|
+
commandCaps: ["cover"]
|
|
19125
|
+
}),
|
|
19126
|
+
actuator({
|
|
19127
|
+
id: "valve",
|
|
19128
|
+
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.",
|
|
19129
|
+
deviceType: DeviceType.Valve,
|
|
19130
|
+
outputCap: "group-active",
|
|
19131
|
+
outputField: "active",
|
|
19132
|
+
member: {
|
|
19133
|
+
cap: "valve",
|
|
19134
|
+
fieldPath: "state"
|
|
19135
|
+
},
|
|
19136
|
+
activeWhen: [
|
|
19137
|
+
"open",
|
|
19138
|
+
"opening",
|
|
19139
|
+
"stopped"
|
|
19140
|
+
],
|
|
19141
|
+
commandCaps: ["valve"]
|
|
19142
|
+
}),
|
|
19143
|
+
actuator({
|
|
19144
|
+
id: "lock",
|
|
19145
|
+
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.",
|
|
19146
|
+
deviceType: DeviceType.Lock,
|
|
19147
|
+
outputCap: "group-active",
|
|
19148
|
+
outputField: "active",
|
|
19149
|
+
member: {
|
|
19150
|
+
cap: "lock-control",
|
|
19151
|
+
fieldPath: "state"
|
|
19152
|
+
},
|
|
19153
|
+
activeWhen: ["locked"],
|
|
19154
|
+
commandCaps: ["lock-control"]
|
|
19155
|
+
}),
|
|
19156
|
+
actuator({
|
|
19157
|
+
id: "media-player",
|
|
19158
|
+
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.",
|
|
19159
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19160
|
+
outputCap: "group-active",
|
|
19161
|
+
outputField: "active",
|
|
19162
|
+
member: {
|
|
19163
|
+
cap: "media-player",
|
|
19164
|
+
fieldPath: "state"
|
|
19165
|
+
},
|
|
19166
|
+
activeWhen: ["playing", "buffering"],
|
|
19167
|
+
commandCaps: ["media-player"]
|
|
19168
|
+
}),
|
|
19169
|
+
actuator({
|
|
19170
|
+
id: "climate",
|
|
19171
|
+
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.",
|
|
19172
|
+
deviceType: DeviceType.Thermostat,
|
|
19173
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19174
|
+
outputCap: "group-active",
|
|
19175
|
+
outputField: "active",
|
|
19176
|
+
member: {
|
|
19177
|
+
cap: "climate-control",
|
|
19178
|
+
fieldPath: "mode"
|
|
19179
|
+
},
|
|
19180
|
+
activeWhen: [
|
|
19181
|
+
"heat",
|
|
19182
|
+
"cool",
|
|
19183
|
+
"auto",
|
|
19184
|
+
"heat_cool",
|
|
19185
|
+
"fan_only",
|
|
19186
|
+
"dry"
|
|
19187
|
+
],
|
|
19188
|
+
commandCaps: ["climate-control"]
|
|
19189
|
+
})
|
|
19190
|
+
];
|
|
19191
|
+
function actuator(input) {
|
|
19192
|
+
return {
|
|
19193
|
+
id: input.id,
|
|
19194
|
+
summary: input.summary,
|
|
19195
|
+
deviceType: input.deviceType,
|
|
19196
|
+
outputCap: input.outputCap,
|
|
19197
|
+
outputField: input.outputField,
|
|
19198
|
+
commandCaps: input.commandCaps,
|
|
19199
|
+
family: "actuator",
|
|
19200
|
+
role: void 0,
|
|
19201
|
+
memberDeviceType: input.deviceType,
|
|
19202
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19203
|
+
activeWhen: input.activeWhen,
|
|
19204
|
+
quantity: "none",
|
|
19205
|
+
baseUnit: void 0,
|
|
19206
|
+
aggregates: BINARY_AGGREGATES,
|
|
19207
|
+
defaultAggregate: "any",
|
|
19208
|
+
empty: "offline",
|
|
19209
|
+
accept: [input.member],
|
|
19210
|
+
companions: [CHANGED]
|
|
19211
|
+
};
|
|
19212
|
+
}
|
|
19213
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19214
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19215
|
+
DeviceType.Camera;
|
|
18490
19216
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18491
19217
|
/**
|
|
18492
19218
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20200,12 +20926,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
20200
20926
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20201
20927
|
* in-place so dispatch keeps working.
|
|
20202
20928
|
*
|
|
20203
|
-
* **
|
|
20204
|
-
*
|
|
20205
|
-
*
|
|
20206
|
-
*
|
|
20207
|
-
* (`ha-domain-mapping`)
|
|
20208
|
-
* stored after that point.
|
|
20929
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20930
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20931
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20932
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20933
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20934
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20209
20935
|
*
|
|
20210
20936
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20211
20937
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20219,6 +20945,14 @@ var SourceInfoSchema = object({
|
|
|
20219
20945
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20220
20946
|
* Used to detect rename when `id` changes. */
|
|
20221
20947
|
uniqueId: string().optional(),
|
|
20948
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20949
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20950
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20951
|
+
dateTimeShape: _enum([
|
|
20952
|
+
"date",
|
|
20953
|
+
"time",
|
|
20954
|
+
"datetime"
|
|
20955
|
+
]).optional(),
|
|
20222
20956
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20223
20957
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20224
20958
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41131,7 +41865,8 @@ method(object({
|
|
|
41131
41865
|
"enum"
|
|
41132
41866
|
]),
|
|
41133
41867
|
enumValues: array(string()).optional(),
|
|
41134
|
-
item: boolean().optional()
|
|
41868
|
+
item: boolean().optional(),
|
|
41869
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41135
41870
|
})).readonly(),
|
|
41136
41871
|
itemArray: object({
|
|
41137
41872
|
path: string(),
|
|
@@ -43492,7 +44227,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43492
44227
|
});
|
|
43493
44228
|
/**
|
|
43494
44229
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43495
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44230
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43496
44231
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43497
44232
|
* the originating provider config (mode + sourcePort) so the
|
|
43498
44233
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44931,8 +45666,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44931
45666
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44932
45667
|
var MaskGridShapeSchema = object({
|
|
44933
45668
|
kind: literal("grid"),
|
|
44934
|
-
gridWidth: number(),
|
|
44935
|
-
gridHeight: number(),
|
|
45669
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45670
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44936
45671
|
cells: array(boolean())
|
|
44937
45672
|
});
|
|
44938
45673
|
discriminatedUnion("kind", [
|
|
@@ -45044,6 +45779,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45044
45779
|
"detection-blind",
|
|
45045
45780
|
"motion-noisy",
|
|
45046
45781
|
"motion-calm",
|
|
45782
|
+
"package-llm-silent",
|
|
45783
|
+
"package-llm-answered",
|
|
45047
45784
|
"recording-stalled",
|
|
45048
45785
|
"recording-healthy",
|
|
45049
45786
|
"recording-degraded",
|
|
@@ -46133,7 +46870,20 @@ var NcRuleInputSchema = object({
|
|
|
46133
46870
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46134
46871
|
* path does not run Zod defaults.
|
|
46135
46872
|
*/
|
|
46136
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46873
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46874
|
+
/**
|
|
46875
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46876
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46877
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46878
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46879
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46880
|
+
*
|
|
46881
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46882
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46883
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46884
|
+
* `false`, so it needs no `clear` key.
|
|
46885
|
+
*/
|
|
46886
|
+
askVerdict: boolean().optional()
|
|
46137
46887
|
});
|
|
46138
46888
|
/**
|
|
46139
46889
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56071,6 +56821,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56071
56821
|
deprecated: string().optional(),
|
|
56072
56822
|
distTags: array(string()).readonly()
|
|
56073
56823
|
});
|
|
56824
|
+
/**
|
|
56825
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56826
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56827
|
+
* tarball failure — never an empty string standing in for either.
|
|
56828
|
+
*/
|
|
56829
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56830
|
+
object({
|
|
56831
|
+
status: literal("ok"),
|
|
56832
|
+
markdown: string()
|
|
56833
|
+
}),
|
|
56834
|
+
object({ status: literal("missing") }),
|
|
56835
|
+
object({
|
|
56836
|
+
status: literal("error"),
|
|
56837
|
+
message: string()
|
|
56838
|
+
})
|
|
56839
|
+
]);
|
|
56840
|
+
var PackageDocsSchema = object({
|
|
56841
|
+
name: string(),
|
|
56842
|
+
version: string(),
|
|
56843
|
+
readme: PackageDocBodySchema,
|
|
56844
|
+
changelog: PackageDocBodySchema
|
|
56845
|
+
});
|
|
56074
56846
|
var SearchResultSchema = object({
|
|
56075
56847
|
name: string(),
|
|
56076
56848
|
version: string(),
|
|
@@ -56289,7 +57061,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56289
57061
|
}), object({ success: literal(true) }), {
|
|
56290
57062
|
kind: "mutation",
|
|
56291
57063
|
auth: "admin"
|
|
56292
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57064
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57065
|
+
name: string().min(1),
|
|
57066
|
+
version: string().min(1).optional()
|
|
57067
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56293
57068
|
kind: "mutation",
|
|
56294
57069
|
auth: "admin"
|
|
56295
57070
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56339,46 +57114,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56339
57114
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56340
57115
|
object({
|
|
56341
57116
|
/** Carbon dioxide concentration in ppm. */
|
|
56342
|
-
co2Ppm: number().min(0).optional(),
|
|
57117
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56343
57118
|
/** Total volatile organic compounds in ppb. */
|
|
56344
|
-
vocPpb: number().min(0).optional(),
|
|
57119
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56345
57120
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56346
|
-
pm25: number().min(0).optional(),
|
|
57121
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56347
57122
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56348
|
-
pm10: number().min(0).optional(),
|
|
57123
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56349
57124
|
/** Composite AQI value (typically 0..500). */
|
|
56350
|
-
aqi: number().optional(),
|
|
57125
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56351
57126
|
/** Ms epoch when the slice was last updated. */
|
|
56352
|
-
lastFetchedAt: number()
|
|
56353
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56354
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56355
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56356
|
-
* per slice is unambiguous. */
|
|
56357
|
-
unit: string().optional(),
|
|
56358
|
-
/** Suggested decimal places for numeric display.
|
|
56359
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56360
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56361
|
-
* auto-formatting when absent. */
|
|
56362
|
-
precision: number().int().min(0).max(10).optional()
|
|
57127
|
+
lastFetchedAt: number()
|
|
56363
57128
|
});
|
|
56364
57129
|
DeviceType.Sensor;
|
|
56365
57130
|
object({
|
|
56366
|
-
/** Current illuminance in lux (lx). */
|
|
56367
|
-
lux: number().min(0).meta({
|
|
56368
|
-
|
|
57131
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57132
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57133
|
+
precision: 0,
|
|
56369
57134
|
label: "Illuminance"
|
|
56370
|
-
}),
|
|
57135
|
+
})),
|
|
56371
57136
|
/** Ms epoch when the slice was last updated. */
|
|
56372
|
-
lastFetchedAt: number()
|
|
56373
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56374
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56375
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56376
|
-
unit: string().optional(),
|
|
56377
|
-
/** Suggested decimal places for numeric display.
|
|
56378
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56379
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56380
|
-
* auto-formatting when absent. */
|
|
56381
|
-
precision: number().int().min(0).max(10).optional()
|
|
57137
|
+
lastFetchedAt: number()
|
|
56382
57138
|
});
|
|
56383
57139
|
DeviceType.Sensor;
|
|
56384
57140
|
/**
|
|
@@ -56523,10 +57279,7 @@ var BatteryStatusSchema = object({
|
|
|
56523
57279
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56524
57280
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56525
57281
|
*/
|
|
56526
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56527
|
-
unit: "%",
|
|
56528
|
-
label: "Charge"
|
|
56529
|
-
}),
|
|
57282
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56530
57283
|
/**
|
|
56531
57284
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56532
57285
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56553,7 +57306,14 @@ var BatteryStatusSchema = object({
|
|
|
56553
57306
|
*/
|
|
56554
57307
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56555
57308
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56556
|
-
lastUpdated: number(),
|
|
57309
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57310
|
+
/**
|
|
57311
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57312
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57313
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57314
|
+
* `numeric-sensor` on the same device.
|
|
57315
|
+
*/
|
|
57316
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56557
57317
|
/**
|
|
56558
57318
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56559
57319
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56593,7 +57353,7 @@ var BatteryStatusSchema = object({
|
|
|
56593
57353
|
*/
|
|
56594
57354
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56595
57355
|
});
|
|
56596
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57356
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56597
57357
|
method(object({
|
|
56598
57358
|
deviceId: number(),
|
|
56599
57359
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56613,7 +57373,7 @@ object({
|
|
|
56613
57373
|
DeviceType.Sensor;
|
|
56614
57374
|
object({
|
|
56615
57375
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56616
|
-
percentage: number().min(0).max(100),
|
|
57376
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56617
57377
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56618
57378
|
lastChangedAt: number()
|
|
56619
57379
|
});
|
|
@@ -57008,21 +57768,21 @@ object({
|
|
|
57008
57768
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57009
57769
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57010
57770
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57011
|
-
target: number().nullable(),
|
|
57771
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57012
57772
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57013
57773
|
* in `heat_cool` mode. */
|
|
57014
|
-
targetHigh: number().nullable(),
|
|
57774
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57015
57775
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57016
57776
|
* in `heat_cool` mode. */
|
|
57017
|
-
targetLow: number().nullable(),
|
|
57777
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57018
57778
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57019
57779
|
* humidity control. */
|
|
57020
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57780
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57021
57781
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57022
57782
|
* the device's internal sensor. */
|
|
57023
|
-
currentTemp: number().nullable(),
|
|
57783
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57024
57784
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57025
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57785
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57026
57786
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57027
57787
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57028
57788
|
swingVertical: boolean().nullable(),
|
|
@@ -57030,11 +57790,11 @@ object({
|
|
|
57030
57790
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57031
57791
|
swingHorizontal: boolean().nullable(),
|
|
57032
57792
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57033
|
-
minTemp: number().nullable().optional(),
|
|
57793
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57034
57794
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57035
|
-
maxTemp: number().nullable().optional(),
|
|
57795
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57036
57796
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57037
|
-
tempStep: number().positive().nullable().optional(),
|
|
57797
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57038
57798
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57039
57799
|
lastFetchedAt: number()
|
|
57040
57800
|
});
|
|
@@ -57113,17 +57873,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
57113
57873
|
* modes to expose in the picker without a slice fetch.
|
|
57114
57874
|
*/
|
|
57115
57875
|
var RgbTripletSchema = object({
|
|
57116
|
-
r: number().int().min(0).max(255),
|
|
57117
|
-
g: number().int().min(0).max(255),
|
|
57118
|
-
b: number().int().min(0).max(255)
|
|
57876
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57877
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57878
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57119
57879
|
});
|
|
57120
57880
|
var HsvTripletSchema = object({
|
|
57121
57881
|
/** Hue in degrees, 0..360. */
|
|
57122
|
-
h: number().min(0).max(360),
|
|
57882
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57123
57883
|
/** Saturation as 0..100 inclusive. */
|
|
57124
|
-
s: number().min(0).max(100),
|
|
57884
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57125
57885
|
/** Value/brightness as 0..100 inclusive. */
|
|
57126
|
-
v: number().min(0).max(100)
|
|
57886
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57127
57887
|
});
|
|
57128
57888
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57129
57889
|
object({
|
|
@@ -57152,7 +57912,7 @@ object({
|
|
|
57152
57912
|
/** Populated when `mode === 'hsv'`. */
|
|
57153
57913
|
hsv: HsvTripletSchema.optional(),
|
|
57154
57914
|
/** Populated when `mode === 'mired'`. */
|
|
57155
|
-
mireds: number().int().optional(),
|
|
57915
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57156
57916
|
/** Ms epoch of the last operator-driven change. */
|
|
57157
57917
|
lastChangedAt: number()
|
|
57158
57918
|
});
|
|
@@ -57276,18 +58036,12 @@ _enum([
|
|
|
57276
58036
|
"empty",
|
|
57277
58037
|
"full"
|
|
57278
58038
|
]);
|
|
57279
|
-
/**
|
|
57280
|
-
|
|
57281
|
-
|
|
57282
|
-
"days",
|
|
57283
|
-
"hours",
|
|
57284
|
-
"cycles"
|
|
57285
|
-
]);
|
|
57286
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57287
|
-
* days). `value` null = unknown (D393). */
|
|
58039
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58040
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58041
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57288
58042
|
var ConsumableRemainingSchema = object({
|
|
57289
|
-
value: number().min(0).nullable(),
|
|
57290
|
-
|
|
58043
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58044
|
+
kind: ConsumableRemainingKindSchema
|
|
57291
58045
|
});
|
|
57292
58046
|
var ConsumablesStatusSchema = object({
|
|
57293
58047
|
items: array(object({
|
|
@@ -57296,7 +58050,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57296
58050
|
/** Display name. */
|
|
57297
58051
|
label: string().min(1),
|
|
57298
58052
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57299
|
-
level: number().min(0).max(100).nullable(),
|
|
58053
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57300
58054
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57301
58055
|
status: ConsumableStatusSchema.nullable(),
|
|
57302
58056
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57313,7 +58067,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57313
58067
|
})),
|
|
57314
58068
|
lastChangedAt: number()
|
|
57315
58069
|
});
|
|
57316
|
-
Object.values(DeviceType), [...
|
|
58070
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57317
58071
|
Object.values(DeviceType), method(object({
|
|
57318
58072
|
deviceId: number().int().nonnegative(),
|
|
57319
58073
|
key: string().min(1)
|
|
@@ -57338,39 +58092,17 @@ object({
|
|
|
57338
58092
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57339
58093
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57340
58094
|
* or time-only — HA accepts all three forms). */
|
|
57341
|
-
value: union([number(), string()]),
|
|
58095
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57342
58096
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57343
58097
|
options: array(string()),
|
|
57344
58098
|
/** Ms epoch when the slice was last updated. */
|
|
57345
58099
|
lastChangedAt: number(),
|
|
57346
|
-
/**
|
|
57347
|
-
|
|
57348
|
-
|
|
57349
|
-
|
|
57350
|
-
/**
|
|
57351
|
-
|
|
57352
|
-
min: number().optional(),
|
|
57353
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57354
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57355
|
-
max: number().optional(),
|
|
57356
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57357
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57358
|
-
step: number().optional(),
|
|
57359
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57360
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57361
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57362
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57363
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57364
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57365
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57366
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57367
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57368
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57369
|
-
format: _enum([
|
|
57370
|
-
"date",
|
|
57371
|
-
"time",
|
|
57372
|
-
"datetime"
|
|
57373
|
-
]).optional()
|
|
58100
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58101
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58102
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58103
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58104
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58105
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57374
58106
|
});
|
|
57375
58107
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57376
58108
|
object({
|
|
@@ -57408,9 +58140,9 @@ object({
|
|
|
57408
58140
|
]),
|
|
57409
58141
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57410
58142
|
* no intermediate position surface. */
|
|
57411
|
-
position: number().min(0).max(100).nullable(),
|
|
58143
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57412
58144
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57413
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58145
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57414
58146
|
/** Ms epoch when the slice was last updated. */
|
|
57415
58147
|
lastChangedAt: number()
|
|
57416
58148
|
});
|
|
@@ -57468,9 +58200,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57468
58200
|
object({
|
|
57469
58201
|
mode: DayNightModeSchema,
|
|
57470
58202
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57471
|
-
sensitivity: number().optional(),
|
|
58203
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57472
58204
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57473
|
-
switchDelaySec: number().optional(),
|
|
58205
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57474
58206
|
lastFetchedAt: number()
|
|
57475
58207
|
});
|
|
57476
58208
|
/**
|
|
@@ -57625,11 +58357,11 @@ object({
|
|
|
57625
58357
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57626
58358
|
availablePrograms: array(string()),
|
|
57627
58359
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57628
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58360
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57629
58361
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57630
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58362
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57631
58363
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57632
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58364
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57633
58365
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57634
58366
|
doorOpen: boolean().nullable(),
|
|
57635
58367
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57653,7 +58385,7 @@ object({
|
|
|
57653
58385
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57654
58386
|
machineCareDue: boolean().nullable(),
|
|
57655
58387
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57656
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58388
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57657
58389
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57658
58390
|
halfLoad: boolean().nullable(),
|
|
57659
58391
|
hygienePlus: boolean().nullable(),
|
|
@@ -57668,7 +58400,7 @@ object({
|
|
|
57668
58400
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57669
58401
|
activeEvents: array(string()),
|
|
57670
58402
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57671
|
-
errorCode: number().nullable(),
|
|
58403
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57672
58404
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57673
58405
|
errorLabel: string().nullable(),
|
|
57674
58406
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -57814,24 +58546,14 @@ object({
|
|
|
57814
58546
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
57815
58547
|
lastPressedAt: number().nullable(),
|
|
57816
58548
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
57817
|
-
pressCountSinceStart: number()
|
|
58549
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
57818
58550
|
});
|
|
57819
58551
|
object({
|
|
57820
58552
|
deviceId: number(),
|
|
57821
58553
|
timestamp: number()
|
|
57822
58554
|
});
|
|
57823
58555
|
DeviceType.Button, DeviceType.Camera;
|
|
57824
|
-
|
|
57825
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
57826
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
57827
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
57828
|
-
* The option set is stable across observations; it is persisted in the
|
|
57829
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
57830
|
-
* stored in `sourceInfo`.
|
|
57831
|
-
*/
|
|
57832
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
57833
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
57834
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58556
|
+
_enum([
|
|
57835
58557
|
"date",
|
|
57836
58558
|
"time",
|
|
57837
58559
|
"datetime"
|
|
@@ -57839,12 +58561,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
57839
58561
|
object({
|
|
57840
58562
|
value: string(),
|
|
57841
58563
|
/**
|
|
57842
|
-
* Set
|
|
57843
|
-
* as
|
|
57844
|
-
*
|
|
57845
|
-
* a time-only sensor → `'time'`.
|
|
58564
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58565
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58566
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
57846
58567
|
*/
|
|
57847
|
-
|
|
58568
|
+
timestamp: boolean().optional(),
|
|
57848
58569
|
/** Ms epoch when the slice was last updated. */
|
|
57849
58570
|
lastFetchedAt: number()
|
|
57850
58571
|
});
|
|
@@ -57863,13 +58584,13 @@ var EventFireSchema = object({
|
|
|
57863
58584
|
deviceId: number(),
|
|
57864
58585
|
eventType: string(),
|
|
57865
58586
|
data: record(string(), unknown()).nullable(),
|
|
57866
|
-
timestamp: number(),
|
|
57867
|
-
seq: number()
|
|
58587
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58588
|
+
seq: number().meta(readingMeta("count"))
|
|
57868
58589
|
});
|
|
57869
58590
|
object({
|
|
57870
58591
|
eventTypes: array(string()),
|
|
57871
58592
|
lastEvent: EventFireSchema.nullable(),
|
|
57872
|
-
eventCountSinceStart: number()
|
|
58593
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
57873
58594
|
});
|
|
57874
58595
|
DeviceType.EventEmitter;
|
|
57875
58596
|
var IdentitySchema = object({
|
|
@@ -58258,10 +58979,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58258
58979
|
object({
|
|
58259
58980
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58260
58981
|
* speed surface (single-speed fan). */
|
|
58261
|
-
percentage: number().min(0).max(100).nullable(),
|
|
58982
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58262
58983
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58263
58984
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58264
|
-
percentageStep: number().positive().optional(),
|
|
58985
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
58265
58986
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
58266
58987
|
* — empty string when no preset is active or supported. */
|
|
58267
58988
|
preset: string(),
|
|
@@ -58343,7 +59064,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58343
59064
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58344
59065
|
model: string().nullable(),
|
|
58345
59066
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58346
|
-
channelCount: number().nullable(),
|
|
59067
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58347
59068
|
/**
|
|
58348
59069
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58349
59070
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58375,9 +59096,45 @@ object({
|
|
|
58375
59096
|
lastChangedAt: number()
|
|
58376
59097
|
});
|
|
58377
59098
|
DeviceType.Sensor;
|
|
59099
|
+
object({
|
|
59100
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
59101
|
+
results: array(object({
|
|
59102
|
+
deviceId: number().int().nonnegative(),
|
|
59103
|
+
cap: string().min(1),
|
|
59104
|
+
method: string().min(1),
|
|
59105
|
+
ok: boolean(),
|
|
59106
|
+
error: string().optional(),
|
|
59107
|
+
/** Ms epoch of the attempt. */
|
|
59108
|
+
at: number()
|
|
59109
|
+
})) });
|
|
59110
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
59111
|
+
object({
|
|
59112
|
+
active: boolean().meta({ label: "Active" }),
|
|
59113
|
+
/** Ms epoch when the slice was last updated. */
|
|
59114
|
+
lastChangedAt: number()
|
|
59115
|
+
});
|
|
59116
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
59117
|
+
object({
|
|
59118
|
+
/** Members whose current value entered the aggregate. */
|
|
59119
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
59120
|
+
precision: 0,
|
|
59121
|
+
label: "Reporting"
|
|
59122
|
+
})),
|
|
59123
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
59124
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
59125
|
+
precision: 0,
|
|
59126
|
+
label: "Excluded"
|
|
59127
|
+
})),
|
|
59128
|
+
/** `included` + `excluded`. */
|
|
59129
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
59130
|
+
precision: 0,
|
|
59131
|
+
label: "Members"
|
|
59132
|
+
}))
|
|
59133
|
+
});
|
|
59134
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58378
59135
|
object({
|
|
58379
59136
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58380
|
-
position: number().min(0).max(100).nullable(),
|
|
59137
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58381
59138
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58382
59139
|
lastFetchedAt: number()
|
|
58383
59140
|
});
|
|
@@ -58386,9 +59143,9 @@ object({
|
|
|
58386
59143
|
/** Whether the humidifier is currently on. */
|
|
58387
59144
|
on: boolean(),
|
|
58388
59145
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58389
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59146
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58390
59147
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58391
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59148
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58392
59149
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58393
59150
|
* device has no mode surface. */
|
|
58394
59151
|
mode: string().nullable(),
|
|
@@ -58398,9 +59155,9 @@ object({
|
|
|
58398
59155
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58399
59156
|
action: string().nullable(),
|
|
58400
59157
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58401
|
-
minHumidity: number().nullable(),
|
|
59158
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58402
59159
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58403
|
-
maxHumidity: number().nullable(),
|
|
59160
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58404
59161
|
/** Ms epoch when the slice was last updated. */
|
|
58405
59162
|
lastChangedAt: number()
|
|
58406
59163
|
});
|
|
@@ -58424,22 +59181,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58424
59181
|
auth: "protected"
|
|
58425
59182
|
});
|
|
58426
59183
|
object({
|
|
58427
|
-
/** Current relative humidity, 0..100. */
|
|
58428
|
-
percent: number().min(0).max(100).meta({
|
|
58429
|
-
|
|
59184
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59185
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59186
|
+
precision: 0,
|
|
58430
59187
|
label: "Humidity"
|
|
58431
|
-
}),
|
|
59188
|
+
})),
|
|
58432
59189
|
/** Ms epoch when the slice was last updated. */
|
|
58433
|
-
lastFetchedAt: number()
|
|
58434
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58435
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58436
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58437
|
-
unit: string().optional(),
|
|
58438
|
-
/** Suggested decimal places for numeric display.
|
|
58439
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58440
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58441
|
-
* auto-formatting when absent. */
|
|
58442
|
-
precision: number().int().min(0).max(10).optional()
|
|
59190
|
+
lastFetchedAt: number()
|
|
58443
59191
|
});
|
|
58444
59192
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58445
59193
|
object({
|
|
@@ -58447,7 +59195,7 @@ object({
|
|
|
58447
59195
|
* entity exposes no `entity_picture` (yet). */
|
|
58448
59196
|
url: string().nullable(),
|
|
58449
59197
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58450
|
-
lastUpdated: number().nullable()
|
|
59198
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58451
59199
|
});
|
|
58452
59200
|
DeviceType.Image;
|
|
58453
59201
|
/**
|
|
@@ -58503,19 +59251,19 @@ var NormalizedRangeSchema = object({
|
|
|
58503
59251
|
});
|
|
58504
59252
|
object({
|
|
58505
59253
|
/** Normalized 0–100. */
|
|
58506
|
-
brightness: number().optional(),
|
|
59254
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58507
59255
|
/** Normalized 0–100. */
|
|
58508
|
-
contrast: number().optional(),
|
|
59256
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58509
59257
|
/** Normalized 0–100. */
|
|
58510
|
-
saturation: number().optional(),
|
|
59258
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58511
59259
|
/** Normalized 0–100. */
|
|
58512
|
-
sharpness: number().optional(),
|
|
59260
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58513
59261
|
mirror: boolean().optional(),
|
|
58514
59262
|
flip: boolean().optional(),
|
|
58515
59263
|
rotate: ImageRotateSchema.optional(),
|
|
58516
59264
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58517
59265
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58518
|
-
warmth: number().optional(),
|
|
59266
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58519
59267
|
exposureMode: ExposureModeSchema.optional(),
|
|
58520
59268
|
backlightMode: BacklightModeSchema.optional(),
|
|
58521
59269
|
lastFetchedAt: number()
|
|
@@ -58760,10 +59508,10 @@ var IntercomAbilitySchema = object({
|
|
|
58760
59508
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58761
59509
|
codecs: array(string()),
|
|
58762
59510
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58763
|
-
sampleRate: number(),
|
|
59511
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58764
59512
|
duplex: _enum(["half", "full"]),
|
|
58765
59513
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58766
|
-
maxBacklogMs: number()
|
|
59514
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58767
59515
|
});
|
|
58768
59516
|
var IntercomStatusSchema = object({
|
|
58769
59517
|
/** True while a talk session is open. */
|
|
@@ -58874,13 +59622,13 @@ object({
|
|
|
58874
59622
|
activity: LawnMowerActivitySchema,
|
|
58875
59623
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
58876
59624
|
* reading. */
|
|
58877
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59625
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58878
59626
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
58879
59627
|
* task is active / progress is unavailable. */
|
|
58880
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59628
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58881
59629
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
58882
59630
|
* or null when unknown. */
|
|
58883
|
-
currentCode: number().nullable(),
|
|
59631
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
58884
59632
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
58885
59633
|
currentCodeLabel: string().nullable(),
|
|
58886
59634
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -59290,7 +60038,14 @@ DeviceType.Lock, method(object({
|
|
|
59290
60038
|
auth: "protected"
|
|
59291
60039
|
}), method(object({
|
|
59292
60040
|
deviceId: number().int().nonnegative(),
|
|
59293
|
-
code: string().min(1).optional()
|
|
60041
|
+
code: string().min(1).optional(),
|
|
60042
|
+
/**
|
|
60043
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
60044
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
60045
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
60046
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
60047
|
+
*/
|
|
60048
|
+
confirm: boolean().optional()
|
|
59294
60049
|
}), _void(), {
|
|
59295
60050
|
kind: "mutation",
|
|
59296
60051
|
auth: "protected"
|
|
@@ -59298,6 +60053,11 @@ DeviceType.Lock, method(object({
|
|
|
59298
60053
|
kind: "mutation",
|
|
59299
60054
|
auth: "protected"
|
|
59300
60055
|
});
|
|
60056
|
+
object({
|
|
60057
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
60058
|
+
lastFetchedAt: number()
|
|
60059
|
+
});
|
|
60060
|
+
DeviceType.Sensor;
|
|
59301
60061
|
/**
|
|
59302
60062
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59303
60063
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59342,7 +60102,7 @@ object({
|
|
|
59342
60102
|
state: MediaPlayerStateSchema,
|
|
59343
60103
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59344
60104
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59345
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
60105
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59346
60106
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59347
60107
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59348
60108
|
isMuted: boolean().nullable(),
|
|
@@ -59355,10 +60115,10 @@ object({
|
|
|
59355
60115
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59356
60116
|
/** Current playback position in ms. Null when not seekable or
|
|
59357
60117
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59358
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
60118
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59359
60119
|
/** Total duration of the current media in ms. Null when unknown
|
|
59360
60120
|
* (live stream) or nothing is playing. */
|
|
59361
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
60121
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59362
60122
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59363
60123
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59364
60124
|
shuffle: boolean().nullable(),
|
|
@@ -59658,7 +60418,7 @@ object({
|
|
|
59658
60418
|
* it, every provider seeded it at boot, and every session left it
|
|
59659
60419
|
* `detected: true` after its detach.
|
|
59660
60420
|
*/
|
|
59661
|
-
autoClearAfterMs: number().nullable()
|
|
60421
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59662
60422
|
});
|
|
59663
60423
|
/**
|
|
59664
60424
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59708,7 +60468,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59708
60468
|
});
|
|
59709
60469
|
object({
|
|
59710
60470
|
enabled: boolean(),
|
|
59711
|
-
sensitivity: number(),
|
|
60471
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59712
60472
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59713
60473
|
regions: array(MotionZoneRegionSchema),
|
|
59714
60474
|
lastFetchedAt: number()
|
|
@@ -60012,7 +60772,7 @@ var NavigationStatusSchema = object({
|
|
|
60012
60772
|
following: boolean(),
|
|
60013
60773
|
flash: boolean(),
|
|
60014
60774
|
lightMode: NavigationLightModeSchema,
|
|
60015
|
-
lightLevel: number().min(40).max(100),
|
|
60775
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
60016
60776
|
/** Ms epoch when the slice was last updated. */
|
|
60017
60777
|
lastChangedAt: number()
|
|
60018
60778
|
});
|
|
@@ -60058,13 +60818,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
60058
60818
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
60059
60819
|
* SKIP a null rather than coerce it.
|
|
60060
60820
|
*/
|
|
60061
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
60821
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60062
60822
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
60063
|
-
rssiDbm: number().optional(),
|
|
60823
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
60064
60824
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
60065
60825
|
ssid: string().optional(),
|
|
60066
60826
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
60067
|
-
lastUpdated: number()
|
|
60827
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
60068
60828
|
});
|
|
60069
60829
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
60070
60830
|
deviceId: number(),
|
|
@@ -60383,7 +61143,7 @@ object({
|
|
|
60383
61143
|
lastError: string().nullable(),
|
|
60384
61144
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60385
61145
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60386
|
-
queueDepth: number().int().nonnegative(),
|
|
61146
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60387
61147
|
/** Per-feature capability matrix — authoritative source for the
|
|
60388
61148
|
* compose-form field gating. */
|
|
60389
61149
|
supports: NotifierSupportsSchema
|
|
@@ -60433,15 +61193,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60433
61193
|
acceptedAt: number()
|
|
60434
61194
|
});
|
|
60435
61195
|
object({
|
|
60436
|
-
|
|
60437
|
-
|
|
60438
|
-
* Populated live from the upstream source on each state push.
|
|
60439
|
-
* Absent for unitless sensors. */
|
|
60440
|
-
unit: string().optional(),
|
|
60441
|
-
/** Suggested decimal places for numeric display.
|
|
60442
|
-
* Populated live from the upstream source when provided.
|
|
60443
|
-
* Falls back to auto-formatting when absent. */
|
|
60444
|
-
precision: number().int().min(0).max(10).optional(),
|
|
61196
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
61197
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60445
61198
|
/** Ms epoch when the slice was last updated. */
|
|
60446
61199
|
lastFetchedAt: number()
|
|
60447
61200
|
});
|
|
@@ -60731,23 +61484,26 @@ object({
|
|
|
60731
61484
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60732
61485
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60733
61486
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60734
|
-
foodLevel: number().nullable(),
|
|
61487
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60735
61488
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60736
61489
|
* single-hopper models. */
|
|
60737
|
-
food1: number().nullable(),
|
|
61490
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60738
61491
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60739
61492
|
* single-hopper models. */
|
|
60740
|
-
food2: number().nullable(),
|
|
61493
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60741
61494
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60742
61495
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60743
61496
|
* below the feeder's low threshold. */
|
|
60744
61497
|
lowFood: boolean(),
|
|
60745
61498
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60746
61499
|
* device has no battery reading. */
|
|
60747
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60748
|
-
/**
|
|
60749
|
-
*
|
|
60750
|
-
|
|
61500
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61501
|
+
/**
|
|
61502
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61503
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61504
|
+
* model has no desiccant sensor.
|
|
61505
|
+
*/
|
|
61506
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60751
61507
|
/** True while a feed is in progress. */
|
|
60752
61508
|
feeding: boolean(),
|
|
60753
61509
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60758,7 +61514,7 @@ object({
|
|
|
60758
61514
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60759
61515
|
error: string().nullable(),
|
|
60760
61516
|
/** Raw device error code (0 / null = no error). */
|
|
60761
|
-
errorCode: number().nullable(),
|
|
61517
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60762
61518
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60763
61519
|
isDualHopper: boolean(),
|
|
60764
61520
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60768,7 +61524,7 @@ object({
|
|
|
60768
61524
|
/** Play a chime when dispensing. */
|
|
60769
61525
|
feedSound: boolean(),
|
|
60770
61526
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60771
|
-
volume: number(),
|
|
61527
|
+
volume: number().meta(readingMeta("none")),
|
|
60772
61528
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60773
61529
|
lastFetchedAt: number()
|
|
60774
61530
|
});
|
|
@@ -61205,38 +61961,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61205
61961
|
});
|
|
61206
61962
|
object({
|
|
61207
61963
|
/** Instantaneous power draw in watts. */
|
|
61208
|
-
watts: number().optional().meta({
|
|
61209
|
-
unit: "W",
|
|
61210
|
-
label: "Power"
|
|
61211
|
-
}),
|
|
61964
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61212
61965
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61213
|
-
kwhTotal: number().optional().meta({
|
|
61214
|
-
unit: "kWh",
|
|
61215
|
-
label: "Energy"
|
|
61216
|
-
}),
|
|
61966
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61217
61967
|
/** Voltage in volts. */
|
|
61218
|
-
volts: number().optional(),
|
|
61968
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61219
61969
|
/** Current in amperes. */
|
|
61220
|
-
amps: number().optional(),
|
|
61221
|
-
/** Apparent power in volt-amperes
|
|
61222
|
-
va: number().optional(),
|
|
61970
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61971
|
+
/** Apparent power in volt-amperes. */
|
|
61972
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61223
61973
|
/** Power factor (0..1) if reported. */
|
|
61224
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
61974
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61225
61975
|
/** Ms epoch when the slice was last updated. */
|
|
61226
|
-
lastFetchedAt: number()
|
|
61227
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
61228
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
61229
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
61230
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
61231
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
61232
|
-
unit: string().optional(),
|
|
61233
|
-
/** Suggested decimal places for numeric display.
|
|
61234
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61235
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61236
|
-
* auto-formatting when absent. */
|
|
61237
|
-
precision: number().int().min(0).max(10).optional()
|
|
61976
|
+
lastFetchedAt: number()
|
|
61238
61977
|
});
|
|
61239
|
-
|
|
61978
|
+
[
|
|
61979
|
+
DeviceType.Sensor,
|
|
61980
|
+
DeviceType.Switch,
|
|
61981
|
+
DeviceType.Light,
|
|
61982
|
+
DeviceType.Fan,
|
|
61983
|
+
DeviceType.Climate,
|
|
61984
|
+
DeviceType.Thermostat,
|
|
61985
|
+
DeviceType.Humidifier,
|
|
61986
|
+
DeviceType.WaterHeater,
|
|
61987
|
+
DeviceType.MediaPlayer,
|
|
61988
|
+
DeviceType.Washer,
|
|
61989
|
+
DeviceType.Dryer,
|
|
61990
|
+
DeviceType.Dishwasher,
|
|
61991
|
+
DeviceType.Vacuum,
|
|
61992
|
+
DeviceType.LawnMower,
|
|
61993
|
+
DeviceType.PetFeeder
|
|
61994
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61240
61995
|
/**
|
|
61241
61996
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61242
61997
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61255,11 +62010,11 @@ DeviceType.Sensor;
|
|
|
61255
62010
|
*/
|
|
61256
62011
|
var GpsLocationSchema = object({
|
|
61257
62012
|
/** Latitude in decimal degrees, -90..90. */
|
|
61258
|
-
latitude: number().min(-90).max(90),
|
|
62013
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
61259
62014
|
/** Longitude in decimal degrees, -180..180. */
|
|
61260
|
-
longitude: number().min(-180).max(180),
|
|
62015
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
61261
62016
|
/** Reported accuracy in meters (lower = better). */
|
|
61262
|
-
accuracyMeters: number().nonnegative()
|
|
62017
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
61263
62018
|
});
|
|
61264
62019
|
object({
|
|
61265
62020
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -61271,25 +62026,16 @@ object({
|
|
|
61271
62026
|
gps: GpsLocationSchema.nullable(),
|
|
61272
62027
|
/** Optional battery level of the tracking device (0..100). Null
|
|
61273
62028
|
* when not reported. */
|
|
61274
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
62029
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61275
62030
|
/** Ms epoch when the slice was last updated. */
|
|
61276
62031
|
lastChangedAt: number()
|
|
61277
62032
|
});
|
|
61278
62033
|
DeviceType.Presence;
|
|
61279
62034
|
object({
|
|
61280
|
-
/** Current pressure in hPa. */
|
|
61281
|
-
hpa: number(),
|
|
62035
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
62036
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61282
62037
|
/** Ms epoch when the slice was last updated. */
|
|
61283
|
-
lastFetchedAt: number()
|
|
61284
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61285
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61286
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61287
|
-
unit: string().optional(),
|
|
61288
|
-
/** Suggested decimal places for numeric display.
|
|
61289
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61290
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61291
|
-
* auto-formatting when absent. */
|
|
61292
|
-
precision: number().int().min(0).max(10).optional()
|
|
62038
|
+
lastFetchedAt: number()
|
|
61293
62039
|
});
|
|
61294
62040
|
DeviceType.Sensor;
|
|
61295
62041
|
/**
|
|
@@ -61622,8 +62368,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61622
62368
|
}), _void(), { kind: "mutation" });
|
|
61623
62369
|
var PtzAutotrackSettingsSchema = object({
|
|
61624
62370
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61625
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61626
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62371
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62372
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61627
62373
|
});
|
|
61628
62374
|
/**
|
|
61629
62375
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61680,7 +62426,7 @@ object({
|
|
|
61680
62426
|
/** null = unknown — never coerced to false (D393). */
|
|
61681
62427
|
running: boolean().nullable(),
|
|
61682
62428
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61683
|
-
since: number().nullable(),
|
|
62429
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61684
62430
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61685
62431
|
phase: string().nullable(),
|
|
61686
62432
|
/** null until a reading has been published (D393). */
|
|
@@ -61692,7 +62438,7 @@ object({
|
|
|
61692
62438
|
phase: string().nullable()
|
|
61693
62439
|
});
|
|
61694
62440
|
Object.values(DeviceType);
|
|
61695
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62441
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61696
62442
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61697
62443
|
kind: "mutation",
|
|
61698
62444
|
auth: "admin"
|
|
@@ -62878,9 +63624,9 @@ var RecordTriggerSchema = _enum([
|
|
|
62878
63624
|
*/
|
|
62879
63625
|
var RecordWindowSchema = object({
|
|
62880
63626
|
trigger: RecordTriggerSchema,
|
|
62881
|
-
day: number().int().min(0).max(6),
|
|
62882
|
-
startMinute: number().int().min(0).max(1439),
|
|
62883
|
-
endMinute: number().int().min(1).max(1440)
|
|
63627
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63628
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63629
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
62884
63630
|
});
|
|
62885
63631
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
62886
63632
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -62949,10 +63695,10 @@ object({
|
|
|
62949
63695
|
/** Master "record to the card at all" switch. */
|
|
62950
63696
|
enabled: boolean().nullable(),
|
|
62951
63697
|
overwriteWhenFull: boolean().nullable(),
|
|
62952
|
-
preRecordSec: number().nullable(),
|
|
62953
|
-
postRecordSec: number().nullable(),
|
|
63698
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63699
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
62954
63700
|
/** Length of one recorded file, in minutes. */
|
|
62955
|
-
segmentMinutes: number().nullable(),
|
|
63701
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
62956
63702
|
/** The primary track's weekly windows, flattened. */
|
|
62957
63703
|
windows: array(RecordWindowSchema),
|
|
62958
63704
|
/**
|
|
@@ -62968,7 +63714,7 @@ object({
|
|
|
62968
63714
|
* provider reporting a non-zero count also reports the schedule as not
|
|
62969
63715
|
* writable.
|
|
62970
63716
|
*/
|
|
62971
|
-
unreadableWindows: number(),
|
|
63717
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
62972
63718
|
/**
|
|
62973
63719
|
* The camera is scheduled to record and has NO usable storage.
|
|
62974
63720
|
*
|
|
@@ -63605,7 +64351,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63605
64351
|
url: string().optional(),
|
|
63606
64352
|
codec: string().optional(),
|
|
63607
64353
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63608
|
-
fps: number().positive().optional(),
|
|
64354
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63609
64355
|
label: string().optional(),
|
|
63610
64356
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63611
64357
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63635,18 +64381,18 @@ var StreamProfileSchema = _enum([
|
|
|
63635
64381
|
]);
|
|
63636
64382
|
/** The current encoding config of one stream profile. */
|
|
63637
64383
|
var StreamProfileConfigSchema = object({
|
|
63638
|
-
width: number(),
|
|
63639
|
-
height: number(),
|
|
64384
|
+
width: number().meta(readingMeta("none")),
|
|
64385
|
+
height: number().meta(readingMeta("none")),
|
|
63640
64386
|
codec: _enum(["h264", "h265"]),
|
|
63641
|
-
framerate: number(),
|
|
63642
|
-
bitrate: number(),
|
|
64387
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64388
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63643
64389
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63644
64390
|
encoderProfile: _enum([
|
|
63645
64391
|
"high",
|
|
63646
64392
|
"main",
|
|
63647
64393
|
"baseline"
|
|
63648
64394
|
]).optional(),
|
|
63649
|
-
gop: number().optional(),
|
|
64395
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63650
64396
|
/**
|
|
63651
64397
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63652
64398
|
*
|
|
@@ -63731,7 +64477,7 @@ object({
|
|
|
63731
64477
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63732
64478
|
lastChangedAt: number()
|
|
63733
64479
|
});
|
|
63734
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64480
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63735
64481
|
deviceId: number(),
|
|
63736
64482
|
on: boolean()
|
|
63737
64483
|
}), _void(), {
|
|
@@ -64289,23 +65035,13 @@ object({
|
|
|
64289
65035
|
});
|
|
64290
65036
|
DeviceType.Sensor;
|
|
64291
65037
|
object({
|
|
64292
|
-
/** Current temperature in Celsius. */
|
|
64293
|
-
celsius: number().meta({
|
|
64294
|
-
|
|
65038
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
65039
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
65040
|
+
precision: 1,
|
|
64295
65041
|
label: "Temperature"
|
|
64296
|
-
}),
|
|
65042
|
+
})),
|
|
64297
65043
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64298
|
-
lastFetchedAt: number()
|
|
64299
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64300
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64301
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64302
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64303
|
-
unit: string().optional(),
|
|
64304
|
-
/** Suggested decimal places for numeric display.
|
|
64305
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64306
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64307
|
-
* auto-formatting when absent. */
|
|
64308
|
-
precision: number().int().min(0).max(10).optional()
|
|
65044
|
+
lastFetchedAt: number()
|
|
64309
65045
|
});
|
|
64310
65046
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64311
65047
|
/**
|
|
@@ -64557,16 +65293,16 @@ object({
|
|
|
64557
65293
|
]),
|
|
64558
65294
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64559
65295
|
* reading. */
|
|
64560
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65296
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64561
65297
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64562
65298
|
* the vacuum has no speed control. */
|
|
64563
65299
|
fanSpeed: string().nullable(),
|
|
64564
65300
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64565
65301
|
availableFanSpeeds: array(string()),
|
|
64566
65302
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64567
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65303
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64568
65304
|
/** Current error code (0 / null = no error). */
|
|
64569
|
-
errorCode: number().nullable(),
|
|
65305
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64570
65306
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64571
65307
|
errorLabel: string().nullable(),
|
|
64572
65308
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64605,7 +65341,7 @@ object({
|
|
|
64605
65341
|
]),
|
|
64606
65342
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64607
65343
|
* intermediate position surface. */
|
|
64608
|
-
position: number().min(0).max(100).nullable(),
|
|
65344
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64609
65345
|
/** Ms epoch when the slice was last updated. */
|
|
64610
65346
|
lastChangedAt: number()
|
|
64611
65347
|
});
|
|
@@ -64633,9 +65369,9 @@ object({
|
|
|
64633
65369
|
DeviceType.Sensor;
|
|
64634
65370
|
object({
|
|
64635
65371
|
/** Current measured temperature. Null when not reported. */
|
|
64636
|
-
currentTemp: number().nullable(),
|
|
65372
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64637
65373
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64638
|
-
targetTemp: number().nullable(),
|
|
65374
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64639
65375
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64640
65376
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64641
65377
|
* device reports an unknown state. */
|
|
@@ -64646,9 +65382,9 @@ object({
|
|
|
64646
65382
|
* has no away surface. */
|
|
64647
65383
|
away: boolean().nullable(),
|
|
64648
65384
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64649
|
-
minTemp: number().nullable(),
|
|
65385
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64650
65386
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64651
|
-
maxTemp: number().nullable(),
|
|
65387
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64652
65388
|
/** Ms epoch when the slice was last updated. */
|
|
64653
65389
|
lastChangedAt: number()
|
|
64654
65390
|
});
|
|
@@ -64672,25 +65408,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64672
65408
|
auth: "protected"
|
|
64673
65409
|
});
|
|
64674
65410
|
object({
|
|
64675
|
-
/** Verbatim
|
|
64676
|
-
* when no condition has been reported yet. */
|
|
65411
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64677
65412
|
condition: string().nullable(),
|
|
64678
|
-
/** Current temperature in
|
|
64679
|
-
temperature: number().nullable(),
|
|
64680
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64681
|
-
temperatureUnit: string().nullable(),
|
|
65413
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65414
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64682
65415
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64683
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64684
|
-
/** Barometric pressure in
|
|
64685
|
-
pressure: number().nullable(),
|
|
64686
|
-
/**
|
|
64687
|
-
|
|
64688
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64689
|
-
windSpeed: number().nullable(),
|
|
64690
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64691
|
-
windSpeedUnit: string().nullable(),
|
|
65416
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65417
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65418
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65419
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65420
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64692
65421
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64693
|
-
windBearing: number().nullable(),
|
|
65422
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64694
65423
|
/** Ms epoch when the slice was last updated. */
|
|
64695
65424
|
lastFetchedAt: number()
|
|
64696
65425
|
});
|
|
@@ -65440,8 +66169,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65440
66169
|
kind: "mutation",
|
|
65441
66170
|
auth: "admin"
|
|
65442
66171
|
});
|
|
66172
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65443
66173
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65444
|
-
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;
|
|
66174
|
+
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;
|
|
65445
66175
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65446
66176
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65447
66177
|
new Set(CAP_NAMES);
|
|
@@ -65494,7 +66224,7 @@ var AccessoryKind = {
|
|
|
65494
66224
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65495
66225
|
};
|
|
65496
66226
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65497
|
-
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;
|
|
66227
|
+
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;
|
|
65498
66228
|
new Set(Object.values(DeviceType));
|
|
65499
66229
|
Object.freeze({
|
|
65500
66230
|
"accessories.getStatus": {
|
|
@@ -65602,6 +66332,13 @@ Object.freeze({
|
|
|
65602
66332
|
access: "view",
|
|
65603
66333
|
role: "admin"
|
|
65604
66334
|
},
|
|
66335
|
+
"addons.getPackageDocs": {
|
|
66336
|
+
capName: "addons",
|
|
66337
|
+
capScope: "system",
|
|
66338
|
+
addonId: null,
|
|
66339
|
+
access: "view",
|
|
66340
|
+
role: "admin"
|
|
66341
|
+
},
|
|
65605
66342
|
"addons.getVersions": {
|
|
65606
66343
|
capName: "addons",
|
|
65607
66344
|
capScope: "system",
|
|
@@ -68710,6 +69447,27 @@ Object.freeze({
|
|
|
68710
69447
|
access: "view",
|
|
68711
69448
|
role: "viewer"
|
|
68712
69449
|
},
|
|
69450
|
+
"groupActive.getStatus": {
|
|
69451
|
+
capName: "group-active",
|
|
69452
|
+
capScope: "device",
|
|
69453
|
+
addonId: null,
|
|
69454
|
+
access: "view",
|
|
69455
|
+
role: "viewer"
|
|
69456
|
+
},
|
|
69457
|
+
"groupCommands.getStatus": {
|
|
69458
|
+
capName: "group-commands",
|
|
69459
|
+
capScope: "device",
|
|
69460
|
+
addonId: null,
|
|
69461
|
+
access: "view",
|
|
69462
|
+
role: "viewer"
|
|
69463
|
+
},
|
|
69464
|
+
"groupStatus.getStatus": {
|
|
69465
|
+
capName: "group-status",
|
|
69466
|
+
capScope: "device",
|
|
69467
|
+
addonId: null,
|
|
69468
|
+
access: "view",
|
|
69469
|
+
role: "viewer"
|
|
69470
|
+
},
|
|
68713
69471
|
"heatingValve.getStatus": {
|
|
68714
69472
|
capName: "heating-valve",
|
|
68715
69473
|
capScope: "device",
|
|
@@ -69662,6 +70420,13 @@ Object.freeze({
|
|
|
69662
70420
|
access: "create",
|
|
69663
70421
|
role: "admin"
|
|
69664
70422
|
},
|
|
70423
|
+
"meter.getStatus": {
|
|
70424
|
+
capName: "meter",
|
|
70425
|
+
capScope: "device",
|
|
70426
|
+
addonId: null,
|
|
70427
|
+
access: "view",
|
|
70428
|
+
role: "viewer"
|
|
70429
|
+
},
|
|
69665
70430
|
"metricsProvider.collectSnapshot": {
|
|
69666
70431
|
capName: "metrics-provider",
|
|
69667
70432
|
capScope: "system",
|
|
@@ -77760,7 +78525,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77760
78525
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77761
78526
|
icon: "square"
|
|
77762
78527
|
}
|
|
77763
|
-
}
|
|
78528
|
+
},
|
|
78529
|
+
overrides: { byType: {
|
|
78530
|
+
[DeviceType.Washer]: {
|
|
78531
|
+
state: { running: {
|
|
78532
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78533
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78534
|
+
} },
|
|
78535
|
+
events: {
|
|
78536
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78537
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78538
|
+
}
|
|
78539
|
+
},
|
|
78540
|
+
[DeviceType.Dryer]: {
|
|
78541
|
+
state: { running: {
|
|
78542
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78543
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78544
|
+
} },
|
|
78545
|
+
events: {
|
|
78546
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78547
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78548
|
+
}
|
|
78549
|
+
},
|
|
78550
|
+
[DeviceType.Dishwasher]: {
|
|
78551
|
+
state: { running: {
|
|
78552
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78553
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78554
|
+
} },
|
|
78555
|
+
events: {
|
|
78556
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78557
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78558
|
+
}
|
|
78559
|
+
}
|
|
78560
|
+
} }
|
|
77764
78561
|
},
|
|
77765
78562
|
update: {
|
|
77766
78563
|
scope: "device",
|
|
@@ -78532,6 +79329,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78532
79329
|
icon: "flame"
|
|
78533
79330
|
}]
|
|
78534
79331
|
},
|
|
79332
|
+
"group-active": {
|
|
79333
|
+
scope: "device",
|
|
79334
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79335
|
+
},
|
|
79336
|
+
"group-commands": {
|
|
79337
|
+
scope: "device",
|
|
79338
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79339
|
+
},
|
|
79340
|
+
"group-status": {
|
|
79341
|
+
scope: "device",
|
|
79342
|
+
noun: t("Group", "Gruppo"),
|
|
79343
|
+
state: [
|
|
79344
|
+
{
|
|
79345
|
+
kind: "numeric",
|
|
79346
|
+
field: "included",
|
|
79347
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79348
|
+
label: t("Reporting", "Rispondono"),
|
|
79349
|
+
icon: "users"
|
|
79350
|
+
},
|
|
79351
|
+
{
|
|
79352
|
+
kind: "numeric",
|
|
79353
|
+
field: "excluded",
|
|
79354
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79355
|
+
label: t("Excluded", "Esclusi"),
|
|
79356
|
+
icon: "users"
|
|
79357
|
+
},
|
|
79358
|
+
{
|
|
79359
|
+
kind: "numeric",
|
|
79360
|
+
field: "total",
|
|
79361
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79362
|
+
label: t("Members", "Membri"),
|
|
79363
|
+
icon: "sigma"
|
|
79364
|
+
}
|
|
79365
|
+
]
|
|
79366
|
+
},
|
|
78535
79367
|
"humidity-sensor": {
|
|
78536
79368
|
scope: "device",
|
|
78537
79369
|
noun: t("Humidity", "Umidità"),
|
|
@@ -78557,6 +79389,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78557
79389
|
}],
|
|
78558
79390
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78559
79391
|
},
|
|
79392
|
+
meter: {
|
|
79393
|
+
scope: "device",
|
|
79394
|
+
noun: t("Meter", "Contatore"),
|
|
79395
|
+
state: [{
|
|
79396
|
+
kind: "numeric",
|
|
79397
|
+
field: "value",
|
|
79398
|
+
quantity: t("the total", "il totale"),
|
|
79399
|
+
label: t("Total", "Totale"),
|
|
79400
|
+
icon: "gauge"
|
|
79401
|
+
}]
|
|
79402
|
+
},
|
|
78560
79403
|
"numeric-sensor": {
|
|
78561
79404
|
scope: "device",
|
|
78562
79405
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78565,7 +79408,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78565
79408
|
field: "value",
|
|
78566
79409
|
quantity: t("the reading", "il valore"),
|
|
78567
79410
|
label: t("Reading", "Valore"),
|
|
78568
|
-
unitField: "unit",
|
|
78569
79411
|
icon: "gauge"
|
|
78570
79412
|
}]
|
|
78571
79413
|
},
|
|
@@ -78701,7 +79543,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78701
79543
|
field: "temperature",
|
|
78702
79544
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78703
79545
|
label: t("Temperature", "Temperatura"),
|
|
78704
|
-
|
|
79546
|
+
unit: "°C",
|
|
78705
79547
|
icon: "thermometer"
|
|
78706
79548
|
},
|
|
78707
79549
|
{
|
|
@@ -78717,7 +79559,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78717
79559
|
field: "windSpeed",
|
|
78718
79560
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78719
79561
|
label: t("Wind", "Vento"),
|
|
78720
|
-
|
|
79562
|
+
unit: "m/s",
|
|
78721
79563
|
icon: "wind"
|
|
78722
79564
|
},
|
|
78723
79565
|
{
|
|
@@ -78725,7 +79567,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78725
79567
|
field: "pressure",
|
|
78726
79568
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78727
79569
|
label: t("Pressure", "Pressione"),
|
|
78728
|
-
|
|
79570
|
+
unit: "hPa",
|
|
78729
79571
|
icon: "gauge"
|
|
78730
79572
|
}
|
|
78731
79573
|
]
|
|
@@ -79030,8 +79872,47 @@ function projectAction(cap, action) {
|
|
|
79030
79872
|
};
|
|
79031
79873
|
}
|
|
79032
79874
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
79033
|
-
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;
|
|
79875
|
+
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;
|
|
79034
79876
|
DeviceFeature.BatteryOperated;
|
|
79877
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79878
|
+
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.";
|
|
79879
|
+
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.";
|
|
79880
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79881
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79882
|
+
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.";
|
|
79883
|
+
function withheld(reason) {
|
|
79884
|
+
return {
|
|
79885
|
+
[DeviceType.Washer]: {
|
|
79886
|
+
exported: false,
|
|
79887
|
+
reason
|
|
79888
|
+
},
|
|
79889
|
+
[DeviceType.Dryer]: {
|
|
79890
|
+
exported: false,
|
|
79891
|
+
reason
|
|
79892
|
+
},
|
|
79893
|
+
[DeviceType.Dishwasher]: {
|
|
79894
|
+
exported: false,
|
|
79895
|
+
reason
|
|
79896
|
+
}
|
|
79897
|
+
};
|
|
79898
|
+
}
|
|
79899
|
+
function offered(received) {
|
|
79900
|
+
return {
|
|
79901
|
+
[DeviceType.Washer]: {
|
|
79902
|
+
exported: true,
|
|
79903
|
+
as: received
|
|
79904
|
+
},
|
|
79905
|
+
[DeviceType.Dryer]: {
|
|
79906
|
+
exported: true,
|
|
79907
|
+
as: received
|
|
79908
|
+
},
|
|
79909
|
+
[DeviceType.Dishwasher]: {
|
|
79910
|
+
exported: true,
|
|
79911
|
+
as: received
|
|
79912
|
+
}
|
|
79913
|
+
};
|
|
79914
|
+
}
|
|
79915
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
79035
79916
|
Object.freeze({
|
|
79036
79917
|
"accessories.getStatus": [{
|
|
79037
79918
|
name: "deviceId",
|
|
@@ -79998,6 +80879,21 @@ Object.freeze({
|
|
|
79998
80879
|
form: "single",
|
|
79999
80880
|
optional: false
|
|
80000
80881
|
}],
|
|
80882
|
+
"groupActive.getStatus": [{
|
|
80883
|
+
name: "deviceId",
|
|
80884
|
+
form: "single",
|
|
80885
|
+
optional: false
|
|
80886
|
+
}],
|
|
80887
|
+
"groupCommands.getStatus": [{
|
|
80888
|
+
name: "deviceId",
|
|
80889
|
+
form: "single",
|
|
80890
|
+
optional: false
|
|
80891
|
+
}],
|
|
80892
|
+
"groupStatus.getStatus": [{
|
|
80893
|
+
name: "deviceId",
|
|
80894
|
+
form: "single",
|
|
80895
|
+
optional: false
|
|
80896
|
+
}],
|
|
80001
80897
|
"heatingValve.getStatus": [{
|
|
80002
80898
|
name: "deviceId",
|
|
80003
80899
|
form: "single",
|
|
@@ -80198,6 +81094,11 @@ Object.freeze({
|
|
|
80198
81094
|
form: "single",
|
|
80199
81095
|
optional: false
|
|
80200
81096
|
}],
|
|
81097
|
+
"meter.getStatus": [{
|
|
81098
|
+
name: "deviceId",
|
|
81099
|
+
form: "single",
|
|
81100
|
+
optional: false
|
|
81101
|
+
}],
|
|
80201
81102
|
"motion.getStatus": [{
|
|
80202
81103
|
name: "deviceId",
|
|
80203
81104
|
form: "single",
|
|
@@ -81805,7 +82706,6 @@ Object.freeze({
|
|
|
81805
82706
|
"network-access": "ingress",
|
|
81806
82707
|
"smtp-provider": "email"
|
|
81807
82708
|
});
|
|
81808
|
-
DeviceType.Camera;
|
|
81809
82709
|
/**
|
|
81810
82710
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
81811
82711
|
* `z.infer`, they do not restate the shape.
|
|
@@ -81982,6 +82882,8 @@ new Map(Object.entries({
|
|
|
81982
82882
|
"detection-blind": "device-events",
|
|
81983
82883
|
"motion-noisy": "device-events",
|
|
81984
82884
|
"motion-calm": "device-events",
|
|
82885
|
+
"package-llm-silent": "device-events",
|
|
82886
|
+
"package-llm-answered": "device-events",
|
|
81985
82887
|
"recording-stalled": "device-events",
|
|
81986
82888
|
"recording-healthy": "device-events",
|
|
81987
82889
|
"recording-degraded": "device-events",
|
|
@@ -82065,6 +82967,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
82065
82967
|
label: "Motion without a subject",
|
|
82066
82968
|
kinds: ["motion-noisy", "motion-calm"]
|
|
82067
82969
|
},
|
|
82970
|
+
{
|
|
82971
|
+
id: "package-llm",
|
|
82972
|
+
family: "device-events",
|
|
82973
|
+
label: "Package confirm",
|
|
82974
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
82975
|
+
},
|
|
82068
82976
|
{
|
|
82069
82977
|
id: "recording",
|
|
82070
82978
|
family: "device-events",
|
|
@@ -82246,6 +83154,8 @@ var DEVICE_EVENTS = [
|
|
|
82246
83154
|
"detection-blind",
|
|
82247
83155
|
"motion-noisy",
|
|
82248
83156
|
"motion-calm",
|
|
83157
|
+
"package-llm-silent",
|
|
83158
|
+
"package-llm-answered",
|
|
82249
83159
|
"recording-stalled",
|
|
82250
83160
|
"recording-healthy",
|
|
82251
83161
|
"recording-degraded",
|
|
@@ -82514,6 +83424,15 @@ new Map([
|
|
|
82514
83424
|
snapshotLabel: "Cameras with constant motion now",
|
|
82515
83425
|
snapshotSection: null
|
|
82516
83426
|
},
|
|
83427
|
+
{
|
|
83428
|
+
id: "package-llm-confirm",
|
|
83429
|
+
family: "device-events",
|
|
83430
|
+
label: "Package confirm (not answering / answering again)",
|
|
83431
|
+
bad: ["package-llm-silent"],
|
|
83432
|
+
recovery: ["package-llm-answered"],
|
|
83433
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
83434
|
+
snapshotSection: null
|
|
83435
|
+
},
|
|
82517
83436
|
{
|
|
82518
83437
|
id: "recording-health",
|
|
82519
83438
|
family: "device-events",
|
|
@@ -84117,7 +85036,7 @@ function pickOauthRedirectOrigin(book) {
|
|
|
84117
85036
|
return book.roles.publicEndpoint.resolved ?? book.roles.internal.resolved ?? null;
|
|
84118
85037
|
}
|
|
84119
85038
|
var googleBrokersEntryKind = defineEntryKind("brokers", {
|
|
84120
|
-
title: "Google
|
|
85039
|
+
title: "Google brokers",
|
|
84121
85040
|
schema: entryBody({
|
|
84122
85041
|
clientId: GoogleBrokerEntrySchema.shape.clientId,
|
|
84123
85042
|
clientSecret: GoogleBrokerEntrySchema.shape.clientSecret,
|
|
@@ -84186,7 +85105,7 @@ var GoogleBrokerStore = class GoogleBrokerStore {
|
|
|
84186
85105
|
//#endregion
|
|
84187
85106
|
//#region src/google-services.addon.ts
|
|
84188
85107
|
/**
|
|
84189
|
-
* Google
|
|
85108
|
+
* Google — hub-only broker kind `google` + calendar-source + Gmail smtp.
|
|
84190
85109
|
* One OAuth account = one broker entry; feature caps aggregate connected brokers.
|
|
84191
85110
|
*/
|
|
84192
85111
|
var ADDON_ID = "google-services";
|