@camstack/addon-provider-tuya 0.2.146 → 0.2.148
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 +16 -1
- package/README.md +24 -8
- package/dist/addon.js +1513 -274
- package/dist/addon.mjs +1513 -274
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -818,7 +818,7 @@ async function discoverDevices(options = {}, binder = createDgramBinder()) {
|
|
|
818
818
|
return [...byId.values()];
|
|
819
819
|
}
|
|
820
820
|
//#endregion
|
|
821
|
-
//#region ../types/dist/event-category-
|
|
821
|
+
//#region ../types/dist/event-category-DmZDPDf_.mjs
|
|
822
822
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
823
823
|
EventCategory["SystemBoot"] = "system.boot";
|
|
824
824
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -1445,7 +1445,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
1445
1445
|
* (a track was promoted to a stationary-registry entry) or departs (the
|
|
1446
1446
|
* object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
|
|
1447
1447
|
* the dedicated "Stationary" section — never the live event feed. Payload:
|
|
1448
|
-
* `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
|
|
1448
|
+
* `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
|
|
1449
1449
|
*/
|
|
1450
1450
|
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
1451
1451
|
/**
|
|
@@ -1583,6 +1583,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
1583
1583
|
*/
|
|
1584
1584
|
EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
|
|
1585
1585
|
/**
|
|
1586
|
+
* An action run started or ended. Emitted by the `actions` surface.
|
|
1587
|
+
* Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
|
|
1588
|
+
*/
|
|
1589
|
+
EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
|
|
1590
|
+
/**
|
|
1586
1591
|
* Progress update from a running model conversion job.
|
|
1587
1592
|
* Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
|
|
1588
1593
|
* Emitted by `addon-model-studio` on the converting node.
|
|
@@ -6261,7 +6266,7 @@ var ZodIssueCode = {
|
|
|
6261
6266
|
var ZodFirstPartyTypeKind;
|
|
6262
6267
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6263
6268
|
//#endregion
|
|
6264
|
-
//#region ../types/dist/sleep-
|
|
6269
|
+
//#region ../types/dist/sleep-Crlmu_tO.mjs
|
|
6265
6270
|
/**
|
|
6266
6271
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6267
6272
|
* window to float samples (D455).
|
|
@@ -9381,6 +9386,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
|
|
|
9381
9386
|
/** Every capability name, so addon code can check a name without the schema graph. */
|
|
9382
9387
|
var CAP_NAMES = Object.freeze([
|
|
9383
9388
|
"accessories",
|
|
9389
|
+
"action-source",
|
|
9390
|
+
"actions",
|
|
9384
9391
|
"addon-pages",
|
|
9385
9392
|
"addon-pages-source",
|
|
9386
9393
|
"addon-routes",
|
|
@@ -9454,6 +9461,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9454
9461
|
"filesystem-browse",
|
|
9455
9462
|
"flood",
|
|
9456
9463
|
"gas",
|
|
9464
|
+
"group-active",
|
|
9457
9465
|
"group-commands",
|
|
9458
9466
|
"group-status",
|
|
9459
9467
|
"heating-valve",
|
|
@@ -9476,6 +9484,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
9476
9484
|
"login-method",
|
|
9477
9485
|
"media-player",
|
|
9478
9486
|
"mesh-network",
|
|
9487
|
+
"meter",
|
|
9479
9488
|
"metrics-provider",
|
|
9480
9489
|
"model-convert",
|
|
9481
9490
|
"model-distributor",
|
|
@@ -9567,11 +9576,11 @@ var CAP_NAMES = Object.freeze([
|
|
|
9567
9576
|
Object.freeze({
|
|
9568
9577
|
"air-quality-sensor": [
|
|
9569
9578
|
{
|
|
9570
|
-
"path": "
|
|
9579
|
+
"path": "co2",
|
|
9571
9580
|
"valueType": "number"
|
|
9572
9581
|
},
|
|
9573
9582
|
{
|
|
9574
|
-
"path": "
|
|
9583
|
+
"path": "voc",
|
|
9575
9584
|
"valueType": "number"
|
|
9576
9585
|
},
|
|
9577
9586
|
{
|
|
@@ -9621,7 +9630,7 @@ Object.freeze({
|
|
|
9621
9630
|
}
|
|
9622
9631
|
],
|
|
9623
9632
|
"ambient-light-sensor": [{
|
|
9624
|
-
"path": "
|
|
9633
|
+
"path": "illuminance",
|
|
9625
9634
|
"valueType": "number"
|
|
9626
9635
|
}],
|
|
9627
9636
|
"audio-metrics": [
|
|
@@ -9682,7 +9691,7 @@ Object.freeze({
|
|
|
9682
9691
|
],
|
|
9683
9692
|
"battery": [
|
|
9684
9693
|
{
|
|
9685
|
-
"path": "
|
|
9694
|
+
"path": "level",
|
|
9686
9695
|
"valueType": "number"
|
|
9687
9696
|
},
|
|
9688
9697
|
{
|
|
@@ -9704,7 +9713,7 @@ Object.freeze({
|
|
|
9704
9713
|
"valueType": "number"
|
|
9705
9714
|
},
|
|
9706
9715
|
{
|
|
9707
|
-
"path": "
|
|
9716
|
+
"path": "voltage",
|
|
9708
9717
|
"valueType": "number"
|
|
9709
9718
|
},
|
|
9710
9719
|
{
|
|
@@ -9725,7 +9734,7 @@ Object.freeze({
|
|
|
9725
9734
|
"valueType": "boolean"
|
|
9726
9735
|
}],
|
|
9727
9736
|
"brightness": [{
|
|
9728
|
-
"path": "
|
|
9737
|
+
"path": "level",
|
|
9729
9738
|
"valueType": "number"
|
|
9730
9739
|
}],
|
|
9731
9740
|
"broker": [{
|
|
@@ -9926,7 +9935,7 @@ Object.freeze({
|
|
|
9926
9935
|
"valueType": "number"
|
|
9927
9936
|
},
|
|
9928
9937
|
{
|
|
9929
|
-
"path": "
|
|
9938
|
+
"path": "colorTemperature",
|
|
9930
9939
|
"valueType": "number"
|
|
9931
9940
|
}
|
|
9932
9941
|
],
|
|
@@ -10105,15 +10114,15 @@ Object.freeze({
|
|
|
10105
10114
|
"valueType": "string"
|
|
10106
10115
|
},
|
|
10107
10116
|
{
|
|
10108
|
-
"path": "
|
|
10117
|
+
"path": "remaining",
|
|
10109
10118
|
"valueType": "number"
|
|
10110
10119
|
},
|
|
10111
10120
|
{
|
|
10112
|
-
"path": "
|
|
10121
|
+
"path": "delayedStart",
|
|
10113
10122
|
"valueType": "number"
|
|
10114
10123
|
},
|
|
10115
10124
|
{
|
|
10116
|
-
"path": "
|
|
10125
|
+
"path": "progress",
|
|
10117
10126
|
"valueType": "number"
|
|
10118
10127
|
},
|
|
10119
10128
|
{
|
|
@@ -10227,7 +10236,7 @@ Object.freeze({
|
|
|
10227
10236
|
],
|
|
10228
10237
|
"fan-control": [
|
|
10229
10238
|
{
|
|
10230
|
-
"path": "
|
|
10239
|
+
"path": "speed",
|
|
10231
10240
|
"valueType": "number"
|
|
10232
10241
|
},
|
|
10233
10242
|
{
|
|
@@ -10274,6 +10283,10 @@ Object.freeze({
|
|
|
10274
10283
|
"path": "detected",
|
|
10275
10284
|
"valueType": "boolean"
|
|
10276
10285
|
}],
|
|
10286
|
+
"group-active": [{
|
|
10287
|
+
"path": "active",
|
|
10288
|
+
"valueType": "boolean"
|
|
10289
|
+
}],
|
|
10277
10290
|
"group-status": [
|
|
10278
10291
|
{
|
|
10279
10292
|
"path": "included",
|
|
@@ -10323,7 +10336,7 @@ Object.freeze({
|
|
|
10323
10336
|
}
|
|
10324
10337
|
],
|
|
10325
10338
|
"humidity-sensor": [{
|
|
10326
|
-
"path": "
|
|
10339
|
+
"path": "humidity",
|
|
10327
10340
|
"valueType": "number"
|
|
10328
10341
|
}],
|
|
10329
10342
|
"image": [{
|
|
@@ -10433,7 +10446,7 @@ Object.freeze({
|
|
|
10433
10446
|
"valueType": "number"
|
|
10434
10447
|
},
|
|
10435
10448
|
{
|
|
10436
|
-
"path": "
|
|
10449
|
+
"path": "progress",
|
|
10437
10450
|
"valueType": "number"
|
|
10438
10451
|
},
|
|
10439
10452
|
{
|
|
@@ -10512,11 +10525,11 @@ Object.freeze({
|
|
|
10512
10525
|
"valueType": "string"
|
|
10513
10526
|
},
|
|
10514
10527
|
{
|
|
10515
|
-
"path": "
|
|
10528
|
+
"path": "position",
|
|
10516
10529
|
"valueType": "number"
|
|
10517
10530
|
},
|
|
10518
10531
|
{
|
|
10519
|
-
"path": "
|
|
10532
|
+
"path": "duration",
|
|
10520
10533
|
"valueType": "number"
|
|
10521
10534
|
},
|
|
10522
10535
|
{
|
|
@@ -10533,6 +10546,10 @@ Object.freeze({
|
|
|
10533
10546
|
]
|
|
10534
10547
|
}
|
|
10535
10548
|
],
|
|
10549
|
+
"meter": [{
|
|
10550
|
+
"path": "value",
|
|
10551
|
+
"valueType": "number"
|
|
10552
|
+
}],
|
|
10536
10553
|
"motion": [
|
|
10537
10554
|
{
|
|
10538
10555
|
"path": "detected",
|
|
@@ -10614,11 +10631,11 @@ Object.freeze({
|
|
|
10614
10631
|
]
|
|
10615
10632
|
},
|
|
10616
10633
|
{
|
|
10617
|
-
"path": "
|
|
10634
|
+
"path": "signal",
|
|
10618
10635
|
"valueType": "number"
|
|
10619
10636
|
},
|
|
10620
10637
|
{
|
|
10621
|
-
"path": "
|
|
10638
|
+
"path": "rssi",
|
|
10622
10639
|
"valueType": "number"
|
|
10623
10640
|
},
|
|
10624
10641
|
{
|
|
@@ -10673,6 +10690,18 @@ Object.freeze({
|
|
|
10673
10690
|
"path": "foodLevel",
|
|
10674
10691
|
"valueType": "number"
|
|
10675
10692
|
},
|
|
10693
|
+
{
|
|
10694
|
+
"path": "bowlFood",
|
|
10695
|
+
"valueType": "number"
|
|
10696
|
+
},
|
|
10697
|
+
{
|
|
10698
|
+
"path": "eating",
|
|
10699
|
+
"valueType": "boolean"
|
|
10700
|
+
},
|
|
10701
|
+
{
|
|
10702
|
+
"path": "supportsMarkRefilled",
|
|
10703
|
+
"valueType": "boolean"
|
|
10704
|
+
},
|
|
10676
10705
|
{
|
|
10677
10706
|
"path": "food1",
|
|
10678
10707
|
"valueType": "number"
|
|
@@ -10737,23 +10766,23 @@ Object.freeze({
|
|
|
10737
10766
|
],
|
|
10738
10767
|
"power-meter": [
|
|
10739
10768
|
{
|
|
10740
|
-
"path": "
|
|
10769
|
+
"path": "power",
|
|
10741
10770
|
"valueType": "number"
|
|
10742
10771
|
},
|
|
10743
10772
|
{
|
|
10744
|
-
"path": "
|
|
10773
|
+
"path": "energy",
|
|
10745
10774
|
"valueType": "number"
|
|
10746
10775
|
},
|
|
10747
10776
|
{
|
|
10748
|
-
"path": "
|
|
10777
|
+
"path": "voltage",
|
|
10749
10778
|
"valueType": "number"
|
|
10750
10779
|
},
|
|
10751
10780
|
{
|
|
10752
|
-
"path": "
|
|
10781
|
+
"path": "current",
|
|
10753
10782
|
"valueType": "number"
|
|
10754
10783
|
},
|
|
10755
10784
|
{
|
|
10756
|
-
"path": "
|
|
10785
|
+
"path": "apparentPower",
|
|
10757
10786
|
"valueType": "number"
|
|
10758
10787
|
},
|
|
10759
10788
|
{
|
|
@@ -10781,14 +10810,10 @@ Object.freeze({
|
|
|
10781
10810
|
{
|
|
10782
10811
|
"path": "gps.accuracyMeters",
|
|
10783
10812
|
"valueType": "number"
|
|
10784
|
-
},
|
|
10785
|
-
{
|
|
10786
|
-
"path": "batteryPercent",
|
|
10787
|
-
"valueType": "number"
|
|
10788
10813
|
}
|
|
10789
10814
|
],
|
|
10790
10815
|
"pressure-sensor": [{
|
|
10791
|
-
"path": "
|
|
10816
|
+
"path": "pressure",
|
|
10792
10817
|
"valueType": "number"
|
|
10793
10818
|
}],
|
|
10794
10819
|
"privacy-mask": [{
|
|
@@ -11102,7 +11127,7 @@ Object.freeze({
|
|
|
11102
11127
|
"valueType": "boolean"
|
|
11103
11128
|
}],
|
|
11104
11129
|
"temperature-sensor": [{
|
|
11105
|
-
"path": "
|
|
11130
|
+
"path": "temperature",
|
|
11106
11131
|
"valueType": "number"
|
|
11107
11132
|
}],
|
|
11108
11133
|
"update": [
|
|
@@ -11150,7 +11175,7 @@ Object.freeze({
|
|
|
11150
11175
|
"valueType": "string"
|
|
11151
11176
|
},
|
|
11152
11177
|
{
|
|
11153
|
-
"path": "
|
|
11178
|
+
"path": "progress",
|
|
11154
11179
|
"valueType": "number"
|
|
11155
11180
|
},
|
|
11156
11181
|
{
|
|
@@ -11276,7 +11301,7 @@ object({
|
|
|
11276
11301
|
params: record(string(), union([string(), number()])).optional()
|
|
11277
11302
|
});
|
|
11278
11303
|
//#endregion
|
|
11279
|
-
//#region ../types/dist/err-msg-
|
|
11304
|
+
//#region ../types/dist/err-msg-DIorGYeC.mjs
|
|
11280
11305
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
11281
11306
|
DeviceType["Camera"] = "camera";
|
|
11282
11307
|
DeviceType["Hub"] = "hub";
|
|
@@ -11370,8 +11395,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
11370
11395
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
11371
11396
|
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
11372
11397
|
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
11373
|
-
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
11398
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations.
|
|
11399
|
+
* A plug-built dishwasher carries running-state and power instead. */
|
|
11374
11400
|
DeviceType["Dishwasher"] = "dishwasher";
|
|
11401
|
+
/** Washing machine. A plug-built one is running while its power stays
|
|
11402
|
+
* above a threshold. No program cap — that surface is the dishwasher's. */
|
|
11403
|
+
DeviceType["Washer"] = "washer";
|
|
11404
|
+
/** Tumble dryer. Same plug-built running surface as {@link Washer}. */
|
|
11405
|
+
DeviceType["Dryer"] = "dryer";
|
|
11375
11406
|
return DeviceType;
|
|
11376
11407
|
}({});
|
|
11377
11408
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -11629,7 +11660,7 @@ function errMsg(err) {
|
|
|
11629
11660
|
return String(err);
|
|
11630
11661
|
}
|
|
11631
11662
|
//#endregion
|
|
11632
|
-
//#region ../types/dist/composition-
|
|
11663
|
+
//#region ../types/dist/composition-CZImLpOI.mjs
|
|
11633
11664
|
/**
|
|
11634
11665
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11635
11666
|
*
|
|
@@ -11944,6 +11975,13 @@ var table = {
|
|
|
11944
11975
|
apply: () => {
|
|
11945
11976
|
throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
|
|
11946
11977
|
}
|
|
11978
|
+
},
|
|
11979
|
+
schmitt: {
|
|
11980
|
+
minArgs: 3,
|
|
11981
|
+
maxArgs: 5,
|
|
11982
|
+
apply: () => {
|
|
11983
|
+
throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
|
|
11984
|
+
}
|
|
11947
11985
|
}
|
|
11948
11986
|
};
|
|
11949
11987
|
Object.freeze(Object.assign(Object.create(null), table));
|
|
@@ -12385,6 +12423,99 @@ function validateExpressionSource(src) {
|
|
|
12385
12423
|
return null;
|
|
12386
12424
|
}
|
|
12387
12425
|
/**
|
|
12426
|
+
* One power reading becomes a washer, dryer or dishwasher (D944 helper).
|
|
12427
|
+
*
|
|
12428
|
+
* Standby of the control board is under 5 W; a motor or a heater is far
|
|
12429
|
+
* above that, so 5 W is the line. A door lock or a short pump spike is not
|
|
12430
|
+
* a cycle, so running starts only after 30 s above the line.
|
|
12431
|
+
*
|
|
12432
|
+
* A wash, dry or dishwasher pause (soak, heat-wait, heater off between
|
|
12433
|
+
* bursts) lasts several minutes. Ending the cycle on the first dip would
|
|
12434
|
+
* report "finished" in the middle of the program, so the stop dwell is
|
|
12435
|
+
* 10 minutes on every type. The number is stored per type so one machine
|
|
12436
|
+
* can move later without moving the others.
|
|
12437
|
+
*/
|
|
12438
|
+
var APPLIANCE_TEMPLATE_ID = "appliance";
|
|
12439
|
+
var APPLIANCE_KINDS = [
|
|
12440
|
+
"washer",
|
|
12441
|
+
"dryer",
|
|
12442
|
+
"dishwasher"
|
|
12443
|
+
];
|
|
12444
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
12445
|
+
/**
|
|
12446
|
+
* Statistics and integrals over a history read (D944).
|
|
12447
|
+
*
|
|
12448
|
+
* Pure: the same points always give the same answer, so a restart recomputes
|
|
12449
|
+
* rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
|
|
12450
|
+
* never the mean of the samples. A hole with no held value is not integrated
|
|
12451
|
+
* as zero. A truncated read is not published.
|
|
12452
|
+
*/
|
|
12453
|
+
var STATISTIC_STATS = [
|
|
12454
|
+
"min",
|
|
12455
|
+
"max",
|
|
12456
|
+
"mean",
|
|
12457
|
+
"sum",
|
|
12458
|
+
"count",
|
|
12459
|
+
"change"
|
|
12460
|
+
];
|
|
12461
|
+
/**
|
|
12462
|
+
* The range a statistics or integral helper asks history for (D944).
|
|
12463
|
+
*
|
|
12464
|
+
* Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
|
|
12465
|
+
* or 25 hours across a DST change. A tier is eligible only when its retention
|
|
12466
|
+
* is strictly longer than the longest that range can be. Forever qualifies.
|
|
12467
|
+
* Equal to a tier's retention is a refusal, not a short answer.
|
|
12468
|
+
*/
|
|
12469
|
+
var MINUTE_MS = 6e4;
|
|
12470
|
+
var HOUR_MS = 60 * MINUTE_MS;
|
|
12471
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
12472
|
+
var ROLLING_SPANS = [
|
|
12473
|
+
"1h",
|
|
12474
|
+
"24h",
|
|
12475
|
+
"2d",
|
|
12476
|
+
"7d",
|
|
12477
|
+
"30d",
|
|
12478
|
+
"custom"
|
|
12479
|
+
];
|
|
12480
|
+
var CALENDAR_PERIODS = [
|
|
12481
|
+
"today",
|
|
12482
|
+
"yesterday",
|
|
12483
|
+
"this-week",
|
|
12484
|
+
"this-month"
|
|
12485
|
+
];
|
|
12486
|
+
var RESET_PERIODS = [
|
|
12487
|
+
"never",
|
|
12488
|
+
"daily",
|
|
12489
|
+
"weekly",
|
|
12490
|
+
"monthly"
|
|
12491
|
+
];
|
|
12492
|
+
5 * MINUTE_MS;
|
|
12493
|
+
24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
|
|
12494
|
+
7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
|
|
12495
|
+
var rollingWindowObject = object({
|
|
12496
|
+
kind: literal("rolling"),
|
|
12497
|
+
span: _enum(ROLLING_SPANS),
|
|
12498
|
+
customMinutes: number().int().min(5).optional()
|
|
12499
|
+
}).check((payload) => {
|
|
12500
|
+
if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
|
|
12501
|
+
code: "custom",
|
|
12502
|
+
message: "a custom range needs a duration in minutes",
|
|
12503
|
+
path: ["customMinutes"],
|
|
12504
|
+
input: payload.value
|
|
12505
|
+
});
|
|
12506
|
+
if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
|
|
12507
|
+
code: "custom",
|
|
12508
|
+
message: "only a custom range carries a duration",
|
|
12509
|
+
path: ["customMinutes"],
|
|
12510
|
+
input: payload.value
|
|
12511
|
+
});
|
|
12512
|
+
});
|
|
12513
|
+
var RollingWindowSchema = rollingWindowObject;
|
|
12514
|
+
var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
|
|
12515
|
+
kind: literal("calendar"),
|
|
12516
|
+
period: _enum(CALENDAR_PERIODS)
|
|
12517
|
+
})]);
|
|
12518
|
+
/**
|
|
12388
12519
|
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
12389
12520
|
* id. Split out so helper schemas can name it without a cycle through
|
|
12390
12521
|
* `composition.ts` (D659).
|
|
@@ -12410,7 +12541,13 @@ var GROUP_TEMPLATE_IDS = [
|
|
|
12410
12541
|
"occupancy",
|
|
12411
12542
|
"binary",
|
|
12412
12543
|
"switch",
|
|
12413
|
-
"light"
|
|
12544
|
+
"light",
|
|
12545
|
+
"fan",
|
|
12546
|
+
"cover",
|
|
12547
|
+
"valve",
|
|
12548
|
+
"lock",
|
|
12549
|
+
"media-player",
|
|
12550
|
+
"climate"
|
|
12414
12551
|
];
|
|
12415
12552
|
var NUMERIC_AGGREGATES = [
|
|
12416
12553
|
"mean",
|
|
@@ -12440,14 +12577,73 @@ var HelperMemberSchema = object({
|
|
|
12440
12577
|
cap: string().min(1),
|
|
12441
12578
|
fieldPath: string().min(1)
|
|
12442
12579
|
});
|
|
12443
|
-
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
|
|
12580
|
+
var HelperSpecSchema = discriminatedUnion("kind", [
|
|
12581
|
+
object({
|
|
12582
|
+
kind: literal("group"),
|
|
12583
|
+
templateId: GroupTemplateIdSchema,
|
|
12584
|
+
aggregate: AggregateReducerSchema,
|
|
12585
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
12586
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
12587
|
+
active: ActiveCriterionSchema.optional()
|
|
12588
|
+
}),
|
|
12589
|
+
object({
|
|
12590
|
+
kind: literal("appliance"),
|
|
12591
|
+
templateId: literal(APPLIANCE_TEMPLATE_ID),
|
|
12592
|
+
appliance: _enum(APPLIANCE_KINDS),
|
|
12593
|
+
thresholdWatts: number().positive(),
|
|
12594
|
+
startDwellMs: number().int().nonnegative(),
|
|
12595
|
+
stopDwellMs: number().int().nonnegative(),
|
|
12596
|
+
member: HelperMemberSchema
|
|
12597
|
+
}),
|
|
12598
|
+
object({
|
|
12599
|
+
kind: literal("statistic"),
|
|
12600
|
+
stat: _enum(STATISTIC_STATS),
|
|
12601
|
+
window: StatisticWindowSchema,
|
|
12602
|
+
source: HelperMemberSchema
|
|
12603
|
+
}),
|
|
12604
|
+
object({
|
|
12605
|
+
kind: literal("integral"),
|
|
12606
|
+
reset: _enum(RESET_PERIODS),
|
|
12607
|
+
output: _enum(["energy", "meter"]),
|
|
12608
|
+
source: HelperMemberSchema
|
|
12609
|
+
}),
|
|
12610
|
+
object({
|
|
12611
|
+
kind: literal("threshold"),
|
|
12612
|
+
source: HelperMemberSchema,
|
|
12613
|
+
high: number(),
|
|
12614
|
+
low: number(),
|
|
12615
|
+
onForMs: number().int().nonnegative(),
|
|
12616
|
+
offForMs: number().int().nonnegative()
|
|
12617
|
+
}),
|
|
12618
|
+
object({
|
|
12619
|
+
kind: literal("arithmetic"),
|
|
12620
|
+
op: _enum([
|
|
12621
|
+
"sum",
|
|
12622
|
+
"difference",
|
|
12623
|
+
"ratio"
|
|
12624
|
+
]),
|
|
12625
|
+
inputs: array(HelperMemberSchema).min(2).max(64)
|
|
12626
|
+
}),
|
|
12627
|
+
object({
|
|
12628
|
+
kind: literal("expression"),
|
|
12629
|
+
expr: string().min(1),
|
|
12630
|
+
inputs: array(object({
|
|
12631
|
+
name: string().min(1),
|
|
12632
|
+
member: HelperMemberSchema
|
|
12633
|
+
})).min(1).max(64),
|
|
12634
|
+
output: _enum(["number", "boolean"])
|
|
12635
|
+
}),
|
|
12636
|
+
object({
|
|
12637
|
+
kind: literal("derivative"),
|
|
12638
|
+
window: RollingWindowSchema,
|
|
12639
|
+
per: _enum([
|
|
12640
|
+
"second",
|
|
12641
|
+
"minute",
|
|
12642
|
+
"hour"
|
|
12643
|
+
]),
|
|
12644
|
+
source: HelperMemberSchema
|
|
12645
|
+
})
|
|
12646
|
+
]);
|
|
12451
12647
|
/** A composed device's stableId is this prefix plus the block id. */
|
|
12452
12648
|
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12453
12649
|
/** Longest snippet a `code` source may carry (slice 4). */
|
|
@@ -12508,6 +12704,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12508
12704
|
"all"
|
|
12509
12705
|
]),
|
|
12510
12706
|
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12707
|
+
/**
|
|
12708
|
+
* Set when the reads are an enum state, not a yes/no: the listed states
|
|
12709
|
+
* count as active (a cover is `open`). A state outside the list is inactive;
|
|
12710
|
+
* a read that is not a state at all is left out. Only `any` / `all` use it.
|
|
12711
|
+
*/
|
|
12712
|
+
activeWhen: array(string().min(1)).min(1).optional(),
|
|
12511
12713
|
/** `value` is the reading; the others are the member counts. */
|
|
12512
12714
|
publish: _enum([
|
|
12513
12715
|
"value",
|
|
@@ -12521,6 +12723,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
|
12521
12723
|
"omit",
|
|
12522
12724
|
"offline"
|
|
12523
12725
|
])
|
|
12726
|
+
}),
|
|
12727
|
+
object({
|
|
12728
|
+
kind: literal("series"),
|
|
12729
|
+
read: CompositionFieldReadSchema,
|
|
12730
|
+
/** `value` is the statistic or the integral. The others are the gap counts. */
|
|
12731
|
+
publish: _enum([
|
|
12732
|
+
"value",
|
|
12733
|
+
"included",
|
|
12734
|
+
"excluded",
|
|
12735
|
+
"total"
|
|
12736
|
+
]),
|
|
12737
|
+
/**
|
|
12738
|
+
* What an unanswered `value` does. Counts ignore this. `offline` leaves the
|
|
12739
|
+
* device unseeded until history answers, so a restart cannot publish 0.
|
|
12740
|
+
*/
|
|
12741
|
+
empty: _enum([
|
|
12742
|
+
"null",
|
|
12743
|
+
"omit",
|
|
12744
|
+
"offline"
|
|
12745
|
+
])
|
|
12524
12746
|
})
|
|
12525
12747
|
]);
|
|
12526
12748
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
@@ -15958,6 +16180,14 @@ var AutomationConditionLeafSchema = object({
|
|
|
15958
16180
|
array(union([string(), number()]))
|
|
15959
16181
|
])
|
|
15960
16182
|
});
|
|
16183
|
+
var AutomationConditionStationaryPresentSchema = object({
|
|
16184
|
+
kind: literal("stationary-present"),
|
|
16185
|
+
deviceId: number().int().nonnegative(),
|
|
16186
|
+
/** Class names; a macro class matches every raw class that maps to it. */
|
|
16187
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
16188
|
+
/** The parked object must be in at least one of these zones. */
|
|
16189
|
+
zones: array(string().min(1)).min(1).optional()
|
|
16190
|
+
});
|
|
15961
16191
|
/**
|
|
15962
16192
|
* The expression leaf, declared as a plain object rather than an intersection
|
|
15963
16193
|
* with {@link ExpressionSourceSchema}: a discriminated union has to be able to
|
|
@@ -15991,7 +16221,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
|
|
|
15991
16221
|
child: AutomationConditionSchema
|
|
15992
16222
|
}),
|
|
15993
16223
|
AutomationConditionLeafSchema,
|
|
15994
|
-
AutomationConditionExpressionSchema
|
|
16224
|
+
AutomationConditionExpressionSchema,
|
|
16225
|
+
AutomationConditionStationaryPresentSchema
|
|
15995
16226
|
]));
|
|
15996
16227
|
/**
|
|
15997
16228
|
* What starts a run.
|
|
@@ -16032,7 +16263,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
16032
16263
|
kind: literal("schedule"),
|
|
16033
16264
|
cron: string().min(1).max(120)
|
|
16034
16265
|
}),
|
|
16035
|
-
object({ kind: literal("manual") })
|
|
16266
|
+
object({ kind: literal("manual") }),
|
|
16267
|
+
object({
|
|
16268
|
+
kind: literal("detection"),
|
|
16269
|
+
/** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
|
|
16270
|
+
* matches every raw class that maps to it; any other name matches
|
|
16271
|
+
* exactly. */
|
|
16272
|
+
classes: array(string().min(1)).min(1),
|
|
16273
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
16274
|
+
/** The track must have visited at least one of these zones. */
|
|
16275
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
16276
|
+
/** Best-so-far confidence the track must reach. */
|
|
16277
|
+
minScore: number().min(0).max(1).optional()
|
|
16278
|
+
}),
|
|
16279
|
+
object({
|
|
16280
|
+
kind: literal("stationary"),
|
|
16281
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
16282
|
+
/** Class names; a macro class matches like the detection trigger. */
|
|
16283
|
+
classes: array(string().min(1)).min(1).optional(),
|
|
16284
|
+
/** The parked object must be in at least one of these zones. */
|
|
16285
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
16286
|
+
/** `appeared`: it became parked. `departed`: the registry retired it.
|
|
16287
|
+
* The vocabulary of `PipelineAnalyticsStationaryChanged`. */
|
|
16288
|
+
phase: _enum(["appeared", "departed"])
|
|
16289
|
+
}),
|
|
16290
|
+
object({
|
|
16291
|
+
kind: literal("interval"),
|
|
16292
|
+
minutes: number().int().min(1).max(1440)
|
|
16293
|
+
})
|
|
16036
16294
|
]);
|
|
16037
16295
|
/**
|
|
16038
16296
|
* One action step.
|
|
@@ -16052,28 +16310,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
16052
16310
|
* is called. The runner still receives a number and is untouched; the
|
|
16053
16311
|
* resolution is the recipe's job, not the runner's.
|
|
16054
16312
|
*/
|
|
16313
|
+
var AutomationWaitStepSchema = object({
|
|
16314
|
+
kind: literal("wait"),
|
|
16315
|
+
seconds: number().min(0).max(300)
|
|
16316
|
+
});
|
|
16317
|
+
var AutomationCapStepSchema = object({
|
|
16318
|
+
kind: literal("cap"),
|
|
16319
|
+
/**
|
|
16320
|
+
* One device, several same-family devices (locks / climate family / …),
|
|
16321
|
+
* or `{ $var }` for the device that triggered the run. An array is
|
|
16322
|
+
* fan-out at codegen — each id gets the same cap.method call.
|
|
16323
|
+
*/
|
|
16324
|
+
deviceId: union([
|
|
16325
|
+
number().int(),
|
|
16326
|
+
array(number().int()).min(1),
|
|
16327
|
+
object({ $var: string().min(1) })
|
|
16328
|
+
]),
|
|
16329
|
+
cap: string().min(1),
|
|
16330
|
+
method: string().min(1),
|
|
16331
|
+
/** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
16332
|
+
* SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
|
|
16333
|
+
* the expression leaf. */
|
|
16334
|
+
args: record(string(), unknown()).optional()
|
|
16335
|
+
});
|
|
16336
|
+
/**
|
|
16337
|
+
* The steps an internal Action may contain: cap and wait, and nothing that can
|
|
16338
|
+
* call back into an Action — so an Action can never reach itself (no cycles).
|
|
16339
|
+
*/
|
|
16340
|
+
var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
|
|
16055
16341
|
var AutomationActionSchema = discriminatedUnion("kind", [
|
|
16342
|
+
AutomationWaitStepSchema,
|
|
16343
|
+
AutomationCapStepSchema,
|
|
16056
16344
|
object({
|
|
16057
|
-
kind: literal("
|
|
16058
|
-
|
|
16059
|
-
|
|
16060
|
-
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
*/
|
|
16067
|
-
deviceId: union([
|
|
16068
|
-
number().int(),
|
|
16069
|
-
array(number().int()).min(1),
|
|
16070
|
-
object({ $var: string().min(1) })
|
|
16071
|
-
]),
|
|
16072
|
-
cap: string().min(1),
|
|
16073
|
-
method: string().min(1),
|
|
16074
|
-
/** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
|
|
16075
|
-
* evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
|
|
16076
|
-
args: record(string(), unknown()).optional()
|
|
16345
|
+
kind: literal("action"),
|
|
16346
|
+
/** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
|
|
16347
|
+
actionId: string().min(1),
|
|
16348
|
+
/** Values for the action's declared variables; the others take their default. */
|
|
16349
|
+
variables: record(string(), union([
|
|
16350
|
+
string(),
|
|
16351
|
+
number(),
|
|
16352
|
+
boolean()
|
|
16353
|
+
])).optional()
|
|
16077
16354
|
}),
|
|
16078
16355
|
object({
|
|
16079
16356
|
kind: literal("code"),
|
|
@@ -16082,10 +16359,357 @@ var AutomationActionSchema = discriminatedUnion("kind", [
|
|
|
16082
16359
|
code: string().min(1).max(2e4)
|
|
16083
16360
|
})
|
|
16084
16361
|
]);
|
|
16362
|
+
/**
|
|
16363
|
+
* How a trigger that arrives while the automation is busy (or cooling down) is
|
|
16364
|
+
* handled. One of the automation's execution modes, never a property of its
|
|
16365
|
+
* actions. Absent means `single`.
|
|
16366
|
+
*
|
|
16367
|
+
* - `single` — drop the trigger while a run is in progress (traced + logged).
|
|
16368
|
+
* - `restart` — abort the run in progress (at its next step boundary), start fresh.
|
|
16369
|
+
* - `queued` — queue up to `max` triggers, drop the rest (traced).
|
|
16370
|
+
* - `parallel` — up to `max` runs at once, drop the rest (traced).
|
|
16371
|
+
* - `cooldown` — `single`, and no new run until `minutes` after the last run
|
|
16372
|
+
* STARTED; persisted across a restart. A manual trigger bypasses only this
|
|
16373
|
+
* wait, never the single/queued limits.
|
|
16374
|
+
*/
|
|
16375
|
+
var AutomationRunModeSchema = discriminatedUnion("mode", [
|
|
16376
|
+
object({ mode: literal("single") }),
|
|
16377
|
+
object({ mode: literal("restart") }),
|
|
16378
|
+
object({
|
|
16379
|
+
mode: literal("queued"),
|
|
16380
|
+
max: number().int().min(1).max(10)
|
|
16381
|
+
}),
|
|
16382
|
+
object({
|
|
16383
|
+
mode: literal("parallel"),
|
|
16384
|
+
max: number().int().min(1).max(10)
|
|
16385
|
+
}),
|
|
16386
|
+
object({
|
|
16387
|
+
mode: literal("cooldown"),
|
|
16388
|
+
minutes: number().int().min(1).max(1440)
|
|
16389
|
+
})
|
|
16390
|
+
]);
|
|
16085
16391
|
var AutomationRecipeSchema = object({
|
|
16086
16392
|
triggers: array(AutomationTriggerSchema),
|
|
16087
16393
|
conditions: AutomationConditionSchema.optional(),
|
|
16088
|
-
actions: array(AutomationActionSchema)
|
|
16394
|
+
actions: array(AutomationActionSchema),
|
|
16395
|
+
runMode: AutomationRunModeSchema.optional(),
|
|
16396
|
+
/** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
|
|
16397
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
16398
|
+
});
|
|
16399
|
+
new Set([
|
|
16400
|
+
{
|
|
16401
|
+
id: "person",
|
|
16402
|
+
name: "Person"
|
|
16403
|
+
},
|
|
16404
|
+
{
|
|
16405
|
+
id: "vehicle",
|
|
16406
|
+
name: "Vehicle"
|
|
16407
|
+
},
|
|
16408
|
+
{
|
|
16409
|
+
id: "animal",
|
|
16410
|
+
name: "Animal"
|
|
16411
|
+
},
|
|
16412
|
+
{
|
|
16413
|
+
id: "package",
|
|
16414
|
+
name: "Package"
|
|
16415
|
+
}
|
|
16416
|
+
].map((l) => l.id));
|
|
16417
|
+
var COCO_TO_MACRO = {
|
|
16418
|
+
mapping: {
|
|
16419
|
+
person: "person",
|
|
16420
|
+
bicycle: "vehicle",
|
|
16421
|
+
car: "vehicle",
|
|
16422
|
+
motorcycle: "vehicle",
|
|
16423
|
+
airplane: "vehicle",
|
|
16424
|
+
bus: "vehicle",
|
|
16425
|
+
train: "vehicle",
|
|
16426
|
+
truck: "vehicle",
|
|
16427
|
+
boat: "vehicle",
|
|
16428
|
+
bird: "animal",
|
|
16429
|
+
cat: "animal",
|
|
16430
|
+
dog: "animal",
|
|
16431
|
+
horse: "animal",
|
|
16432
|
+
sheep: "animal",
|
|
16433
|
+
cow: "animal",
|
|
16434
|
+
elephant: "animal",
|
|
16435
|
+
bear: "animal",
|
|
16436
|
+
zebra: "animal",
|
|
16437
|
+
giraffe: "animal",
|
|
16438
|
+
suitcase: "package",
|
|
16439
|
+
backpack: "package",
|
|
16440
|
+
handbag: "package"
|
|
16441
|
+
},
|
|
16442
|
+
preserveOriginal: false
|
|
16443
|
+
};
|
|
16444
|
+
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
16445
|
+
/**
|
|
16446
|
+
* Run traces — what an automation (or, later, an Action run) DID, node by node,
|
|
16447
|
+
* so the editor can paint every block green or red with its reason.
|
|
16448
|
+
*
|
|
16449
|
+
* A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
|
|
16450
|
+
* every condition node (containers and leaves, including the ones a
|
|
16451
|
+
* short-circuit never reached), the run-mode verdict and every action step —
|
|
16452
|
+
* each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
|
|
16453
|
+
* for an Action run). Skipped
|
|
16454
|
+
* evaluations are traced too, and identical consecutive skips collapse into a
|
|
16455
|
+
* repeat count so a trigger that fails every 5 minutes cannot flush real runs.
|
|
16456
|
+
*
|
|
16457
|
+
* {@link AutomationStepTraceSchema} is deliberately free of automation
|
|
16458
|
+
* vocabulary so an Action run records the same step shape.
|
|
16459
|
+
*/
|
|
16460
|
+
/** A value a trace may show: JSON primitives and short lists, nothing deeper. */
|
|
16461
|
+
var TraceValueSchema = union([
|
|
16462
|
+
string(),
|
|
16463
|
+
number(),
|
|
16464
|
+
boolean(),
|
|
16465
|
+
_null(),
|
|
16466
|
+
array(union([string(), number()]))
|
|
16467
|
+
]);
|
|
16468
|
+
var AutomationRunOutcomeSchema = _enum([
|
|
16469
|
+
"ran",
|
|
16470
|
+
"skipped-trigger",
|
|
16471
|
+
"skipped-conditions",
|
|
16472
|
+
"skipped-cooldown",
|
|
16473
|
+
"skipped-overlap",
|
|
16474
|
+
"failed",
|
|
16475
|
+
"aborted"
|
|
16476
|
+
]);
|
|
16477
|
+
/** `not-evaluated` = a short-circuit never reached the node. */
|
|
16478
|
+
var TraceNodeOutcomeSchema = _enum([
|
|
16479
|
+
"pass",
|
|
16480
|
+
"fail",
|
|
16481
|
+
"not-evaluated"
|
|
16482
|
+
]);
|
|
16483
|
+
var AutomationTriggerTraceSchema = object({
|
|
16484
|
+
kind: string().min(1),
|
|
16485
|
+
outcome: _enum(["pass", "fail"]),
|
|
16486
|
+
/** Why an event was rejected ("class person not in [dog]") or what fired. */
|
|
16487
|
+
reason: string(),
|
|
16488
|
+
/** deviceId, className, trackId, score … — only what the trigger exposes. */
|
|
16489
|
+
vars: record(string(), TraceValueSchema)
|
|
16490
|
+
});
|
|
16491
|
+
var AutomationConditionTraceNodeSchema = object({
|
|
16492
|
+
/** `conditions` for the root, `conditions.<i>` for its i-th child, … */
|
|
16493
|
+
path: string().min(1),
|
|
16494
|
+
kind: _enum([
|
|
16495
|
+
"all",
|
|
16496
|
+
"any",
|
|
16497
|
+
"not",
|
|
16498
|
+
"condition",
|
|
16499
|
+
"expression",
|
|
16500
|
+
"stationary-present"
|
|
16501
|
+
]),
|
|
16502
|
+
outcome: TraceNodeOutcomeSchema,
|
|
16503
|
+
reason: string(),
|
|
16504
|
+
deviceId: number().int().optional(),
|
|
16505
|
+
cap: string().optional(),
|
|
16506
|
+
fieldPath: string().optional(),
|
|
16507
|
+
operator: string().optional(),
|
|
16508
|
+
expected: TraceValueSchema.optional(),
|
|
16509
|
+
/** What the mirror held; `null` when it held nothing (unknown). */
|
|
16510
|
+
observed: TraceValueSchema.optional()
|
|
16511
|
+
});
|
|
16512
|
+
var AutomationRunVerdictSchema = object({
|
|
16513
|
+
mode: AutomationRunModeSchema,
|
|
16514
|
+
decision: _enum([
|
|
16515
|
+
"run",
|
|
16516
|
+
"queued",
|
|
16517
|
+
"restart",
|
|
16518
|
+
"drop",
|
|
16519
|
+
"cooldown",
|
|
16520
|
+
"bypass"
|
|
16521
|
+
]),
|
|
16522
|
+
reason: string()
|
|
16523
|
+
});
|
|
16524
|
+
/** One executed (or not-run) step — shared by automations and Action runs. */
|
|
16525
|
+
var AutomationStepTraceSchema = object({
|
|
16526
|
+
/** `actions.<i>` */
|
|
16527
|
+
path: string().min(1),
|
|
16528
|
+
kind: string().min(1),
|
|
16529
|
+
cap: string().optional(),
|
|
16530
|
+
method: string().optional(),
|
|
16531
|
+
deviceId: number().int().optional(),
|
|
16532
|
+
startedAt: number().optional(),
|
|
16533
|
+
endedAt: number().optional(),
|
|
16534
|
+
outcome: _enum([
|
|
16535
|
+
"ok",
|
|
16536
|
+
"error",
|
|
16537
|
+
"not-run"
|
|
16538
|
+
]),
|
|
16539
|
+
message: string().optional()
|
|
16540
|
+
});
|
|
16541
|
+
var AutomationRunTraceSchema = object({
|
|
16542
|
+
runId: string().min(1),
|
|
16543
|
+
startedAt: number(),
|
|
16544
|
+
endedAt: number(),
|
|
16545
|
+
trigger: AutomationTriggerTraceSchema,
|
|
16546
|
+
conditions: array(AutomationConditionTraceNodeSchema),
|
|
16547
|
+
verdict: AutomationRunVerdictSchema.optional(),
|
|
16548
|
+
steps: array(AutomationStepTraceSchema),
|
|
16549
|
+
outcome: AutomationRunOutcomeSchema,
|
|
16550
|
+
/** How many identical consecutive skips this trace stands for (>= 1). */
|
|
16551
|
+
repeat: number().int().min(1),
|
|
16552
|
+
/** When the latest of those repeats happened. */
|
|
16553
|
+
lastAt: number()
|
|
16554
|
+
});
|
|
16555
|
+
/**
|
|
16556
|
+
* What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
|
|
16557
|
+
* `action:<actionId>`): the cooldown stamp and the trace ring.
|
|
16558
|
+
*/
|
|
16559
|
+
var AutomationStateDocSchema = object({
|
|
16560
|
+
version: literal(1),
|
|
16561
|
+
lastRunStartedAt: number().nullable(),
|
|
16562
|
+
traces: array(AutomationRunTraceSchema)
|
|
16563
|
+
});
|
|
16564
|
+
/**
|
|
16565
|
+
* Actions — named, runnable things an operator (or an automation) can start,
|
|
16566
|
+
* declared as LIST ENTRIES, never as devices.
|
|
16567
|
+
*
|
|
16568
|
+
* An entry is either **internal** (a short list of cap/wait steps kept in the
|
|
16569
|
+
* hub's `actions` record kind) or declared by an addon through the
|
|
16570
|
+
* `action-source` collection (a Home Assistant script, a scene …). The one
|
|
16571
|
+
* surface the UI and automations talk to is the `actions` cap; it keeps no
|
|
16572
|
+
* catalog of its own (D3) — every `list` asks the providers live.
|
|
16573
|
+
*
|
|
16574
|
+
* This file is the data half: the entry schema, the variables an entry may
|
|
16575
|
+
* declare, and the pure resolution of the values a run was given. It holds no
|
|
16576
|
+
* runtime.
|
|
16577
|
+
*/
|
|
16578
|
+
/** What a variable's value is. `select` takes one of `options`. */
|
|
16579
|
+
var ActionVariableTypeSchema = _enum([
|
|
16580
|
+
"string",
|
|
16581
|
+
"number",
|
|
16582
|
+
"boolean",
|
|
16583
|
+
"select"
|
|
16584
|
+
]);
|
|
16585
|
+
var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
16586
|
+
var ActionVariableValueSchema = union([
|
|
16587
|
+
string(),
|
|
16588
|
+
number(),
|
|
16589
|
+
boolean()
|
|
16590
|
+
]);
|
|
16591
|
+
/**
|
|
16592
|
+
* One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
|
|
16593
|
+
* value) or `{{vars.name}}` (inside a string) in their args.
|
|
16594
|
+
*/
|
|
16595
|
+
var ActionVariableSchema = object({
|
|
16596
|
+
name: string().regex(ACTION_VARIABLE_NAME_RE),
|
|
16597
|
+
label: string().min(1).max(120).optional(),
|
|
16598
|
+
type: ActionVariableTypeSchema,
|
|
16599
|
+
required: boolean().optional(),
|
|
16600
|
+
default: ActionVariableValueSchema.optional(),
|
|
16601
|
+
/** The allowed values of a `select`. */
|
|
16602
|
+
options: array(string().min(1)).min(1).optional()
|
|
16603
|
+
}).superRefine((v, ctx) => {
|
|
16604
|
+
if (v.type === "select" && v.options === void 0) ctx.addIssue({
|
|
16605
|
+
code: "custom",
|
|
16606
|
+
message: "a select variable needs options",
|
|
16607
|
+
path: ["options"]
|
|
16608
|
+
});
|
|
16609
|
+
if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
|
|
16610
|
+
code: "custom",
|
|
16611
|
+
message: variableValueError(v, v.default) ?? "invalid default",
|
|
16612
|
+
path: ["default"]
|
|
16613
|
+
});
|
|
16614
|
+
});
|
|
16615
|
+
/** Why `value` is not a legal value for the variable, or null when it is. */
|
|
16616
|
+
function variableValueError(variable, value) {
|
|
16617
|
+
switch (variable.type) {
|
|
16618
|
+
case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
|
|
16619
|
+
case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
|
|
16620
|
+
case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
|
|
16621
|
+
case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
|
|
16622
|
+
}
|
|
16623
|
+
}
|
|
16624
|
+
var ActionSourceKindSchema = _enum(["internal", "addon"]);
|
|
16625
|
+
function isInternalActionId(actionId) {
|
|
16626
|
+
return actionId.startsWith("internal:") && actionId.length > 9;
|
|
16627
|
+
}
|
|
16628
|
+
/** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
|
|
16629
|
+
function addonIdOfActionId(actionId) {
|
|
16630
|
+
if (isInternalActionId(actionId)) return null;
|
|
16631
|
+
const at = actionId.indexOf(":");
|
|
16632
|
+
return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
|
|
16633
|
+
}
|
|
16634
|
+
var ActionStatusSchema = object({
|
|
16635
|
+
isRunning: boolean(),
|
|
16636
|
+
/** Ms epoch the latest run STARTED; null when it never ran. */
|
|
16637
|
+
lastRunAt: number().nullable(),
|
|
16638
|
+
/** The latest run's failure; null on success or when it never ran. */
|
|
16639
|
+
lastError: string().nullable()
|
|
16640
|
+
});
|
|
16641
|
+
var ActionEntrySchema = object({
|
|
16642
|
+
/** `internal:<uuid>` or `<addonId>:<localId>`. */
|
|
16643
|
+
id: string().min(3),
|
|
16644
|
+
name: string().min(1).max(120),
|
|
16645
|
+
/** The addon that declared it; `core-blocks` for an internal one. */
|
|
16646
|
+
addonId: string().min(1),
|
|
16647
|
+
source: ActionSourceKindSchema,
|
|
16648
|
+
/** An addon-declared entry is edited where it was declared. */
|
|
16649
|
+
readOnly: boolean(),
|
|
16650
|
+
/** Internal only: cap and wait steps. No action-in-action, so no cycles. */
|
|
16651
|
+
steps: array(ActionStepSchema).min(1).max(50).optional(),
|
|
16652
|
+
variables: array(ActionVariableSchema).max(20).optional(),
|
|
16653
|
+
status: ActionStatusSchema
|
|
16654
|
+
}).superRefine((entry, ctx) => {
|
|
16655
|
+
if (entry.source === "internal") {
|
|
16656
|
+
if (!isInternalActionId(entry.id)) ctx.addIssue({
|
|
16657
|
+
code: "custom",
|
|
16658
|
+
message: "an internal action id is internal:<uuid>",
|
|
16659
|
+
path: ["id"]
|
|
16660
|
+
});
|
|
16661
|
+
return;
|
|
16662
|
+
}
|
|
16663
|
+
if (entry.steps !== void 0) ctx.addIssue({
|
|
16664
|
+
code: "custom",
|
|
16665
|
+
message: "only an internal action carries steps",
|
|
16666
|
+
path: ["steps"]
|
|
16667
|
+
});
|
|
16668
|
+
if (!entry.readOnly) ctx.addIssue({
|
|
16669
|
+
code: "custom",
|
|
16670
|
+
message: "an addon action is read-only here",
|
|
16671
|
+
path: ["readOnly"]
|
|
16672
|
+
});
|
|
16673
|
+
if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
|
|
16674
|
+
code: "custom",
|
|
16675
|
+
message: "an addon action id is <addonId>:<localId>",
|
|
16676
|
+
path: ["id"]
|
|
16677
|
+
});
|
|
16678
|
+
});
|
|
16679
|
+
/** What an operator writes for an internal action. */
|
|
16680
|
+
var ActionInputSchema = object({
|
|
16681
|
+
name: string().min(1).max(120),
|
|
16682
|
+
steps: array(ActionStepSchema).min(1).max(50),
|
|
16683
|
+
variables: array(ActionVariableSchema).max(20).optional()
|
|
16684
|
+
});
|
|
16685
|
+
/** Who started a run. Absent = the operator pressed it. */
|
|
16686
|
+
var ActionRunOriginSchema = object({
|
|
16687
|
+
/** The automation block whose step started it. */
|
|
16688
|
+
blockId: string().min(1).optional() });
|
|
16689
|
+
/** `started` = the caller did not ask to wait. */
|
|
16690
|
+
var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
|
|
16691
|
+
var ActionRunResultSchema = object({
|
|
16692
|
+
runId: string().min(1),
|
|
16693
|
+
outcome: ActionRunOutcomeSchema,
|
|
16694
|
+
/** Why it did not run, or what failed. */
|
|
16695
|
+
message: string().optional()
|
|
16696
|
+
});
|
|
16697
|
+
_enum([
|
|
16698
|
+
"not-found",
|
|
16699
|
+
"read-only",
|
|
16700
|
+
"invalid-variables",
|
|
16701
|
+
"invalid-steps",
|
|
16702
|
+
"not-linked",
|
|
16703
|
+
"busy"
|
|
16704
|
+
]);
|
|
16705
|
+
object({
|
|
16706
|
+
actionId: string(),
|
|
16707
|
+
runId: string(),
|
|
16708
|
+
isRunning: boolean(),
|
|
16709
|
+
/** Set when the run ended. */
|
|
16710
|
+
outcome: AutomationRunOutcomeSchema.optional(),
|
|
16711
|
+
lastRunAt: number().nullable(),
|
|
16712
|
+
lastError: string().nullable()
|
|
16089
16713
|
});
|
|
16090
16714
|
/**
|
|
16091
16715
|
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
@@ -17680,7 +18304,22 @@ var BrokerProviderInfoSchema = object({
|
|
|
17680
18304
|
*/
|
|
17681
18305
|
interactiveConnectPath: string().min(1).optional(),
|
|
17682
18306
|
/** Relative hub path to disconnect the linked account (same popup pattern). */
|
|
17683
|
-
interactiveDisconnectPath: string().min(1).optional()
|
|
18307
|
+
interactiveDisconnectPath: string().min(1).optional(),
|
|
18308
|
+
/**
|
|
18309
|
+
* The kind signs in through a server-held interactive session instead of
|
|
18310
|
+
* (or before) typed credentials. `basePath` is a hub-relative route set
|
|
18311
|
+
* served by the owning addon (`/addon/<id>/...`) speaking the sign-in
|
|
18312
|
+
* contract: `POST {basePath}/start` (body: the form's settings) answers
|
|
18313
|
+
* `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
|
|
18314
|
+
* `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
|
|
18315
|
+
* 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
|
|
18316
|
+
* (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
|
|
18317
|
+
* existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
|
|
18318
|
+
* (`{ sessionId }`) drops the session. The dialog that edits a broker
|
|
18319
|
+
* offers it as the default path; the fields the session fills are
|
|
18320
|
+
* marked `filledBySignIn` in the kind's settings schema.
|
|
18321
|
+
*/
|
|
18322
|
+
signIn: object({ basePath: string().min(1) }).optional()
|
|
17684
18323
|
}))
|
|
17685
18324
|
});
|
|
17686
18325
|
var ListInputSchema = object({
|
|
@@ -18757,7 +19396,7 @@ var CompositionEventPlanSchema = object({
|
|
|
18757
19396
|
stateField: string(),
|
|
18758
19397
|
fieldKey: string()
|
|
18759
19398
|
});
|
|
18760
|
-
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.
|
|
19399
|
+
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
|
|
18761
19400
|
var CompositionProblemSchema = object({
|
|
18762
19401
|
code: _enum([
|
|
18763
19402
|
"reserved-variant",
|
|
@@ -18785,7 +19424,8 @@ var CompositionProblemSchema = object({
|
|
|
18785
19424
|
"native-capability-replace",
|
|
18786
19425
|
"mixed-quantity",
|
|
18787
19426
|
"helper-mismatch",
|
|
18788
|
-
"member-constraint"
|
|
19427
|
+
"member-constraint",
|
|
19428
|
+
"retention"
|
|
18789
19429
|
]),
|
|
18790
19430
|
path: string(),
|
|
18791
19431
|
message: string()
|
|
@@ -19019,13 +19659,17 @@ Object.freeze({
|
|
|
19019
19659
|
latchedAt: {
|
|
19020
19660
|
kind: "fixed",
|
|
19021
19661
|
result: ["number", "null"]
|
|
19662
|
+
},
|
|
19663
|
+
schmitt: {
|
|
19664
|
+
kind: "fixed",
|
|
19665
|
+
result: ["boolean", "null"]
|
|
19022
19666
|
}
|
|
19023
19667
|
});
|
|
19024
19668
|
/**
|
|
19025
19669
|
* One catalog row per base reading a group helper can build (D944 §3).
|
|
19026
19670
|
* Data, not a form default written into the block.
|
|
19027
19671
|
*/
|
|
19028
|
-
var NOW = {
|
|
19672
|
+
var NOW$2 = {
|
|
19029
19673
|
fieldPath: "lastFetchedAt",
|
|
19030
19674
|
expr: "now"
|
|
19031
19675
|
};
|
|
@@ -19039,6 +19683,8 @@ function numeric(input) {
|
|
|
19039
19683
|
family: "numeric",
|
|
19040
19684
|
deviceType: DeviceType.Sensor,
|
|
19041
19685
|
memberDeviceType: DeviceType.Sensor,
|
|
19686
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19687
|
+
activeWhen: void 0,
|
|
19042
19688
|
commandCaps: [],
|
|
19043
19689
|
baseUnit: baseUnitOf(input.quantity),
|
|
19044
19690
|
aggregates: NUMERIC_AGGREGATES,
|
|
@@ -19054,6 +19700,8 @@ function binary(input) {
|
|
|
19054
19700
|
family: "binary",
|
|
19055
19701
|
deviceType: DeviceType.Sensor,
|
|
19056
19702
|
memberDeviceType: DeviceType.Sensor,
|
|
19703
|
+
memberDeviceTypes: [DeviceType.Sensor],
|
|
19704
|
+
activeWhen: void 0,
|
|
19057
19705
|
commandCaps: [],
|
|
19058
19706
|
quantity: "none",
|
|
19059
19707
|
baseUnit: void 0,
|
|
@@ -19067,73 +19715,73 @@ var GROUP_TEMPLATES = [
|
|
|
19067
19715
|
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
19068
19716
|
role: DeviceRole.TemperatureSensor,
|
|
19069
19717
|
outputCap: "temperature-sensor",
|
|
19070
|
-
outputField: "
|
|
19718
|
+
outputField: "temperature",
|
|
19071
19719
|
quantity: "temperature",
|
|
19072
19720
|
defaultAggregate: "mean",
|
|
19073
19721
|
empty: "null",
|
|
19074
|
-
companions: [NOW]
|
|
19722
|
+
companions: [NOW$2]
|
|
19075
19723
|
}),
|
|
19076
19724
|
numeric({
|
|
19077
19725
|
id: "humidity",
|
|
19078
19726
|
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19079
19727
|
role: DeviceRole.HumiditySensor,
|
|
19080
19728
|
outputCap: "humidity-sensor",
|
|
19081
|
-
outputField: "
|
|
19729
|
+
outputField: "humidity",
|
|
19082
19730
|
quantity: "humidity",
|
|
19083
19731
|
defaultAggregate: "mean",
|
|
19084
19732
|
empty: "null",
|
|
19085
|
-
companions: [NOW]
|
|
19733
|
+
companions: [NOW$2]
|
|
19086
19734
|
}),
|
|
19087
19735
|
numeric({
|
|
19088
19736
|
id: "pressure",
|
|
19089
19737
|
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
19090
19738
|
role: DeviceRole.PressureSensor,
|
|
19091
19739
|
outputCap: "pressure-sensor",
|
|
19092
|
-
outputField: "
|
|
19740
|
+
outputField: "pressure",
|
|
19093
19741
|
quantity: "pressure",
|
|
19094
19742
|
defaultAggregate: "mean",
|
|
19095
19743
|
empty: "null",
|
|
19096
|
-
companions: [NOW]
|
|
19744
|
+
companions: [NOW$2]
|
|
19097
19745
|
}),
|
|
19098
19746
|
numeric({
|
|
19099
19747
|
id: "illuminance",
|
|
19100
19748
|
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
19101
19749
|
role: DeviceRole.AmbientLightSensor,
|
|
19102
19750
|
outputCap: "ambient-light-sensor",
|
|
19103
|
-
outputField: "
|
|
19751
|
+
outputField: "illuminance",
|
|
19104
19752
|
quantity: "illuminance",
|
|
19105
19753
|
defaultAggregate: "mean",
|
|
19106
19754
|
empty: "null",
|
|
19107
|
-
companions: [NOW]
|
|
19755
|
+
companions: [NOW$2]
|
|
19108
19756
|
}),
|
|
19109
19757
|
numeric({
|
|
19110
19758
|
id: "power",
|
|
19111
19759
|
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
19112
19760
|
role: DeviceRole.PowerSensor,
|
|
19113
19761
|
outputCap: "power-meter",
|
|
19114
|
-
outputField: "
|
|
19762
|
+
outputField: "power",
|
|
19115
19763
|
quantity: "power",
|
|
19116
19764
|
defaultAggregate: "sum",
|
|
19117
19765
|
empty: "omit",
|
|
19118
|
-
companions: [NOW]
|
|
19766
|
+
companions: [NOW$2]
|
|
19119
19767
|
}),
|
|
19120
19768
|
numeric({
|
|
19121
19769
|
id: "energy",
|
|
19122
19770
|
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
19123
19771
|
role: DeviceRole.EnergySensor,
|
|
19124
19772
|
outputCap: "power-meter",
|
|
19125
|
-
outputField: "
|
|
19773
|
+
outputField: "energy",
|
|
19126
19774
|
quantity: "energy",
|
|
19127
19775
|
defaultAggregate: "sum",
|
|
19128
19776
|
empty: "omit",
|
|
19129
|
-
companions: [NOW]
|
|
19777
|
+
companions: [NOW$2]
|
|
19130
19778
|
}),
|
|
19131
19779
|
numeric({
|
|
19132
19780
|
id: "battery",
|
|
19133
19781
|
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
19134
19782
|
role: DeviceRole.BatterySensor,
|
|
19135
19783
|
outputCap: "battery",
|
|
19136
|
-
outputField: "
|
|
19784
|
+
outputField: "level",
|
|
19137
19785
|
quantity: "percentage",
|
|
19138
19786
|
defaultAggregate: "mean",
|
|
19139
19787
|
empty: "null",
|
|
@@ -19161,7 +19809,7 @@ var GROUP_TEMPLATES = [
|
|
|
19161
19809
|
quantity: "device",
|
|
19162
19810
|
defaultAggregate: "mean",
|
|
19163
19811
|
empty: "null",
|
|
19164
|
-
companions: [NOW]
|
|
19812
|
+
companions: [NOW$2]
|
|
19165
19813
|
}),
|
|
19166
19814
|
binary({
|
|
19167
19815
|
id: "motion",
|
|
@@ -19255,6 +19903,11 @@ var GROUP_TEMPLATES = [
|
|
|
19255
19903
|
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.",
|
|
19256
19904
|
deviceType: DeviceType.Switch,
|
|
19257
19905
|
outputCap: "switch",
|
|
19906
|
+
outputField: "on",
|
|
19907
|
+
member: {
|
|
19908
|
+
cap: "switch",
|
|
19909
|
+
fieldPath: "on"
|
|
19910
|
+
},
|
|
19258
19911
|
commandCaps: ["switch"]
|
|
19259
19912
|
}),
|
|
19260
19913
|
actuator({
|
|
@@ -19262,34 +19915,136 @@ var GROUP_TEMPLATES = [
|
|
|
19262
19915
|
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.",
|
|
19263
19916
|
deviceType: DeviceType.Light,
|
|
19264
19917
|
outputCap: "switch",
|
|
19918
|
+
outputField: "on",
|
|
19919
|
+
member: {
|
|
19920
|
+
cap: "switch",
|
|
19921
|
+
fieldPath: "on"
|
|
19922
|
+
},
|
|
19265
19923
|
commandCaps: [
|
|
19266
19924
|
"switch",
|
|
19267
19925
|
"brightness",
|
|
19268
19926
|
"color"
|
|
19269
19927
|
]
|
|
19928
|
+
}),
|
|
19929
|
+
actuator({
|
|
19930
|
+
id: "fan",
|
|
19931
|
+
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.",
|
|
19932
|
+
deviceType: DeviceType.Fan,
|
|
19933
|
+
outputCap: "switch",
|
|
19934
|
+
outputField: "on",
|
|
19935
|
+
member: {
|
|
19936
|
+
cap: "switch",
|
|
19937
|
+
fieldPath: "on"
|
|
19938
|
+
},
|
|
19939
|
+
commandCaps: ["switch", "fan-control"]
|
|
19940
|
+
}),
|
|
19941
|
+
actuator({
|
|
19942
|
+
id: "cover",
|
|
19943
|
+
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.",
|
|
19944
|
+
deviceType: DeviceType.Cover,
|
|
19945
|
+
outputCap: "group-active",
|
|
19946
|
+
outputField: "active",
|
|
19947
|
+
member: {
|
|
19948
|
+
cap: "cover",
|
|
19949
|
+
fieldPath: "state"
|
|
19950
|
+
},
|
|
19951
|
+
activeWhen: [
|
|
19952
|
+
"open",
|
|
19953
|
+
"opening",
|
|
19954
|
+
"stopped"
|
|
19955
|
+
],
|
|
19956
|
+
commandCaps: ["cover"]
|
|
19957
|
+
}),
|
|
19958
|
+
actuator({
|
|
19959
|
+
id: "valve",
|
|
19960
|
+
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.",
|
|
19961
|
+
deviceType: DeviceType.Valve,
|
|
19962
|
+
outputCap: "group-active",
|
|
19963
|
+
outputField: "active",
|
|
19964
|
+
member: {
|
|
19965
|
+
cap: "valve",
|
|
19966
|
+
fieldPath: "state"
|
|
19967
|
+
},
|
|
19968
|
+
activeWhen: [
|
|
19969
|
+
"open",
|
|
19970
|
+
"opening",
|
|
19971
|
+
"stopped"
|
|
19972
|
+
],
|
|
19973
|
+
commandCaps: ["valve"]
|
|
19974
|
+
}),
|
|
19975
|
+
actuator({
|
|
19976
|
+
id: "lock",
|
|
19977
|
+
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.",
|
|
19978
|
+
deviceType: DeviceType.Lock,
|
|
19979
|
+
outputCap: "group-active",
|
|
19980
|
+
outputField: "active",
|
|
19981
|
+
member: {
|
|
19982
|
+
cap: "lock-control",
|
|
19983
|
+
fieldPath: "state"
|
|
19984
|
+
},
|
|
19985
|
+
activeWhen: ["locked"],
|
|
19986
|
+
commandCaps: ["lock-control"]
|
|
19987
|
+
}),
|
|
19988
|
+
actuator({
|
|
19989
|
+
id: "media-player",
|
|
19990
|
+
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.",
|
|
19991
|
+
deviceType: DeviceType.MediaPlayer,
|
|
19992
|
+
outputCap: "group-active",
|
|
19993
|
+
outputField: "active",
|
|
19994
|
+
member: {
|
|
19995
|
+
cap: "media-player",
|
|
19996
|
+
fieldPath: "state"
|
|
19997
|
+
},
|
|
19998
|
+
activeWhen: ["playing", "buffering"],
|
|
19999
|
+
commandCaps: ["media-player"]
|
|
20000
|
+
}),
|
|
20001
|
+
actuator({
|
|
20002
|
+
id: "climate",
|
|
20003
|
+
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.",
|
|
20004
|
+
deviceType: DeviceType.Thermostat,
|
|
20005
|
+
memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
|
|
20006
|
+
outputCap: "group-active",
|
|
20007
|
+
outputField: "active",
|
|
20008
|
+
member: {
|
|
20009
|
+
cap: "climate-control",
|
|
20010
|
+
fieldPath: "mode"
|
|
20011
|
+
},
|
|
20012
|
+
activeWhen: [
|
|
20013
|
+
"heat",
|
|
20014
|
+
"cool",
|
|
20015
|
+
"auto",
|
|
20016
|
+
"heat_cool",
|
|
20017
|
+
"fan_only",
|
|
20018
|
+
"dry"
|
|
20019
|
+
],
|
|
20020
|
+
commandCaps: ["climate-control"]
|
|
19270
20021
|
})
|
|
19271
20022
|
];
|
|
19272
20023
|
function actuator(input) {
|
|
19273
20024
|
return {
|
|
19274
|
-
|
|
20025
|
+
id: input.id,
|
|
20026
|
+
summary: input.summary,
|
|
20027
|
+
deviceType: input.deviceType,
|
|
20028
|
+
outputCap: input.outputCap,
|
|
20029
|
+
outputField: input.outputField,
|
|
20030
|
+
commandCaps: input.commandCaps,
|
|
19275
20031
|
family: "actuator",
|
|
19276
20032
|
role: void 0,
|
|
19277
20033
|
memberDeviceType: input.deviceType,
|
|
19278
|
-
|
|
20034
|
+
memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
|
|
20035
|
+
activeWhen: input.activeWhen,
|
|
19279
20036
|
quantity: "none",
|
|
19280
20037
|
baseUnit: void 0,
|
|
19281
20038
|
aggregates: BINARY_AGGREGATES,
|
|
19282
20039
|
defaultAggregate: "any",
|
|
19283
20040
|
empty: "offline",
|
|
19284
|
-
accept: [
|
|
19285
|
-
cap: "switch",
|
|
19286
|
-
fieldPath: "on"
|
|
19287
|
-
}],
|
|
20041
|
+
accept: [input.member],
|
|
19288
20042
|
companions: [CHANGED]
|
|
19289
20043
|
};
|
|
19290
20044
|
}
|
|
19291
20045
|
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
19292
20046
|
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
20047
|
+
DeviceType.Camera;
|
|
19293
20048
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
19294
20049
|
/**
|
|
19295
20050
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19604,7 +20359,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
19604
20359
|
kind: "mutation",
|
|
19605
20360
|
auth: "admin",
|
|
19606
20361
|
access: "view"
|
|
19607
|
-
})
|
|
20362
|
+
}), method(object({
|
|
20363
|
+
blockId: string().min(1),
|
|
20364
|
+
trace: AutomationRunTraceSchema.optional(),
|
|
20365
|
+
runStartedAt: number().optional(),
|
|
20366
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
20367
|
+
}), _void(), {
|
|
20368
|
+
kind: "mutation",
|
|
20369
|
+
auth: "admin"
|
|
20370
|
+
}), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
|
|
20371
|
+
traces: array(AutomationRunTraceSchema),
|
|
20372
|
+
lastError: string().nullable()
|
|
20373
|
+
}), { auth: "admin" });
|
|
19608
20374
|
/**
|
|
19609
20375
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
19610
20376
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -44513,7 +45279,7 @@ var NetworkAccessStatusSchema = object({
|
|
|
44513
45279
|
});
|
|
44514
45280
|
/**
|
|
44515
45281
|
* Optional, richer endpoint shape returned by providers that expose
|
|
44516
|
-
* MORE than one ingress concurrently (Tailscale
|
|
45282
|
+
* MORE than one ingress concurrently (Tailscale Funnel with mixed
|
|
44517
45283
|
* serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
|
|
44518
45284
|
* the originating provider config (mode + sourcePort) so the
|
|
44519
45285
|
* orchestrator UI can label rows distinctly. Providers that expose only
|
|
@@ -44906,51 +45672,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
|
|
|
44906
45672
|
kind: "mutation",
|
|
44907
45673
|
auth: "admin"
|
|
44908
45674
|
});
|
|
44909
|
-
new Set([
|
|
44910
|
-
{
|
|
44911
|
-
id: "person",
|
|
44912
|
-
name: "Person"
|
|
44913
|
-
},
|
|
44914
|
-
{
|
|
44915
|
-
id: "vehicle",
|
|
44916
|
-
name: "Vehicle"
|
|
44917
|
-
},
|
|
44918
|
-
{
|
|
44919
|
-
id: "animal",
|
|
44920
|
-
name: "Animal"
|
|
44921
|
-
},
|
|
44922
|
-
{
|
|
44923
|
-
id: "package",
|
|
44924
|
-
name: "Package"
|
|
44925
|
-
}
|
|
44926
|
-
].map((l) => l.id));
|
|
44927
|
-
var COCO_TO_MACRO = {
|
|
44928
|
-
mapping: {
|
|
44929
|
-
person: "person",
|
|
44930
|
-
bicycle: "vehicle",
|
|
44931
|
-
car: "vehicle",
|
|
44932
|
-
motorcycle: "vehicle",
|
|
44933
|
-
airplane: "vehicle",
|
|
44934
|
-
bus: "vehicle",
|
|
44935
|
-
train: "vehicle",
|
|
44936
|
-
truck: "vehicle",
|
|
44937
|
-
boat: "vehicle",
|
|
44938
|
-
bird: "animal",
|
|
44939
|
-
cat: "animal",
|
|
44940
|
-
dog: "animal",
|
|
44941
|
-
horse: "animal",
|
|
44942
|
-
sheep: "animal",
|
|
44943
|
-
cow: "animal",
|
|
44944
|
-
elephant: "animal",
|
|
44945
|
-
bear: "animal",
|
|
44946
|
-
zebra: "animal",
|
|
44947
|
-
giraffe: "animal",
|
|
44948
|
-
suitcase: "package",
|
|
44949
|
-
backpack: "package",
|
|
44950
|
-
handbag: "package"
|
|
44951
|
-
},
|
|
44952
|
-
preserveOriginal: false
|
|
44953
|
-
};
|
|
44954
45675
|
var AUDIO_MACRO_LABELS = [
|
|
44955
45676
|
{
|
|
44956
45677
|
id: "speech",
|
|
@@ -47200,7 +47921,20 @@ var NcRuleInputSchema = object({
|
|
|
47200
47921
|
* save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
|
|
47201
47922
|
* path does not run Zod defaults.
|
|
47202
47923
|
*/
|
|
47203
|
-
groupingSec: number().int().min(5).max(60).optional()
|
|
47924
|
+
groupingSec: number().int().min(5).max(60).optional(),
|
|
47925
|
+
/**
|
|
47926
|
+
* ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
|
|
47927
|
+
* carries "Correct" / "Wrong" buttons (and, where the channel has room, a
|
|
47928
|
+
* "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
|
|
47929
|
+
* same mark the Library writes, and records whose notification it was and
|
|
47930
|
+
* when. A channel with no buttons gets the same two choices as links.
|
|
47931
|
+
*
|
|
47932
|
+
* `.optional()`, never `.default()` (a Zod default does not run on the addon
|
|
47933
|
+
* cap path): absent and `false` both mean off, which is what every rule
|
|
47934
|
+
* authored before this field meant. An editor turns it off by writing
|
|
47935
|
+
* `false`, so it needs no `clear` key.
|
|
47936
|
+
*/
|
|
47937
|
+
askVerdict: boolean().optional()
|
|
47204
47938
|
});
|
|
47205
47939
|
/**
|
|
47206
47940
|
* Partial patch for `updateRule` — any subset of the input fields, plus the
|
|
@@ -57504,9 +58238,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
57504
58238
|
*/
|
|
57505
58239
|
var AirQualitySensorStatusSchema = object({
|
|
57506
58240
|
/** Carbon dioxide concentration in ppm. */
|
|
57507
|
-
|
|
58241
|
+
co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
57508
58242
|
/** Total volatile organic compounds in ppb. */
|
|
57509
|
-
|
|
58243
|
+
voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
57510
58244
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
57511
58245
|
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
57512
58246
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
@@ -57539,12 +58273,12 @@ var airQualitySensorCapability = {
|
|
|
57539
58273
|
* History (D850): recorded series.
|
|
57540
58274
|
*/
|
|
57541
58275
|
history: { fields: {
|
|
57542
|
-
|
|
58276
|
+
co2: {
|
|
57543
58277
|
kind: "gauge",
|
|
57544
58278
|
unit: "ppm",
|
|
57545
58279
|
deadband: 5
|
|
57546
58280
|
},
|
|
57547
|
-
|
|
58281
|
+
voc: {
|
|
57548
58282
|
kind: "gauge",
|
|
57549
58283
|
unit: "ppb",
|
|
57550
58284
|
deadband: 5
|
|
@@ -57575,7 +58309,7 @@ var airQualitySensorCapability = {
|
|
|
57575
58309
|
*/
|
|
57576
58310
|
var AmbientLightSensorStatusSchema = object({
|
|
57577
58311
|
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57578
|
-
|
|
58312
|
+
illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57579
58313
|
precision: 0,
|
|
57580
58314
|
label: "Illuminance"
|
|
57581
58315
|
})),
|
|
@@ -57604,7 +58338,7 @@ var ambientLightSensorCapability = {
|
|
|
57604
58338
|
/**
|
|
57605
58339
|
* History (D850): recorded series. Wide range, so a RELATIVE deadband (10 %).
|
|
57606
58340
|
*/
|
|
57607
|
-
history: { fields: {
|
|
58341
|
+
history: { fields: { illuminance: {
|
|
57608
58342
|
kind: "gauge",
|
|
57609
58343
|
unit: "lx",
|
|
57610
58344
|
deadbandPct: 10,
|
|
@@ -57743,6 +58477,84 @@ var audioMetricsCapability = {
|
|
|
57743
58477
|
*/
|
|
57744
58478
|
history: "none"
|
|
57745
58479
|
};
|
|
58480
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
58481
|
+
actionId: string().min(1),
|
|
58482
|
+
variables: record(string(), ActionVariableValueSchema).optional()
|
|
58483
|
+
}), _void(), {
|
|
58484
|
+
kind: "mutation",
|
|
58485
|
+
auth: "admin"
|
|
58486
|
+
}), method(object({ actionId: string().min(1) }), _void(), {
|
|
58487
|
+
kind: "mutation",
|
|
58488
|
+
auth: "admin"
|
|
58489
|
+
});
|
|
58490
|
+
/**
|
|
58491
|
+
* actions — the ONE surface for runnable actions, for the UI and for
|
|
58492
|
+
* automations. Provided by the core-blocks builtin on the hub.
|
|
58493
|
+
*
|
|
58494
|
+
* An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
|
|
58495
|
+
* steps, kept in the hub's `actions` record kind) or declared by an addon over
|
|
58496
|
+
* `action-source`. `list` asks every `action-source` provider LIVE and overlays
|
|
58497
|
+
* the run status from the hub's `runs` ledger; there is no catalog here to
|
|
58498
|
+
* drift (D3).
|
|
58499
|
+
*
|
|
58500
|
+
* **Permissions follow the camera, as linked devices do.** An action is linked
|
|
58501
|
+
* to cameras by the operator (`setLinks`, D356: nothing links itself). A
|
|
58502
|
+
* non-admin may `get` / `run` an action only through a camera they may see that
|
|
58503
|
+
* links it: they name the camera (`deviceId`, a top-level field so the scope
|
|
58504
|
+
* gate sees it) and the provider refuses an action that camera does not link.
|
|
58505
|
+
* An admin, and an in-process caller (an automation block), may run any action.
|
|
58506
|
+
* Every refusal is typed (`[not-linked] …`) and logged.
|
|
58507
|
+
*
|
|
58508
|
+
* A second `run` of an action that is already running is REFUSED — traced and
|
|
58509
|
+
* logged — never queued.
|
|
58510
|
+
*/
|
|
58511
|
+
var ActionIdInput = object({ actionId: string().min(1) });
|
|
58512
|
+
var ActionLinksSchema = object({
|
|
58513
|
+
deviceId: number().int().nonnegative(),
|
|
58514
|
+
actionIds: array(string().min(1)).max(100)
|
|
58515
|
+
});
|
|
58516
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
58517
|
+
actionId: string().min(1),
|
|
58518
|
+
deviceId: number().int().nonnegative().optional()
|
|
58519
|
+
}), object({ action: ActionEntrySchema.nullable() }), {
|
|
58520
|
+
role: "viewer",
|
|
58521
|
+
auth: "protected",
|
|
58522
|
+
kind: "query",
|
|
58523
|
+
caller: "required"
|
|
58524
|
+
}), method(object({
|
|
58525
|
+
actionId: string().min(1),
|
|
58526
|
+
variables: record(string(), ActionVariableValueSchema).optional(),
|
|
58527
|
+
wait: boolean().optional(),
|
|
58528
|
+
origin: ActionRunOriginSchema.optional(),
|
|
58529
|
+
deviceId: number().int().nonnegative().optional()
|
|
58530
|
+
}), ActionRunResultSchema, {
|
|
58531
|
+
role: "viewer",
|
|
58532
|
+
auth: "protected",
|
|
58533
|
+
kind: "mutation",
|
|
58534
|
+
caller: "required"
|
|
58535
|
+
}), method(ActionIdInput, _void(), {
|
|
58536
|
+
kind: "mutation",
|
|
58537
|
+
auth: "admin"
|
|
58538
|
+
}), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
|
|
58539
|
+
kind: "mutation",
|
|
58540
|
+
auth: "admin"
|
|
58541
|
+
}), method(object({
|
|
58542
|
+
actionId: string().min(1),
|
|
58543
|
+
action: ActionInputSchema.partial()
|
|
58544
|
+
}), object({ action: ActionEntrySchema }), {
|
|
58545
|
+
kind: "mutation",
|
|
58546
|
+
auth: "admin"
|
|
58547
|
+
}), method(ActionIdInput, _void(), {
|
|
58548
|
+
kind: "mutation",
|
|
58549
|
+
auth: "admin"
|
|
58550
|
+
}), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
|
|
58551
|
+
role: "viewer",
|
|
58552
|
+
auth: "protected",
|
|
58553
|
+
kind: "query"
|
|
58554
|
+
}), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
|
|
58555
|
+
kind: "mutation",
|
|
58556
|
+
auth: "admin"
|
|
58557
|
+
});
|
|
57746
58558
|
/**
|
|
57747
58559
|
* Automation-control cap. Models HA `automation.*` entities on
|
|
57748
58560
|
* `DeviceType.Automation`. An automation is a trigger+condition+
|
|
@@ -57839,7 +58651,7 @@ var BatteryStatusSchema = object({
|
|
|
57839
58651
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
57840
58652
|
* declines to band a non-finite reading, which is the correct shape.
|
|
57841
58653
|
*/
|
|
57842
|
-
|
|
58654
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
57843
58655
|
/**
|
|
57844
58656
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
57845
58657
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -57849,7 +58661,7 @@ var BatteryStatusSchema = object({
|
|
|
57849
58661
|
* `'unknown'` is the absence of an answer: the provider has not read the
|
|
57850
58662
|
* power fields yet, or the firmware reported neither. Before it existed,
|
|
57851
58663
|
* two unreadable fields produced `'none'`, and a camera nobody had reached
|
|
57852
|
-
* was drawn "on battery alone" — the same D315 defect `
|
|
58664
|
+
* was drawn "on battery alone" — the same D315 defect `level` closed
|
|
57853
58665
|
* by going nullable. Consumers SKIP it (no charger state published, no
|
|
57854
58666
|
* glyph, no HomeKit ChargingState) rather than coerce it either way.
|
|
57855
58667
|
*/
|
|
@@ -57873,7 +58685,7 @@ var BatteryStatusSchema = object({
|
|
|
57873
58685
|
* that only report charge. A second reading on this cap, not a second
|
|
57874
58686
|
* `numeric-sensor` on the same device.
|
|
57875
58687
|
*/
|
|
57876
|
-
|
|
58688
|
+
voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
57877
58689
|
/**
|
|
57878
58690
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
57879
58691
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -57907,7 +58719,7 @@ var BatteryStatusSchema = object({
|
|
|
57907
58719
|
/**
|
|
57908
58720
|
* True when the source is a BINARY low-battery indicator (HA
|
|
57909
58721
|
* `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
|
|
57910
|
-
* charge level — `
|
|
58722
|
+
* charge level — `level` is then a coarse stand-in (100 = normal,
|
|
57911
58723
|
* sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
|
|
57912
58724
|
* misleading exact percentage. Absent/false → genuine 0–100 % reading.
|
|
57913
58725
|
*/
|
|
@@ -57920,21 +58732,22 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
57920
58732
|
DeviceType.Switch,
|
|
57921
58733
|
DeviceType.PetFeeder,
|
|
57922
58734
|
DeviceType.Container,
|
|
57923
|
-
DeviceType.Thermostat
|
|
58735
|
+
DeviceType.Thermostat,
|
|
58736
|
+
DeviceType.EventEmitter
|
|
57924
58737
|
];
|
|
57925
58738
|
/** Generic Customize target for the percentage reading (D936). */
|
|
57926
58739
|
var batteryCustomize = {
|
|
57927
58740
|
version: 1,
|
|
57928
58741
|
targets: [{
|
|
57929
|
-
id: "
|
|
58742
|
+
id: "level",
|
|
57930
58743
|
cardinality: "scalar",
|
|
57931
58744
|
vocabulary: {
|
|
57932
58745
|
cap: "battery",
|
|
57933
|
-
stateField: "
|
|
58746
|
+
stateField: "level"
|
|
57934
58747
|
},
|
|
57935
58748
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
57936
58749
|
apply: "add",
|
|
57937
|
-
path: "
|
|
58750
|
+
path: "level",
|
|
57938
58751
|
sources: [{
|
|
57939
58752
|
kind: "field",
|
|
57940
58753
|
valueKinds: ["number", "string"],
|
|
@@ -58028,7 +58841,7 @@ onStatusChanged: { data: object({
|
|
|
58028
58841
|
schema: BatteryStatusSchema,
|
|
58029
58842
|
kind: "push",
|
|
58030
58843
|
empty: {
|
|
58031
|
-
|
|
58844
|
+
level: null,
|
|
58032
58845
|
charging: "unknown",
|
|
58033
58846
|
sleeping: false,
|
|
58034
58847
|
lastUpdated: 0
|
|
@@ -58055,11 +58868,11 @@ onStatusChanged: { data: object({
|
|
|
58055
58868
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
58056
58869
|
*/
|
|
58057
58870
|
history: { fields: {
|
|
58058
|
-
|
|
58871
|
+
level: {
|
|
58059
58872
|
kind: "gauge",
|
|
58060
58873
|
unit: "%"
|
|
58061
58874
|
},
|
|
58062
|
-
|
|
58875
|
+
voltage: {
|
|
58063
58876
|
kind: "gauge",
|
|
58064
58877
|
unit: "V"
|
|
58065
58878
|
}
|
|
@@ -58119,14 +58932,14 @@ var binaryCapability = {
|
|
|
58119
58932
|
* controls to this single-method surface.
|
|
58120
58933
|
*
|
|
58121
58934
|
* The cap is intentionally minimal: a single `setBrightness({deviceId,
|
|
58122
|
-
*
|
|
58935
|
+
* level})` mutation plus the auto-injected `getStatus`. Drivers
|
|
58123
58936
|
* that expose richer controls (color temperature, scenes, schedules)
|
|
58124
58937
|
* should surface those via the device's `getSettingsUISchema()`
|
|
58125
58938
|
* instead of bloating this cap.
|
|
58126
58939
|
*/
|
|
58127
58940
|
var BrightnessStatusSchema = object({
|
|
58128
58941
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
58129
|
-
|
|
58942
|
+
level: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
58130
58943
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
58131
58944
|
lastChangedAt: number()
|
|
58132
58945
|
});
|
|
@@ -58138,7 +58951,7 @@ var brightnessCapability = {
|
|
|
58138
58951
|
deviceTypes: [DeviceType.Light],
|
|
58139
58952
|
methods: { setBrightness: method(object({
|
|
58140
58953
|
deviceId: number().int().nonnegative(),
|
|
58141
|
-
|
|
58954
|
+
level: number().min(0).max(100)
|
|
58142
58955
|
}), _void(), {
|
|
58143
58956
|
kind: "mutation",
|
|
58144
58957
|
auth: "protected"
|
|
@@ -58151,7 +58964,7 @@ var brightnessCapability = {
|
|
|
58151
58964
|
*/
|
|
58152
58965
|
onBrightnessChanged: { data: object({
|
|
58153
58966
|
deviceId: number(),
|
|
58154
|
-
|
|
58967
|
+
level: number().min(0).max(100),
|
|
58155
58968
|
lastChangedAt: number()
|
|
58156
58969
|
}) } },
|
|
58157
58970
|
status: {
|
|
@@ -58174,7 +58987,7 @@ onBrightnessChanged: { data: object({
|
|
|
58174
58987
|
/**
|
|
58175
58988
|
* History (D850): recorded series. Actuator tier: level keeps every change.
|
|
58176
58989
|
*/
|
|
58177
|
-
history: { fields: {
|
|
58990
|
+
history: { fields: { level: {
|
|
58178
58991
|
kind: "gauge",
|
|
58179
58992
|
unit: "%",
|
|
58180
58993
|
minIntervalMs: 0
|
|
@@ -58771,11 +59584,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
|
|
|
58771
59584
|
}),
|
|
58772
59585
|
object({
|
|
58773
59586
|
mode: literal("mired"),
|
|
58774
|
-
|
|
59587
|
+
colorTemperature: number().int().min(50).max(1e3)
|
|
58775
59588
|
})
|
|
58776
59589
|
]);
|
|
58777
59590
|
var ColorStatusSchema = object({
|
|
58778
|
-
/** Active color mode — which of `rgb` / `hsv` / `
|
|
59591
|
+
/** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
|
|
58779
59592
|
* the bulb's current state. */
|
|
58780
59593
|
mode: _enum([
|
|
58781
59594
|
"rgb",
|
|
@@ -58787,7 +59600,7 @@ var ColorStatusSchema = object({
|
|
|
58787
59600
|
/** Populated when `mode === 'hsv'`. */
|
|
58788
59601
|
hsv: HsvTripletSchema.optional(),
|
|
58789
59602
|
/** Populated when `mode === 'mired'`. */
|
|
58790
|
-
|
|
59603
|
+
colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
58791
59604
|
/** Ms epoch of the last operator-driven change. */
|
|
58792
59605
|
lastChangedAt: number()
|
|
58793
59606
|
});
|
|
@@ -58819,7 +59632,7 @@ onColorChanged: { data: object({
|
|
|
58819
59632
|
]),
|
|
58820
59633
|
rgb: RgbTripletSchema.optional(),
|
|
58821
59634
|
hsv: HsvTripletSchema.optional(),
|
|
58822
|
-
|
|
59635
|
+
colorTemperature: number().int().optional(),
|
|
58823
59636
|
lastChangedAt: number()
|
|
58824
59637
|
}) } },
|
|
58825
59638
|
status: {
|
|
@@ -59704,11 +60517,11 @@ var DishwasherStatusSchema = object({
|
|
|
59704
60517
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
59705
60518
|
availablePrograms: array(string()),
|
|
59706
60519
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
59707
|
-
|
|
60520
|
+
remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59708
60521
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
59709
|
-
|
|
60522
|
+
delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59710
60523
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
59711
|
-
|
|
60524
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59712
60525
|
/** True when the door is reported open; null when the door state is not known. */
|
|
59713
60526
|
doorOpen: boolean().nullable(),
|
|
59714
60527
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -59927,14 +60740,14 @@ var dishwasherCapability = {
|
|
|
59927
60740
|
runtimeState: DishwasherStatusSchema,
|
|
59928
60741
|
durability: "session",
|
|
59929
60742
|
history: { fields: {
|
|
59930
|
-
|
|
60743
|
+
progress: {
|
|
59931
60744
|
kind: "gauge",
|
|
59932
60745
|
unit: "%",
|
|
59933
60746
|
deadband: 2
|
|
59934
60747
|
},
|
|
59935
60748
|
state: { kind: "enum" },
|
|
59936
60749
|
operationState: { kind: "enum" },
|
|
59937
|
-
|
|
60750
|
+
remaining: {
|
|
59938
60751
|
kind: "gauge",
|
|
59939
60752
|
unit: "s",
|
|
59940
60753
|
minIntervalMs: 6e4
|
|
@@ -60525,7 +61338,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
60525
61338
|
var FanControlStatusSchema = object({
|
|
60526
61339
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
60527
61340
|
* speed surface (single-speed fan). */
|
|
60528
|
-
|
|
61341
|
+
speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60529
61342
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
60530
61343
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
60531
61344
|
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
@@ -60552,7 +61365,7 @@ var fanControlCapability = {
|
|
|
60552
61365
|
methods: {
|
|
60553
61366
|
setPercentage: method(object({
|
|
60554
61367
|
deviceId: number().int().nonnegative(),
|
|
60555
|
-
|
|
61368
|
+
speed: number().min(0).max(100)
|
|
60556
61369
|
}), _void(), {
|
|
60557
61370
|
kind: "mutation",
|
|
60558
61371
|
auth: "protected"
|
|
@@ -60585,7 +61398,7 @@ var fanControlCapability = {
|
|
|
60585
61398
|
},
|
|
60586
61399
|
/**
|
|
60587
61400
|
* Runtime-state slice — mirrored by the kernel. UI fan speed
|
|
60588
|
-
* sliders read `
|
|
61401
|
+
* sliders read `speed` for live updates.
|
|
60589
61402
|
*/
|
|
60590
61403
|
runtimeState: FanControlStatusSchema,
|
|
60591
61404
|
/**
|
|
@@ -60599,7 +61412,7 @@ var fanControlCapability = {
|
|
|
60599
61412
|
* History (D850): recorded series. Actuator tier: speed keeps every change.
|
|
60600
61413
|
*/
|
|
60601
61414
|
history: { fields: {
|
|
60602
|
-
|
|
61415
|
+
speed: {
|
|
60603
61416
|
kind: "gauge",
|
|
60604
61417
|
unit: "%",
|
|
60605
61418
|
minIntervalMs: 0
|
|
@@ -60788,7 +61601,17 @@ var groupCommandsCapability = {
|
|
|
60788
61601
|
scope: "device",
|
|
60789
61602
|
deviceNative: true,
|
|
60790
61603
|
mode: "singleton",
|
|
60791
|
-
deviceTypes: [
|
|
61604
|
+
deviceTypes: [
|
|
61605
|
+
DeviceType.Switch,
|
|
61606
|
+
DeviceType.Light,
|
|
61607
|
+
DeviceType.Fan,
|
|
61608
|
+
DeviceType.Cover,
|
|
61609
|
+
DeviceType.Valve,
|
|
61610
|
+
DeviceType.Lock,
|
|
61611
|
+
DeviceType.MediaPlayer,
|
|
61612
|
+
DeviceType.Thermostat,
|
|
61613
|
+
DeviceType.Climate
|
|
61614
|
+
],
|
|
60792
61615
|
methods: {},
|
|
60793
61616
|
status: {
|
|
60794
61617
|
schema: GroupCommandsSchema,
|
|
@@ -60806,6 +61629,49 @@ var groupCommandsCapability = {
|
|
|
60806
61629
|
history: "none"
|
|
60807
61630
|
};
|
|
60808
61631
|
/**
|
|
61632
|
+
* Whether a helper actuator group counts as active (D944): at least one
|
|
61633
|
+
* included member is, or every included member is. What "active" means is the
|
|
61634
|
+
* type's: a cover is open, a lock is locked, a media player is playing, a
|
|
61635
|
+
* climate device is not off. A group of lights, switches and fans reports
|
|
61636
|
+
* `switch.on` instead; this cap is for the types whose own state is not a
|
|
61637
|
+
* yes/no. Unknown members are left out (`group-status` counts them) and an
|
|
61638
|
+
* empty included set takes the device offline, never `active: false`.
|
|
61639
|
+
*/
|
|
61640
|
+
var GroupActiveSchema = object({
|
|
61641
|
+
active: boolean().meta({ label: "Active" }),
|
|
61642
|
+
/** Ms epoch when the slice was last updated. */
|
|
61643
|
+
lastChangedAt: number()
|
|
61644
|
+
});
|
|
61645
|
+
var groupActiveCapability = {
|
|
61646
|
+
name: "group-active",
|
|
61647
|
+
scope: "device",
|
|
61648
|
+
deviceNative: true,
|
|
61649
|
+
mode: "singleton",
|
|
61650
|
+
deviceTypes: [
|
|
61651
|
+
DeviceType.Cover,
|
|
61652
|
+
DeviceType.Valve,
|
|
61653
|
+
DeviceType.Lock,
|
|
61654
|
+
DeviceType.MediaPlayer,
|
|
61655
|
+
DeviceType.Climate,
|
|
61656
|
+
DeviceType.Thermostat
|
|
61657
|
+
],
|
|
61658
|
+
methods: {},
|
|
61659
|
+
status: {
|
|
61660
|
+
schema: GroupActiveSchema,
|
|
61661
|
+
kind: "push"
|
|
61662
|
+
},
|
|
61663
|
+
runtimeState: GroupActiveSchema,
|
|
61664
|
+
/**
|
|
61665
|
+
* Runtime-state durability: **session** — recomputed from the members on the
|
|
61666
|
+
* next source event; a restored value would outlive the members it named.
|
|
61667
|
+
*
|
|
61668
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
61669
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
61670
|
+
*/
|
|
61671
|
+
durability: "session",
|
|
61672
|
+
history: "none"
|
|
61673
|
+
};
|
|
61674
|
+
/**
|
|
60809
61675
|
* How many members of a helper group answered (D944). Counts are integers,
|
|
60810
61676
|
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60811
61677
|
* The reading itself stays on the output capability. History is none — the
|
|
@@ -60836,7 +61702,14 @@ var groupStatusCapability = {
|
|
|
60836
61702
|
deviceTypes: [
|
|
60837
61703
|
DeviceType.Sensor,
|
|
60838
61704
|
DeviceType.Switch,
|
|
60839
|
-
DeviceType.Light
|
|
61705
|
+
DeviceType.Light,
|
|
61706
|
+
DeviceType.Fan,
|
|
61707
|
+
DeviceType.Cover,
|
|
61708
|
+
DeviceType.Valve,
|
|
61709
|
+
DeviceType.Lock,
|
|
61710
|
+
DeviceType.MediaPlayer,
|
|
61711
|
+
DeviceType.Thermostat,
|
|
61712
|
+
DeviceType.Climate
|
|
60840
61713
|
],
|
|
60841
61714
|
methods: {},
|
|
60842
61715
|
status: {
|
|
@@ -60984,7 +61857,7 @@ var humidifierCapability = {
|
|
|
60984
61857
|
*/
|
|
60985
61858
|
var HumiditySensorStatusSchema = object({
|
|
60986
61859
|
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60987
|
-
|
|
61860
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60988
61861
|
precision: 0,
|
|
60989
61862
|
label: "Humidity"
|
|
60990
61863
|
})),
|
|
@@ -61013,7 +61886,7 @@ var humiditySensorCapability = {
|
|
|
61013
61886
|
/**
|
|
61014
61887
|
* History (D850): recorded series.
|
|
61015
61888
|
*/
|
|
61016
|
-
history: { fields: {
|
|
61889
|
+
history: { fields: { humidity: {
|
|
61017
61890
|
kind: "gauge",
|
|
61018
61891
|
unit: "%",
|
|
61019
61892
|
deadband: .5
|
|
@@ -61653,7 +62526,7 @@ var LawnMowerControlStatusSchema = object({
|
|
|
61653
62526
|
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61654
62527
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
61655
62528
|
* task is active / progress is unavailable. */
|
|
61656
|
-
|
|
62529
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61657
62530
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
61658
62531
|
* or null when unknown. */
|
|
61659
62532
|
currentCode: number().nullable().meta(readingMeta("none")),
|
|
@@ -62109,7 +62982,14 @@ var lockControlCapability = {
|
|
|
62109
62982
|
}),
|
|
62110
62983
|
unlock: method(object({
|
|
62111
62984
|
deviceId: number().int().nonnegative(),
|
|
62112
|
-
code: string().min(1).optional()
|
|
62985
|
+
code: string().min(1).optional(),
|
|
62986
|
+
/**
|
|
62987
|
+
* Honoured by a helper lock GROUP only (D944): unlocking several doors
|
|
62988
|
+
* with one call is refused unless the caller says it was confirmed. A
|
|
62989
|
+
* single lock ignores it. The refusal lives in the callee, so no
|
|
62990
|
+
* automation or API caller reaches the doors by skipping a dialog.
|
|
62991
|
+
*/
|
|
62992
|
+
confirm: boolean().optional()
|
|
62113
62993
|
}), _void(), {
|
|
62114
62994
|
kind: "mutation",
|
|
62115
62995
|
auth: "protected"
|
|
@@ -62146,6 +63026,44 @@ var lockControlCapability = {
|
|
|
62146
63026
|
volatileStateFields: ["lastChangedAt"]
|
|
62147
63027
|
};
|
|
62148
63028
|
/**
|
|
63029
|
+
* A monotonic total between resets (D944). Energy uses `power-meter.energy`
|
|
63030
|
+
* so dashboards keep one series; every other instantaneous reading lands here.
|
|
63031
|
+
* `value` is the time integral in the source quantity's accumulated base
|
|
63032
|
+
* (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
|
|
63033
|
+
*/
|
|
63034
|
+
var MeterStatusSchema = object({
|
|
63035
|
+
value: number().nullable().meta(readingMeta("device", { label: "Total" })),
|
|
63036
|
+
lastFetchedAt: number()
|
|
63037
|
+
});
|
|
63038
|
+
var meterCapability = {
|
|
63039
|
+
name: "meter",
|
|
63040
|
+
scope: "device",
|
|
63041
|
+
deviceNative: true,
|
|
63042
|
+
mode: "singleton",
|
|
63043
|
+
deviceTypes: [DeviceType.Sensor],
|
|
63044
|
+
methods: {},
|
|
63045
|
+
status: {
|
|
63046
|
+
schema: MeterStatusSchema,
|
|
63047
|
+
kind: "push"
|
|
63048
|
+
},
|
|
63049
|
+
runtimeState: MeterStatusSchema,
|
|
63050
|
+
/**
|
|
63051
|
+
* Runtime-state durability: **restored** — the total is a cache of the
|
|
63052
|
+
* history integral. A restart shows it only until the history pass
|
|
63053
|
+
* recomputes the open period; it is not an in-memory buffer.
|
|
63054
|
+
*
|
|
63055
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
63056
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
63057
|
+
*/
|
|
63058
|
+
durability: "restored",
|
|
63059
|
+
history: { fields: { value: {
|
|
63060
|
+
kind: "counter",
|
|
63061
|
+
deadband: .001,
|
|
63062
|
+
minIntervalMs: 6e4
|
|
63063
|
+
} } },
|
|
63064
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
63065
|
+
};
|
|
63066
|
+
/**
|
|
62149
63067
|
* Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
|
|
62150
63068
|
* Apple TV, Spotify, Roku, generic OTT receivers, …) on
|
|
62151
63069
|
* `DeviceType.MediaPlayer`. Disjoint from the camera streaming
|
|
@@ -62202,10 +63120,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
62202
63120
|
currentMedia: MediaInfoSchema.nullable(),
|
|
62203
63121
|
/** Current playback position in ms. Null when not seekable or
|
|
62204
63122
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
62205
|
-
|
|
63123
|
+
position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
62206
63124
|
/** Total duration of the current media in ms. Null when unknown
|
|
62207
63125
|
* (live stream) or nothing is playing. */
|
|
62208
|
-
|
|
63126
|
+
duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
62209
63127
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
62210
63128
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
62211
63129
|
shuffle: boolean().nullable(),
|
|
@@ -62244,7 +63162,7 @@ var mediaPlayerCapability = {
|
|
|
62244
63162
|
}),
|
|
62245
63163
|
seek: method(object({
|
|
62246
63164
|
deviceId: number().int().nonnegative(),
|
|
62247
|
-
|
|
63165
|
+
position: number().int().nonnegative()
|
|
62248
63166
|
}), _void(), {
|
|
62249
63167
|
kind: "mutation",
|
|
62250
63168
|
auth: "protected"
|
|
@@ -62316,7 +63234,7 @@ var mediaPlayerCapability = {
|
|
|
62316
63234
|
/**
|
|
62317
63235
|
* History (D850): volume (a level an operator or an automation sets; the
|
|
62318
63236
|
* default 10 s floor folds a slider drag into its end value) and mute.
|
|
62319
|
-
* `
|
|
63237
|
+
* `position` is not recorded: it moves continuously while playing.
|
|
62320
63238
|
*/
|
|
62321
63239
|
history: { fields: {
|
|
62322
63240
|
volumeLevel: {
|
|
@@ -63278,9 +64196,9 @@ var NetworkLinkStatusSchema = object({
|
|
|
63278
64196
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
63279
64197
|
* SKIP a null rather than coerce it.
|
|
63280
64198
|
*/
|
|
63281
|
-
|
|
64199
|
+
signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63282
64200
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
63283
|
-
|
|
64201
|
+
rssi: number().optional().meta(readingMeta("signal-level")),
|
|
63284
64202
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
63285
64203
|
ssid: string().optional(),
|
|
63286
64204
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
@@ -63316,7 +64234,7 @@ onStatusChanged: { data: object({
|
|
|
63316
64234
|
kind: "push",
|
|
63317
64235
|
empty: {
|
|
63318
64236
|
type: "unknown",
|
|
63319
|
-
|
|
64237
|
+
signal: null,
|
|
63320
64238
|
lastUpdated: 0
|
|
63321
64239
|
}
|
|
63322
64240
|
},
|
|
@@ -63339,13 +64257,13 @@ onStatusChanged: { data: object({
|
|
|
63339
64257
|
* History (D850): recorded series.
|
|
63340
64258
|
*/
|
|
63341
64259
|
history: { fields: {
|
|
63342
|
-
|
|
64260
|
+
signal: {
|
|
63343
64261
|
kind: "gauge",
|
|
63344
64262
|
unit: "%",
|
|
63345
64263
|
deadband: 3,
|
|
63346
64264
|
minIntervalMs: 6e4
|
|
63347
64265
|
},
|
|
63348
|
-
|
|
64266
|
+
rssi: {
|
|
63349
64267
|
kind: "gauge",
|
|
63350
64268
|
unit: "dBm",
|
|
63351
64269
|
deadband: 2,
|
|
@@ -64090,10 +65008,20 @@ var PetFeederDeviceStatusSchema = _enum([
|
|
|
64090
65008
|
]);
|
|
64091
65009
|
var gramsPortion = number().int().min(4).max(200);
|
|
64092
65010
|
var PetFeederStatusSchema = object({
|
|
64093
|
-
/** Food
|
|
64094
|
-
*
|
|
64095
|
-
* bowl
|
|
65011
|
+
/** Food in the TANK (hopper), as the feeder's own sensor reports it
|
|
65012
|
+
* (`state.food`). A coarse level code, not grams — `0` is empty. The
|
|
65013
|
+
* amount in the bowl is `bowlFood`. On dual-hopper models this is the
|
|
65014
|
+
* combined reading; per-hopper levels live in `food1`/`food2`. Null when
|
|
65015
|
+
* the device has not reported yet. */
|
|
64096
65016
|
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
65017
|
+
/** Food in the BOWL as the feeder reports it (`state.bowl`), in the
|
|
65018
|
+
* feeder's own units. Null when the model reports none. */
|
|
65019
|
+
bowlFood: number().nullable().meta(readingMeta("none")),
|
|
65020
|
+
/** True while the pet is eating (`state.eating`). */
|
|
65021
|
+
eating: boolean(),
|
|
65022
|
+
/** Whether `markFoodReplenished` does anything on this model. When false
|
|
65023
|
+
* the client must not offer it. */
|
|
65024
|
+
supportsMarkRefilled: boolean(),
|
|
64097
65025
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
64098
65026
|
* single-hopper models. */
|
|
64099
65027
|
food1: number().nullable().meta(readingMeta("none")),
|
|
@@ -64101,8 +65029,8 @@ var PetFeederStatusSchema = object({
|
|
|
64101
65029
|
* single-hopper models. */
|
|
64102
65030
|
food2: number().nullable().meta(readingMeta("none")),
|
|
64103
65031
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
64104
|
-
* (`device_class: problem`, on = low). True when the
|
|
64105
|
-
*
|
|
65032
|
+
* (`device_class: problem`, on = low). True when the tank reports empty,
|
|
65033
|
+
* or, on a dual-hopper model, when EITHER hopper is empty. */
|
|
64106
65034
|
lowFood: boolean(),
|
|
64107
65035
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
64108
65036
|
* device has no battery reading. */
|
|
@@ -64170,7 +65098,9 @@ var petFeederCapability = {
|
|
|
64170
65098
|
kind: "mutation",
|
|
64171
65099
|
auth: "protected"
|
|
64172
65100
|
}),
|
|
64173
|
-
/**
|
|
65101
|
+
/** Tell the PetKit cloud a hopper was refilled so it stops its low-food
|
|
65102
|
+
* reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
|
|
65103
|
+
* change any sensor reading. */
|
|
64174
65104
|
markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
64175
65105
|
kind: "mutation",
|
|
64176
65106
|
auth: "protected"
|
|
@@ -64243,6 +65173,7 @@ var petFeederCapability = {
|
|
|
64243
65173
|
*/
|
|
64244
65174
|
history: { fields: {
|
|
64245
65175
|
foodLevel: { kind: "gauge" },
|
|
65176
|
+
bowlFood: { kind: "gauge" },
|
|
64246
65177
|
food1: { kind: "gauge" },
|
|
64247
65178
|
food2: { kind: "gauge" },
|
|
64248
65179
|
batteryPower: {
|
|
@@ -64652,27 +65583,89 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
64652
65583
|
* in real-world devices.
|
|
64653
65584
|
*/
|
|
64654
65585
|
var PowerMeterStatusSchema = object({
|
|
64655
|
-
/** Instantaneous power draw
|
|
64656
|
-
|
|
65586
|
+
/** Instantaneous power draw (watts). */
|
|
65587
|
+
power: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
64657
65588
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
64658
|
-
|
|
64659
|
-
/** Voltage
|
|
64660
|
-
|
|
65589
|
+
energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
65590
|
+
/** Voltage (volts). */
|
|
65591
|
+
voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
64661
65592
|
/** Current in amperes. */
|
|
64662
|
-
|
|
65593
|
+
current: number().optional().meta(readingMeta("current", { label: "Current" })),
|
|
64663
65594
|
/** Apparent power in volt-amperes. */
|
|
64664
|
-
|
|
65595
|
+
apparentPower: number().optional().meta(readingMeta("apparent-power")),
|
|
64665
65596
|
/** Power factor (0..1) if reported. */
|
|
64666
65597
|
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
64667
65598
|
/** Ms epoch when the slice was last updated. */
|
|
64668
65599
|
lastFetchedAt: number()
|
|
64669
65600
|
});
|
|
65601
|
+
/**
|
|
65602
|
+
* Loads that draw metered mains power (D951). The reading is a feature of the
|
|
65603
|
+
* device itself — a plug, a lamp, a fan, an air conditioner, a boiler, a
|
|
65604
|
+
* vacuum dock — not a separate sensor beside it. A `Sensor` stays: a clamp
|
|
65605
|
+
* meter or a standalone energy monitor IS the device. Cover, lock, valve,
|
|
65606
|
+
* camera and the like are left out: their draw is not what anyone meters.
|
|
65607
|
+
*/
|
|
65608
|
+
var POWER_METER_DEVICE_TYPES = [
|
|
65609
|
+
DeviceType.Sensor,
|
|
65610
|
+
DeviceType.Switch,
|
|
65611
|
+
DeviceType.Light,
|
|
65612
|
+
DeviceType.Fan,
|
|
65613
|
+
DeviceType.Climate,
|
|
65614
|
+
DeviceType.Thermostat,
|
|
65615
|
+
DeviceType.Humidifier,
|
|
65616
|
+
DeviceType.WaterHeater,
|
|
65617
|
+
DeviceType.MediaPlayer,
|
|
65618
|
+
DeviceType.Washer,
|
|
65619
|
+
DeviceType.Dryer,
|
|
65620
|
+
DeviceType.Dishwasher,
|
|
65621
|
+
DeviceType.Vacuum,
|
|
65622
|
+
DeviceType.LawnMower,
|
|
65623
|
+
DeviceType.PetFeeder
|
|
65624
|
+
];
|
|
65625
|
+
/** Everything but a bare `Sensor`: a sensor that takes its reading from another sensor adds nothing. */
|
|
65626
|
+
var POWER_METER_CUSTOMIZE_DEVICE_TYPES = POWER_METER_DEVICE_TYPES.filter((type) => type !== DeviceType.Sensor);
|
|
65627
|
+
/** One scalar target per reading; each is sourced from a device of its own (D951). */
|
|
65628
|
+
function powerTarget(id, unit) {
|
|
65629
|
+
return {
|
|
65630
|
+
id,
|
|
65631
|
+
cardinality: "scalar",
|
|
65632
|
+
vocabulary: {
|
|
65633
|
+
cap: "power-meter",
|
|
65634
|
+
stateField: id
|
|
65635
|
+
},
|
|
65636
|
+
deviceTypes: POWER_METER_CUSTOMIZE_DEVICE_TYPES,
|
|
65637
|
+
apply: "add",
|
|
65638
|
+
path: id,
|
|
65639
|
+
sources: [{
|
|
65640
|
+
kind: "numeric",
|
|
65641
|
+
requiredUnit: unit,
|
|
65642
|
+
transforms: [{ kind: "identity" }]
|
|
65643
|
+
}],
|
|
65644
|
+
companions: [{
|
|
65645
|
+
kind: "clock",
|
|
65646
|
+
path: "lastFetchedAt",
|
|
65647
|
+
when: "always"
|
|
65648
|
+
}],
|
|
65649
|
+
sourceReport: { status: "assignment-status" },
|
|
65650
|
+
advancedExpression: true
|
|
65651
|
+
};
|
|
65652
|
+
}
|
|
65653
|
+
/** "Power and energy" extension: power, energy, voltage and current from other devices (D951). */
|
|
65654
|
+
var powerMeterCustomize = {
|
|
65655
|
+
version: 1,
|
|
65656
|
+
targets: [
|
|
65657
|
+
powerTarget("power", "W"),
|
|
65658
|
+
powerTarget("energy", "kWh"),
|
|
65659
|
+
powerTarget("voltage", "V"),
|
|
65660
|
+
powerTarget("current", "A")
|
|
65661
|
+
]
|
|
65662
|
+
};
|
|
64670
65663
|
var powerMeterCapability = {
|
|
64671
65664
|
name: "power-meter",
|
|
64672
65665
|
scope: "device",
|
|
64673
65666
|
deviceNative: true,
|
|
64674
65667
|
mode: "singleton",
|
|
64675
|
-
deviceTypes:
|
|
65668
|
+
deviceTypes: POWER_METER_DEVICE_TYPES,
|
|
64676
65669
|
methods: {},
|
|
64677
65670
|
status: {
|
|
64678
65671
|
schema: PowerMeterStatusSchema,
|
|
@@ -64680,41 +65673,41 @@ var powerMeterCapability = {
|
|
|
64680
65673
|
},
|
|
64681
65674
|
runtimeState: PowerMeterStatusSchema,
|
|
64682
65675
|
/**
|
|
64683
|
-
* Runtime-state durability: **restored** — as `numeric-sensor`; `
|
|
65676
|
+
* Runtime-state durability: **restored** — as `numeric-sensor`; `energy` is an accumulator whose restored value is the baseline.
|
|
64684
65677
|
*
|
|
64685
65678
|
* See `RuntimeStateDurability`. Enforced by
|
|
64686
65679
|
* `scripts/check-runtime-state-durability.ts`.
|
|
64687
65680
|
*/
|
|
64688
65681
|
durability: "restored",
|
|
64689
65682
|
/**
|
|
64690
|
-
* History (D850): recorded series. Gauges are floored at 30 s; `
|
|
65683
|
+
* History (D850): recorded series. Gauges are floored at 30 s; `energy` is the one monotonic meter (counter).
|
|
64691
65684
|
*/
|
|
64692
65685
|
history: { fields: {
|
|
64693
|
-
|
|
65686
|
+
power: {
|
|
64694
65687
|
kind: "gauge",
|
|
64695
65688
|
unit: "W",
|
|
64696
65689
|
deadband: 1,
|
|
64697
65690
|
minIntervalMs: 3e4
|
|
64698
65691
|
},
|
|
64699
|
-
|
|
65692
|
+
energy: {
|
|
64700
65693
|
kind: "counter",
|
|
64701
65694
|
unit: "kWh",
|
|
64702
65695
|
deadband: .01,
|
|
64703
65696
|
minIntervalMs: 6e4
|
|
64704
65697
|
},
|
|
64705
|
-
|
|
65698
|
+
voltage: {
|
|
64706
65699
|
kind: "gauge",
|
|
64707
65700
|
unit: "V",
|
|
64708
65701
|
deadband: 1,
|
|
64709
65702
|
minIntervalMs: 3e4
|
|
64710
65703
|
},
|
|
64711
|
-
|
|
65704
|
+
current: {
|
|
64712
65705
|
kind: "gauge",
|
|
64713
65706
|
unit: "A",
|
|
64714
65707
|
deadband: .05,
|
|
64715
65708
|
minIntervalMs: 3e4
|
|
64716
65709
|
},
|
|
64717
|
-
|
|
65710
|
+
apparentPower: {
|
|
64718
65711
|
kind: "gauge",
|
|
64719
65712
|
unit: "VA",
|
|
64720
65713
|
deadband: 1,
|
|
@@ -64729,7 +65722,8 @@ var powerMeterCapability = {
|
|
|
64729
65722
|
} },
|
|
64730
65723
|
/** Clock fields: written, but excluded from the compare that decides
|
|
64731
65724
|
* whether persisting is worth a SQLite commit. */
|
|
64732
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
65725
|
+
volatileStateFields: ["lastFetchedAt"],
|
|
65726
|
+
customize: powerMeterCustomize
|
|
64733
65727
|
};
|
|
64734
65728
|
/**
|
|
64735
65729
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -64763,9 +65757,6 @@ var PresenceStatusSchema = object({
|
|
|
64763
65757
|
location: string().nullable(),
|
|
64764
65758
|
/** GPS coordinates when available. Null otherwise. */
|
|
64765
65759
|
gps: GpsLocationSchema.nullable(),
|
|
64766
|
-
/** Optional battery level of the tracking device (0..100). Null
|
|
64767
|
-
* when not reported. */
|
|
64768
|
-
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64769
65760
|
/** Ms epoch when the slice was last updated. */
|
|
64770
65761
|
lastChangedAt: number()
|
|
64771
65762
|
});
|
|
@@ -64794,14 +65785,7 @@ var presenceCapability = {
|
|
|
64794
65785
|
* `scripts/check-runtime-state-durability.ts`.
|
|
64795
65786
|
*/
|
|
64796
65787
|
durability: "restored",
|
|
64797
|
-
|
|
64798
|
-
* History (D850): recorded series.
|
|
64799
|
-
*/
|
|
64800
|
-
history: { fields: { batteryPercent: {
|
|
64801
|
-
kind: "gauge",
|
|
64802
|
-
unit: "%",
|
|
64803
|
-
deadband: 1
|
|
64804
|
-
} } },
|
|
65788
|
+
history: "none",
|
|
64805
65789
|
/** Clock fields: written, but excluded from the compare that decides
|
|
64806
65790
|
* whether persisting is worth a SQLite commit. */
|
|
64807
65791
|
volatileStateFields: ["lastChangedAt"]
|
|
@@ -64816,7 +65800,7 @@ var presenceCapability = {
|
|
|
64816
65800
|
*/
|
|
64817
65801
|
var PressureSensorStatusSchema = object({
|
|
64818
65802
|
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64819
|
-
|
|
65803
|
+
pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
64820
65804
|
/** Ms epoch when the slice was last updated. */
|
|
64821
65805
|
lastFetchedAt: number()
|
|
64822
65806
|
});
|
|
@@ -64842,7 +65826,7 @@ var pressureSensorCapability = {
|
|
|
64842
65826
|
/**
|
|
64843
65827
|
* History (D850): recorded series.
|
|
64844
65828
|
*/
|
|
64845
|
-
history: { fields: {
|
|
65829
|
+
history: { fields: { pressure: {
|
|
64846
65830
|
kind: "gauge",
|
|
64847
65831
|
unit: "hPa",
|
|
64848
65832
|
deadband: .1
|
|
@@ -65410,6 +66394,8 @@ var runningCustomize = {
|
|
|
65410
66394
|
stateField: "running"
|
|
65411
66395
|
},
|
|
65412
66396
|
deviceTypes: [
|
|
66397
|
+
DeviceType.Washer,
|
|
66398
|
+
DeviceType.Dryer,
|
|
65413
66399
|
DeviceType.Dishwasher,
|
|
65414
66400
|
DeviceType.Vacuum,
|
|
65415
66401
|
DeviceType.LawnMower,
|
|
@@ -67899,7 +68885,8 @@ var switchCapability = {
|
|
|
67899
68885
|
deviceTypes: [
|
|
67900
68886
|
DeviceType.Switch,
|
|
67901
68887
|
DeviceType.Siren,
|
|
67902
|
-
DeviceType.Light
|
|
68888
|
+
DeviceType.Light,
|
|
68889
|
+
DeviceType.Fan
|
|
67903
68890
|
],
|
|
67904
68891
|
methods: { setState: method(object({
|
|
67905
68892
|
deviceId: number(),
|
|
@@ -68538,7 +69525,7 @@ var tamperCapability = {
|
|
|
68538
69525
|
*/
|
|
68539
69526
|
var TemperatureSensorStatusSchema = object({
|
|
68540
69527
|
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68541
|
-
|
|
69528
|
+
temperature: number().nullable().meta(readingMeta("temperature", {
|
|
68542
69529
|
precision: 1,
|
|
68543
69530
|
label: "Temperature"
|
|
68544
69531
|
})),
|
|
@@ -68567,7 +69554,7 @@ var temperatureSensorCapability = {
|
|
|
68567
69554
|
/**
|
|
68568
69555
|
* History (D850): recorded series.
|
|
68569
69556
|
*/
|
|
68570
|
-
history: { fields: {
|
|
69557
|
+
history: { fields: { temperature: {
|
|
68571
69558
|
kind: "gauge",
|
|
68572
69559
|
unit: "°C",
|
|
68573
69560
|
deadband: .1
|
|
@@ -68864,7 +69851,7 @@ var VacuumControlStatusSchema = object({
|
|
|
68864
69851
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
68865
69852
|
availableFanSpeeds: array(string()),
|
|
68866
69853
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
68867
|
-
|
|
69854
|
+
progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68868
69855
|
/** Current error code (0 / null = no error). */
|
|
68869
69856
|
errorCode: number().nullable().meta(readingMeta("none")),
|
|
68870
69857
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
@@ -70112,8 +71099,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
|
|
|
70112
71099
|
kind: "mutation",
|
|
70113
71100
|
auth: "admin"
|
|
70114
71101
|
});
|
|
71102
|
+
DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
|
|
70115
71103
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
70116
|
-
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;
|
|
71104
|
+
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;
|
|
70117
71105
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
70118
71106
|
DeviceRole.BinarySensor, DeviceRole.MotionSensor;
|
|
70119
71107
|
new Set(CAP_NAMES);
|
|
@@ -70442,6 +71430,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70442
71430
|
featureProbe: featureProbeCapability,
|
|
70443
71431
|
flood: floodCapability,
|
|
70444
71432
|
gas: gasCapability,
|
|
71433
|
+
groupActive: groupActiveCapability,
|
|
70445
71434
|
groupCommands: groupCommandsCapability,
|
|
70446
71435
|
groupStatus: groupStatusCapability,
|
|
70447
71436
|
heatingValve: heatingValveCapability,
|
|
@@ -70453,6 +71442,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70453
71442
|
lawnMowerControl: lawnMowerControlCapability,
|
|
70454
71443
|
lockControl: lockControlCapability,
|
|
70455
71444
|
mediaPlayer: mediaPlayerCapability,
|
|
71445
|
+
meter: meterCapability,
|
|
70456
71446
|
motion: motionCapability,
|
|
70457
71447
|
motionTrigger: motionTriggerCapability,
|
|
70458
71448
|
motionZones: motionZonesCapability,
|
|
@@ -70515,7 +71505,7 @@ var BaseDevice = class {
|
|
|
70515
71505
|
* `device-local-state.ts`. Drivers access via:
|
|
70516
71506
|
*
|
|
70517
71507
|
* `this.state.battery.sleeping = true` // patches the battery slice
|
|
70518
|
-
* `const pct = this.state.battery.
|
|
71508
|
+
* `const pct = this.state.battery.level` // reads the battery slice
|
|
70519
71509
|
* `this.state.deviceStatus.online = true` // mirrors `markOnline(true)`
|
|
70520
71510
|
*
|
|
70521
71511
|
* Adding a new cap with `runtimeState:` automatically extends this
|
|
@@ -70555,7 +71545,7 @@ var BaseDevice = class {
|
|
|
70555
71545
|
* shape; drivers don't redeclare it, they just write through.
|
|
70556
71546
|
*
|
|
70557
71547
|
* Read: `this.runtimeState.getCapState('battery')` →
|
|
70558
|
-
* `{
|
|
71548
|
+
* `{level, charging, sleeping, lastUpdated}` for any
|
|
70559
71549
|
* provider that registers `batteryCapability`.
|
|
70560
71550
|
* Write: `this.runtimeState.setCapState('battery', { … })`.
|
|
70561
71551
|
*
|
|
@@ -71712,7 +72702,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
71712
72702
|
return toDeviceSummary(device, this.addonId);
|
|
71713
72703
|
}
|
|
71714
72704
|
};
|
|
71715
|
-
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;
|
|
72705
|
+
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;
|
|
71716
72706
|
new Set(Object.values(DeviceType));
|
|
71717
72707
|
Object.freeze({
|
|
71718
72708
|
"accessories.getStatus": {
|
|
@@ -71729,6 +72719,104 @@ Object.freeze({
|
|
|
71729
72719
|
access: "create",
|
|
71730
72720
|
role: "admin"
|
|
71731
72721
|
},
|
|
72722
|
+
"actions.create": {
|
|
72723
|
+
capName: "actions",
|
|
72724
|
+
capScope: "system",
|
|
72725
|
+
addonId: null,
|
|
72726
|
+
access: "create",
|
|
72727
|
+
role: "admin"
|
|
72728
|
+
},
|
|
72729
|
+
"actions.delete": {
|
|
72730
|
+
capName: "actions",
|
|
72731
|
+
capScope: "system",
|
|
72732
|
+
addonId: null,
|
|
72733
|
+
access: "delete",
|
|
72734
|
+
role: "admin"
|
|
72735
|
+
},
|
|
72736
|
+
"actions.get": {
|
|
72737
|
+
capName: "actions",
|
|
72738
|
+
capScope: "system",
|
|
72739
|
+
addonId: null,
|
|
72740
|
+
access: "view",
|
|
72741
|
+
role: "viewer"
|
|
72742
|
+
},
|
|
72743
|
+
"actions.getLinks": {
|
|
72744
|
+
capName: "actions",
|
|
72745
|
+
capScope: "system",
|
|
72746
|
+
addonId: null,
|
|
72747
|
+
access: "view",
|
|
72748
|
+
role: "admin"
|
|
72749
|
+
},
|
|
72750
|
+
"actions.getTraces": {
|
|
72751
|
+
capName: "actions",
|
|
72752
|
+
capScope: "system",
|
|
72753
|
+
addonId: null,
|
|
72754
|
+
access: "view",
|
|
72755
|
+
role: "admin"
|
|
72756
|
+
},
|
|
72757
|
+
"actions.list": {
|
|
72758
|
+
capName: "actions",
|
|
72759
|
+
capScope: "system",
|
|
72760
|
+
addonId: null,
|
|
72761
|
+
access: "view",
|
|
72762
|
+
role: "admin"
|
|
72763
|
+
},
|
|
72764
|
+
"actions.listForCamera": {
|
|
72765
|
+
capName: "actions",
|
|
72766
|
+
capScope: "system",
|
|
72767
|
+
addonId: null,
|
|
72768
|
+
access: "view",
|
|
72769
|
+
role: "viewer"
|
|
72770
|
+
},
|
|
72771
|
+
"actions.run": {
|
|
72772
|
+
capName: "actions",
|
|
72773
|
+
capScope: "system",
|
|
72774
|
+
addonId: null,
|
|
72775
|
+
access: "create",
|
|
72776
|
+
role: "viewer"
|
|
72777
|
+
},
|
|
72778
|
+
"actions.setLinks": {
|
|
72779
|
+
capName: "actions",
|
|
72780
|
+
capScope: "system",
|
|
72781
|
+
addonId: null,
|
|
72782
|
+
access: "create",
|
|
72783
|
+
role: "admin"
|
|
72784
|
+
},
|
|
72785
|
+
"actions.stop": {
|
|
72786
|
+
capName: "actions",
|
|
72787
|
+
capScope: "system",
|
|
72788
|
+
addonId: null,
|
|
72789
|
+
access: "create",
|
|
72790
|
+
role: "admin"
|
|
72791
|
+
},
|
|
72792
|
+
"actions.update": {
|
|
72793
|
+
capName: "actions",
|
|
72794
|
+
capScope: "system",
|
|
72795
|
+
addonId: null,
|
|
72796
|
+
access: "create",
|
|
72797
|
+
role: "admin"
|
|
72798
|
+
},
|
|
72799
|
+
"actionSource.listActions": {
|
|
72800
|
+
capName: "action-source",
|
|
72801
|
+
capScope: "system",
|
|
72802
|
+
addonId: null,
|
|
72803
|
+
access: "view",
|
|
72804
|
+
role: "admin"
|
|
72805
|
+
},
|
|
72806
|
+
"actionSource.runAction": {
|
|
72807
|
+
capName: "action-source",
|
|
72808
|
+
capScope: "system",
|
|
72809
|
+
addonId: null,
|
|
72810
|
+
access: "create",
|
|
72811
|
+
role: "admin"
|
|
72812
|
+
},
|
|
72813
|
+
"actionSource.stopAction": {
|
|
72814
|
+
capName: "action-source",
|
|
72815
|
+
capScope: "system",
|
|
72816
|
+
addonId: null,
|
|
72817
|
+
access: "create",
|
|
72818
|
+
role: "admin"
|
|
72819
|
+
},
|
|
71732
72820
|
"addonPages.listPages": {
|
|
71733
72821
|
capName: "addon-pages",
|
|
71734
72822
|
capScope: "system",
|
|
@@ -73010,6 +74098,13 @@ Object.freeze({
|
|
|
73010
74098
|
access: "view",
|
|
73011
74099
|
role: "admin"
|
|
73012
74100
|
},
|
|
74101
|
+
"coreBlocks.getAutomationRunState": {
|
|
74102
|
+
capName: "core-blocks",
|
|
74103
|
+
capScope: "system",
|
|
74104
|
+
addonId: null,
|
|
74105
|
+
access: "view",
|
|
74106
|
+
role: "admin"
|
|
74107
|
+
},
|
|
73013
74108
|
"coreBlocks.getBlockSettings": {
|
|
73014
74109
|
capName: "core-blocks",
|
|
73015
74110
|
capScope: "system",
|
|
@@ -73031,6 +74126,13 @@ Object.freeze({
|
|
|
73031
74126
|
access: "view",
|
|
73032
74127
|
role: "admin"
|
|
73033
74128
|
},
|
|
74129
|
+
"coreBlocks.getTraces": {
|
|
74130
|
+
capName: "core-blocks",
|
|
74131
|
+
capScope: "system",
|
|
74132
|
+
addonId: null,
|
|
74133
|
+
access: "view",
|
|
74134
|
+
role: "admin"
|
|
74135
|
+
},
|
|
73034
74136
|
"coreBlocks.getTypeDefs": {
|
|
73035
74137
|
capName: "core-blocks",
|
|
73036
74138
|
capScope: "system",
|
|
@@ -73066,6 +74168,13 @@ Object.freeze({
|
|
|
73066
74168
|
access: "create",
|
|
73067
74169
|
role: "admin"
|
|
73068
74170
|
},
|
|
74171
|
+
"coreBlocks.reportAutomationRun": {
|
|
74172
|
+
capName: "core-blocks",
|
|
74173
|
+
capScope: "system",
|
|
74174
|
+
addonId: null,
|
|
74175
|
+
access: "create",
|
|
74176
|
+
role: "admin"
|
|
74177
|
+
},
|
|
73069
74178
|
"coreBlocks.restart": {
|
|
73070
74179
|
capName: "core-blocks",
|
|
73071
74180
|
capScope: "system",
|
|
@@ -74935,6 +76044,13 @@ Object.freeze({
|
|
|
74935
76044
|
access: "view",
|
|
74936
76045
|
role: "viewer"
|
|
74937
76046
|
},
|
|
76047
|
+
"groupActive.getStatus": {
|
|
76048
|
+
capName: "group-active",
|
|
76049
|
+
capScope: "device",
|
|
76050
|
+
addonId: null,
|
|
76051
|
+
access: "view",
|
|
76052
|
+
role: "viewer"
|
|
76053
|
+
},
|
|
74938
76054
|
"groupCommands.getStatus": {
|
|
74939
76055
|
capName: "group-commands",
|
|
74940
76056
|
capScope: "device",
|
|
@@ -75901,6 +77017,13 @@ Object.freeze({
|
|
|
75901
77017
|
access: "create",
|
|
75902
77018
|
role: "admin"
|
|
75903
77019
|
},
|
|
77020
|
+
"meter.getStatus": {
|
|
77021
|
+
capName: "meter",
|
|
77022
|
+
capScope: "device",
|
|
77023
|
+
addonId: null,
|
|
77024
|
+
access: "view",
|
|
77025
|
+
role: "viewer"
|
|
77026
|
+
},
|
|
75904
77027
|
"metricsProvider.collectSnapshot": {
|
|
75905
77028
|
capName: "metrics-provider",
|
|
75906
77029
|
capScope: "system",
|
|
@@ -81625,7 +82748,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81625
82748
|
label: t("Full brightness", "Luminosità massima"),
|
|
81626
82749
|
phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
|
|
81627
82750
|
icon: "sun",
|
|
81628
|
-
args: {
|
|
82751
|
+
args: { level: 100 }
|
|
81629
82752
|
},
|
|
81630
82753
|
{
|
|
81631
82754
|
id: "brightness.half",
|
|
@@ -81633,7 +82756,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81633
82756
|
label: t("Half brightness", "Luminosità a metà"),
|
|
81634
82757
|
phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
|
|
81635
82758
|
icon: "sun-dim",
|
|
81636
|
-
args: {
|
|
82759
|
+
args: { level: 50 }
|
|
81637
82760
|
},
|
|
81638
82761
|
{
|
|
81639
82762
|
id: "brightness.off",
|
|
@@ -81641,16 +82764,16 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81641
82764
|
label: t("Brightness off", "Luminosità a zero"),
|
|
81642
82765
|
phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
|
|
81643
82766
|
icon: "lightbulb-off",
|
|
81644
|
-
args: {
|
|
82767
|
+
args: { level: 0 }
|
|
81645
82768
|
},
|
|
81646
82769
|
{
|
|
81647
82770
|
id: "brightness.set",
|
|
81648
82771
|
method: "setBrightness",
|
|
81649
82772
|
label: t("Set brightness", "Imposta la luminosità"),
|
|
81650
|
-
phrase: t("Set the brightness of {device} to {
|
|
82773
|
+
phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
|
|
81651
82774
|
icon: "sun-medium",
|
|
81652
82775
|
openArgs: [{
|
|
81653
|
-
key: "
|
|
82776
|
+
key: "level",
|
|
81654
82777
|
label: PERCENT,
|
|
81655
82778
|
offer: {
|
|
81656
82779
|
kind: "number",
|
|
@@ -81664,13 +82787,13 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81664
82787
|
],
|
|
81665
82788
|
state: [{
|
|
81666
82789
|
kind: "numeric",
|
|
81667
|
-
field: "
|
|
82790
|
+
field: "level",
|
|
81668
82791
|
quantity: t("the brightness", "la luminosità"),
|
|
81669
82792
|
label: t("Brightness", "Luminosità"),
|
|
81670
82793
|
unit: "%",
|
|
81671
82794
|
icon: "sun"
|
|
81672
82795
|
}],
|
|
81673
|
-
events: { onBrightnessChanged: { notOperatorFacing: "the `
|
|
82796
|
+
events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
|
|
81674
82797
|
},
|
|
81675
82798
|
color: {
|
|
81676
82799
|
scope: "device",
|
|
@@ -81684,7 +82807,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81684
82807
|
icon: "sun",
|
|
81685
82808
|
args: { color: {
|
|
81686
82809
|
mode: "mired",
|
|
81687
|
-
|
|
82810
|
+
colorTemperature: 370
|
|
81688
82811
|
} }
|
|
81689
82812
|
},
|
|
81690
82813
|
{
|
|
@@ -81695,7 +82818,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
81695
82818
|
icon: "snowflake",
|
|
81696
82819
|
args: { color: {
|
|
81697
82820
|
mode: "mired",
|
|
81698
|
-
|
|
82821
|
+
colorTemperature: 200
|
|
81699
82822
|
} }
|
|
81700
82823
|
},
|
|
81701
82824
|
{
|
|
@@ -82309,7 +83432,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
82309
83432
|
label: t("Fan off", "Ventilatore spento"),
|
|
82310
83433
|
phrase: t("Stop {device}", "Ferma {device}"),
|
|
82311
83434
|
icon: "power-off",
|
|
82312
|
-
args: {
|
|
83435
|
+
args: { speed: 0 }
|
|
82313
83436
|
},
|
|
82314
83437
|
{
|
|
82315
83438
|
id: "fan.full",
|
|
@@ -82317,16 +83440,16 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
82317
83440
|
label: t("Fan full", "Ventilatore al massimo"),
|
|
82318
83441
|
phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
|
|
82319
83442
|
icon: "fan",
|
|
82320
|
-
args: {
|
|
83443
|
+
args: { speed: 100 }
|
|
82321
83444
|
},
|
|
82322
83445
|
{
|
|
82323
83446
|
id: "fan.speed",
|
|
82324
83447
|
method: "setPercentage",
|
|
82325
83448
|
label: t("Set speed", "Imposta la velocità"),
|
|
82326
|
-
phrase: t("Set the speed of {device} to {
|
|
83449
|
+
phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
|
|
82327
83450
|
icon: "fan",
|
|
82328
83451
|
openArgs: [{
|
|
82329
|
-
key: "
|
|
83452
|
+
key: "speed",
|
|
82330
83453
|
label: t("Speed", "Velocità"),
|
|
82331
83454
|
offer: {
|
|
82332
83455
|
kind: "number",
|
|
@@ -82388,7 +83511,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
82388
83511
|
],
|
|
82389
83512
|
state: [{
|
|
82390
83513
|
kind: "numeric",
|
|
82391
|
-
field: "
|
|
83514
|
+
field: "speed",
|
|
82392
83515
|
quantity: t("the speed", "la velocità"),
|
|
82393
83516
|
label: t("Speed", "Velocità"),
|
|
82394
83517
|
unit: "%",
|
|
@@ -83186,7 +84309,7 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
83186
84309
|
},
|
|
83187
84310
|
{
|
|
83188
84311
|
kind: "numeric",
|
|
83189
|
-
field: "
|
|
84312
|
+
field: "progress",
|
|
83190
84313
|
quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
|
|
83191
84314
|
label: t("Progress", "Avanzamento"),
|
|
83192
84315
|
unit: "%",
|
|
@@ -83544,10 +84667,10 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
83544
84667
|
id: "media.seek",
|
|
83545
84668
|
method: "seek",
|
|
83546
84669
|
label: t("Seek", "Vai al punto"),
|
|
83547
|
-
phrase: t("Move {device} to {
|
|
84670
|
+
phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
|
|
83548
84671
|
icon: "fast-forward",
|
|
83549
84672
|
openArgs: [{
|
|
83550
|
-
key: "
|
|
84673
|
+
key: "position",
|
|
83551
84674
|
label: t("Position", "Posizione"),
|
|
83552
84675
|
offer: {
|
|
83553
84676
|
kind: "number",
|
|
@@ -83999,7 +85122,39 @@ var APPLIANCE_CAP_VOCABULARY = {
|
|
|
83999
85122
|
phrase: t("When {device} finishes", "Quando {device} finisce"),
|
|
84000
85123
|
icon: "square"
|
|
84001
85124
|
}
|
|
84002
|
-
}
|
|
85125
|
+
},
|
|
85126
|
+
overrides: { byType: {
|
|
85127
|
+
[DeviceType.Washer]: {
|
|
85128
|
+
state: { running: {
|
|
85129
|
+
whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
|
|
85130
|
+
whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
|
|
85131
|
+
} },
|
|
85132
|
+
events: {
|
|
85133
|
+
onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
|
|
85134
|
+
onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
|
|
85135
|
+
}
|
|
85136
|
+
},
|
|
85137
|
+
[DeviceType.Dryer]: {
|
|
85138
|
+
state: { running: {
|
|
85139
|
+
whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
|
|
85140
|
+
whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
|
|
85141
|
+
} },
|
|
85142
|
+
events: {
|
|
85143
|
+
onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
|
|
85144
|
+
onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
|
|
85145
|
+
}
|
|
85146
|
+
},
|
|
85147
|
+
[DeviceType.Dishwasher]: {
|
|
85148
|
+
state: { running: {
|
|
85149
|
+
whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
|
|
85150
|
+
whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
|
|
85151
|
+
} },
|
|
85152
|
+
events: {
|
|
85153
|
+
onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
|
|
85154
|
+
onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
|
|
85155
|
+
}
|
|
85156
|
+
}
|
|
85157
|
+
} }
|
|
84003
85158
|
},
|
|
84004
85159
|
update: {
|
|
84005
85160
|
scope: "device",
|
|
@@ -84564,7 +85719,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84564
85719
|
state: [
|
|
84565
85720
|
{
|
|
84566
85721
|
kind: "numeric",
|
|
84567
|
-
field: "
|
|
85722
|
+
field: "co2",
|
|
84568
85723
|
quantity: t("the CO₂", "la CO₂"),
|
|
84569
85724
|
label: t("CO₂", "CO₂"),
|
|
84570
85725
|
unit: "ppm",
|
|
@@ -84572,7 +85727,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84572
85727
|
},
|
|
84573
85728
|
{
|
|
84574
85729
|
kind: "numeric",
|
|
84575
|
-
field: "
|
|
85730
|
+
field: "voc",
|
|
84576
85731
|
quantity: t("the VOC level", "il livello di COV"),
|
|
84577
85732
|
label: t("VOC", "COV"),
|
|
84578
85733
|
unit: "ppb",
|
|
@@ -84608,7 +85763,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84608
85763
|
noun: t("Light level", "Luminosità ambiente"),
|
|
84609
85764
|
state: [{
|
|
84610
85765
|
kind: "numeric",
|
|
84611
|
-
field: "
|
|
85766
|
+
field: "illuminance",
|
|
84612
85767
|
quantity: t("the light level", "la luminosità"),
|
|
84613
85768
|
label: t("Illuminance", "Illuminamento"),
|
|
84614
85769
|
unit: "lx",
|
|
@@ -84771,6 +85926,10 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84771
85926
|
icon: "flame"
|
|
84772
85927
|
}]
|
|
84773
85928
|
},
|
|
85929
|
+
"group-active": {
|
|
85930
|
+
scope: "device",
|
|
85931
|
+
noun: t("Group state", "Stato del gruppo")
|
|
85932
|
+
},
|
|
84774
85933
|
"group-commands": {
|
|
84775
85934
|
scope: "device",
|
|
84776
85935
|
noun: t("Group command", "Comando di gruppo")
|
|
@@ -84807,7 +85966,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84807
85966
|
noun: t("Humidity", "Umidità"),
|
|
84808
85967
|
state: [{
|
|
84809
85968
|
kind: "numeric",
|
|
84810
|
-
field: "
|
|
85969
|
+
field: "humidity",
|
|
84811
85970
|
quantity: t("the humidity", "l’umidità"),
|
|
84812
85971
|
label: t("Humidity", "Umidità"),
|
|
84813
85972
|
unit: "%",
|
|
@@ -84827,6 +85986,17 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84827
85986
|
}],
|
|
84828
85987
|
events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
|
|
84829
85988
|
},
|
|
85989
|
+
meter: {
|
|
85990
|
+
scope: "device",
|
|
85991
|
+
noun: t("Meter", "Contatore"),
|
|
85992
|
+
state: [{
|
|
85993
|
+
kind: "numeric",
|
|
85994
|
+
field: "value",
|
|
85995
|
+
quantity: t("the total", "il totale"),
|
|
85996
|
+
label: t("Total", "Totale"),
|
|
85997
|
+
icon: "gauge"
|
|
85998
|
+
}]
|
|
85999
|
+
},
|
|
84830
86000
|
"numeric-sensor": {
|
|
84831
86001
|
scope: "device",
|
|
84832
86002
|
noun: t("Sensor", "Sensore"),
|
|
@@ -84844,7 +86014,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84844
86014
|
state: [
|
|
84845
86015
|
{
|
|
84846
86016
|
kind: "numeric",
|
|
84847
|
-
field: "
|
|
86017
|
+
field: "power",
|
|
84848
86018
|
quantity: t("the power draw", "il consumo"),
|
|
84849
86019
|
label: t("Power", "Potenza"),
|
|
84850
86020
|
unit: "W",
|
|
@@ -84852,7 +86022,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84852
86022
|
},
|
|
84853
86023
|
{
|
|
84854
86024
|
kind: "numeric",
|
|
84855
|
-
field: "
|
|
86025
|
+
field: "energy",
|
|
84856
86026
|
quantity: t("the energy used", "l’energia consumata"),
|
|
84857
86027
|
label: t("Energy", "Energia"),
|
|
84858
86028
|
unit: "kWh",
|
|
@@ -84860,7 +86030,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84860
86030
|
},
|
|
84861
86031
|
{
|
|
84862
86032
|
kind: "numeric",
|
|
84863
|
-
field: "
|
|
86033
|
+
field: "voltage",
|
|
84864
86034
|
quantity: t("the voltage", "la tensione"),
|
|
84865
86035
|
label: t("Voltage", "Tensione"),
|
|
84866
86036
|
unit: "V",
|
|
@@ -84868,7 +86038,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84868
86038
|
},
|
|
84869
86039
|
{
|
|
84870
86040
|
kind: "numeric",
|
|
84871
|
-
field: "
|
|
86041
|
+
field: "current",
|
|
84872
86042
|
quantity: t("the current", "la corrente"),
|
|
84873
86043
|
label: t("Current", "Corrente"),
|
|
84874
86044
|
unit: "A",
|
|
@@ -84885,13 +86055,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84885
86055
|
label: t("Where", "Posizione"),
|
|
84886
86056
|
phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
|
|
84887
86057
|
icon: "map-pin"
|
|
84888
|
-
}, {
|
|
84889
|
-
kind: "numeric",
|
|
84890
|
-
field: "batteryPercent",
|
|
84891
|
-
quantity: t("the phone battery", "la batteria del telefono"),
|
|
84892
|
-
label: t("Battery", "Batteria"),
|
|
84893
|
-
unit: "%",
|
|
84894
|
-
icon: "battery"
|
|
84895
86058
|
}]
|
|
84896
86059
|
},
|
|
84897
86060
|
"pressure-sensor": {
|
|
@@ -84899,7 +86062,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84899
86062
|
noun: t("Pressure", "Pressione"),
|
|
84900
86063
|
state: [{
|
|
84901
86064
|
kind: "numeric",
|
|
84902
|
-
field: "
|
|
86065
|
+
field: "pressure",
|
|
84903
86066
|
quantity: t("the pressure", "la pressione"),
|
|
84904
86067
|
label: t("Pressure", "Pressione"),
|
|
84905
86068
|
unit: "hPa",
|
|
@@ -84935,7 +86098,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84935
86098
|
noun: t("Temperature", "Temperatura"),
|
|
84936
86099
|
state: [{
|
|
84937
86100
|
kind: "numeric",
|
|
84938
|
-
field: "
|
|
86101
|
+
field: "temperature",
|
|
84939
86102
|
quantity: t("the temperature", "la temperatura"),
|
|
84940
86103
|
label: t("Temperature", "Temperatura"),
|
|
84941
86104
|
unit: "°C",
|
|
@@ -85006,7 +86169,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85006
86169
|
state: [
|
|
85007
86170
|
{
|
|
85008
86171
|
kind: "numeric",
|
|
85009
|
-
field: "
|
|
86172
|
+
field: "level",
|
|
85010
86173
|
quantity: t("the battery level", "il livello della batteria"),
|
|
85011
86174
|
label: t("Battery", "Batteria"),
|
|
85012
86175
|
unit: "%",
|
|
@@ -85048,7 +86211,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85048
86211
|
icon: "battery-charging"
|
|
85049
86212
|
}
|
|
85050
86213
|
],
|
|
85051
|
-
events: { onStatusChanged: { notOperatorFacing: "the
|
|
86214
|
+
events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
|
|
85052
86215
|
extraEvents: [{
|
|
85053
86216
|
category: EventCategory.DeviceAwake,
|
|
85054
86217
|
label: t("Woke up", "Risvegliato"),
|
|
@@ -85066,7 +86229,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
85066
86229
|
noun: t("Network link", "Collegamento di rete"),
|
|
85067
86230
|
state: [{
|
|
85068
86231
|
kind: "numeric",
|
|
85069
|
-
field: "
|
|
86232
|
+
field: "signal",
|
|
85070
86233
|
quantity: t("the signal strength", "l’intensità del segnale"),
|
|
85071
86234
|
label: t("Signal", "Segnale"),
|
|
85072
86235
|
unit: "%",
|
|
@@ -85159,6 +86322,8 @@ var ML = "model and training machinery — no device action";
|
|
|
85159
86322
|
var INTERNAL = "internal plumbing between addons — never operator-facing";
|
|
85160
86323
|
/** Every system-scoped cap, with why it is not a device's vocabulary. */
|
|
85161
86324
|
var SYSTEM_CAP_VOCABULARY = {
|
|
86325
|
+
"action-source": system(INTERNAL),
|
|
86326
|
+
actions: system("declared actions — run from the Actions page and from the cameras that link them"),
|
|
85162
86327
|
"addon-pages": system(UI_PLUMBING),
|
|
85163
86328
|
"addon-pages-source": system(UI_PLUMBING),
|
|
85164
86329
|
"addon-routes": system(UI_PLUMBING),
|
|
@@ -85299,8 +86464,47 @@ function projectAction(cap, action) {
|
|
|
85299
86464
|
};
|
|
85300
86465
|
}
|
|
85301
86466
|
Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
|
|
85302
|
-
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;
|
|
86467
|
+
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;
|
|
85303
86468
|
DeviceFeature.BatteryOperated;
|
|
86469
|
+
DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
|
|
86470
|
+
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.";
|
|
86471
|
+
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.";
|
|
86472
|
+
var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
|
|
86473
|
+
var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
|
|
86474
|
+
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.";
|
|
86475
|
+
function withheld(reason) {
|
|
86476
|
+
return {
|
|
86477
|
+
[DeviceType.Washer]: {
|
|
86478
|
+
exported: false,
|
|
86479
|
+
reason
|
|
86480
|
+
},
|
|
86481
|
+
[DeviceType.Dryer]: {
|
|
86482
|
+
exported: false,
|
|
86483
|
+
reason
|
|
86484
|
+
},
|
|
86485
|
+
[DeviceType.Dishwasher]: {
|
|
86486
|
+
exported: false,
|
|
86487
|
+
reason
|
|
86488
|
+
}
|
|
86489
|
+
};
|
|
86490
|
+
}
|
|
86491
|
+
function offered(received) {
|
|
86492
|
+
return {
|
|
86493
|
+
[DeviceType.Washer]: {
|
|
86494
|
+
exported: true,
|
|
86495
|
+
as: received
|
|
86496
|
+
},
|
|
86497
|
+
[DeviceType.Dryer]: {
|
|
86498
|
+
exported: true,
|
|
86499
|
+
as: received
|
|
86500
|
+
},
|
|
86501
|
+
[DeviceType.Dishwasher]: {
|
|
86502
|
+
exported: true,
|
|
86503
|
+
as: received
|
|
86504
|
+
}
|
|
86505
|
+
};
|
|
86506
|
+
}
|
|
86507
|
+
offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
|
|
85304
86508
|
Object.freeze({
|
|
85305
86509
|
"accessories.getStatus": [{
|
|
85306
86510
|
name: "deviceId",
|
|
@@ -85316,6 +86520,31 @@ Object.freeze({
|
|
|
85316
86520
|
form: "single",
|
|
85317
86521
|
optional: false
|
|
85318
86522
|
}],
|
|
86523
|
+
"actions.get": [{
|
|
86524
|
+
name: "deviceId",
|
|
86525
|
+
form: "single",
|
|
86526
|
+
optional: true
|
|
86527
|
+
}],
|
|
86528
|
+
"actions.getLinks": [{
|
|
86529
|
+
name: "deviceId",
|
|
86530
|
+
form: "single",
|
|
86531
|
+
optional: false
|
|
86532
|
+
}],
|
|
86533
|
+
"actions.listForCamera": [{
|
|
86534
|
+
name: "deviceId",
|
|
86535
|
+
form: "single",
|
|
86536
|
+
optional: false
|
|
86537
|
+
}],
|
|
86538
|
+
"actions.run": [{
|
|
86539
|
+
name: "deviceId",
|
|
86540
|
+
form: "single",
|
|
86541
|
+
optional: true
|
|
86542
|
+
}],
|
|
86543
|
+
"actions.setLinks": [{
|
|
86544
|
+
name: "deviceId",
|
|
86545
|
+
form: "single",
|
|
86546
|
+
optional: false
|
|
86547
|
+
}],
|
|
85319
86548
|
"addonSettings.getDeviceSettings": [{
|
|
85320
86549
|
name: "deviceId",
|
|
85321
86550
|
form: "single",
|
|
@@ -86267,6 +87496,11 @@ Object.freeze({
|
|
|
86267
87496
|
form: "single",
|
|
86268
87497
|
optional: false
|
|
86269
87498
|
}],
|
|
87499
|
+
"groupActive.getStatus": [{
|
|
87500
|
+
name: "deviceId",
|
|
87501
|
+
form: "single",
|
|
87502
|
+
optional: false
|
|
87503
|
+
}],
|
|
86270
87504
|
"groupCommands.getStatus": [{
|
|
86271
87505
|
name: "deviceId",
|
|
86272
87506
|
form: "single",
|
|
@@ -86477,6 +87711,11 @@ Object.freeze({
|
|
|
86477
87711
|
form: "single",
|
|
86478
87712
|
optional: false
|
|
86479
87713
|
}],
|
|
87714
|
+
"meter.getStatus": [{
|
|
87715
|
+
name: "deviceId",
|
|
87716
|
+
form: "single",
|
|
87717
|
+
optional: false
|
|
87718
|
+
}],
|
|
86480
87719
|
"motion.getStatus": [{
|
|
86481
87720
|
name: "deviceId",
|
|
86482
87721
|
form: "single",
|
|
@@ -88084,7 +89323,6 @@ Object.freeze({
|
|
|
88084
89323
|
"network-access": "ingress",
|
|
88085
89324
|
"smtp-provider": "email"
|
|
88086
89325
|
});
|
|
88087
|
-
DeviceType.Camera;
|
|
88088
89326
|
/**
|
|
88089
89327
|
* A saved Customize assignment (D936). The schema is the type: callers use
|
|
88090
89328
|
* `z.infer`, they do not restate the shape.
|
|
@@ -89388,6 +90626,7 @@ DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
|
89388
90626
|
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
89389
90627
|
DEFAULT_NATIVE_LEASE_SETTINGS.sceneBudgetMb;
|
|
89390
90628
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
90629
|
+
String.raw`(?<=^|["'(\s>,\[{])`;
|
|
89391
90630
|
var MB = 1024 * 1024;
|
|
89392
90631
|
1024 * MB, 3072 * MB;
|
|
89393
90632
|
//#endregion
|
|
@@ -90099,7 +91338,7 @@ var TuyaTemperatureSensorDevice = class extends TuyaChildDevice {
|
|
|
90099
91338
|
}
|
|
90100
91339
|
#slice(celsius) {
|
|
90101
91340
|
return {
|
|
90102
|
-
celsius,
|
|
91341
|
+
temperature: celsius,
|
|
90103
91342
|
lastFetchedAt: Date.now()
|
|
90104
91343
|
};
|
|
90105
91344
|
}
|
|
@@ -90111,7 +91350,7 @@ var TuyaTemperatureSensorDevice = class extends TuyaChildDevice {
|
|
|
90111
91350
|
recomputeSlice() {
|
|
90112
91351
|
const celsius = this.#read();
|
|
90113
91352
|
if (celsius === null) return;
|
|
90114
|
-
if (this.runtimeState.getCapState(CAP_NAME$1)?.
|
|
91353
|
+
if (this.runtimeState.getCapState(CAP_NAME$1)?.temperature === celsius) return;
|
|
90115
91354
|
this.runtimeState.setCapState(CAP_NAME$1, this.#slice(celsius));
|
|
90116
91355
|
}
|
|
90117
91356
|
};
|