@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -325,6 +325,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
325
325
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
326
326
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
327
327
|
/**
|
|
328
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
329
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
330
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
331
|
+
*/
|
|
332
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
333
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
334
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
335
|
+
/**
|
|
328
336
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
329
337
|
* (a settings change via `setAgentInferenceDevices` /
|
|
330
338
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5567,7 +5575,7 @@ var ZodIssueCode = {
|
|
|
5567
5575
|
var ZodFirstPartyTypeKind;
|
|
5568
5576
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5569
5577
|
//#endregion
|
|
5570
|
-
//#region ../types/dist/sleep
|
|
5578
|
+
//#region ../types/dist/sleep--jXS9hWo.mjs
|
|
5571
5579
|
/**
|
|
5572
5580
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5573
5581
|
* window to float samples (D455).
|
|
@@ -8309,6 +8317,99 @@ function defineEntryKind(name, spec) {
|
|
|
8309
8317
|
if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
|
|
8310
8318
|
return defined;
|
|
8311
8319
|
}
|
|
8320
|
+
var READING_QUANTITIES = [
|
|
8321
|
+
"temperature",
|
|
8322
|
+
"pressure",
|
|
8323
|
+
"speed",
|
|
8324
|
+
"precipitation",
|
|
8325
|
+
"precipitation-rate",
|
|
8326
|
+
"length",
|
|
8327
|
+
"area",
|
|
8328
|
+
"illuminance",
|
|
8329
|
+
"irradiance",
|
|
8330
|
+
"power",
|
|
8331
|
+
"energy",
|
|
8332
|
+
"voltage",
|
|
8333
|
+
"current",
|
|
8334
|
+
"apparent-power",
|
|
8335
|
+
"humidity",
|
|
8336
|
+
"percentage",
|
|
8337
|
+
"concentration-volume",
|
|
8338
|
+
"concentration-mass",
|
|
8339
|
+
"concentration-ppb",
|
|
8340
|
+
"volume",
|
|
8341
|
+
"duration",
|
|
8342
|
+
"duration-ms",
|
|
8343
|
+
"information",
|
|
8344
|
+
"sound-level",
|
|
8345
|
+
"signal-level",
|
|
8346
|
+
"colour-temperature",
|
|
8347
|
+
"angle",
|
|
8348
|
+
"bitrate",
|
|
8349
|
+
"rate",
|
|
8350
|
+
"mass",
|
|
8351
|
+
"index",
|
|
8352
|
+
"ratio",
|
|
8353
|
+
"count",
|
|
8354
|
+
"none",
|
|
8355
|
+
"device"
|
|
8356
|
+
];
|
|
8357
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8358
|
+
new Set(READING_QUANTITIES);
|
|
8359
|
+
/**
|
|
8360
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8361
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8362
|
+
*/
|
|
8363
|
+
var QUANTITY_BASE = {
|
|
8364
|
+
temperature: "°C",
|
|
8365
|
+
pressure: "hPa",
|
|
8366
|
+
speed: "m/s",
|
|
8367
|
+
precipitation: "mm",
|
|
8368
|
+
"precipitation-rate": "mm/h",
|
|
8369
|
+
length: "m",
|
|
8370
|
+
area: "m²",
|
|
8371
|
+
illuminance: "lx",
|
|
8372
|
+
irradiance: "W/m²",
|
|
8373
|
+
power: "W",
|
|
8374
|
+
energy: "kWh",
|
|
8375
|
+
voltage: "V",
|
|
8376
|
+
current: "A",
|
|
8377
|
+
"apparent-power": "VA",
|
|
8378
|
+
humidity: "%",
|
|
8379
|
+
percentage: "%",
|
|
8380
|
+
"concentration-volume": "ppm",
|
|
8381
|
+
"concentration-mass": "µg/m³",
|
|
8382
|
+
"concentration-ppb": "ppb",
|
|
8383
|
+
volume: "L",
|
|
8384
|
+
duration: "s",
|
|
8385
|
+
"duration-ms": "ms",
|
|
8386
|
+
information: "B",
|
|
8387
|
+
"sound-level": "dBFS",
|
|
8388
|
+
"signal-level": "dBm",
|
|
8389
|
+
"colour-temperature": "mired",
|
|
8390
|
+
angle: "°",
|
|
8391
|
+
bitrate: "kbps",
|
|
8392
|
+
rate: "fps",
|
|
8393
|
+
mass: "kg",
|
|
8394
|
+
index: "none",
|
|
8395
|
+
ratio: "none",
|
|
8396
|
+
count: "none",
|
|
8397
|
+
none: "none",
|
|
8398
|
+
device: "device"
|
|
8399
|
+
};
|
|
8400
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8401
|
+
function baseUnitOf(quantity) {
|
|
8402
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8403
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8404
|
+
return symbol;
|
|
8405
|
+
}
|
|
8406
|
+
function readingMeta(quantity, extras) {
|
|
8407
|
+
return {
|
|
8408
|
+
quantity,
|
|
8409
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8410
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8411
|
+
};
|
|
8412
|
+
}
|
|
8312
8413
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8313
8414
|
var CamProfileSchema = _enum([
|
|
8314
8415
|
"high",
|
|
@@ -8336,8 +8437,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8336
8437
|
"derived"
|
|
8337
8438
|
]);
|
|
8338
8439
|
var CamStreamResolutionSchema = object({
|
|
8339
|
-
width: number().int().positive(),
|
|
8340
|
-
height: number().int().positive()
|
|
8440
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8441
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8341
8442
|
});
|
|
8342
8443
|
var CameraStreamSchema = object({
|
|
8343
8444
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8851,6 +8952,9 @@ var CAP_NAMES = Object.freeze([
|
|
|
8851
8952
|
"filesystem-browse",
|
|
8852
8953
|
"flood",
|
|
8853
8954
|
"gas",
|
|
8955
|
+
"group-active",
|
|
8956
|
+
"group-commands",
|
|
8957
|
+
"group-status",
|
|
8854
8958
|
"heating-valve",
|
|
8855
8959
|
"humidifier",
|
|
8856
8960
|
"humidity-sensor",
|
|
@@ -8871,6 +8975,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8871
8975
|
"login-method",
|
|
8872
8976
|
"media-player",
|
|
8873
8977
|
"mesh-network",
|
|
8978
|
+
"meter",
|
|
8874
8979
|
"metrics-provider",
|
|
8875
8980
|
"model-convert",
|
|
8876
8981
|
"model-distributor",
|
|
@@ -8980,14 +9085,6 @@ Object.freeze({
|
|
|
8980
9085
|
{
|
|
8981
9086
|
"path": "aqi",
|
|
8982
9087
|
"valueType": "number"
|
|
8983
|
-
},
|
|
8984
|
-
{
|
|
8985
|
-
"path": "unit",
|
|
8986
|
-
"valueType": "string"
|
|
8987
|
-
},
|
|
8988
|
-
{
|
|
8989
|
-
"path": "precision",
|
|
8990
|
-
"valueType": "number"
|
|
8991
9088
|
}
|
|
8992
9089
|
],
|
|
8993
9090
|
"alarm-panel": [
|
|
@@ -9023,20 +9120,10 @@ Object.freeze({
|
|
|
9023
9120
|
"valueType": "boolean"
|
|
9024
9121
|
}
|
|
9025
9122
|
],
|
|
9026
|
-
"ambient-light-sensor": [
|
|
9027
|
-
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
},
|
|
9031
|
-
{
|
|
9032
|
-
"path": "unit",
|
|
9033
|
-
"valueType": "string"
|
|
9034
|
-
},
|
|
9035
|
-
{
|
|
9036
|
-
"path": "precision",
|
|
9037
|
-
"valueType": "number"
|
|
9038
|
-
}
|
|
9039
|
-
],
|
|
9123
|
+
"ambient-light-sensor": [{
|
|
9124
|
+
"path": "lux",
|
|
9125
|
+
"valueType": "number"
|
|
9126
|
+
}],
|
|
9040
9127
|
"audio-metrics": [
|
|
9041
9128
|
{
|
|
9042
9129
|
"path": "ts",
|
|
@@ -9116,6 +9203,10 @@ Object.freeze({
|
|
|
9116
9203
|
"path": "lastUpdated",
|
|
9117
9204
|
"valueType": "number"
|
|
9118
9205
|
},
|
|
9206
|
+
{
|
|
9207
|
+
"path": "volts",
|
|
9208
|
+
"valueType": "number"
|
|
9209
|
+
},
|
|
9119
9210
|
{
|
|
9120
9211
|
"path": "lastContactAt",
|
|
9121
9212
|
"valueType": "number"
|
|
@@ -9358,10 +9449,6 @@ Object.freeze({
|
|
|
9358
9449
|
"datetime"
|
|
9359
9450
|
]
|
|
9360
9451
|
},
|
|
9361
|
-
{
|
|
9362
|
-
"path": "unit",
|
|
9363
|
-
"valueType": "string"
|
|
9364
|
-
},
|
|
9365
9452
|
{
|
|
9366
9453
|
"path": "min",
|
|
9367
9454
|
"valueType": "number"
|
|
@@ -9373,19 +9460,6 @@ Object.freeze({
|
|
|
9373
9460
|
{
|
|
9374
9461
|
"path": "step",
|
|
9375
9462
|
"valueType": "number"
|
|
9376
|
-
},
|
|
9377
|
-
{
|
|
9378
|
-
"path": "precision",
|
|
9379
|
-
"valueType": "number"
|
|
9380
|
-
},
|
|
9381
|
-
{
|
|
9382
|
-
"path": "format",
|
|
9383
|
-
"valueType": "enum",
|
|
9384
|
-
"enumValues": [
|
|
9385
|
-
"date",
|
|
9386
|
-
"time",
|
|
9387
|
-
"datetime"
|
|
9388
|
-
]
|
|
9389
9463
|
}
|
|
9390
9464
|
],
|
|
9391
9465
|
"cover": [
|
|
@@ -9626,13 +9700,8 @@ Object.freeze({
|
|
|
9626
9700
|
"path": "value",
|
|
9627
9701
|
"valueType": "string"
|
|
9628
9702
|
}, {
|
|
9629
|
-
"path": "
|
|
9630
|
-
"valueType": "
|
|
9631
|
-
"enumValues": [
|
|
9632
|
-
"date",
|
|
9633
|
-
"time",
|
|
9634
|
-
"datetime"
|
|
9635
|
-
]
|
|
9703
|
+
"path": "timestamp",
|
|
9704
|
+
"valueType": "boolean"
|
|
9636
9705
|
}],
|
|
9637
9706
|
"event-emitter": [
|
|
9638
9707
|
{
|
|
@@ -9705,6 +9774,24 @@ Object.freeze({
|
|
|
9705
9774
|
"path": "detected",
|
|
9706
9775
|
"valueType": "boolean"
|
|
9707
9776
|
}],
|
|
9777
|
+
"group-active": [{
|
|
9778
|
+
"path": "active",
|
|
9779
|
+
"valueType": "boolean"
|
|
9780
|
+
}],
|
|
9781
|
+
"group-status": [
|
|
9782
|
+
{
|
|
9783
|
+
"path": "included",
|
|
9784
|
+
"valueType": "number"
|
|
9785
|
+
},
|
|
9786
|
+
{
|
|
9787
|
+
"path": "excluded",
|
|
9788
|
+
"valueType": "number"
|
|
9789
|
+
},
|
|
9790
|
+
{
|
|
9791
|
+
"path": "total",
|
|
9792
|
+
"valueType": "number"
|
|
9793
|
+
}
|
|
9794
|
+
],
|
|
9708
9795
|
"heating-valve": [{
|
|
9709
9796
|
"path": "position",
|
|
9710
9797
|
"valueType": "number"
|
|
@@ -9739,20 +9826,10 @@ Object.freeze({
|
|
|
9739
9826
|
"valueType": "number"
|
|
9740
9827
|
}
|
|
9741
9828
|
],
|
|
9742
|
-
"humidity-sensor": [
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
},
|
|
9747
|
-
{
|
|
9748
|
-
"path": "unit",
|
|
9749
|
-
"valueType": "string"
|
|
9750
|
-
},
|
|
9751
|
-
{
|
|
9752
|
-
"path": "precision",
|
|
9753
|
-
"valueType": "number"
|
|
9754
|
-
}
|
|
9755
|
-
],
|
|
9829
|
+
"humidity-sensor": [{
|
|
9830
|
+
"path": "percent",
|
|
9831
|
+
"valueType": "number"
|
|
9832
|
+
}],
|
|
9756
9833
|
"image": [{
|
|
9757
9834
|
"path": "url",
|
|
9758
9835
|
"valueType": "string"
|
|
@@ -9960,6 +10037,10 @@ Object.freeze({
|
|
|
9960
10037
|
]
|
|
9961
10038
|
}
|
|
9962
10039
|
],
|
|
10040
|
+
"meter": [{
|
|
10041
|
+
"path": "value",
|
|
10042
|
+
"valueType": "number"
|
|
10043
|
+
}],
|
|
9963
10044
|
"motion": [
|
|
9964
10045
|
{
|
|
9965
10046
|
"path": "detected",
|
|
@@ -10091,20 +10172,10 @@ Object.freeze({
|
|
|
10091
10172
|
"valueType": "boolean"
|
|
10092
10173
|
}
|
|
10093
10174
|
],
|
|
10094
|
-
"numeric-sensor": [
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
},
|
|
10099
|
-
{
|
|
10100
|
-
"path": "unit",
|
|
10101
|
-
"valueType": "string"
|
|
10102
|
-
},
|
|
10103
|
-
{
|
|
10104
|
-
"path": "precision",
|
|
10105
|
-
"valueType": "number"
|
|
10106
|
-
}
|
|
10107
|
-
],
|
|
10175
|
+
"numeric-sensor": [{
|
|
10176
|
+
"path": "value",
|
|
10177
|
+
"valueType": "number"
|
|
10178
|
+
}],
|
|
10108
10179
|
"pet-feeder": [
|
|
10109
10180
|
{
|
|
10110
10181
|
"path": "foodLevel",
|
|
@@ -10196,14 +10267,6 @@ Object.freeze({
|
|
|
10196
10267
|
{
|
|
10197
10268
|
"path": "powerFactor",
|
|
10198
10269
|
"valueType": "number"
|
|
10199
|
-
},
|
|
10200
|
-
{
|
|
10201
|
-
"path": "unit",
|
|
10202
|
-
"valueType": "string"
|
|
10203
|
-
},
|
|
10204
|
-
{
|
|
10205
|
-
"path": "precision",
|
|
10206
|
-
"valueType": "number"
|
|
10207
10270
|
}
|
|
10208
10271
|
],
|
|
10209
10272
|
"presence": [
|
|
@@ -10232,20 +10295,10 @@ Object.freeze({
|
|
|
10232
10295
|
"valueType": "number"
|
|
10233
10296
|
}
|
|
10234
10297
|
],
|
|
10235
|
-
"pressure-sensor": [
|
|
10236
|
-
|
|
10237
|
-
|
|
10238
|
-
|
|
10239
|
-
},
|
|
10240
|
-
{
|
|
10241
|
-
"path": "unit",
|
|
10242
|
-
"valueType": "string"
|
|
10243
|
-
},
|
|
10244
|
-
{
|
|
10245
|
-
"path": "precision",
|
|
10246
|
-
"valueType": "number"
|
|
10247
|
-
}
|
|
10248
|
-
],
|
|
10298
|
+
"pressure-sensor": [{
|
|
10299
|
+
"path": "hpa",
|
|
10300
|
+
"valueType": "number"
|
|
10301
|
+
}],
|
|
10249
10302
|
"privacy-mask": [{
|
|
10250
10303
|
"path": "enabled",
|
|
10251
10304
|
"valueType": "boolean"
|
|
@@ -10556,20 +10609,10 @@ Object.freeze({
|
|
|
10556
10609
|
"path": "tampered",
|
|
10557
10610
|
"valueType": "boolean"
|
|
10558
10611
|
}],
|
|
10559
|
-
"temperature-sensor": [
|
|
10560
|
-
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
},
|
|
10564
|
-
{
|
|
10565
|
-
"path": "unit",
|
|
10566
|
-
"valueType": "string"
|
|
10567
|
-
},
|
|
10568
|
-
{
|
|
10569
|
-
"path": "precision",
|
|
10570
|
-
"valueType": "number"
|
|
10571
|
-
}
|
|
10572
|
-
],
|
|
10612
|
+
"temperature-sensor": [{
|
|
10613
|
+
"path": "celsius",
|
|
10614
|
+
"valueType": "number"
|
|
10615
|
+
}],
|
|
10573
10616
|
"update": [
|
|
10574
10617
|
{
|
|
10575
10618
|
"path": "currentVersion",
|
|
@@ -10680,10 +10723,6 @@ Object.freeze({
|
|
|
10680
10723
|
"path": "temperature",
|
|
10681
10724
|
"valueType": "number"
|
|
10682
10725
|
},
|
|
10683
|
-
{
|
|
10684
|
-
"path": "temperatureUnit",
|
|
10685
|
-
"valueType": "string"
|
|
10686
|
-
},
|
|
10687
10726
|
{
|
|
10688
10727
|
"path": "humidity",
|
|
10689
10728
|
"valueType": "number"
|
|
@@ -10692,18 +10731,10 @@ Object.freeze({
|
|
|
10692
10731
|
"path": "pressure",
|
|
10693
10732
|
"valueType": "number"
|
|
10694
10733
|
},
|
|
10695
|
-
{
|
|
10696
|
-
"path": "pressureUnit",
|
|
10697
|
-
"valueType": "string"
|
|
10698
|
-
},
|
|
10699
10734
|
{
|
|
10700
10735
|
"path": "windSpeed",
|
|
10701
10736
|
"valueType": "number"
|
|
10702
10737
|
},
|
|
10703
|
-
{
|
|
10704
|
-
"path": "windSpeedUnit",
|
|
10705
|
-
"valueType": "string"
|
|
10706
|
-
},
|
|
10707
10738
|
{
|
|
10708
10739
|
"path": "windBearing",
|
|
10709
10740
|
"valueType": "number"
|
|
@@ -10767,7 +10798,7 @@ function userError(code, params, englishFallback) {
|
|
|
10767
10798
|
return new CamstackError(code, params, englishFallback);
|
|
10768
10799
|
}
|
|
10769
10800
|
//#endregion
|
|
10770
|
-
//#region ../types/dist/err-msg-
|
|
10801
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
10771
10802
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
10772
10803
|
DeviceType["Camera"] = "camera";
|
|
10773
10804
|
DeviceType["Hub"] = "hub";
|
|
@@ -10861,8 +10892,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
10861
10892
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
10862
10893
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
10863
10894
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
10864
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10895
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
10896
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
10865
10897
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
10898
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
10899
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
10900
|
+
DeviceType["Washer"] = "washer";
|
|
10901
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
10902
|
+
DeviceType["Dryer"] = "dryer";
|
|
10866
10903
|
return DeviceType;
|
|
10867
10904
|
}({});
|
|
10868
10905
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11110,7 +11147,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
11110
11147
|
return DeviceRole;
|
|
11111
11148
|
}({});
|
|
11112
11149
|
//#endregion
|
|
11113
|
-
//#region ../types/dist/composition-
|
|
11150
|
+
//#region ../types/dist/composition-Bb8iwHEJ.mjs
|
|
11114
11151
|
/**
|
|
11115
11152
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11116
11153
|
*
|
|
@@ -11425,6 +11462,13 @@ var table = {
|
|
|
11425
11462
|
apply: () => {
|
|
11426
11463
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11427
11464
|
}
|
|
11465
|
+
},
|
|
11466
|
+
schmitt: {
|
|
11467
|
+
minArgs: 3,
|
|
11468
|
+
maxArgs: 5,
|
|
11469
|
+
apply: () => {
|
|
11470
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11471
|
+
}
|
|
11428
11472
|
}
|
|
11429
11473
|
};
|
|
11430
11474
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -11865,15 +11909,232 @@ function validateExpressionSource(src) {
|
|
|
11865
11909
|
}
|
|
11866
11910
|
return null;
|
|
11867
11911
|
}
|
|
11868
|
-
/**
|
|
11869
|
-
|
|
11870
|
-
|
|
11871
|
-
|
|
11912
|
+
/**
|
|
11913
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
11914
|
+
*
|
|
11915
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
11916
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
11917
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
11918
|
+
*
|
|
11919
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
11920
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
11921
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
11922
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
11923
|
+
* can move later without moving the others.
|
|
11924
|
+
*/
|
|
11925
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
11926
|
+
var APPLIANCE_KINDS = [
|
|
11927
|
+
"washer",
|
|
11928
|
+
"dryer",
|
|
11929
|
+
"dishwasher"
|
|
11930
|
+
];
|
|
11931
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
11932
|
+
/**
|
|
11933
|
+
* Statistics and integrals over a history read (D944).
|
|
11934
|
+
*
|
|
11935
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
11936
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
11937
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
11938
|
+
* as zero. A truncated read is not published.
|
|
11939
|
+
*/
|
|
11940
|
+
var STATISTIC_STATS = [
|
|
11941
|
+
"min",
|
|
11942
|
+
"max",
|
|
11943
|
+
"mean",
|
|
11944
|
+
"sum",
|
|
11945
|
+
"count",
|
|
11946
|
+
"change"
|
|
11947
|
+
];
|
|
11948
|
+
/**
|
|
11949
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
11950
|
+
*
|
|
11951
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
11952
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
11953
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
11954
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
11955
|
+
*/
|
|
11956
|
+
var MINUTE_MS = 6e4;
|
|
11957
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
11958
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
11959
|
+
var ROLLING_SPANS = [
|
|
11960
|
+
"1h",
|
|
11961
|
+
"24h",
|
|
11962
|
+
"2d",
|
|
11963
|
+
"7d",
|
|
11964
|
+
"30d",
|
|
11965
|
+
"custom"
|
|
11966
|
+
];
|
|
11967
|
+
var CALENDAR_PERIODS = [
|
|
11968
|
+
"today",
|
|
11969
|
+
"yesterday",
|
|
11970
|
+
"this-week",
|
|
11971
|
+
"this-month"
|
|
11972
|
+
];
|
|
11973
|
+
var RESET_PERIODS = [
|
|
11974
|
+
"never",
|
|
11975
|
+
"daily",
|
|
11976
|
+
"weekly",
|
|
11977
|
+
"monthly"
|
|
11978
|
+
];
|
|
11979
|
+
5 * MINUTE_MS;
|
|
11980
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
11981
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
11982
|
+
var rollingWindowObject = object({
|
|
11983
|
+
kind: literal("rolling"),
|
|
11984
|
+
span: _enum(ROLLING_SPANS),
|
|
11985
|
+
customMinutes: number().int().min(5).optional()
|
|
11986
|
+
}).check((payload) => {
|
|
11987
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
11988
|
+
code: "custom",
|
|
11989
|
+
message: "a custom range needs a duration in minutes",
|
|
11990
|
+
path: ["customMinutes"],
|
|
11991
|
+
input: payload.value
|
|
11992
|
+
});
|
|
11993
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
11994
|
+
code: "custom",
|
|
11995
|
+
message: "only a custom range carries a duration",
|
|
11996
|
+
path: ["customMinutes"],
|
|
11997
|
+
input: payload.value
|
|
11998
|
+
});
|
|
11999
|
+
});
|
|
12000
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12001
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12002
|
+
kind: literal("calendar"),
|
|
12003
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12004
|
+
})]);
|
|
12005
|
+
/**
|
|
12006
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
12007
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
12008
|
+
* `composition.ts` (D659).
|
|
12009
|
+
*/
|
|
11872
12010
|
var CompositionSourceRefSchema = object({
|
|
11873
12011
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11874
12012
|
addonId: string().min(1),
|
|
11875
12013
|
stableId: string().min(1)
|
|
11876
12014
|
});
|
|
12015
|
+
var GROUP_TEMPLATE_IDS = [
|
|
12016
|
+
"temperature",
|
|
12017
|
+
"humidity",
|
|
12018
|
+
"pressure",
|
|
12019
|
+
"illuminance",
|
|
12020
|
+
"power",
|
|
12021
|
+
"energy",
|
|
12022
|
+
"battery",
|
|
12023
|
+
"numeric",
|
|
12024
|
+
"motion",
|
|
12025
|
+
"contact",
|
|
12026
|
+
"leak",
|
|
12027
|
+
"smoke",
|
|
12028
|
+
"occupancy",
|
|
12029
|
+
"binary",
|
|
12030
|
+
"switch",
|
|
12031
|
+
"light",
|
|
12032
|
+
"fan",
|
|
12033
|
+
"cover",
|
|
12034
|
+
"valve",
|
|
12035
|
+
"lock",
|
|
12036
|
+
"media-player",
|
|
12037
|
+
"climate"
|
|
12038
|
+
];
|
|
12039
|
+
var NUMERIC_AGGREGATES = [
|
|
12040
|
+
"mean",
|
|
12041
|
+
"median",
|
|
12042
|
+
"min",
|
|
12043
|
+
"max",
|
|
12044
|
+
"sum"
|
|
12045
|
+
];
|
|
12046
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
12047
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
12048
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
12049
|
+
var AGGREGATE_REDUCERS = [
|
|
12050
|
+
"mean",
|
|
12051
|
+
"median",
|
|
12052
|
+
"min",
|
|
12053
|
+
"max",
|
|
12054
|
+
"sum",
|
|
12055
|
+
"any",
|
|
12056
|
+
"all"
|
|
12057
|
+
];
|
|
12058
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
12059
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
12060
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
12061
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
12062
|
+
var HelperMemberSchema = object({
|
|
12063
|
+
source: CompositionSourceRefSchema,
|
|
12064
|
+
cap: string().min(1),
|
|
12065
|
+
fieldPath: string().min(1)
|
|
12066
|
+
});
|
|
12067
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12068
|
+
object({
|
|
12069
|
+
kind: literal("group"),
|
|
12070
|
+
templateId: GroupTemplateIdSchema,
|
|
12071
|
+
aggregate: AggregateReducerSchema,
|
|
12072
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12073
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12074
|
+
active: ActiveCriterionSchema.optional()
|
|
12075
|
+
}),
|
|
12076
|
+
object({
|
|
12077
|
+
kind: literal("appliance"),
|
|
12078
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12079
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12080
|
+
thresholdWatts: number().positive(),
|
|
12081
|
+
startDwellMs: number().int().nonnegative(),
|
|
12082
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12083
|
+
member: HelperMemberSchema
|
|
12084
|
+
}),
|
|
12085
|
+
object({
|
|
12086
|
+
kind: literal("statistic"),
|
|
12087
|
+
stat: _enum(STATISTIC_STATS),
|
|
12088
|
+
window: StatisticWindowSchema,
|
|
12089
|
+
source: HelperMemberSchema
|
|
12090
|
+
}),
|
|
12091
|
+
object({
|
|
12092
|
+
kind: literal("integral"),
|
|
12093
|
+
reset: _enum(RESET_PERIODS),
|
|
12094
|
+
output: _enum(["energy", "meter"]),
|
|
12095
|
+
source: HelperMemberSchema
|
|
12096
|
+
}),
|
|
12097
|
+
object({
|
|
12098
|
+
kind: literal("threshold"),
|
|
12099
|
+
source: HelperMemberSchema,
|
|
12100
|
+
high: number(),
|
|
12101
|
+
low: number(),
|
|
12102
|
+
onForMs: number().int().nonnegative(),
|
|
12103
|
+
offForMs: number().int().nonnegative()
|
|
12104
|
+
}),
|
|
12105
|
+
object({
|
|
12106
|
+
kind: literal("arithmetic"),
|
|
12107
|
+
op: _enum([
|
|
12108
|
+
"sum",
|
|
12109
|
+
"difference",
|
|
12110
|
+
"ratio"
|
|
12111
|
+
]),
|
|
12112
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12113
|
+
}),
|
|
12114
|
+
object({
|
|
12115
|
+
kind: literal("expression"),
|
|
12116
|
+
expr: string().min(1),
|
|
12117
|
+
inputs: array(object({
|
|
12118
|
+
name: string().min(1),
|
|
12119
|
+
member: HelperMemberSchema
|
|
12120
|
+
})).min(1).max(64),
|
|
12121
|
+
output: _enum(["number", "boolean"])
|
|
12122
|
+
}),
|
|
12123
|
+
object({
|
|
12124
|
+
kind: literal("derivative"),
|
|
12125
|
+
window: RollingWindowSchema,
|
|
12126
|
+
per: _enum([
|
|
12127
|
+
"second",
|
|
12128
|
+
"minute",
|
|
12129
|
+
"hour"
|
|
12130
|
+
]),
|
|
12131
|
+
source: HelperMemberSchema
|
|
12132
|
+
})
|
|
12133
|
+
]);
|
|
12134
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12135
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12136
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12137
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11877
12138
|
/** One field of one capability of one source device. */
|
|
11878
12139
|
var CompositionFieldReadSchema = object({
|
|
11879
12140
|
source: CompositionSourceRefSchema,
|
|
@@ -11917,7 +12178,59 @@ var CompositionCodeSourceSchema = object({
|
|
|
11917
12178
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11918
12179
|
CompositionFromSourceSchema,
|
|
11919
12180
|
CompositionExpressionSourceSchema,
|
|
11920
|
-
CompositionCodeSourceSchema
|
|
12181
|
+
CompositionCodeSourceSchema,
|
|
12182
|
+
object({
|
|
12183
|
+
kind: literal("aggregate"),
|
|
12184
|
+
reducer: _enum([
|
|
12185
|
+
"mean",
|
|
12186
|
+
"median",
|
|
12187
|
+
"min",
|
|
12188
|
+
"max",
|
|
12189
|
+
"sum",
|
|
12190
|
+
"any",
|
|
12191
|
+
"all"
|
|
12192
|
+
]),
|
|
12193
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12194
|
+
/**
|
|
12195
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12196
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12197
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12198
|
+
*/
|
|
12199
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12200
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12201
|
+
publish: _enum([
|
|
12202
|
+
"value",
|
|
12203
|
+
"included",
|
|
12204
|
+
"excluded",
|
|
12205
|
+
"total"
|
|
12206
|
+
]),
|
|
12207
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12208
|
+
empty: _enum([
|
|
12209
|
+
"null",
|
|
12210
|
+
"omit",
|
|
12211
|
+
"offline"
|
|
12212
|
+
])
|
|
12213
|
+
}),
|
|
12214
|
+
object({
|
|
12215
|
+
kind: literal("series"),
|
|
12216
|
+
read: CompositionFieldReadSchema,
|
|
12217
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12218
|
+
publish: _enum([
|
|
12219
|
+
"value",
|
|
12220
|
+
"included",
|
|
12221
|
+
"excluded",
|
|
12222
|
+
"total"
|
|
12223
|
+
]),
|
|
12224
|
+
/**
|
|
12225
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12226
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12227
|
+
*/
|
|
12228
|
+
empty: _enum([
|
|
12229
|
+
"null",
|
|
12230
|
+
"omit",
|
|
12231
|
+
"offline"
|
|
12232
|
+
])
|
|
12233
|
+
})
|
|
11921
12234
|
]);
|
|
11922
12235
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11923
12236
|
kind: literal("forward"),
|
|
@@ -11963,7 +12276,13 @@ var CompositionSchema = object({
|
|
|
11963
12276
|
kind: literal("existing"),
|
|
11964
12277
|
device: CompositionSourceRefSchema
|
|
11965
12278
|
})]),
|
|
11966
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12279
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12280
|
+
/**
|
|
12281
|
+
* Present when the block is a helper template. Absent on a free
|
|
12282
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12283
|
+
* never the compiled features.
|
|
12284
|
+
*/
|
|
12285
|
+
helper: HelperSpecSchema.optional()
|
|
11967
12286
|
}).superRefine((composition, ctx) => {
|
|
11968
12287
|
const seen = /* @__PURE__ */ new Set();
|
|
11969
12288
|
composition.features.forEach((feature, index) => {
|
|
@@ -17206,7 +17525,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17206
17525
|
*/
|
|
17207
17526
|
interactiveConnectPath: string().min(1).optional(),
|
|
17208
17527
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17209
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
17528
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
17529
|
+
/**
|
|
17530
|
+
* The kind signs in through a server-held interactive session instead of
|
|
17531
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
17532
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
17533
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
17534
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
17535
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
17536
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
17537
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
17538
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
17539
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
17540
|
+
* offers it as the default path; the fields the session fills are
|
|
17541
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
17542
|
+
*/
|
|
17543
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17210
17544
|
}))
|
|
17211
17545
|
});
|
|
17212
17546
|
var ListInputSchema = object({
|
|
@@ -18250,7 +18584,12 @@ var CompositionProblemSchema = object({
|
|
|
18250
18584
|
"item-field-reserved",
|
|
18251
18585
|
"target-missing",
|
|
18252
18586
|
"target-unreadable",
|
|
18253
|
-
"not-replaceable"
|
|
18587
|
+
"not-replaceable",
|
|
18588
|
+
"native-capability-replace",
|
|
18589
|
+
"mixed-quantity",
|
|
18590
|
+
"helper-mismatch",
|
|
18591
|
+
"member-constraint",
|
|
18592
|
+
"retention"
|
|
18254
18593
|
]),
|
|
18255
18594
|
path: string(),
|
|
18256
18595
|
message: string()
|
|
@@ -18271,7 +18610,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18271
18610
|
"null",
|
|
18272
18611
|
"offline",
|
|
18273
18612
|
"unknown",
|
|
18274
|
-
"release"
|
|
18613
|
+
"release",
|
|
18614
|
+
"omit"
|
|
18275
18615
|
]);
|
|
18276
18616
|
/**
|
|
18277
18617
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18308,9 +18648,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18308
18648
|
reads: array(CompositionFieldReadSchema)
|
|
18309
18649
|
});
|
|
18310
18650
|
/**
|
|
18311
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18312
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18313
|
-
*
|
|
18651
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18652
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18653
|
+
* Replacing a capability the device already serves is refused
|
|
18654
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18655
|
+
* wire for a claim the hub already holds.
|
|
18314
18656
|
*/
|
|
18315
18657
|
var CompositionFeatureModeSchema = _enum([
|
|
18316
18658
|
"new",
|
|
@@ -18481,8 +18823,392 @@ Object.freeze({
|
|
|
18481
18823
|
latchedAt: {
|
|
18482
18824
|
kind: "fixed",
|
|
18483
18825
|
result: ["number", "null"]
|
|
18826
|
+
},
|
|
18827
|
+
schmitt: {
|
|
18828
|
+
kind: "fixed",
|
|
18829
|
+
result: ["boolean", "null"]
|
|
18484
18830
|
}
|
|
18485
18831
|
});
|
|
18832
|
+
/**
|
|
18833
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18834
|
+
* Data, not a form default written into the block.
|
|
18835
|
+
*/
|
|
18836
|
+
var NOW$2 = {
|
|
18837
|
+
fieldPath: "lastFetchedAt",
|
|
18838
|
+
expr: "now"
|
|
18839
|
+
};
|
|
18840
|
+
var CHANGED = {
|
|
18841
|
+
fieldPath: "lastChangedAt",
|
|
18842
|
+
expr: "now"
|
|
18843
|
+
};
|
|
18844
|
+
function numeric(input) {
|
|
18845
|
+
return {
|
|
18846
|
+
...input,
|
|
18847
|
+
family: "numeric",
|
|
18848
|
+
deviceType: DeviceType.Sensor,
|
|
18849
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18850
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18851
|
+
activeWhen: void 0,
|
|
18852
|
+
commandCaps: [],
|
|
18853
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18854
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18855
|
+
accept: [{
|
|
18856
|
+
cap: input.outputCap,
|
|
18857
|
+
fieldPath: input.outputField
|
|
18858
|
+
}]
|
|
18859
|
+
};
|
|
18860
|
+
}
|
|
18861
|
+
function binary(input) {
|
|
18862
|
+
return {
|
|
18863
|
+
...input,
|
|
18864
|
+
family: "binary",
|
|
18865
|
+
deviceType: DeviceType.Sensor,
|
|
18866
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18867
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
18868
|
+
activeWhen: void 0,
|
|
18869
|
+
commandCaps: [],
|
|
18870
|
+
quantity: "none",
|
|
18871
|
+
baseUnit: void 0,
|
|
18872
|
+
aggregates: BINARY_AGGREGATES,
|
|
18873
|
+
empty: "offline"
|
|
18874
|
+
};
|
|
18875
|
+
}
|
|
18876
|
+
var GROUP_TEMPLATES = [
|
|
18877
|
+
numeric({
|
|
18878
|
+
id: "temperature",
|
|
18879
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18880
|
+
role: DeviceRole.TemperatureSensor,
|
|
18881
|
+
outputCap: "temperature-sensor",
|
|
18882
|
+
outputField: "celsius",
|
|
18883
|
+
quantity: "temperature",
|
|
18884
|
+
defaultAggregate: "mean",
|
|
18885
|
+
empty: "null",
|
|
18886
|
+
companions: [NOW$2]
|
|
18887
|
+
}),
|
|
18888
|
+
numeric({
|
|
18889
|
+
id: "humidity",
|
|
18890
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18891
|
+
role: DeviceRole.HumiditySensor,
|
|
18892
|
+
outputCap: "humidity-sensor",
|
|
18893
|
+
outputField: "percent",
|
|
18894
|
+
quantity: "humidity",
|
|
18895
|
+
defaultAggregate: "mean",
|
|
18896
|
+
empty: "null",
|
|
18897
|
+
companions: [NOW$2]
|
|
18898
|
+
}),
|
|
18899
|
+
numeric({
|
|
18900
|
+
id: "pressure",
|
|
18901
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18902
|
+
role: DeviceRole.PressureSensor,
|
|
18903
|
+
outputCap: "pressure-sensor",
|
|
18904
|
+
outputField: "hpa",
|
|
18905
|
+
quantity: "pressure",
|
|
18906
|
+
defaultAggregate: "mean",
|
|
18907
|
+
empty: "null",
|
|
18908
|
+
companions: [NOW$2]
|
|
18909
|
+
}),
|
|
18910
|
+
numeric({
|
|
18911
|
+
id: "illuminance",
|
|
18912
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18913
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18914
|
+
outputCap: "ambient-light-sensor",
|
|
18915
|
+
outputField: "lux",
|
|
18916
|
+
quantity: "illuminance",
|
|
18917
|
+
defaultAggregate: "mean",
|
|
18918
|
+
empty: "null",
|
|
18919
|
+
companions: [NOW$2]
|
|
18920
|
+
}),
|
|
18921
|
+
numeric({
|
|
18922
|
+
id: "power",
|
|
18923
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18924
|
+
role: DeviceRole.PowerSensor,
|
|
18925
|
+
outputCap: "power-meter",
|
|
18926
|
+
outputField: "watts",
|
|
18927
|
+
quantity: "power",
|
|
18928
|
+
defaultAggregate: "sum",
|
|
18929
|
+
empty: "omit",
|
|
18930
|
+
companions: [NOW$2]
|
|
18931
|
+
}),
|
|
18932
|
+
numeric({
|
|
18933
|
+
id: "energy",
|
|
18934
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18935
|
+
role: DeviceRole.EnergySensor,
|
|
18936
|
+
outputCap: "power-meter",
|
|
18937
|
+
outputField: "kwhTotal",
|
|
18938
|
+
quantity: "energy",
|
|
18939
|
+
defaultAggregate: "sum",
|
|
18940
|
+
empty: "omit",
|
|
18941
|
+
companions: [NOW$2]
|
|
18942
|
+
}),
|
|
18943
|
+
numeric({
|
|
18944
|
+
id: "battery",
|
|
18945
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18946
|
+
role: DeviceRole.BatterySensor,
|
|
18947
|
+
outputCap: "battery",
|
|
18948
|
+
outputField: "percentage",
|
|
18949
|
+
quantity: "percentage",
|
|
18950
|
+
defaultAggregate: "mean",
|
|
18951
|
+
empty: "null",
|
|
18952
|
+
companions: [
|
|
18953
|
+
{
|
|
18954
|
+
fieldPath: "charging",
|
|
18955
|
+
expr: "\"unknown\""
|
|
18956
|
+
},
|
|
18957
|
+
{
|
|
18958
|
+
fieldPath: "sleeping",
|
|
18959
|
+
expr: "false"
|
|
18960
|
+
},
|
|
18961
|
+
{
|
|
18962
|
+
fieldPath: "lastUpdated",
|
|
18963
|
+
expr: "now"
|
|
18964
|
+
}
|
|
18965
|
+
]
|
|
18966
|
+
}),
|
|
18967
|
+
numeric({
|
|
18968
|
+
id: "numeric",
|
|
18969
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18970
|
+
role: DeviceRole.NumericSensor,
|
|
18971
|
+
outputCap: "numeric-sensor",
|
|
18972
|
+
outputField: "value",
|
|
18973
|
+
quantity: "device",
|
|
18974
|
+
defaultAggregate: "mean",
|
|
18975
|
+
empty: "null",
|
|
18976
|
+
companions: [NOW$2]
|
|
18977
|
+
}),
|
|
18978
|
+
binary({
|
|
18979
|
+
id: "motion",
|
|
18980
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18981
|
+
role: DeviceRole.MotionSensor,
|
|
18982
|
+
outputCap: "motion",
|
|
18983
|
+
outputField: "detected",
|
|
18984
|
+
defaultAggregate: "any",
|
|
18985
|
+
accept: [{
|
|
18986
|
+
cap: "motion",
|
|
18987
|
+
fieldPath: "detected"
|
|
18988
|
+
}],
|
|
18989
|
+
companions: [{
|
|
18990
|
+
fieldPath: "lastDetectedAt",
|
|
18991
|
+
expr: "null"
|
|
18992
|
+
}, {
|
|
18993
|
+
fieldPath: "autoClearAfterMs",
|
|
18994
|
+
expr: "null"
|
|
18995
|
+
}]
|
|
18996
|
+
}),
|
|
18997
|
+
binary({
|
|
18998
|
+
id: "contact",
|
|
18999
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
19000
|
+
role: DeviceRole.ContactSensor,
|
|
19001
|
+
outputCap: "contact",
|
|
19002
|
+
outputField: "entryOpen",
|
|
19003
|
+
defaultAggregate: "any",
|
|
19004
|
+
accept: [{
|
|
19005
|
+
cap: "contact",
|
|
19006
|
+
fieldPath: "entryOpen"
|
|
19007
|
+
}],
|
|
19008
|
+
companions: [CHANGED]
|
|
19009
|
+
}),
|
|
19010
|
+
binary({
|
|
19011
|
+
id: "leak",
|
|
19012
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
19013
|
+
role: DeviceRole.LeakSensor,
|
|
19014
|
+
outputCap: "flood",
|
|
19015
|
+
outputField: "flooded",
|
|
19016
|
+
defaultAggregate: "any",
|
|
19017
|
+
accept: [{
|
|
19018
|
+
cap: "flood",
|
|
19019
|
+
fieldPath: "flooded"
|
|
19020
|
+
}],
|
|
19021
|
+
companions: [CHANGED]
|
|
19022
|
+
}),
|
|
19023
|
+
binary({
|
|
19024
|
+
id: "smoke",
|
|
19025
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
19026
|
+
role: DeviceRole.SmokeSensor,
|
|
19027
|
+
outputCap: "smoke",
|
|
19028
|
+
outputField: "detected",
|
|
19029
|
+
defaultAggregate: "any",
|
|
19030
|
+
accept: [{
|
|
19031
|
+
cap: "smoke",
|
|
19032
|
+
fieldPath: "detected"
|
|
19033
|
+
}],
|
|
19034
|
+
companions: [CHANGED]
|
|
19035
|
+
}),
|
|
19036
|
+
binary({
|
|
19037
|
+
id: "occupancy",
|
|
19038
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
19039
|
+
role: DeviceRole.BinarySensor,
|
|
19040
|
+
outputCap: "binary",
|
|
19041
|
+
outputField: "on",
|
|
19042
|
+
defaultAggregate: "any",
|
|
19043
|
+
accept: [{
|
|
19044
|
+
cap: "motion",
|
|
19045
|
+
fieldPath: "detected"
|
|
19046
|
+
}, {
|
|
19047
|
+
cap: "binary",
|
|
19048
|
+
fieldPath: "on"
|
|
19049
|
+
}],
|
|
19050
|
+
companions: [CHANGED]
|
|
19051
|
+
}),
|
|
19052
|
+
binary({
|
|
19053
|
+
id: "binary",
|
|
19054
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
19055
|
+
role: DeviceRole.BinarySensor,
|
|
19056
|
+
outputCap: "binary",
|
|
19057
|
+
outputField: "on",
|
|
19058
|
+
defaultAggregate: "any",
|
|
19059
|
+
accept: [{
|
|
19060
|
+
cap: "binary",
|
|
19061
|
+
fieldPath: "on"
|
|
19062
|
+
}],
|
|
19063
|
+
companions: [CHANGED]
|
|
19064
|
+
}),
|
|
19065
|
+
actuator({
|
|
19066
|
+
id: "switch",
|
|
19067
|
+
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.",
|
|
19068
|
+
deviceType: DeviceType.Switch,
|
|
19069
|
+
outputCap: "switch",
|
|
19070
|
+
outputField: "on",
|
|
19071
|
+
member: {
|
|
19072
|
+
cap: "switch",
|
|
19073
|
+
fieldPath: "on"
|
|
19074
|
+
},
|
|
19075
|
+
commandCaps: ["switch"]
|
|
19076
|
+
}),
|
|
19077
|
+
actuator({
|
|
19078
|
+
id: "light",
|
|
19079
|
+
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.",
|
|
19080
|
+
deviceType: DeviceType.Light,
|
|
19081
|
+
outputCap: "switch",
|
|
19082
|
+
outputField: "on",
|
|
19083
|
+
member: {
|
|
19084
|
+
cap: "switch",
|
|
19085
|
+
fieldPath: "on"
|
|
19086
|
+
},
|
|
19087
|
+
commandCaps: [
|
|
19088
|
+
"switch",
|
|
19089
|
+
"brightness",
|
|
19090
|
+
"color"
|
|
19091
|
+
]
|
|
19092
|
+
}),
|
|
19093
|
+
actuator({
|
|
19094
|
+
id: "fan",
|
|
19095
|
+
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.",
|
|
19096
|
+
deviceType: DeviceType.Fan,
|
|
19097
|
+
outputCap: "switch",
|
|
19098
|
+
outputField: "on",
|
|
19099
|
+
member: {
|
|
19100
|
+
cap: "switch",
|
|
19101
|
+
fieldPath: "on"
|
|
19102
|
+
},
|
|
19103
|
+
commandCaps: ["switch", "fan-control"]
|
|
19104
|
+
}),
|
|
19105
|
+
actuator({
|
|
19106
|
+
id: "cover",
|
|
19107
|
+
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.",
|
|
19108
|
+
deviceType: DeviceType.Cover,
|
|
19109
|
+
outputCap: "group-active",
|
|
19110
|
+
outputField: "active",
|
|
19111
|
+
member: {
|
|
19112
|
+
cap: "cover",
|
|
19113
|
+
fieldPath: "state"
|
|
19114
|
+
},
|
|
19115
|
+
activeWhen: [
|
|
19116
|
+
"open",
|
|
19117
|
+
"opening",
|
|
19118
|
+
"stopped"
|
|
19119
|
+
],
|
|
19120
|
+
commandCaps: ["cover"]
|
|
19121
|
+
}),
|
|
19122
|
+
actuator({
|
|
19123
|
+
id: "valve",
|
|
19124
|
+
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.",
|
|
19125
|
+
deviceType: DeviceType.Valve,
|
|
19126
|
+
outputCap: "group-active",
|
|
19127
|
+
outputField: "active",
|
|
19128
|
+
member: {
|
|
19129
|
+
cap: "valve",
|
|
19130
|
+
fieldPath: "state"
|
|
19131
|
+
},
|
|
19132
|
+
activeWhen: [
|
|
19133
|
+
"open",
|
|
19134
|
+
"opening",
|
|
19135
|
+
"stopped"
|
|
19136
|
+
],
|
|
19137
|
+
commandCaps: ["valve"]
|
|
19138
|
+
}),
|
|
19139
|
+
actuator({
|
|
19140
|
+
id: "lock",
|
|
19141
|
+
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.",
|
|
19142
|
+
deviceType: DeviceType.Lock,
|
|
19143
|
+
outputCap: "group-active",
|
|
19144
|
+
outputField: "active",
|
|
19145
|
+
member: {
|
|
19146
|
+
cap: "lock-control",
|
|
19147
|
+
fieldPath: "state"
|
|
19148
|
+
},
|
|
19149
|
+
activeWhen: ["locked"],
|
|
19150
|
+
commandCaps: ["lock-control"]
|
|
19151
|
+
}),
|
|
19152
|
+
actuator({
|
|
19153
|
+
id: "media-player",
|
|
19154
|
+
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.",
|
|
19155
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19156
|
+
outputCap: "group-active",
|
|
19157
|
+
outputField: "active",
|
|
19158
|
+
member: {
|
|
19159
|
+
cap: "media-player",
|
|
19160
|
+
fieldPath: "state"
|
|
19161
|
+
},
|
|
19162
|
+
activeWhen: ["playing", "buffering"],
|
|
19163
|
+
commandCaps: ["media-player"]
|
|
19164
|
+
}),
|
|
19165
|
+
actuator({
|
|
19166
|
+
id: "climate",
|
|
19167
|
+
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.",
|
|
19168
|
+
deviceType: DeviceType.Thermostat,
|
|
19169
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
19170
|
+
outputCap: "group-active",
|
|
19171
|
+
outputField: "active",
|
|
19172
|
+
member: {
|
|
19173
|
+
cap: "climate-control",
|
|
19174
|
+
fieldPath: "mode"
|
|
19175
|
+
},
|
|
19176
|
+
activeWhen: [
|
|
19177
|
+
"heat",
|
|
19178
|
+
"cool",
|
|
19179
|
+
"auto",
|
|
19180
|
+
"heat_cool",
|
|
19181
|
+
"fan_only",
|
|
19182
|
+
"dry"
|
|
19183
|
+
],
|
|
19184
|
+
commandCaps: ["climate-control"]
|
|
19185
|
+
})
|
|
19186
|
+
];
|
|
19187
|
+
function actuator(input) {
|
|
19188
|
+
return {
|
|
19189
|
+
id: input.id,
|
|
19190
|
+
summary: input.summary,
|
|
19191
|
+
deviceType: input.deviceType,
|
|
19192
|
+
outputCap: input.outputCap,
|
|
19193
|
+
outputField: input.outputField,
|
|
19194
|
+
commandCaps: input.commandCaps,
|
|
19195
|
+
family: "actuator",
|
|
19196
|
+
role: void 0,
|
|
19197
|
+
memberDeviceType: input.deviceType,
|
|
19198
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
19199
|
+
activeWhen: input.activeWhen,
|
|
19200
|
+
quantity: "none",
|
|
19201
|
+
baseUnit: void 0,
|
|
19202
|
+
aggregates: BINARY_AGGREGATES,
|
|
19203
|
+
defaultAggregate: "any",
|
|
19204
|
+
empty: "offline",
|
|
19205
|
+
accept: [input.member],
|
|
19206
|
+
companions: [CHANGED]
|
|
19207
|
+
};
|
|
19208
|
+
}
|
|
19209
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19210
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
19211
|
+
DeviceType.Camera;
|
|
18486
19212
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18487
19213
|
/**
|
|
18488
19214
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20196,12 +20922,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
20196
20922
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20197
20923
|
* in-place so dispatch keeps working.
|
|
20198
20924
|
*
|
|
20199
|
-
* **
|
|
20200
|
-
*
|
|
20201
|
-
*
|
|
20202
|
-
*
|
|
20203
|
-
* (`ha-domain-mapping`)
|
|
20204
|
-
* stored after that point.
|
|
20925
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20926
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20927
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20928
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20929
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20930
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20205
20931
|
*
|
|
20206
20932
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20207
20933
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20215,6 +20941,14 @@ var SourceInfoSchema = object({
|
|
|
20215
20941
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20216
20942
|
* Used to detect rename when `id` changes. */
|
|
20217
20943
|
uniqueId: string().optional(),
|
|
20944
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20945
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20946
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20947
|
+
dateTimeShape: _enum([
|
|
20948
|
+
"date",
|
|
20949
|
+
"time",
|
|
20950
|
+
"datetime"
|
|
20951
|
+
]).optional(),
|
|
20218
20952
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20219
20953
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20220
20954
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41127,7 +41861,8 @@ method(object({
|
|
|
41127
41861
|
"enum"
|
|
41128
41862
|
]),
|
|
41129
41863
|
enumValues: array(string()).optional(),
|
|
41130
|
-
item: boolean().optional()
|
|
41864
|
+
item: boolean().optional(),
|
|
41865
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41131
41866
|
})).readonly(),
|
|
41132
41867
|
itemArray: object({
|
|
41133
41868
|
path: string(),
|
|
@@ -43488,7 +44223,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
43488
44223
|
});
|
|
43489
44224
|
/**
|
|
43490
44225
|
* Optional, richer endpoint shape returned by providers that expose
|
|
43491
|
-
* MORE than one ingress concurrently (Tailscale
|
|
44226
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
43492
44227
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
43493
44228
|
* the originating provider config (mode + sourcePort) so the
|
|
43494
44229
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44927,8 +45662,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44927
45662
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44928
45663
|
var MaskGridShapeSchema = object({
|
|
44929
45664
|
kind: literal("grid"),
|
|
44930
|
-
gridWidth: number(),
|
|
44931
|
-
gridHeight: number(),
|
|
45665
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45666
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44932
45667
|
cells: array(boolean())
|
|
44933
45668
|
});
|
|
44934
45669
|
discriminatedUnion("kind", [
|
|
@@ -45040,6 +45775,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
45040
45775
|
"detection-blind",
|
|
45041
45776
|
"motion-noisy",
|
|
45042
45777
|
"motion-calm",
|
|
45778
|
+
"package-llm-silent",
|
|
45779
|
+
"package-llm-answered",
|
|
45043
45780
|
"recording-stalled",
|
|
45044
45781
|
"recording-healthy",
|
|
45045
45782
|
"recording-degraded",
|
|
@@ -46129,7 +46866,20 @@ var NcRuleInputSchema = object({
|
|
|
46129
46866
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
46130
46867
|
* path does not run Zod defaults.
|
|
46131
46868
|
*/
|
|
46132
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
46869
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
46870
|
+
/**
|
|
46871
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
46872
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
46873
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
46874
|
+
* same mark the Library writes, and records whose notification it was and
|
|
46875
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
46876
|
+
*
|
|
46877
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
46878
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
46879
|
+
* authored before this field meant. An editor turns it off by writing
|
|
46880
|
+
* `false`, so it needs no `clear` key.
|
|
46881
|
+
*/
|
|
46882
|
+
askVerdict: boolean().optional()
|
|
46133
46883
|
});
|
|
46134
46884
|
/**
|
|
46135
46885
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -56067,6 +56817,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56067
56817
|
deprecated: string().optional(),
|
|
56068
56818
|
distTags: array(string()).readonly()
|
|
56069
56819
|
});
|
|
56820
|
+
/**
|
|
56821
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56822
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56823
|
+
* tarball failure — never an empty string standing in for either.
|
|
56824
|
+
*/
|
|
56825
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56826
|
+
object({
|
|
56827
|
+
status: literal("ok"),
|
|
56828
|
+
markdown: string()
|
|
56829
|
+
}),
|
|
56830
|
+
object({ status: literal("missing") }),
|
|
56831
|
+
object({
|
|
56832
|
+
status: literal("error"),
|
|
56833
|
+
message: string()
|
|
56834
|
+
})
|
|
56835
|
+
]);
|
|
56836
|
+
var PackageDocsSchema = object({
|
|
56837
|
+
name: string(),
|
|
56838
|
+
version: string(),
|
|
56839
|
+
readme: PackageDocBodySchema,
|
|
56840
|
+
changelog: PackageDocBodySchema
|
|
56841
|
+
});
|
|
56070
56842
|
var SearchResultSchema = object({
|
|
56071
56843
|
name: string(),
|
|
56072
56844
|
version: string(),
|
|
@@ -56285,7 +57057,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56285
57057
|
}), object({ success: literal(true) }), {
|
|
56286
57058
|
kind: "mutation",
|
|
56287
57059
|
auth: "admin"
|
|
56288
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57060
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
57061
|
+
name: string().min(1),
|
|
57062
|
+
version: string().min(1).optional()
|
|
57063
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56289
57064
|
kind: "mutation",
|
|
56290
57065
|
auth: "admin"
|
|
56291
57066
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56335,46 +57110,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56335
57110
|
}), LogStreamEntrySchema, { kind: "subscription" });
|
|
56336
57111
|
object({
|
|
56337
57112
|
/** Carbon dioxide concentration in ppm. */
|
|
56338
|
-
co2Ppm: number().min(0).optional(),
|
|
57113
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56339
57114
|
/** Total volatile organic compounds in ppb. */
|
|
56340
|
-
vocPpb: number().min(0).optional(),
|
|
57115
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56341
57116
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56342
|
-
pm25: number().min(0).optional(),
|
|
57117
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56343
57118
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56344
|
-
pm10: number().min(0).optional(),
|
|
57119
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56345
57120
|
/** Composite AQI value (typically 0..500). */
|
|
56346
|
-
aqi: number().optional(),
|
|
57121
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56347
57122
|
/** Ms epoch when the slice was last updated. */
|
|
56348
|
-
lastFetchedAt: number()
|
|
56349
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56350
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56351
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56352
|
-
* per slice is unambiguous. */
|
|
56353
|
-
unit: string().optional(),
|
|
56354
|
-
/** Suggested decimal places for numeric display.
|
|
56355
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56356
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56357
|
-
* auto-formatting when absent. */
|
|
56358
|
-
precision: number().int().min(0).max(10).optional()
|
|
57123
|
+
lastFetchedAt: number()
|
|
56359
57124
|
});
|
|
56360
57125
|
DeviceType.Sensor;
|
|
56361
57126
|
object({
|
|
56362
|
-
/** Current illuminance in lux (lx). */
|
|
56363
|
-
lux: number().min(0).meta({
|
|
56364
|
-
|
|
57127
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57128
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57129
|
+
precision: 0,
|
|
56365
57130
|
label: "Illuminance"
|
|
56366
|
-
}),
|
|
57131
|
+
})),
|
|
56367
57132
|
/** Ms epoch when the slice was last updated. */
|
|
56368
|
-
lastFetchedAt: number()
|
|
56369
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56370
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56371
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56372
|
-
unit: string().optional(),
|
|
56373
|
-
/** Suggested decimal places for numeric display.
|
|
56374
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56375
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56376
|
-
* auto-formatting when absent. */
|
|
56377
|
-
precision: number().int().min(0).max(10).optional()
|
|
57133
|
+
lastFetchedAt: number()
|
|
56378
57134
|
});
|
|
56379
57135
|
DeviceType.Sensor;
|
|
56380
57136
|
/**
|
|
@@ -56519,10 +57275,7 @@ var BatteryStatusSchema = object({
|
|
|
56519
57275
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56520
57276
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56521
57277
|
*/
|
|
56522
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56523
|
-
unit: "%",
|
|
56524
|
-
label: "Charge"
|
|
56525
|
-
}),
|
|
57278
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56526
57279
|
/**
|
|
56527
57280
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56528
57281
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56549,7 +57302,14 @@ var BatteryStatusSchema = object({
|
|
|
56549
57302
|
*/
|
|
56550
57303
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56551
57304
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56552
|
-
lastUpdated: number(),
|
|
57305
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57306
|
+
/**
|
|
57307
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57308
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57309
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57310
|
+
* `numeric-sensor` on the same device.
|
|
57311
|
+
*/
|
|
57312
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56553
57313
|
/**
|
|
56554
57314
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56555
57315
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56589,7 +57349,7 @@ var BatteryStatusSchema = object({
|
|
|
56589
57349
|
*/
|
|
56590
57350
|
binary: boolean().optional().meta({ label: "Binary indicator" })
|
|
56591
57351
|
});
|
|
56592
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
|
|
57352
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
|
|
56593
57353
|
method(object({
|
|
56594
57354
|
deviceId: number(),
|
|
56595
57355
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
@@ -56609,7 +57369,7 @@ object({
|
|
|
56609
57369
|
DeviceType.Sensor;
|
|
56610
57370
|
object({
|
|
56611
57371
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56612
|
-
percentage: number().min(0).max(100),
|
|
57372
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56613
57373
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56614
57374
|
lastChangedAt: number()
|
|
56615
57375
|
});
|
|
@@ -57004,21 +57764,21 @@ object({
|
|
|
57004
57764
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57005
57765
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57006
57766
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57007
|
-
target: number().nullable(),
|
|
57767
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57008
57768
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57009
57769
|
* in `heat_cool` mode. */
|
|
57010
|
-
targetHigh: number().nullable(),
|
|
57770
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57011
57771
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57012
57772
|
* in `heat_cool` mode. */
|
|
57013
|
-
targetLow: number().nullable(),
|
|
57773
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57014
57774
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57015
57775
|
* humidity control. */
|
|
57016
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57776
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57017
57777
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57018
57778
|
* the device's internal sensor. */
|
|
57019
|
-
currentTemp: number().nullable(),
|
|
57779
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57020
57780
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57021
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57781
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57022
57782
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57023
57783
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57024
57784
|
swingVertical: boolean().nullable(),
|
|
@@ -57026,11 +57786,11 @@ object({
|
|
|
57026
57786
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57027
57787
|
swingHorizontal: boolean().nullable(),
|
|
57028
57788
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57029
|
-
minTemp: number().nullable().optional(),
|
|
57789
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57030
57790
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57031
|
-
maxTemp: number().nullable().optional(),
|
|
57791
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57032
57792
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57033
|
-
tempStep: number().positive().nullable().optional(),
|
|
57793
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57034
57794
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57035
57795
|
lastFetchedAt: number()
|
|
57036
57796
|
});
|
|
@@ -57109,17 +57869,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
|
|
|
57109
57869
|
* modes to expose in the picker without a slice fetch.
|
|
57110
57870
|
*/
|
|
57111
57871
|
var RgbTripletSchema = object({
|
|
57112
|
-
r: number().int().min(0).max(255),
|
|
57113
|
-
g: number().int().min(0).max(255),
|
|
57114
|
-
b: number().int().min(0).max(255)
|
|
57872
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57873
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57874
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57115
57875
|
});
|
|
57116
57876
|
var HsvTripletSchema = object({
|
|
57117
57877
|
/** Hue in degrees, 0..360. */
|
|
57118
|
-
h: number().min(0).max(360),
|
|
57878
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57119
57879
|
/** Saturation as 0..100 inclusive. */
|
|
57120
|
-
s: number().min(0).max(100),
|
|
57880
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57121
57881
|
/** Value/brightness as 0..100 inclusive. */
|
|
57122
|
-
v: number().min(0).max(100)
|
|
57882
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57123
57883
|
});
|
|
57124
57884
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57125
57885
|
object({
|
|
@@ -57148,7 +57908,7 @@ object({
|
|
|
57148
57908
|
/** Populated when `mode === 'hsv'`. */
|
|
57149
57909
|
hsv: HsvTripletSchema.optional(),
|
|
57150
57910
|
/** Populated when `mode === 'mired'`. */
|
|
57151
|
-
mireds: number().int().optional(),
|
|
57911
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57152
57912
|
/** Ms epoch of the last operator-driven change. */
|
|
57153
57913
|
lastChangedAt: number()
|
|
57154
57914
|
});
|
|
@@ -57272,18 +58032,12 @@ _enum([
|
|
|
57272
58032
|
"empty",
|
|
57273
58033
|
"full"
|
|
57274
58034
|
]);
|
|
57275
|
-
/**
|
|
57276
|
-
|
|
57277
|
-
|
|
57278
|
-
"days",
|
|
57279
|
-
"hours",
|
|
57280
|
-
"cycles"
|
|
57281
|
-
]);
|
|
57282
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57283
|
-
* days). `value` null = unknown (D393). */
|
|
58035
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58036
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58037
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57284
58038
|
var ConsumableRemainingSchema = object({
|
|
57285
|
-
value: number().min(0).nullable(),
|
|
57286
|
-
|
|
58039
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58040
|
+
kind: ConsumableRemainingKindSchema
|
|
57287
58041
|
});
|
|
57288
58042
|
var ConsumablesStatusSchema = object({
|
|
57289
58043
|
items: array(object({
|
|
@@ -57292,7 +58046,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57292
58046
|
/** Display name. */
|
|
57293
58047
|
label: string().min(1),
|
|
57294
58048
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57295
|
-
level: number().min(0).max(100).nullable(),
|
|
58049
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57296
58050
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57297
58051
|
status: ConsumableStatusSchema.nullable(),
|
|
57298
58052
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57309,7 +58063,7 @@ var ConsumablesStatusSchema = object({
|
|
|
57309
58063
|
})),
|
|
57310
58064
|
lastChangedAt: number()
|
|
57311
58065
|
});
|
|
57312
|
-
Object.values(DeviceType), [...
|
|
58066
|
+
Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
|
|
57313
58067
|
Object.values(DeviceType), method(object({
|
|
57314
58068
|
deviceId: number().int().nonnegative(),
|
|
57315
58069
|
key: string().min(1)
|
|
@@ -57334,39 +58088,17 @@ object({
|
|
|
57334
58088
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
57335
58089
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
57336
58090
|
* or time-only — HA accepts all three forms). */
|
|
57337
|
-
value: union([number(), string()]),
|
|
58091
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
57338
58092
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
57339
58093
|
options: array(string()),
|
|
57340
58094
|
/** Ms epoch when the slice was last updated. */
|
|
57341
58095
|
lastChangedAt: number(),
|
|
57342
|
-
/**
|
|
57343
|
-
|
|
57344
|
-
|
|
57345
|
-
|
|
57346
|
-
/**
|
|
57347
|
-
|
|
57348
|
-
min: number().optional(),
|
|
57349
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
57350
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57351
|
-
max: number().optional(),
|
|
57352
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
57353
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
57354
|
-
step: number().optional(),
|
|
57355
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
57356
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
57357
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
57358
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
57359
|
-
precision: number().int().min(0).max(10).optional(),
|
|
57360
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
57361
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
57362
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
57363
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
57364
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
57365
|
-
format: _enum([
|
|
57366
|
-
"date",
|
|
57367
|
-
"time",
|
|
57368
|
-
"datetime"
|
|
57369
|
-
]).optional()
|
|
58096
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58097
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58098
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58099
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58100
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58101
|
+
step: number().optional().meta(readingMeta("device"))
|
|
57370
58102
|
});
|
|
57371
58103
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
57372
58104
|
object({
|
|
@@ -57404,9 +58136,9 @@ object({
|
|
|
57404
58136
|
]),
|
|
57405
58137
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
57406
58138
|
* no intermediate position surface. */
|
|
57407
|
-
position: number().min(0).max(100).nullable(),
|
|
58139
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57408
58140
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
57409
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58141
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57410
58142
|
/** Ms epoch when the slice was last updated. */
|
|
57411
58143
|
lastChangedAt: number()
|
|
57412
58144
|
});
|
|
@@ -57464,9 +58196,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
57464
58196
|
object({
|
|
57465
58197
|
mode: DayNightModeSchema,
|
|
57466
58198
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
57467
|
-
sensitivity: number().optional(),
|
|
58199
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
57468
58200
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
57469
|
-
switchDelaySec: number().optional(),
|
|
58201
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
57470
58202
|
lastFetchedAt: number()
|
|
57471
58203
|
});
|
|
57472
58204
|
/**
|
|
@@ -57621,11 +58353,11 @@ object({
|
|
|
57621
58353
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
57622
58354
|
availablePrograms: array(string()),
|
|
57623
58355
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
57624
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58356
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57625
58357
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
57626
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58358
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
57627
58359
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
57628
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58360
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57629
58361
|
/** True when the door is reported open; null when the door state is not known. */
|
|
57630
58362
|
doorOpen: boolean().nullable(),
|
|
57631
58363
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -57649,7 +58381,7 @@ object({
|
|
|
57649
58381
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
57650
58382
|
machineCareDue: boolean().nullable(),
|
|
57651
58383
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
57652
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58384
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
57653
58385
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
57654
58386
|
halfLoad: boolean().nullable(),
|
|
57655
58387
|
hygienePlus: boolean().nullable(),
|
|
@@ -57664,7 +58396,7 @@ object({
|
|
|
57664
58396
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
57665
58397
|
activeEvents: array(string()),
|
|
57666
58398
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
57667
|
-
errorCode: number().nullable(),
|
|
58399
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
57668
58400
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
57669
58401
|
errorLabel: string().nullable(),
|
|
57670
58402
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -57810,24 +58542,14 @@ object({
|
|
|
57810
58542
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
57811
58543
|
lastPressedAt: number().nullable(),
|
|
57812
58544
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
57813
|
-
pressCountSinceStart: number()
|
|
58545
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
57814
58546
|
});
|
|
57815
58547
|
object({
|
|
57816
58548
|
deviceId: number(),
|
|
57817
58549
|
timestamp: number()
|
|
57818
58550
|
});
|
|
57819
58551
|
DeviceType.Button, DeviceType.Camera;
|
|
57820
|
-
|
|
57821
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
57822
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
57823
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
57824
|
-
* The option set is stable across observations; it is persisted in the
|
|
57825
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
57826
|
-
* stored in `sourceInfo`.
|
|
57827
|
-
*/
|
|
57828
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
57829
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
57830
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58552
|
+
_enum([
|
|
57831
58553
|
"date",
|
|
57832
58554
|
"time",
|
|
57833
58555
|
"datetime"
|
|
@@ -57835,12 +58557,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
57835
58557
|
object({
|
|
57836
58558
|
value: string(),
|
|
57837
58559
|
/**
|
|
57838
|
-
* Set
|
|
57839
|
-
* as
|
|
57840
|
-
*
|
|
57841
|
-
* a time-only sensor → `'time'`.
|
|
58560
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58561
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58562
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
57842
58563
|
*/
|
|
57843
|
-
|
|
58564
|
+
timestamp: boolean().optional(),
|
|
57844
58565
|
/** Ms epoch when the slice was last updated. */
|
|
57845
58566
|
lastFetchedAt: number()
|
|
57846
58567
|
});
|
|
@@ -57859,13 +58580,13 @@ var EventFireSchema = object({
|
|
|
57859
58580
|
deviceId: number(),
|
|
57860
58581
|
eventType: string(),
|
|
57861
58582
|
data: record(string(), unknown()).nullable(),
|
|
57862
|
-
timestamp: number(),
|
|
57863
|
-
seq: number()
|
|
58583
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58584
|
+
seq: number().meta(readingMeta("count"))
|
|
57864
58585
|
});
|
|
57865
58586
|
object({
|
|
57866
58587
|
eventTypes: array(string()),
|
|
57867
58588
|
lastEvent: EventFireSchema.nullable(),
|
|
57868
|
-
eventCountSinceStart: number()
|
|
58589
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
57869
58590
|
});
|
|
57870
58591
|
DeviceType.EventEmitter;
|
|
57871
58592
|
var IdentitySchema = object({
|
|
@@ -58254,10 +58975,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
58254
58975
|
object({
|
|
58255
58976
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
58256
58977
|
* speed surface (single-speed fan). */
|
|
58257
|
-
percentage: number().min(0).max(100).nullable(),
|
|
58978
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58258
58979
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
58259
58980
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
58260
|
-
percentageStep: number().positive().optional(),
|
|
58981
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
58261
58982
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
58262
58983
|
* — empty string when no preset is active or supported. */
|
|
58263
58984
|
preset: string(),
|
|
@@ -58339,7 +59060,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
58339
59060
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
58340
59061
|
model: string().nullable(),
|
|
58341
59062
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
58342
|
-
channelCount: number().nullable(),
|
|
59063
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
58343
59064
|
/**
|
|
58344
59065
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
58345
59066
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -58371,9 +59092,45 @@ object({
|
|
|
58371
59092
|
lastChangedAt: number()
|
|
58372
59093
|
});
|
|
58373
59094
|
DeviceType.Sensor;
|
|
59095
|
+
object({
|
|
59096
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
59097
|
+
results: array(object({
|
|
59098
|
+
deviceId: number().int().nonnegative(),
|
|
59099
|
+
cap: string().min(1),
|
|
59100
|
+
method: string().min(1),
|
|
59101
|
+
ok: boolean(),
|
|
59102
|
+
error: string().optional(),
|
|
59103
|
+
/** Ms epoch of the attempt. */
|
|
59104
|
+
at: number()
|
|
59105
|
+
})) });
|
|
59106
|
+
DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
59107
|
+
object({
|
|
59108
|
+
active: boolean().meta({ label: "Active" }),
|
|
59109
|
+
/** Ms epoch when the slice was last updated. */
|
|
59110
|
+
lastChangedAt: number()
|
|
59111
|
+
});
|
|
59112
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
|
|
59113
|
+
object({
|
|
59114
|
+
/** Members whose current value entered the aggregate. */
|
|
59115
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
59116
|
+
precision: 0,
|
|
59117
|
+
label: "Reporting"
|
|
59118
|
+
})),
|
|
59119
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
59120
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
59121
|
+
precision: 0,
|
|
59122
|
+
label: "Excluded"
|
|
59123
|
+
})),
|
|
59124
|
+
/** `included` + `excluded`. */
|
|
59125
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
59126
|
+
precision: 0,
|
|
59127
|
+
label: "Members"
|
|
59128
|
+
}))
|
|
59129
|
+
});
|
|
59130
|
+
DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
|
|
58374
59131
|
object({
|
|
58375
59132
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
58376
|
-
position: number().min(0).max(100).nullable(),
|
|
59133
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58377
59134
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
58378
59135
|
lastFetchedAt: number()
|
|
58379
59136
|
});
|
|
@@ -58382,9 +59139,9 @@ object({
|
|
|
58382
59139
|
/** Whether the humidifier is currently on. */
|
|
58383
59140
|
on: boolean(),
|
|
58384
59141
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
58385
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59142
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58386
59143
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
58387
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59144
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58388
59145
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
58389
59146
|
* device has no mode surface. */
|
|
58390
59147
|
mode: string().nullable(),
|
|
@@ -58394,9 +59151,9 @@ object({
|
|
|
58394
59151
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
58395
59152
|
action: string().nullable(),
|
|
58396
59153
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
58397
|
-
minHumidity: number().nullable(),
|
|
59154
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58398
59155
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
58399
|
-
maxHumidity: number().nullable(),
|
|
59156
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
58400
59157
|
/** Ms epoch when the slice was last updated. */
|
|
58401
59158
|
lastChangedAt: number()
|
|
58402
59159
|
});
|
|
@@ -58420,22 +59177,13 @@ DeviceType.Humidifier, method(object({
|
|
|
58420
59177
|
auth: "protected"
|
|
58421
59178
|
});
|
|
58422
59179
|
object({
|
|
58423
|
-
/** Current relative humidity, 0..100. */
|
|
58424
|
-
percent: number().min(0).max(100).meta({
|
|
58425
|
-
|
|
59180
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59181
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59182
|
+
precision: 0,
|
|
58426
59183
|
label: "Humidity"
|
|
58427
|
-
}),
|
|
59184
|
+
})),
|
|
58428
59185
|
/** Ms epoch when the slice was last updated. */
|
|
58429
|
-
lastFetchedAt: number()
|
|
58430
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
58431
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
58432
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
58433
|
-
unit: string().optional(),
|
|
58434
|
-
/** Suggested decimal places for numeric display.
|
|
58435
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
58436
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
58437
|
-
* auto-formatting when absent. */
|
|
58438
|
-
precision: number().int().min(0).max(10).optional()
|
|
59186
|
+
lastFetchedAt: number()
|
|
58439
59187
|
});
|
|
58440
59188
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
58441
59189
|
object({
|
|
@@ -58443,7 +59191,7 @@ object({
|
|
|
58443
59191
|
* entity exposes no `entity_picture` (yet). */
|
|
58444
59192
|
url: string().nullable(),
|
|
58445
59193
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
58446
|
-
lastUpdated: number().nullable()
|
|
59194
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
58447
59195
|
});
|
|
58448
59196
|
DeviceType.Image;
|
|
58449
59197
|
/**
|
|
@@ -58499,19 +59247,19 @@ var NormalizedRangeSchema = object({
|
|
|
58499
59247
|
});
|
|
58500
59248
|
object({
|
|
58501
59249
|
/** Normalized 0–100. */
|
|
58502
|
-
brightness: number().optional(),
|
|
59250
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
58503
59251
|
/** Normalized 0–100. */
|
|
58504
|
-
contrast: number().optional(),
|
|
59252
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
58505
59253
|
/** Normalized 0–100. */
|
|
58506
|
-
saturation: number().optional(),
|
|
59254
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
58507
59255
|
/** Normalized 0–100. */
|
|
58508
|
-
sharpness: number().optional(),
|
|
59256
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
58509
59257
|
mirror: boolean().optional(),
|
|
58510
59258
|
flip: boolean().optional(),
|
|
58511
59259
|
rotate: ImageRotateSchema.optional(),
|
|
58512
59260
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
58513
59261
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
58514
|
-
warmth: number().optional(),
|
|
59262
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
58515
59263
|
exposureMode: ExposureModeSchema.optional(),
|
|
58516
59264
|
backlightMode: BacklightModeSchema.optional(),
|
|
58517
59265
|
lastFetchedAt: number()
|
|
@@ -58756,10 +59504,10 @@ var IntercomAbilitySchema = object({
|
|
|
58756
59504
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
58757
59505
|
codecs: array(string()),
|
|
58758
59506
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
58759
|
-
sampleRate: number(),
|
|
59507
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
58760
59508
|
duplex: _enum(["half", "full"]),
|
|
58761
59509
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
58762
|
-
maxBacklogMs: number()
|
|
59510
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
58763
59511
|
});
|
|
58764
59512
|
var IntercomStatusSchema = object({
|
|
58765
59513
|
/** True while a talk session is open. */
|
|
@@ -58870,13 +59618,13 @@ object({
|
|
|
58870
59618
|
activity: LawnMowerActivitySchema,
|
|
58871
59619
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
58872
59620
|
* reading. */
|
|
58873
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
59621
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58874
59622
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
58875
59623
|
* task is active / progress is unavailable. */
|
|
58876
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59624
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58877
59625
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
58878
59626
|
* or null when unknown. */
|
|
58879
|
-
currentCode: number().nullable(),
|
|
59627
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
58880
59628
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
58881
59629
|
currentCodeLabel: string().nullable(),
|
|
58882
59630
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -59286,7 +60034,14 @@ DeviceType.Lock, method(object({
|
|
|
59286
60034
|
auth: "protected"
|
|
59287
60035
|
}), method(object({
|
|
59288
60036
|
deviceId: number().int().nonnegative(),
|
|
59289
|
-
code: string().min(1).optional()
|
|
60037
|
+
code: string().min(1).optional(),
|
|
60038
|
+
/**
|
|
60039
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
60040
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
60041
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
60042
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
60043
|
+
*/
|
|
60044
|
+
confirm: boolean().optional()
|
|
59290
60045
|
}), _void(), {
|
|
59291
60046
|
kind: "mutation",
|
|
59292
60047
|
auth: "protected"
|
|
@@ -59294,6 +60049,11 @@ DeviceType.Lock, method(object({
|
|
|
59294
60049
|
kind: "mutation",
|
|
59295
60050
|
auth: "protected"
|
|
59296
60051
|
});
|
|
60052
|
+
object({
|
|
60053
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
60054
|
+
lastFetchedAt: number()
|
|
60055
|
+
});
|
|
60056
|
+
DeviceType.Sensor;
|
|
59297
60057
|
/**
|
|
59298
60058
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
59299
60059
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
@@ -59338,7 +60098,7 @@ object({
|
|
|
59338
60098
|
state: MediaPlayerStateSchema,
|
|
59339
60099
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
59340
60100
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
59341
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
60101
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59342
60102
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
59343
60103
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
59344
60104
|
isMuted: boolean().nullable(),
|
|
@@ -59351,10 +60111,10 @@ object({
|
|
|
59351
60111
|
currentMedia: MediaInfoSchema.nullable(),
|
|
59352
60112
|
/** Current playback position in ms. Null when not seekable or
|
|
59353
60113
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
59354
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
60114
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59355
60115
|
/** Total duration of the current media in ms. Null when unknown
|
|
59356
60116
|
* (live stream) or nothing is playing. */
|
|
59357
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
60117
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
59358
60118
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
59359
60119
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
59360
60120
|
shuffle: boolean().nullable(),
|
|
@@ -59654,7 +60414,7 @@ object({
|
|
|
59654
60414
|
* it, every provider seeded it at boot, and every session left it
|
|
59655
60415
|
* `detected: true` after its detach.
|
|
59656
60416
|
*/
|
|
59657
|
-
autoClearAfterMs: number().nullable()
|
|
60417
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
59658
60418
|
});
|
|
59659
60419
|
/**
|
|
59660
60420
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -59704,7 +60464,7 @@ var MotionZoneRegionSchema = object({
|
|
|
59704
60464
|
});
|
|
59705
60465
|
object({
|
|
59706
60466
|
enabled: boolean(),
|
|
59707
|
-
sensitivity: number(),
|
|
60467
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
59708
60468
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
59709
60469
|
regions: array(MotionZoneRegionSchema),
|
|
59710
60470
|
lastFetchedAt: number()
|
|
@@ -60008,7 +60768,7 @@ var NavigationStatusSchema = object({
|
|
|
60008
60768
|
following: boolean(),
|
|
60009
60769
|
flash: boolean(),
|
|
60010
60770
|
lightMode: NavigationLightModeSchema,
|
|
60011
|
-
lightLevel: number().min(40).max(100),
|
|
60771
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
60012
60772
|
/** Ms epoch when the slice was last updated. */
|
|
60013
60773
|
lastChangedAt: number()
|
|
60014
60774
|
});
|
|
@@ -60054,13 +60814,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
60054
60814
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
60055
60815
|
* SKIP a null rather than coerce it.
|
|
60056
60816
|
*/
|
|
60057
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
60817
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60058
60818
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
60059
|
-
rssiDbm: number().optional(),
|
|
60819
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
60060
60820
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
60061
60821
|
ssid: string().optional(),
|
|
60062
60822
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
60063
|
-
lastUpdated: number()
|
|
60823
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
60064
60824
|
});
|
|
60065
60825
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
|
|
60066
60826
|
deviceId: number(),
|
|
@@ -60379,7 +61139,7 @@ object({
|
|
|
60379
61139
|
lastError: string().nullable(),
|
|
60380
61140
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
60381
61141
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
60382
|
-
queueDepth: number().int().nonnegative(),
|
|
61142
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
60383
61143
|
/** Per-feature capability matrix — authoritative source for the
|
|
60384
61144
|
* compose-form field gating. */
|
|
60385
61145
|
supports: NotifierSupportsSchema
|
|
@@ -60429,15 +61189,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
|
|
|
60429
61189
|
acceptedAt: number()
|
|
60430
61190
|
});
|
|
60431
61191
|
object({
|
|
60432
|
-
|
|
60433
|
-
|
|
60434
|
-
* Populated live from the upstream source on each state push.
|
|
60435
|
-
* Absent for unitless sensors. */
|
|
60436
|
-
unit: string().optional(),
|
|
60437
|
-
/** Suggested decimal places for numeric display.
|
|
60438
|
-
* Populated live from the upstream source when provided.
|
|
60439
|
-
* Falls back to auto-formatting when absent. */
|
|
60440
|
-
precision: number().int().min(0).max(10).optional(),
|
|
61192
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
61193
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
60441
61194
|
/** Ms epoch when the slice was last updated. */
|
|
60442
61195
|
lastFetchedAt: number()
|
|
60443
61196
|
});
|
|
@@ -60727,23 +61480,26 @@ object({
|
|
|
60727
61480
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
60728
61481
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
60729
61482
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
60730
|
-
foodLevel: number().nullable(),
|
|
61483
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
60731
61484
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
60732
61485
|
* single-hopper models. */
|
|
60733
|
-
food1: number().nullable(),
|
|
61486
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
60734
61487
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
60735
61488
|
* single-hopper models. */
|
|
60736
|
-
food2: number().nullable(),
|
|
61489
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
60737
61490
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
60738
61491
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
60739
61492
|
* below the feeder's low threshold. */
|
|
60740
61493
|
lowFood: boolean(),
|
|
60741
61494
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
60742
61495
|
* device has no battery reading. */
|
|
60743
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
60744
|
-
/**
|
|
60745
|
-
*
|
|
60746
|
-
|
|
61496
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61497
|
+
/**
|
|
61498
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
61499
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
61500
|
+
* model has no desiccant sensor.
|
|
61501
|
+
*/
|
|
61502
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
60747
61503
|
/** True while a feed is in progress. */
|
|
60748
61504
|
feeding: boolean(),
|
|
60749
61505
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -60754,7 +61510,7 @@ object({
|
|
|
60754
61510
|
* with `errorCode` for consumers that want the raw integer. */
|
|
60755
61511
|
error: string().nullable(),
|
|
60756
61512
|
/** Raw device error code (0 / null = no error). */
|
|
60757
|
-
errorCode: number().nullable(),
|
|
61513
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
60758
61514
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
60759
61515
|
isDualHopper: boolean(),
|
|
60760
61516
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -60764,7 +61520,7 @@ object({
|
|
|
60764
61520
|
/** Play a chime when dispensing. */
|
|
60765
61521
|
feedSound: boolean(),
|
|
60766
61522
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
60767
|
-
volume: number(),
|
|
61523
|
+
volume: number().meta(readingMeta("none")),
|
|
60768
61524
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
60769
61525
|
lastFetchedAt: number()
|
|
60770
61526
|
});
|
|
@@ -61201,38 +61957,37 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
61201
61957
|
});
|
|
61202
61958
|
object({
|
|
61203
61959
|
/** Instantaneous power draw in watts. */
|
|
61204
|
-
watts: number().optional().meta({
|
|
61205
|
-
unit: "W",
|
|
61206
|
-
label: "Power"
|
|
61207
|
-
}),
|
|
61960
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
61208
61961
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
61209
|
-
kwhTotal: number().optional().meta({
|
|
61210
|
-
unit: "kWh",
|
|
61211
|
-
label: "Energy"
|
|
61212
|
-
}),
|
|
61962
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
61213
61963
|
/** Voltage in volts. */
|
|
61214
|
-
volts: number().optional(),
|
|
61964
|
+
volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
61215
61965
|
/** Current in amperes. */
|
|
61216
|
-
amps: number().optional(),
|
|
61217
|
-
/** Apparent power in volt-amperes
|
|
61218
|
-
va: number().optional(),
|
|
61966
|
+
amps: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
61967
|
+
/** Apparent power in volt-amperes. */
|
|
61968
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
61219
61969
|
/** Power factor (0..1) if reported. */
|
|
61220
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
61970
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
61221
61971
|
/** Ms epoch when the slice was last updated. */
|
|
61222
|
-
lastFetchedAt: number()
|
|
61223
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
61224
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
61225
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
61226
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
61227
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
61228
|
-
unit: string().optional(),
|
|
61229
|
-
/** Suggested decimal places for numeric display.
|
|
61230
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61231
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61232
|
-
* auto-formatting when absent. */
|
|
61233
|
-
precision: number().int().min(0).max(10).optional()
|
|
61972
|
+
lastFetchedAt: number()
|
|
61234
61973
|
});
|
|
61235
|
-
|
|
61974
|
+
[
|
|
61975
|
+
DeviceType.Sensor,
|
|
61976
|
+
DeviceType.Switch,
|
|
61977
|
+
DeviceType.Light,
|
|
61978
|
+
DeviceType.Fan,
|
|
61979
|
+
DeviceType.Climate,
|
|
61980
|
+
DeviceType.Thermostat,
|
|
61981
|
+
DeviceType.Humidifier,
|
|
61982
|
+
DeviceType.WaterHeater,
|
|
61983
|
+
DeviceType.MediaPlayer,
|
|
61984
|
+
DeviceType.Washer,
|
|
61985
|
+
DeviceType.Dryer,
|
|
61986
|
+
DeviceType.Dishwasher,
|
|
61987
|
+
DeviceType.Vacuum,
|
|
61988
|
+
DeviceType.LawnMower,
|
|
61989
|
+
DeviceType.PetFeeder
|
|
61990
|
+
].filter((type) => type !== DeviceType.Sensor);
|
|
61236
61991
|
/**
|
|
61237
61992
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
61238
61993
|
* on `DeviceType.Presence`. Read-only — no setters: presence is
|
|
@@ -61251,11 +62006,11 @@ DeviceType.Sensor;
|
|
|
61251
62006
|
*/
|
|
61252
62007
|
var GpsLocationSchema = object({
|
|
61253
62008
|
/** Latitude in decimal degrees, -90..90. */
|
|
61254
|
-
latitude: number().min(-90).max(90),
|
|
62009
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
61255
62010
|
/** Longitude in decimal degrees, -180..180. */
|
|
61256
|
-
longitude: number().min(-180).max(180),
|
|
62011
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
61257
62012
|
/** Reported accuracy in meters (lower = better). */
|
|
61258
|
-
accuracyMeters: number().nonnegative()
|
|
62013
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
61259
62014
|
});
|
|
61260
62015
|
object({
|
|
61261
62016
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -61267,25 +62022,16 @@ object({
|
|
|
61267
62022
|
gps: GpsLocationSchema.nullable(),
|
|
61268
62023
|
/** Optional battery level of the tracking device (0..100). Null
|
|
61269
62024
|
* when not reported. */
|
|
61270
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
62025
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61271
62026
|
/** Ms epoch when the slice was last updated. */
|
|
61272
62027
|
lastChangedAt: number()
|
|
61273
62028
|
});
|
|
61274
62029
|
DeviceType.Presence;
|
|
61275
62030
|
object({
|
|
61276
|
-
/** Current pressure in hPa. */
|
|
61277
|
-
hpa: number(),
|
|
62031
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
62032
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
61278
62033
|
/** Ms epoch when the slice was last updated. */
|
|
61279
|
-
lastFetchedAt: number()
|
|
61280
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
61281
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
61282
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
61283
|
-
unit: string().optional(),
|
|
61284
|
-
/** Suggested decimal places for numeric display.
|
|
61285
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
61286
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
61287
|
-
* auto-formatting when absent. */
|
|
61288
|
-
precision: number().int().min(0).max(10).optional()
|
|
62034
|
+
lastFetchedAt: number()
|
|
61289
62035
|
});
|
|
61290
62036
|
DeviceType.Sensor;
|
|
61291
62037
|
/**
|
|
@@ -61618,8 +62364,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
61618
62364
|
}), _void(), { kind: "mutation" });
|
|
61619
62365
|
var PtzAutotrackSettingsSchema = object({
|
|
61620
62366
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
61621
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
61622
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
62367
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
62368
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
61623
62369
|
});
|
|
61624
62370
|
/**
|
|
61625
62371
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -61676,7 +62422,7 @@ object({
|
|
|
61676
62422
|
/** null = unknown — never coerced to false (D393). */
|
|
61677
62423
|
running: boolean().nullable(),
|
|
61678
62424
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
61679
|
-
since: number().nullable(),
|
|
62425
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
61680
62426
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
61681
62427
|
phase: string().nullable(),
|
|
61682
62428
|
/** null until a reading has been published (D393). */
|
|
@@ -61688,7 +62434,7 @@ object({
|
|
|
61688
62434
|
phase: string().nullable()
|
|
61689
62435
|
});
|
|
61690
62436
|
Object.values(DeviceType);
|
|
61691
|
-
DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
62437
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
|
|
61692
62438
|
DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
|
|
61693
62439
|
kind: "mutation",
|
|
61694
62440
|
auth: "admin"
|
|
@@ -62874,9 +63620,9 @@ var RecordTriggerSchema = _enum([
|
|
|
62874
63620
|
*/
|
|
62875
63621
|
var RecordWindowSchema = object({
|
|
62876
63622
|
trigger: RecordTriggerSchema,
|
|
62877
|
-
day: number().int().min(0).max(6),
|
|
62878
|
-
startMinute: number().int().min(0).max(1439),
|
|
62879
|
-
endMinute: number().int().min(1).max(1440)
|
|
63623
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
63624
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
63625
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
62880
63626
|
});
|
|
62881
63627
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
62882
63628
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -62945,10 +63691,10 @@ object({
|
|
|
62945
63691
|
/** Master "record to the card at all" switch. */
|
|
62946
63692
|
enabled: boolean().nullable(),
|
|
62947
63693
|
overwriteWhenFull: boolean().nullable(),
|
|
62948
|
-
preRecordSec: number().nullable(),
|
|
62949
|
-
postRecordSec: number().nullable(),
|
|
63694
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
63695
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
62950
63696
|
/** Length of one recorded file, in minutes. */
|
|
62951
|
-
segmentMinutes: number().nullable(),
|
|
63697
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
62952
63698
|
/** The primary track's weekly windows, flattened. */
|
|
62953
63699
|
windows: array(RecordWindowSchema),
|
|
62954
63700
|
/**
|
|
@@ -62964,7 +63710,7 @@ object({
|
|
|
62964
63710
|
* provider reporting a non-zero count also reports the schedule as not
|
|
62965
63711
|
* writable.
|
|
62966
63712
|
*/
|
|
62967
|
-
unreadableWindows: number(),
|
|
63713
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
62968
63714
|
/**
|
|
62969
63715
|
* The camera is scheduled to record and has NO usable storage.
|
|
62970
63716
|
*
|
|
@@ -63601,7 +64347,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
63601
64347
|
url: string().optional(),
|
|
63602
64348
|
codec: string().optional(),
|
|
63603
64349
|
resolution: CamStreamResolutionSchema.optional(),
|
|
63604
|
-
fps: number().positive().optional(),
|
|
64350
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
63605
64351
|
label: string().optional(),
|
|
63606
64352
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
63607
64353
|
deviceFeatures: array(string()).optional(),
|
|
@@ -63631,18 +64377,18 @@ var StreamProfileSchema = _enum([
|
|
|
63631
64377
|
]);
|
|
63632
64378
|
/** The current encoding config of one stream profile. */
|
|
63633
64379
|
var StreamProfileConfigSchema = object({
|
|
63634
|
-
width: number(),
|
|
63635
|
-
height: number(),
|
|
64380
|
+
width: number().meta(readingMeta("none")),
|
|
64381
|
+
height: number().meta(readingMeta("none")),
|
|
63636
64382
|
codec: _enum(["h264", "h265"]),
|
|
63637
|
-
framerate: number(),
|
|
63638
|
-
bitrate: number(),
|
|
64383
|
+
framerate: number().meta(readingMeta("rate")),
|
|
64384
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
63639
64385
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
63640
64386
|
encoderProfile: _enum([
|
|
63641
64387
|
"high",
|
|
63642
64388
|
"main",
|
|
63643
64389
|
"baseline"
|
|
63644
64390
|
]).optional(),
|
|
63645
|
-
gop: number().optional(),
|
|
64391
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
63646
64392
|
/**
|
|
63647
64393
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
63648
64394
|
*
|
|
@@ -63727,7 +64473,7 @@ object({
|
|
|
63727
64473
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
63728
64474
|
lastChangedAt: number()
|
|
63729
64475
|
});
|
|
63730
|
-
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
|
|
64476
|
+
DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
|
|
63731
64477
|
deviceId: number(),
|
|
63732
64478
|
on: boolean()
|
|
63733
64479
|
}), _void(), {
|
|
@@ -64285,23 +65031,13 @@ object({
|
|
|
64285
65031
|
});
|
|
64286
65032
|
DeviceType.Sensor;
|
|
64287
65033
|
object({
|
|
64288
|
-
/** Current temperature in Celsius. */
|
|
64289
|
-
celsius: number().meta({
|
|
64290
|
-
|
|
65034
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
65035
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
65036
|
+
precision: 1,
|
|
64291
65037
|
label: "Temperature"
|
|
64292
|
-
}),
|
|
65038
|
+
})),
|
|
64293
65039
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
64294
|
-
lastFetchedAt: number()
|
|
64295
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64296
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64297
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
64298
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
64299
|
-
unit: string().optional(),
|
|
64300
|
-
/** Suggested decimal places for numeric display.
|
|
64301
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64302
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64303
|
-
* auto-formatting when absent. */
|
|
64304
|
-
precision: number().int().min(0).max(10).optional()
|
|
65040
|
+
lastFetchedAt: number()
|
|
64305
65041
|
});
|
|
64306
65042
|
DeviceType.Sensor, DeviceType.Thermostat;
|
|
64307
65043
|
/**
|
|
@@ -64553,16 +65289,16 @@ object({
|
|
|
64553
65289
|
]),
|
|
64554
65290
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64555
65291
|
* reading. */
|
|
64556
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
65292
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64557
65293
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
64558
65294
|
* the vacuum has no speed control. */
|
|
64559
65295
|
fanSpeed: string().nullable(),
|
|
64560
65296
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64561
65297
|
availableFanSpeeds: array(string()),
|
|
64562
65298
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64563
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
65299
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64564
65300
|
/** Current error code (0 / null = no error). */
|
|
64565
|
-
errorCode: number().nullable(),
|
|
65301
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
64566
65302
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
64567
65303
|
errorLabel: string().nullable(),
|
|
64568
65304
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -64601,7 +65337,7 @@ object({
|
|
|
64601
65337
|
]),
|
|
64602
65338
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
64603
65339
|
* intermediate position surface. */
|
|
64604
|
-
position: number().min(0).max(100).nullable(),
|
|
65340
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64605
65341
|
/** Ms epoch when the slice was last updated. */
|
|
64606
65342
|
lastChangedAt: number()
|
|
64607
65343
|
});
|
|
@@ -64629,9 +65365,9 @@ object({
|
|
|
64629
65365
|
DeviceType.Sensor;
|
|
64630
65366
|
object({
|
|
64631
65367
|
/** Current measured temperature. Null when not reported. */
|
|
64632
|
-
currentTemp: number().nullable(),
|
|
65368
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64633
65369
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
64634
|
-
targetTemp: number().nullable(),
|
|
65370
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64635
65371
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
64636
65372
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
64637
65373
|
* device reports an unknown state. */
|
|
@@ -64642,9 +65378,9 @@ object({
|
|
|
64642
65378
|
* has no away surface. */
|
|
64643
65379
|
away: boolean().nullable(),
|
|
64644
65380
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
64645
|
-
minTemp: number().nullable(),
|
|
65381
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64646
65382
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
64647
|
-
maxTemp: number().nullable(),
|
|
65383
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
64648
65384
|
/** Ms epoch when the slice was last updated. */
|
|
64649
65385
|
lastChangedAt: number()
|
|
64650
65386
|
});
|
|
@@ -64668,25 +65404,18 @@ DeviceType.WaterHeater, method(object({
|
|
|
64668
65404
|
auth: "protected"
|
|
64669
65405
|
});
|
|
64670
65406
|
object({
|
|
64671
|
-
/** Verbatim
|
|
64672
|
-
* when no condition has been reported yet. */
|
|
65407
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
64673
65408
|
condition: string().nullable(),
|
|
64674
|
-
/** Current temperature in
|
|
64675
|
-
temperature: number().nullable(),
|
|
64676
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
64677
|
-
temperatureUnit: string().nullable(),
|
|
65409
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
65410
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
64678
65411
|
/** Relative humidity (0..100). Null when not provided. */
|
|
64679
|
-
humidity: number().min(0).max(100).nullable(),
|
|
64680
|
-
/** Barometric pressure in
|
|
64681
|
-
pressure: number().nullable(),
|
|
64682
|
-
/**
|
|
64683
|
-
|
|
64684
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
64685
|
-
windSpeed: number().nullable(),
|
|
64686
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
64687
|
-
windSpeedUnit: string().nullable(),
|
|
65412
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65413
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
65414
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
65415
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
65416
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
64688
65417
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
64689
|
-
windBearing: number().nullable(),
|
|
65418
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
64690
65419
|
/** Ms epoch when the slice was last updated. */
|
|
64691
65420
|
lastFetchedAt: number()
|
|
64692
65421
|
});
|
|
@@ -65436,8 +66165,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
65436
66165
|
kind: "mutation",
|
|
65437
66166
|
auth: "admin"
|
|
65438
66167
|
});
|
|
66168
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
65439
66169
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
65440
|
-
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;
|
|
66170
|
+
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;
|
|
65441
66171
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
65442
66172
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
65443
66173
|
new Set(CAP_NAMES);
|
|
@@ -65490,7 +66220,7 @@ var AccessoryKind = {
|
|
|
65490
66220
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
65491
66221
|
};
|
|
65492
66222
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
65493
|
-
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;
|
|
66223
|
+
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;
|
|
65494
66224
|
new Set(Object.values(DeviceType));
|
|
65495
66225
|
Object.freeze({
|
|
65496
66226
|
"accessories.getStatus": {
|
|
@@ -65598,6 +66328,13 @@ Object.freeze({
|
|
|
65598
66328
|
access: "view",
|
|
65599
66329
|
role: "admin"
|
|
65600
66330
|
},
|
|
66331
|
+
"addons.getPackageDocs": {
|
|
66332
|
+
capName: "addons",
|
|
66333
|
+
capScope: "system",
|
|
66334
|
+
addonId: null,
|
|
66335
|
+
access: "view",
|
|
66336
|
+
role: "admin"
|
|
66337
|
+
},
|
|
65601
66338
|
"addons.getVersions": {
|
|
65602
66339
|
capName: "addons",
|
|
65603
66340
|
capScope: "system",
|
|
@@ -68706,6 +69443,27 @@ Object.freeze({
|
|
|
68706
69443
|
access: "view",
|
|
68707
69444
|
role: "viewer"
|
|
68708
69445
|
},
|
|
69446
|
+
"groupActive.getStatus": {
|
|
69447
|
+
capName: "group-active",
|
|
69448
|
+
capScope: "device",
|
|
69449
|
+
addonId: null,
|
|
69450
|
+
access: "view",
|
|
69451
|
+
role: "viewer"
|
|
69452
|
+
},
|
|
69453
|
+
"groupCommands.getStatus": {
|
|
69454
|
+
capName: "group-commands",
|
|
69455
|
+
capScope: "device",
|
|
69456
|
+
addonId: null,
|
|
69457
|
+
access: "view",
|
|
69458
|
+
role: "viewer"
|
|
69459
|
+
},
|
|
69460
|
+
"groupStatus.getStatus": {
|
|
69461
|
+
capName: "group-status",
|
|
69462
|
+
capScope: "device",
|
|
69463
|
+
addonId: null,
|
|
69464
|
+
access: "view",
|
|
69465
|
+
role: "viewer"
|
|
69466
|
+
},
|
|
68709
69467
|
"heatingValve.getStatus": {
|
|
68710
69468
|
capName: "heating-valve",
|
|
68711
69469
|
capScope: "device",
|
|
@@ -69658,6 +70416,13 @@ Object.freeze({
|
|
|
69658
70416
|
access: "create",
|
|
69659
70417
|
role: "admin"
|
|
69660
70418
|
},
|
|
70419
|
+
"meter.getStatus": {
|
|
70420
|
+
capName: "meter",
|
|
70421
|
+
capScope: "device",
|
|
70422
|
+
addonId: null,
|
|
70423
|
+
access: "view",
|
|
70424
|
+
role: "viewer"
|
|
70425
|
+
},
|
|
69661
70426
|
"metricsProvider.collectSnapshot": {
|
|
69662
70427
|
capName: "metrics-provider",
|
|
69663
70428
|
capScope: "system",
|
|
@@ -77756,7 +78521,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
77756
78521
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
77757
78522
|
icon: "square"
|
|
77758
78523
|
}
|
|
77759
|
-
}
|
|
78524
|
+
},
|
|
78525
|
+
overrides: { byType: {
|
|
78526
|
+
[DeviceType.Washer]: {
|
|
78527
|
+
state: { running: {
|
|
78528
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
78529
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
78530
|
+
} },
|
|
78531
|
+
events: {
|
|
78532
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
78533
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
78534
|
+
}
|
|
78535
|
+
},
|
|
78536
|
+
[DeviceType.Dryer]: {
|
|
78537
|
+
state: { running: {
|
|
78538
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
78539
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
78540
|
+
} },
|
|
78541
|
+
events: {
|
|
78542
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
78543
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
78544
|
+
}
|
|
78545
|
+
},
|
|
78546
|
+
[DeviceType.Dishwasher]: {
|
|
78547
|
+
state: { running: {
|
|
78548
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
78549
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
78550
|
+
} },
|
|
78551
|
+
events: {
|
|
78552
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
78553
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
78554
|
+
}
|
|
78555
|
+
}
|
|
78556
|
+
} }
|
|
77760
78557
|
},
|
|
77761
78558
|
update: {
|
|
77762
78559
|
scope: "device",
|
|
@@ -78528,6 +79325,41 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78528
79325
|
icon: "flame"
|
|
78529
79326
|
}]
|
|
78530
79327
|
},
|
|
79328
|
+
"group-active": {
|
|
79329
|
+
scope: "device",
|
|
79330
|
+
noun: t("Group state", "Stato del gruppo")
|
|
79331
|
+
},
|
|
79332
|
+
"group-commands": {
|
|
79333
|
+
scope: "device",
|
|
79334
|
+
noun: t("Group command", "Comando di gruppo")
|
|
79335
|
+
},
|
|
79336
|
+
"group-status": {
|
|
79337
|
+
scope: "device",
|
|
79338
|
+
noun: t("Group", "Gruppo"),
|
|
79339
|
+
state: [
|
|
79340
|
+
{
|
|
79341
|
+
kind: "numeric",
|
|
79342
|
+
field: "included",
|
|
79343
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
79344
|
+
label: t("Reporting", "Rispondono"),
|
|
79345
|
+
icon: "users"
|
|
79346
|
+
},
|
|
79347
|
+
{
|
|
79348
|
+
kind: "numeric",
|
|
79349
|
+
field: "excluded",
|
|
79350
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
79351
|
+
label: t("Excluded", "Esclusi"),
|
|
79352
|
+
icon: "users"
|
|
79353
|
+
},
|
|
79354
|
+
{
|
|
79355
|
+
kind: "numeric",
|
|
79356
|
+
field: "total",
|
|
79357
|
+
quantity: t("the member count", "il numero di membri"),
|
|
79358
|
+
label: t("Members", "Membri"),
|
|
79359
|
+
icon: "sigma"
|
|
79360
|
+
}
|
|
79361
|
+
]
|
|
79362
|
+
},
|
|
78531
79363
|
"humidity-sensor": {
|
|
78532
79364
|
scope: "device",
|
|
78533
79365
|
noun: t("Humidity", "Umidità"),
|
|
@@ -78553,6 +79385,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78553
79385
|
}],
|
|
78554
79386
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
78555
79387
|
},
|
|
79388
|
+
meter: {
|
|
79389
|
+
scope: "device",
|
|
79390
|
+
noun: t("Meter", "Contatore"),
|
|
79391
|
+
state: [{
|
|
79392
|
+
kind: "numeric",
|
|
79393
|
+
field: "value",
|
|
79394
|
+
quantity: t("the total", "il totale"),
|
|
79395
|
+
label: t("Total", "Totale"),
|
|
79396
|
+
icon: "gauge"
|
|
79397
|
+
}]
|
|
79398
|
+
},
|
|
78556
79399
|
"numeric-sensor": {
|
|
78557
79400
|
scope: "device",
|
|
78558
79401
|
noun: t("Sensor", "Sensore"),
|
|
@@ -78561,7 +79404,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78561
79404
|
field: "value",
|
|
78562
79405
|
quantity: t("the reading", "il valore"),
|
|
78563
79406
|
label: t("Reading", "Valore"),
|
|
78564
|
-
unitField: "unit",
|
|
78565
79407
|
icon: "gauge"
|
|
78566
79408
|
}]
|
|
78567
79409
|
},
|
|
@@ -78697,7 +79539,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78697
79539
|
field: "temperature",
|
|
78698
79540
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
78699
79541
|
label: t("Temperature", "Temperatura"),
|
|
78700
|
-
|
|
79542
|
+
unit: "°C",
|
|
78701
79543
|
icon: "thermometer"
|
|
78702
79544
|
},
|
|
78703
79545
|
{
|
|
@@ -78713,7 +79555,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78713
79555
|
field: "windSpeed",
|
|
78714
79556
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
78715
79557
|
label: t("Wind", "Vento"),
|
|
78716
|
-
|
|
79558
|
+
unit: "m/s",
|
|
78717
79559
|
icon: "wind"
|
|
78718
79560
|
},
|
|
78719
79561
|
{
|
|
@@ -78721,7 +79563,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
78721
79563
|
field: "pressure",
|
|
78722
79564
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
78723
79565
|
label: t("Pressure", "Pressione"),
|
|
78724
|
-
|
|
79566
|
+
unit: "hPa",
|
|
78725
79567
|
icon: "gauge"
|
|
78726
79568
|
}
|
|
78727
79569
|
]
|
|
@@ -79026,8 +79868,47 @@ function projectAction(cap, action) {
|
|
|
79026
79868
|
};
|
|
79027
79869
|
}
|
|
79028
79870
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
79029
|
-
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;
|
|
79871
|
+
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;
|
|
79030
79872
|
DeviceFeature.BatteryOperated;
|
|
79873
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
79874
|
+
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.";
|
|
79875
|
+
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.";
|
|
79876
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
79877
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
79878
|
+
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.";
|
|
79879
|
+
function withheld(reason) {
|
|
79880
|
+
return {
|
|
79881
|
+
[DeviceType.Washer]: {
|
|
79882
|
+
exported: false,
|
|
79883
|
+
reason
|
|
79884
|
+
},
|
|
79885
|
+
[DeviceType.Dryer]: {
|
|
79886
|
+
exported: false,
|
|
79887
|
+
reason
|
|
79888
|
+
},
|
|
79889
|
+
[DeviceType.Dishwasher]: {
|
|
79890
|
+
exported: false,
|
|
79891
|
+
reason
|
|
79892
|
+
}
|
|
79893
|
+
};
|
|
79894
|
+
}
|
|
79895
|
+
function offered(received) {
|
|
79896
|
+
return {
|
|
79897
|
+
[DeviceType.Washer]: {
|
|
79898
|
+
exported: true,
|
|
79899
|
+
as: received
|
|
79900
|
+
},
|
|
79901
|
+
[DeviceType.Dryer]: {
|
|
79902
|
+
exported: true,
|
|
79903
|
+
as: received
|
|
79904
|
+
},
|
|
79905
|
+
[DeviceType.Dishwasher]: {
|
|
79906
|
+
exported: true,
|
|
79907
|
+
as: received
|
|
79908
|
+
}
|
|
79909
|
+
};
|
|
79910
|
+
}
|
|
79911
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
79031
79912
|
Object.freeze({
|
|
79032
79913
|
"accessories.getStatus": [{
|
|
79033
79914
|
name: "deviceId",
|
|
@@ -79994,6 +80875,21 @@ Object.freeze({
|
|
|
79994
80875
|
form: "single",
|
|
79995
80876
|
optional: false
|
|
79996
80877
|
}],
|
|
80878
|
+
"groupActive.getStatus": [{
|
|
80879
|
+
name: "deviceId",
|
|
80880
|
+
form: "single",
|
|
80881
|
+
optional: false
|
|
80882
|
+
}],
|
|
80883
|
+
"groupCommands.getStatus": [{
|
|
80884
|
+
name: "deviceId",
|
|
80885
|
+
form: "single",
|
|
80886
|
+
optional: false
|
|
80887
|
+
}],
|
|
80888
|
+
"groupStatus.getStatus": [{
|
|
80889
|
+
name: "deviceId",
|
|
80890
|
+
form: "single",
|
|
80891
|
+
optional: false
|
|
80892
|
+
}],
|
|
79997
80893
|
"heatingValve.getStatus": [{
|
|
79998
80894
|
name: "deviceId",
|
|
79999
80895
|
form: "single",
|
|
@@ -80194,6 +81090,11 @@ Object.freeze({
|
|
|
80194
81090
|
form: "single",
|
|
80195
81091
|
optional: false
|
|
80196
81092
|
}],
|
|
81093
|
+
"meter.getStatus": [{
|
|
81094
|
+
name: "deviceId",
|
|
81095
|
+
form: "single",
|
|
81096
|
+
optional: false
|
|
81097
|
+
}],
|
|
80197
81098
|
"motion.getStatus": [{
|
|
80198
81099
|
name: "deviceId",
|
|
80199
81100
|
form: "single",
|
|
@@ -81801,7 +82702,6 @@ Object.freeze({
|
|
|
81801
82702
|
"network-access": "ingress",
|
|
81802
82703
|
"smtp-provider": "email"
|
|
81803
82704
|
});
|
|
81804
|
-
DeviceType.Camera;
|
|
81805
82705
|
/**
|
|
81806
82706
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
81807
82707
|
* `z.infer`, they do not restate the shape.
|
|
@@ -81978,6 +82878,8 @@ new Map(Object.entries({
|
|
|
81978
82878
|
"detection-blind": "device-events",
|
|
81979
82879
|
"motion-noisy": "device-events",
|
|
81980
82880
|
"motion-calm": "device-events",
|
|
82881
|
+
"package-llm-silent": "device-events",
|
|
82882
|
+
"package-llm-answered": "device-events",
|
|
81981
82883
|
"recording-stalled": "device-events",
|
|
81982
82884
|
"recording-healthy": "device-events",
|
|
81983
82885
|
"recording-degraded": "device-events",
|
|
@@ -82061,6 +82963,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
82061
82963
|
label: "Motion without a subject",
|
|
82062
82964
|
kinds: ["motion-noisy", "motion-calm"]
|
|
82063
82965
|
},
|
|
82966
|
+
{
|
|
82967
|
+
id: "package-llm",
|
|
82968
|
+
family: "device-events",
|
|
82969
|
+
label: "Package confirm",
|
|
82970
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
82971
|
+
},
|
|
82064
82972
|
{
|
|
82065
82973
|
id: "recording",
|
|
82066
82974
|
family: "device-events",
|
|
@@ -82242,6 +83150,8 @@ var DEVICE_EVENTS = [
|
|
|
82242
83150
|
"detection-blind",
|
|
82243
83151
|
"motion-noisy",
|
|
82244
83152
|
"motion-calm",
|
|
83153
|
+
"package-llm-silent",
|
|
83154
|
+
"package-llm-answered",
|
|
82245
83155
|
"recording-stalled",
|
|
82246
83156
|
"recording-healthy",
|
|
82247
83157
|
"recording-degraded",
|
|
@@ -82510,6 +83420,15 @@ new Map([
|
|
|
82510
83420
|
snapshotLabel: "Cameras with constant motion now",
|
|
82511
83421
|
snapshotSection: null
|
|
82512
83422
|
},
|
|
83423
|
+
{
|
|
83424
|
+
id: "package-llm-confirm",
|
|
83425
|
+
family: "device-events",
|
|
83426
|
+
label: "Package confirm (not answering / answering again)",
|
|
83427
|
+
bad: ["package-llm-silent"],
|
|
83428
|
+
recovery: ["package-llm-answered"],
|
|
83429
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
83430
|
+
snapshotSection: null
|
|
83431
|
+
},
|
|
82513
83432
|
{
|
|
82514
83433
|
id: "recording-health",
|
|
82515
83434
|
family: "device-events",
|
|
@@ -84113,7 +85032,7 @@ function pickOauthRedirectOrigin(book) {
|
|
|
84113
85032
|
return book.roles.publicEndpoint.resolved ?? book.roles.internal.resolved ?? null;
|
|
84114
85033
|
}
|
|
84115
85034
|
var googleBrokersEntryKind = defineEntryKind("brokers", {
|
|
84116
|
-
title: "Google
|
|
85035
|
+
title: "Google brokers",
|
|
84117
85036
|
schema: entryBody({
|
|
84118
85037
|
clientId: GoogleBrokerEntrySchema.shape.clientId,
|
|
84119
85038
|
clientSecret: GoogleBrokerEntrySchema.shape.clientSecret,
|
|
@@ -84182,7 +85101,7 @@ var GoogleBrokerStore = class GoogleBrokerStore {
|
|
|
84182
85101
|
//#endregion
|
|
84183
85102
|
//#region src/google-services.addon.ts
|
|
84184
85103
|
/**
|
|
84185
|
-
* Google
|
|
85104
|
+
* Google — hub-only broker kind `google` + calendar-source + Gmail smtp.
|
|
84186
85105
|
* One OAuth account = one broker entry; feature caps aggregate connected brokers.
|
|
84187
85106
|
*/
|
|
84188
85107
|
var ADDON_ID = "google-services";
|