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