@camstack/addon-provider-dreame 0.2.155 → 0.2.157
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 +12 -0
- package/README.md +18 -0
- package/dist/addon.js +1643 -536
- package/dist/addon.mjs +1643 -536
- package/package.json +4 -2
package/dist/addon.js
CHANGED
|
@@ -44,7 +44,7 @@ let net = require("net");
|
|
|
44
44
|
net = __toESM(net, 1);
|
|
45
45
|
let zlib = require("zlib");
|
|
46
46
|
zlib = __toESM(zlib, 1);
|
|
47
|
-
//#region ../types/dist/event-category-
|
|
47
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
48
48
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
49
49
|
EventCategory["SystemBoot"] = "system.boot";
|
|
50
50
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -370,6 +370,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
370
370
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
371
371
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
372
372
|
/**
|
|
373
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
374
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
375
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
376
|
+
*/
|
|
377
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
378
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
379
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
380
|
+
/**
|
|
373
381
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
374
382
|
* (a settings change via `setAgentInferenceDevices` /
|
|
375
383
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5479,7 +5487,7 @@ var ZodIssueCode$1 = {
|
|
|
5479
5487
|
var ZodFirstPartyTypeKind$1;
|
|
5480
5488
|
ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
|
|
5481
5489
|
//#endregion
|
|
5482
|
-
//#region ../types/dist/sleep-
|
|
5490
|
+
//#region ../types/dist/sleep-bykKrTgu.mjs
|
|
5483
5491
|
/**
|
|
5484
5492
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5485
5493
|
* window to float samples (D455).
|
|
@@ -8033,6 +8041,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
8033
8041
|
}).strict();
|
|
8034
8042
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
8035
8043
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8044
|
+
var READING_QUANTITIES = [
|
|
8045
|
+
"temperature",
|
|
8046
|
+
"pressure",
|
|
8047
|
+
"speed",
|
|
8048
|
+
"precipitation",
|
|
8049
|
+
"precipitation-rate",
|
|
8050
|
+
"length",
|
|
8051
|
+
"area",
|
|
8052
|
+
"illuminance",
|
|
8053
|
+
"irradiance",
|
|
8054
|
+
"power",
|
|
8055
|
+
"energy",
|
|
8056
|
+
"voltage",
|
|
8057
|
+
"current",
|
|
8058
|
+
"apparent-power",
|
|
8059
|
+
"humidity",
|
|
8060
|
+
"percentage",
|
|
8061
|
+
"concentration-volume",
|
|
8062
|
+
"concentration-mass",
|
|
8063
|
+
"concentration-ppb",
|
|
8064
|
+
"volume",
|
|
8065
|
+
"duration",
|
|
8066
|
+
"duration-ms",
|
|
8067
|
+
"information",
|
|
8068
|
+
"sound-level",
|
|
8069
|
+
"signal-level",
|
|
8070
|
+
"colour-temperature",
|
|
8071
|
+
"angle",
|
|
8072
|
+
"bitrate",
|
|
8073
|
+
"rate",
|
|
8074
|
+
"mass",
|
|
8075
|
+
"index",
|
|
8076
|
+
"ratio",
|
|
8077
|
+
"count",
|
|
8078
|
+
"none",
|
|
8079
|
+
"device"
|
|
8080
|
+
];
|
|
8081
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8082
|
+
new Set(READING_QUANTITIES);
|
|
8083
|
+
/**
|
|
8084
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8085
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8086
|
+
*/
|
|
8087
|
+
var QUANTITY_BASE = {
|
|
8088
|
+
temperature: "°C",
|
|
8089
|
+
pressure: "hPa",
|
|
8090
|
+
speed: "m/s",
|
|
8091
|
+
precipitation: "mm",
|
|
8092
|
+
"precipitation-rate": "mm/h",
|
|
8093
|
+
length: "m",
|
|
8094
|
+
area: "m²",
|
|
8095
|
+
illuminance: "lx",
|
|
8096
|
+
irradiance: "W/m²",
|
|
8097
|
+
power: "W",
|
|
8098
|
+
energy: "kWh",
|
|
8099
|
+
voltage: "V",
|
|
8100
|
+
current: "A",
|
|
8101
|
+
"apparent-power": "VA",
|
|
8102
|
+
humidity: "%",
|
|
8103
|
+
percentage: "%",
|
|
8104
|
+
"concentration-volume": "ppm",
|
|
8105
|
+
"concentration-mass": "µg/m³",
|
|
8106
|
+
"concentration-ppb": "ppb",
|
|
8107
|
+
volume: "L",
|
|
8108
|
+
duration: "s",
|
|
8109
|
+
"duration-ms": "ms",
|
|
8110
|
+
information: "B",
|
|
8111
|
+
"sound-level": "dBFS",
|
|
8112
|
+
"signal-level": "dBm",
|
|
8113
|
+
"colour-temperature": "mired",
|
|
8114
|
+
angle: "°",
|
|
8115
|
+
bitrate: "kbps",
|
|
8116
|
+
rate: "fps",
|
|
8117
|
+
mass: "kg",
|
|
8118
|
+
index: "none",
|
|
8119
|
+
ratio: "none",
|
|
8120
|
+
count: "none",
|
|
8121
|
+
none: "none",
|
|
8122
|
+
device: "device"
|
|
8123
|
+
};
|
|
8124
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8125
|
+
function baseUnitOf(quantity) {
|
|
8126
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8127
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8128
|
+
return symbol;
|
|
8129
|
+
}
|
|
8130
|
+
function readingMeta(quantity, extras) {
|
|
8131
|
+
return {
|
|
8132
|
+
quantity,
|
|
8133
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8134
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8135
|
+
};
|
|
8136
|
+
}
|
|
8036
8137
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8037
8138
|
var CamProfileSchema = _enum([
|
|
8038
8139
|
"high",
|
|
@@ -8060,8 +8161,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8060
8161
|
"derived"
|
|
8061
8162
|
]);
|
|
8062
8163
|
var CamStreamResolutionSchema = object({
|
|
8063
|
-
width: number().int().positive(),
|
|
8064
|
-
height: number().int().positive()
|
|
8164
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8165
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8065
8166
|
});
|
|
8066
8167
|
var CameraStreamSchema = object({
|
|
8067
8168
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8579,6 +8680,8 @@ var CAP_NAMES = Object.freeze([
|
|
|
8579
8680
|
"filesystem-browse",
|
|
8580
8681
|
"flood",
|
|
8581
8682
|
"gas",
|
|
8683
|
+
"group-commands",
|
|
8684
|
+
"group-status",
|
|
8582
8685
|
"heating-valve",
|
|
8583
8686
|
"humidifier",
|
|
8584
8687
|
"humidity-sensor",
|
|
@@ -8708,14 +8811,6 @@ Object.freeze({
|
|
|
8708
8811
|
{
|
|
8709
8812
|
"path": "aqi",
|
|
8710
8813
|
"valueType": "number"
|
|
8711
|
-
},
|
|
8712
|
-
{
|
|
8713
|
-
"path": "unit",
|
|
8714
|
-
"valueType": "string"
|
|
8715
|
-
},
|
|
8716
|
-
{
|
|
8717
|
-
"path": "precision",
|
|
8718
|
-
"valueType": "number"
|
|
8719
8814
|
}
|
|
8720
8815
|
],
|
|
8721
8816
|
"alarm-panel": [
|
|
@@ -8751,20 +8846,10 @@ Object.freeze({
|
|
|
8751
8846
|
"valueType": "boolean"
|
|
8752
8847
|
}
|
|
8753
8848
|
],
|
|
8754
|
-
"ambient-light-sensor": [
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
},
|
|
8759
|
-
{
|
|
8760
|
-
"path": "unit",
|
|
8761
|
-
"valueType": "string"
|
|
8762
|
-
},
|
|
8763
|
-
{
|
|
8764
|
-
"path": "precision",
|
|
8765
|
-
"valueType": "number"
|
|
8766
|
-
}
|
|
8767
|
-
],
|
|
8849
|
+
"ambient-light-sensor": [{
|
|
8850
|
+
"path": "lux",
|
|
8851
|
+
"valueType": "number"
|
|
8852
|
+
}],
|
|
8768
8853
|
"audio-metrics": [
|
|
8769
8854
|
{
|
|
8770
8855
|
"path": "ts",
|
|
@@ -8844,6 +8929,10 @@ Object.freeze({
|
|
|
8844
8929
|
"path": "lastUpdated",
|
|
8845
8930
|
"valueType": "number"
|
|
8846
8931
|
},
|
|
8932
|
+
{
|
|
8933
|
+
"path": "volts",
|
|
8934
|
+
"valueType": "number"
|
|
8935
|
+
},
|
|
8847
8936
|
{
|
|
8848
8937
|
"path": "lastContactAt",
|
|
8849
8938
|
"valueType": "number"
|
|
@@ -9086,10 +9175,6 @@ Object.freeze({
|
|
|
9086
9175
|
"datetime"
|
|
9087
9176
|
]
|
|
9088
9177
|
},
|
|
9089
|
-
{
|
|
9090
|
-
"path": "unit",
|
|
9091
|
-
"valueType": "string"
|
|
9092
|
-
},
|
|
9093
9178
|
{
|
|
9094
9179
|
"path": "min",
|
|
9095
9180
|
"valueType": "number"
|
|
@@ -9101,19 +9186,6 @@ Object.freeze({
|
|
|
9101
9186
|
{
|
|
9102
9187
|
"path": "step",
|
|
9103
9188
|
"valueType": "number"
|
|
9104
|
-
},
|
|
9105
|
-
{
|
|
9106
|
-
"path": "precision",
|
|
9107
|
-
"valueType": "number"
|
|
9108
|
-
},
|
|
9109
|
-
{
|
|
9110
|
-
"path": "format",
|
|
9111
|
-
"valueType": "enum",
|
|
9112
|
-
"enumValues": [
|
|
9113
|
-
"date",
|
|
9114
|
-
"time",
|
|
9115
|
-
"datetime"
|
|
9116
|
-
]
|
|
9117
9189
|
}
|
|
9118
9190
|
],
|
|
9119
9191
|
"cover": [
|
|
@@ -9354,13 +9426,8 @@ Object.freeze({
|
|
|
9354
9426
|
"path": "value",
|
|
9355
9427
|
"valueType": "string"
|
|
9356
9428
|
}, {
|
|
9357
|
-
"path": "
|
|
9358
|
-
"valueType": "
|
|
9359
|
-
"enumValues": [
|
|
9360
|
-
"date",
|
|
9361
|
-
"time",
|
|
9362
|
-
"datetime"
|
|
9363
|
-
]
|
|
9429
|
+
"path": "timestamp",
|
|
9430
|
+
"valueType": "boolean"
|
|
9364
9431
|
}],
|
|
9365
9432
|
"event-emitter": [
|
|
9366
9433
|
{
|
|
@@ -9433,6 +9500,20 @@ Object.freeze({
|
|
|
9433
9500
|
"path": "detected",
|
|
9434
9501
|
"valueType": "boolean"
|
|
9435
9502
|
}],
|
|
9503
|
+
"group-status": [
|
|
9504
|
+
{
|
|
9505
|
+
"path": "included",
|
|
9506
|
+
"valueType": "number"
|
|
9507
|
+
},
|
|
9508
|
+
{
|
|
9509
|
+
"path": "excluded",
|
|
9510
|
+
"valueType": "number"
|
|
9511
|
+
},
|
|
9512
|
+
{
|
|
9513
|
+
"path": "total",
|
|
9514
|
+
"valueType": "number"
|
|
9515
|
+
}
|
|
9516
|
+
],
|
|
9436
9517
|
"heating-valve": [{
|
|
9437
9518
|
"path": "position",
|
|
9438
9519
|
"valueType": "number"
|
|
@@ -9467,20 +9548,10 @@ Object.freeze({
|
|
|
9467
9548
|
"valueType": "number"
|
|
9468
9549
|
}
|
|
9469
9550
|
],
|
|
9470
|
-
"humidity-sensor": [
|
|
9471
|
-
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
},
|
|
9475
|
-
{
|
|
9476
|
-
"path": "unit",
|
|
9477
|
-
"valueType": "string"
|
|
9478
|
-
},
|
|
9479
|
-
{
|
|
9480
|
-
"path": "precision",
|
|
9481
|
-
"valueType": "number"
|
|
9482
|
-
}
|
|
9483
|
-
],
|
|
9551
|
+
"humidity-sensor": [{
|
|
9552
|
+
"path": "percent",
|
|
9553
|
+
"valueType": "number"
|
|
9554
|
+
}],
|
|
9484
9555
|
"image": [{
|
|
9485
9556
|
"path": "url",
|
|
9486
9557
|
"valueType": "string"
|
|
@@ -9819,20 +9890,10 @@ Object.freeze({
|
|
|
9819
9890
|
"valueType": "boolean"
|
|
9820
9891
|
}
|
|
9821
9892
|
],
|
|
9822
|
-
"numeric-sensor": [
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
},
|
|
9827
|
-
{
|
|
9828
|
-
"path": "unit",
|
|
9829
|
-
"valueType": "string"
|
|
9830
|
-
},
|
|
9831
|
-
{
|
|
9832
|
-
"path": "precision",
|
|
9833
|
-
"valueType": "number"
|
|
9834
|
-
}
|
|
9835
|
-
],
|
|
9893
|
+
"numeric-sensor": [{
|
|
9894
|
+
"path": "value",
|
|
9895
|
+
"valueType": "number"
|
|
9896
|
+
}],
|
|
9836
9897
|
"pet-feeder": [
|
|
9837
9898
|
{
|
|
9838
9899
|
"path": "foodLevel",
|
|
@@ -9924,14 +9985,6 @@ Object.freeze({
|
|
|
9924
9985
|
{
|
|
9925
9986
|
"path": "powerFactor",
|
|
9926
9987
|
"valueType": "number"
|
|
9927
|
-
},
|
|
9928
|
-
{
|
|
9929
|
-
"path": "unit",
|
|
9930
|
-
"valueType": "string"
|
|
9931
|
-
},
|
|
9932
|
-
{
|
|
9933
|
-
"path": "precision",
|
|
9934
|
-
"valueType": "number"
|
|
9935
9988
|
}
|
|
9936
9989
|
],
|
|
9937
9990
|
"presence": [
|
|
@@ -9960,20 +10013,10 @@ Object.freeze({
|
|
|
9960
10013
|
"valueType": "number"
|
|
9961
10014
|
}
|
|
9962
10015
|
],
|
|
9963
|
-
"pressure-sensor": [
|
|
9964
|
-
|
|
9965
|
-
|
|
9966
|
-
|
|
9967
|
-
},
|
|
9968
|
-
{
|
|
9969
|
-
"path": "unit",
|
|
9970
|
-
"valueType": "string"
|
|
9971
|
-
},
|
|
9972
|
-
{
|
|
9973
|
-
"path": "precision",
|
|
9974
|
-
"valueType": "number"
|
|
9975
|
-
}
|
|
9976
|
-
],
|
|
10016
|
+
"pressure-sensor": [{
|
|
10017
|
+
"path": "hpa",
|
|
10018
|
+
"valueType": "number"
|
|
10019
|
+
}],
|
|
9977
10020
|
"privacy-mask": [{
|
|
9978
10021
|
"path": "enabled",
|
|
9979
10022
|
"valueType": "boolean"
|
|
@@ -10284,20 +10327,10 @@ Object.freeze({
|
|
|
10284
10327
|
"path": "tampered",
|
|
10285
10328
|
"valueType": "boolean"
|
|
10286
10329
|
}],
|
|
10287
|
-
"temperature-sensor": [
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
},
|
|
10292
|
-
{
|
|
10293
|
-
"path": "unit",
|
|
10294
|
-
"valueType": "string"
|
|
10295
|
-
},
|
|
10296
|
-
{
|
|
10297
|
-
"path": "precision",
|
|
10298
|
-
"valueType": "number"
|
|
10299
|
-
}
|
|
10300
|
-
],
|
|
10330
|
+
"temperature-sensor": [{
|
|
10331
|
+
"path": "celsius",
|
|
10332
|
+
"valueType": "number"
|
|
10333
|
+
}],
|
|
10301
10334
|
"update": [
|
|
10302
10335
|
{
|
|
10303
10336
|
"path": "currentVersion",
|
|
@@ -10408,10 +10441,6 @@ Object.freeze({
|
|
|
10408
10441
|
"path": "temperature",
|
|
10409
10442
|
"valueType": "number"
|
|
10410
10443
|
},
|
|
10411
|
-
{
|
|
10412
|
-
"path": "temperatureUnit",
|
|
10413
|
-
"valueType": "string"
|
|
10414
|
-
},
|
|
10415
10444
|
{
|
|
10416
10445
|
"path": "humidity",
|
|
10417
10446
|
"valueType": "number"
|
|
@@ -10420,18 +10449,10 @@ Object.freeze({
|
|
|
10420
10449
|
"path": "pressure",
|
|
10421
10450
|
"valueType": "number"
|
|
10422
10451
|
},
|
|
10423
|
-
{
|
|
10424
|
-
"path": "pressureUnit",
|
|
10425
|
-
"valueType": "string"
|
|
10426
|
-
},
|
|
10427
10452
|
{
|
|
10428
10453
|
"path": "windSpeed",
|
|
10429
10454
|
"valueType": "number"
|
|
10430
10455
|
},
|
|
10431
|
-
{
|
|
10432
|
-
"path": "windSpeedUnit",
|
|
10433
|
-
"valueType": "string"
|
|
10434
|
-
},
|
|
10435
10456
|
{
|
|
10436
10457
|
"path": "windBearing",
|
|
10437
10458
|
"valueType": "number"
|
|
@@ -10848,7 +10869,7 @@ function errMsg(err) {
|
|
|
10848
10869
|
return String(err);
|
|
10849
10870
|
}
|
|
10850
10871
|
//#endregion
|
|
10851
|
-
//#region ../types/dist/composition-
|
|
10872
|
+
//#region ../types/dist/composition-OhpuespA.mjs
|
|
10852
10873
|
/**
|
|
10853
10874
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10854
10875
|
*
|
|
@@ -11603,15 +11624,74 @@ function validateExpressionSource(src) {
|
|
|
11603
11624
|
}
|
|
11604
11625
|
return null;
|
|
11605
11626
|
}
|
|
11606
|
-
/**
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11627
|
+
/**
|
|
11628
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11629
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11630
|
+
* `composition.ts` (D659).
|
|
11631
|
+
*/
|
|
11610
11632
|
var CompositionSourceRefSchema = object({
|
|
11611
11633
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11612
11634
|
addonId: string().min(1),
|
|
11613
11635
|
stableId: string().min(1)
|
|
11614
11636
|
});
|
|
11637
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11638
|
+
"temperature",
|
|
11639
|
+
"humidity",
|
|
11640
|
+
"pressure",
|
|
11641
|
+
"illuminance",
|
|
11642
|
+
"power",
|
|
11643
|
+
"energy",
|
|
11644
|
+
"battery",
|
|
11645
|
+
"numeric",
|
|
11646
|
+
"motion",
|
|
11647
|
+
"contact",
|
|
11648
|
+
"leak",
|
|
11649
|
+
"smoke",
|
|
11650
|
+
"occupancy",
|
|
11651
|
+
"binary",
|
|
11652
|
+
"switch",
|
|
11653
|
+
"light"
|
|
11654
|
+
];
|
|
11655
|
+
var NUMERIC_AGGREGATES = [
|
|
11656
|
+
"mean",
|
|
11657
|
+
"median",
|
|
11658
|
+
"min",
|
|
11659
|
+
"max",
|
|
11660
|
+
"sum"
|
|
11661
|
+
];
|
|
11662
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11663
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11664
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11665
|
+
var AGGREGATE_REDUCERS = [
|
|
11666
|
+
"mean",
|
|
11667
|
+
"median",
|
|
11668
|
+
"min",
|
|
11669
|
+
"max",
|
|
11670
|
+
"sum",
|
|
11671
|
+
"any",
|
|
11672
|
+
"all"
|
|
11673
|
+
];
|
|
11674
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11675
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11676
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11677
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11678
|
+
var HelperMemberSchema = object({
|
|
11679
|
+
source: CompositionSourceRefSchema,
|
|
11680
|
+
cap: string().min(1),
|
|
11681
|
+
fieldPath: string().min(1)
|
|
11682
|
+
});
|
|
11683
|
+
var HelperSpecSchema = discriminatedUnion("kind", [object({
|
|
11684
|
+
kind: literal("group"),
|
|
11685
|
+
templateId: GroupTemplateIdSchema,
|
|
11686
|
+
aggregate: AggregateReducerSchema,
|
|
11687
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11688
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11689
|
+
active: ActiveCriterionSchema.optional()
|
|
11690
|
+
})]);
|
|
11691
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11692
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11693
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11694
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11615
11695
|
/** One field of one capability of one source device. */
|
|
11616
11696
|
var CompositionFieldReadSchema = object({
|
|
11617
11697
|
source: CompositionSourceRefSchema,
|
|
@@ -11655,7 +11735,33 @@ var CompositionCodeSourceSchema = object({
|
|
|
11655
11735
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11656
11736
|
CompositionFromSourceSchema,
|
|
11657
11737
|
CompositionExpressionSourceSchema,
|
|
11658
|
-
CompositionCodeSourceSchema
|
|
11738
|
+
CompositionCodeSourceSchema,
|
|
11739
|
+
object({
|
|
11740
|
+
kind: literal("aggregate"),
|
|
11741
|
+
reducer: _enum([
|
|
11742
|
+
"mean",
|
|
11743
|
+
"median",
|
|
11744
|
+
"min",
|
|
11745
|
+
"max",
|
|
11746
|
+
"sum",
|
|
11747
|
+
"any",
|
|
11748
|
+
"all"
|
|
11749
|
+
]),
|
|
11750
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11751
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11752
|
+
publish: _enum([
|
|
11753
|
+
"value",
|
|
11754
|
+
"included",
|
|
11755
|
+
"excluded",
|
|
11756
|
+
"total"
|
|
11757
|
+
]),
|
|
11758
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11759
|
+
empty: _enum([
|
|
11760
|
+
"null",
|
|
11761
|
+
"omit",
|
|
11762
|
+
"offline"
|
|
11763
|
+
])
|
|
11764
|
+
})
|
|
11659
11765
|
]);
|
|
11660
11766
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11661
11767
|
kind: literal("forward"),
|
|
@@ -11701,7 +11807,13 @@ var CompositionSchema = object({
|
|
|
11701
11807
|
kind: literal("existing"),
|
|
11702
11808
|
device: CompositionSourceRefSchema
|
|
11703
11809
|
})]),
|
|
11704
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
11810
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
11811
|
+
/**
|
|
11812
|
+
* Present when the block is a helper template. Absent on a free
|
|
11813
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
11814
|
+
* never the compiled features.
|
|
11815
|
+
*/
|
|
11816
|
+
helper: HelperSpecSchema.optional()
|
|
11705
11817
|
}).superRefine((composition, ctx) => {
|
|
11706
11818
|
const seen = /* @__PURE__ */ new Set();
|
|
11707
11819
|
composition.features.forEach((feature, index) => {
|
|
@@ -17909,7 +18021,11 @@ var CompositionProblemSchema = object({
|
|
|
17909
18021
|
"item-field-reserved",
|
|
17910
18022
|
"target-missing",
|
|
17911
18023
|
"target-unreadable",
|
|
17912
|
-
"not-replaceable"
|
|
18024
|
+
"not-replaceable",
|
|
18025
|
+
"native-capability-replace",
|
|
18026
|
+
"mixed-quantity",
|
|
18027
|
+
"helper-mismatch",
|
|
18028
|
+
"member-constraint"
|
|
17913
18029
|
]),
|
|
17914
18030
|
path: string(),
|
|
17915
18031
|
message: string()
|
|
@@ -17930,7 +18046,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17930
18046
|
"null",
|
|
17931
18047
|
"offline",
|
|
17932
18048
|
"unknown",
|
|
17933
|
-
"release"
|
|
18049
|
+
"release",
|
|
18050
|
+
"omit"
|
|
17934
18051
|
]);
|
|
17935
18052
|
/**
|
|
17936
18053
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17967,9 +18084,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17967
18084
|
reads: array(CompositionFieldReadSchema)
|
|
17968
18085
|
});
|
|
17969
18086
|
/**
|
|
17970
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17971
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17972
|
-
*
|
|
18087
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18088
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18089
|
+
* Replacing a capability the device already serves is refused
|
|
18090
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18091
|
+
* wire for a claim the hub already holds.
|
|
17973
18092
|
*/
|
|
17974
18093
|
var CompositionFeatureModeSchema = _enum([
|
|
17975
18094
|
"new",
|
|
@@ -18142,6 +18261,275 @@ Object.freeze({
|
|
|
18142
18261
|
result: ["number", "null"]
|
|
18143
18262
|
}
|
|
18144
18263
|
});
|
|
18264
|
+
/**
|
|
18265
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18266
|
+
* Data, not a form default written into the block.
|
|
18267
|
+
*/
|
|
18268
|
+
var NOW = {
|
|
18269
|
+
fieldPath: "lastFetchedAt",
|
|
18270
|
+
expr: "now"
|
|
18271
|
+
};
|
|
18272
|
+
var CHANGED = {
|
|
18273
|
+
fieldPath: "lastChangedAt",
|
|
18274
|
+
expr: "now"
|
|
18275
|
+
};
|
|
18276
|
+
function numeric(input) {
|
|
18277
|
+
return {
|
|
18278
|
+
...input,
|
|
18279
|
+
family: "numeric",
|
|
18280
|
+
deviceType: DeviceType.Sensor,
|
|
18281
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18282
|
+
commandCaps: [],
|
|
18283
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18284
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18285
|
+
accept: [{
|
|
18286
|
+
cap: input.outputCap,
|
|
18287
|
+
fieldPath: input.outputField
|
|
18288
|
+
}]
|
|
18289
|
+
};
|
|
18290
|
+
}
|
|
18291
|
+
function binary(input) {
|
|
18292
|
+
return {
|
|
18293
|
+
...input,
|
|
18294
|
+
family: "binary",
|
|
18295
|
+
deviceType: DeviceType.Sensor,
|
|
18296
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18297
|
+
commandCaps: [],
|
|
18298
|
+
quantity: "none",
|
|
18299
|
+
baseUnit: void 0,
|
|
18300
|
+
aggregates: BINARY_AGGREGATES,
|
|
18301
|
+
empty: "offline"
|
|
18302
|
+
};
|
|
18303
|
+
}
|
|
18304
|
+
var GROUP_TEMPLATES = [
|
|
18305
|
+
numeric({
|
|
18306
|
+
id: "temperature",
|
|
18307
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18308
|
+
role: DeviceRole.TemperatureSensor,
|
|
18309
|
+
outputCap: "temperature-sensor",
|
|
18310
|
+
outputField: "celsius",
|
|
18311
|
+
quantity: "temperature",
|
|
18312
|
+
defaultAggregate: "mean",
|
|
18313
|
+
empty: "null",
|
|
18314
|
+
companions: [NOW]
|
|
18315
|
+
}),
|
|
18316
|
+
numeric({
|
|
18317
|
+
id: "humidity",
|
|
18318
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18319
|
+
role: DeviceRole.HumiditySensor,
|
|
18320
|
+
outputCap: "humidity-sensor",
|
|
18321
|
+
outputField: "percent",
|
|
18322
|
+
quantity: "humidity",
|
|
18323
|
+
defaultAggregate: "mean",
|
|
18324
|
+
empty: "null",
|
|
18325
|
+
companions: [NOW]
|
|
18326
|
+
}),
|
|
18327
|
+
numeric({
|
|
18328
|
+
id: "pressure",
|
|
18329
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18330
|
+
role: DeviceRole.PressureSensor,
|
|
18331
|
+
outputCap: "pressure-sensor",
|
|
18332
|
+
outputField: "hpa",
|
|
18333
|
+
quantity: "pressure",
|
|
18334
|
+
defaultAggregate: "mean",
|
|
18335
|
+
empty: "null",
|
|
18336
|
+
companions: [NOW]
|
|
18337
|
+
}),
|
|
18338
|
+
numeric({
|
|
18339
|
+
id: "illuminance",
|
|
18340
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18341
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18342
|
+
outputCap: "ambient-light-sensor",
|
|
18343
|
+
outputField: "lux",
|
|
18344
|
+
quantity: "illuminance",
|
|
18345
|
+
defaultAggregate: "mean",
|
|
18346
|
+
empty: "null",
|
|
18347
|
+
companions: [NOW]
|
|
18348
|
+
}),
|
|
18349
|
+
numeric({
|
|
18350
|
+
id: "power",
|
|
18351
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18352
|
+
role: DeviceRole.PowerSensor,
|
|
18353
|
+
outputCap: "power-meter",
|
|
18354
|
+
outputField: "watts",
|
|
18355
|
+
quantity: "power",
|
|
18356
|
+
defaultAggregate: "sum",
|
|
18357
|
+
empty: "omit",
|
|
18358
|
+
companions: [NOW]
|
|
18359
|
+
}),
|
|
18360
|
+
numeric({
|
|
18361
|
+
id: "energy",
|
|
18362
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18363
|
+
role: DeviceRole.EnergySensor,
|
|
18364
|
+
outputCap: "power-meter",
|
|
18365
|
+
outputField: "kwhTotal",
|
|
18366
|
+
quantity: "energy",
|
|
18367
|
+
defaultAggregate: "sum",
|
|
18368
|
+
empty: "omit",
|
|
18369
|
+
companions: [NOW]
|
|
18370
|
+
}),
|
|
18371
|
+
numeric({
|
|
18372
|
+
id: "battery",
|
|
18373
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18374
|
+
role: DeviceRole.BatterySensor,
|
|
18375
|
+
outputCap: "battery",
|
|
18376
|
+
outputField: "percentage",
|
|
18377
|
+
quantity: "percentage",
|
|
18378
|
+
defaultAggregate: "mean",
|
|
18379
|
+
empty: "null",
|
|
18380
|
+
companions: [
|
|
18381
|
+
{
|
|
18382
|
+
fieldPath: "charging",
|
|
18383
|
+
expr: "\"unknown\""
|
|
18384
|
+
},
|
|
18385
|
+
{
|
|
18386
|
+
fieldPath: "sleeping",
|
|
18387
|
+
expr: "false"
|
|
18388
|
+
},
|
|
18389
|
+
{
|
|
18390
|
+
fieldPath: "lastUpdated",
|
|
18391
|
+
expr: "now"
|
|
18392
|
+
}
|
|
18393
|
+
]
|
|
18394
|
+
}),
|
|
18395
|
+
numeric({
|
|
18396
|
+
id: "numeric",
|
|
18397
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18398
|
+
role: DeviceRole.NumericSensor,
|
|
18399
|
+
outputCap: "numeric-sensor",
|
|
18400
|
+
outputField: "value",
|
|
18401
|
+
quantity: "device",
|
|
18402
|
+
defaultAggregate: "mean",
|
|
18403
|
+
empty: "null",
|
|
18404
|
+
companions: [NOW]
|
|
18405
|
+
}),
|
|
18406
|
+
binary({
|
|
18407
|
+
id: "motion",
|
|
18408
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18409
|
+
role: DeviceRole.MotionSensor,
|
|
18410
|
+
outputCap: "motion",
|
|
18411
|
+
outputField: "detected",
|
|
18412
|
+
defaultAggregate: "any",
|
|
18413
|
+
accept: [{
|
|
18414
|
+
cap: "motion",
|
|
18415
|
+
fieldPath: "detected"
|
|
18416
|
+
}],
|
|
18417
|
+
companions: [{
|
|
18418
|
+
fieldPath: "lastDetectedAt",
|
|
18419
|
+
expr: "null"
|
|
18420
|
+
}, {
|
|
18421
|
+
fieldPath: "autoClearAfterMs",
|
|
18422
|
+
expr: "null"
|
|
18423
|
+
}]
|
|
18424
|
+
}),
|
|
18425
|
+
binary({
|
|
18426
|
+
id: "contact",
|
|
18427
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18428
|
+
role: DeviceRole.ContactSensor,
|
|
18429
|
+
outputCap: "contact",
|
|
18430
|
+
outputField: "entryOpen",
|
|
18431
|
+
defaultAggregate: "any",
|
|
18432
|
+
accept: [{
|
|
18433
|
+
cap: "contact",
|
|
18434
|
+
fieldPath: "entryOpen"
|
|
18435
|
+
}],
|
|
18436
|
+
companions: [CHANGED]
|
|
18437
|
+
}),
|
|
18438
|
+
binary({
|
|
18439
|
+
id: "leak",
|
|
18440
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18441
|
+
role: DeviceRole.LeakSensor,
|
|
18442
|
+
outputCap: "flood",
|
|
18443
|
+
outputField: "flooded",
|
|
18444
|
+
defaultAggregate: "any",
|
|
18445
|
+
accept: [{
|
|
18446
|
+
cap: "flood",
|
|
18447
|
+
fieldPath: "flooded"
|
|
18448
|
+
}],
|
|
18449
|
+
companions: [CHANGED]
|
|
18450
|
+
}),
|
|
18451
|
+
binary({
|
|
18452
|
+
id: "smoke",
|
|
18453
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18454
|
+
role: DeviceRole.SmokeSensor,
|
|
18455
|
+
outputCap: "smoke",
|
|
18456
|
+
outputField: "detected",
|
|
18457
|
+
defaultAggregate: "any",
|
|
18458
|
+
accept: [{
|
|
18459
|
+
cap: "smoke",
|
|
18460
|
+
fieldPath: "detected"
|
|
18461
|
+
}],
|
|
18462
|
+
companions: [CHANGED]
|
|
18463
|
+
}),
|
|
18464
|
+
binary({
|
|
18465
|
+
id: "occupancy",
|
|
18466
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18467
|
+
role: DeviceRole.BinarySensor,
|
|
18468
|
+
outputCap: "binary",
|
|
18469
|
+
outputField: "on",
|
|
18470
|
+
defaultAggregate: "any",
|
|
18471
|
+
accept: [{
|
|
18472
|
+
cap: "motion",
|
|
18473
|
+
fieldPath: "detected"
|
|
18474
|
+
}, {
|
|
18475
|
+
cap: "binary",
|
|
18476
|
+
fieldPath: "on"
|
|
18477
|
+
}],
|
|
18478
|
+
companions: [CHANGED]
|
|
18479
|
+
}),
|
|
18480
|
+
binary({
|
|
18481
|
+
id: "binary",
|
|
18482
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18483
|
+
role: DeviceRole.BinarySensor,
|
|
18484
|
+
outputCap: "binary",
|
|
18485
|
+
outputField: "on",
|
|
18486
|
+
defaultAggregate: "any",
|
|
18487
|
+
accept: [{
|
|
18488
|
+
cap: "binary",
|
|
18489
|
+
fieldPath: "on"
|
|
18490
|
+
}],
|
|
18491
|
+
companions: [CHANGED]
|
|
18492
|
+
}),
|
|
18493
|
+
actuator({
|
|
18494
|
+
id: "switch",
|
|
18495
|
+
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.",
|
|
18496
|
+
deviceType: DeviceType.Switch,
|
|
18497
|
+
outputCap: "switch",
|
|
18498
|
+
commandCaps: ["switch"]
|
|
18499
|
+
}),
|
|
18500
|
+
actuator({
|
|
18501
|
+
id: "light",
|
|
18502
|
+
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.",
|
|
18503
|
+
deviceType: DeviceType.Light,
|
|
18504
|
+
outputCap: "switch",
|
|
18505
|
+
commandCaps: [
|
|
18506
|
+
"switch",
|
|
18507
|
+
"brightness",
|
|
18508
|
+
"color"
|
|
18509
|
+
]
|
|
18510
|
+
})
|
|
18511
|
+
];
|
|
18512
|
+
function actuator(input) {
|
|
18513
|
+
return {
|
|
18514
|
+
...input,
|
|
18515
|
+
family: "actuator",
|
|
18516
|
+
role: void 0,
|
|
18517
|
+
memberDeviceType: input.deviceType,
|
|
18518
|
+
outputField: "on",
|
|
18519
|
+
quantity: "none",
|
|
18520
|
+
baseUnit: void 0,
|
|
18521
|
+
aggregates: BINARY_AGGREGATES,
|
|
18522
|
+
defaultAggregate: "any",
|
|
18523
|
+
empty: "offline",
|
|
18524
|
+
accept: [{
|
|
18525
|
+
cap: "switch",
|
|
18526
|
+
fieldPath: "on"
|
|
18527
|
+
}],
|
|
18528
|
+
companions: [CHANGED]
|
|
18529
|
+
};
|
|
18530
|
+
}
|
|
18531
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18532
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18145
18533
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18146
18534
|
/**
|
|
18147
18535
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19855,12 +20243,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
19855
20243
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19856
20244
|
* in-place so dispatch keeps working.
|
|
19857
20245
|
*
|
|
19858
|
-
* **
|
|
19859
|
-
*
|
|
19860
|
-
*
|
|
19861
|
-
*
|
|
19862
|
-
* (`ha-domain-mapping`)
|
|
19863
|
-
* stored after that point.
|
|
20246
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20247
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20248
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20249
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20250
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20251
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19864
20252
|
*
|
|
19865
20253
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19866
20254
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19874,6 +20262,14 @@ var SourceInfoSchema = object({
|
|
|
19874
20262
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19875
20263
|
* Used to detect rename when `id` changes. */
|
|
19876
20264
|
uniqueId: string().optional(),
|
|
20265
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20266
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20267
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20268
|
+
dateTimeShape: _enum([
|
|
20269
|
+
"date",
|
|
20270
|
+
"time",
|
|
20271
|
+
"datetime"
|
|
20272
|
+
]).optional(),
|
|
19877
20273
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19878
20274
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19879
20275
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -19919,6 +20315,80 @@ function mergeSourceInfo(prev, patch) {
|
|
|
19919
20315
|
return next;
|
|
19920
20316
|
}
|
|
19921
20317
|
/**
|
|
20318
|
+
* Coerce common unit-of-measurement string variants to a canonical form
|
|
20319
|
+
* so the UI's display templates can rely on stable strings. Pure
|
|
20320
|
+
* passthrough for unknown units — kept conservative on purpose, the goal
|
|
20321
|
+
* is to normalise the long tail of HA `unit_of_measurement` values that
|
|
20322
|
+
* have multiple historical spellings (`'°C'` vs `'C'` vs `'celsius'`).
|
|
20323
|
+
*
|
|
20324
|
+
* Extend the map as we encounter real-world data. Returning the raw
|
|
20325
|
+
* input for unknown values is intentional: providers should never
|
|
20326
|
+
* lose information silently here.
|
|
20327
|
+
*/
|
|
20328
|
+
function normalizeUnit(raw) {
|
|
20329
|
+
if (raw == null) return void 0;
|
|
20330
|
+
const trimmed = raw.trim();
|
|
20331
|
+
if (trimmed === "") return void 0;
|
|
20332
|
+
const lower = trimmed.toLowerCase();
|
|
20333
|
+
if (lower === "°c" || lower === "c" || lower === "celsius") return "°C";
|
|
20334
|
+
if (lower === "°f" || lower === "f" || lower === "fahrenheit") return "°F";
|
|
20335
|
+
if (lower === "k" || lower === "kelvin") return "K";
|
|
20336
|
+
if (lower === "%" || lower === "percent" || lower === "percentage") return "%";
|
|
20337
|
+
if (lower === "lx" || lower === "lux") return "lx";
|
|
20338
|
+
if (lower === "hpa" || lower === "hectopascal") return "hPa";
|
|
20339
|
+
if (lower === "kpa") return "kPa";
|
|
20340
|
+
if (lower === "pa") return "Pa";
|
|
20341
|
+
if (lower === "mbar" || lower === "millibar") return "mbar";
|
|
20342
|
+
if (lower === "w" || lower === "watt") return "W";
|
|
20343
|
+
if (lower === "kw" || lower === "kilowatt") return "kW";
|
|
20344
|
+
if (lower === "wh" || lower === "watt-hour") return "Wh";
|
|
20345
|
+
if (lower === "kwh" || lower === "kilowatt-hour") return "kWh";
|
|
20346
|
+
if (lower === "v" || lower === "volt") return "V";
|
|
20347
|
+
if (lower === "a" || lower === "amp" || lower === "ampere") return "A";
|
|
20348
|
+
if (lower === "ma" || lower === "milliampere") return "mA";
|
|
20349
|
+
if (lower === "va") return "VA";
|
|
20350
|
+
if (lower === "ppm") return "ppm";
|
|
20351
|
+
if (lower === "ppb") return "ppb";
|
|
20352
|
+
if (lower === "µg/m³" || lower === "ug/m3" || lower === "µg/m3") return "µg/m³";
|
|
20353
|
+
if (lower === "km/h" || lower === "kph") return "km/h";
|
|
20354
|
+
if (lower === "mph") return "mph";
|
|
20355
|
+
if (lower === "m/s") return "m/s";
|
|
20356
|
+
if (lower === "m") return "m";
|
|
20357
|
+
if (lower === "m²" || lower === "m2") return "m²";
|
|
20358
|
+
if (lower === "mm") return "mm";
|
|
20359
|
+
if (lower === "cm") return "cm";
|
|
20360
|
+
if (lower === "km") return "km";
|
|
20361
|
+
if (lower === "in" || lower === "inch" || lower === "inches") return "in";
|
|
20362
|
+
if (lower === "ft" || lower === "foot" || lower === "feet") return "ft";
|
|
20363
|
+
if (lower === "kg") return "kg";
|
|
20364
|
+
if (lower === "g") return "g";
|
|
20365
|
+
if (lower === "l" || lower === "liter" || lower === "litre" || lower === "liters" || lower === "litres") return "L";
|
|
20366
|
+
if (lower === "ml") return "mL";
|
|
20367
|
+
if (lower === "gal" || lower === "gallon" || lower === "gallons") return "gal";
|
|
20368
|
+
if (lower === "s" || lower === "sec" || lower === "second" || lower === "seconds") return "s";
|
|
20369
|
+
if (lower === "ms") return "ms";
|
|
20370
|
+
if (lower === "min" || lower === "minute" || lower === "minutes") return "min";
|
|
20371
|
+
if (lower === "h" || lower === "hr" || lower === "hour" || lower === "hours") return "h";
|
|
20372
|
+
if (lower === "d" || lower === "day" || lower === "days") return "d";
|
|
20373
|
+
if (lower === "b" || lower === "byte" || lower === "bytes") return "B";
|
|
20374
|
+
if (lower === "kib") return "KiB";
|
|
20375
|
+
if (lower === "mib") return "MiB";
|
|
20376
|
+
if (lower === "gib") return "GiB";
|
|
20377
|
+
if (lower === "tib") return "TiB";
|
|
20378
|
+
if (lower === "kb") return "kB";
|
|
20379
|
+
if (lower === "mb") return "MB";
|
|
20380
|
+
if (lower === "gb") return "GB";
|
|
20381
|
+
if (lower === "dbm") return "dBm";
|
|
20382
|
+
if (lower === "dbfs") return "dBFS";
|
|
20383
|
+
if (lower === "inhg") return "inHg";
|
|
20384
|
+
if (lower === "mm/h") return "mm/h";
|
|
20385
|
+
if (lower === "w/m²" || lower === "w/m2") return "W/m²";
|
|
20386
|
+
if (lower === "°" || lower === "deg" || lower === "degree" || lower === "degrees") return "°";
|
|
20387
|
+
if (lower === "kbps") return "kbps";
|
|
20388
|
+
if (lower === "fps") return "fps";
|
|
20389
|
+
return trimmed;
|
|
20390
|
+
}
|
|
20391
|
+
/**
|
|
19922
20392
|
* Key under which `SourceInfo` lives inside `DeviceMeta.metadata`. The
|
|
19923
20393
|
* blob is a free-form `Record<string, unknown>` shared with hardware-
|
|
19924
20394
|
* identity fields (`manufacturer`, `model`, `firmware`, …); SourceInfo
|
|
@@ -40995,7 +41465,8 @@ method(object({
|
|
|
40995
41465
|
"enum"
|
|
40996
41466
|
]),
|
|
40997
41467
|
enumValues: array(string()).optional(),
|
|
40998
|
-
item: boolean().optional()
|
|
41468
|
+
item: boolean().optional(),
|
|
41469
|
+
quantity: ReadingQuantitySchema.optional()
|
|
40999
41470
|
})).readonly(),
|
|
41000
41471
|
itemArray: object({
|
|
41001
41472
|
path: string(),
|
|
@@ -44851,8 +45322,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44851
45322
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44852
45323
|
var MaskGridShapeSchema = object({
|
|
44853
45324
|
kind: literal("grid"),
|
|
44854
|
-
gridWidth: number(),
|
|
44855
|
-
gridHeight: number(),
|
|
45325
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45326
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44856
45327
|
cells: array(boolean())
|
|
44857
45328
|
});
|
|
44858
45329
|
discriminatedUnion("kind", [
|
|
@@ -44964,6 +45435,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44964
45435
|
"detection-blind",
|
|
44965
45436
|
"motion-noisy",
|
|
44966
45437
|
"motion-calm",
|
|
45438
|
+
"package-llm-silent",
|
|
45439
|
+
"package-llm-answered",
|
|
44967
45440
|
"recording-stalled",
|
|
44968
45441
|
"recording-healthy",
|
|
44969
45442
|
"recording-degraded",
|
|
@@ -56055,6 +56528,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56055
56528
|
deprecated: string().optional(),
|
|
56056
56529
|
distTags: array(string()).readonly()
|
|
56057
56530
|
});
|
|
56531
|
+
/**
|
|
56532
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56533
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56534
|
+
* tarball failure — never an empty string standing in for either.
|
|
56535
|
+
*/
|
|
56536
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56537
|
+
object({
|
|
56538
|
+
status: literal("ok"),
|
|
56539
|
+
markdown: string()
|
|
56540
|
+
}),
|
|
56541
|
+
object({ status: literal("missing") }),
|
|
56542
|
+
object({
|
|
56543
|
+
status: literal("error"),
|
|
56544
|
+
message: string()
|
|
56545
|
+
})
|
|
56546
|
+
]);
|
|
56547
|
+
var PackageDocsSchema = object({
|
|
56548
|
+
name: string(),
|
|
56549
|
+
version: string(),
|
|
56550
|
+
readme: PackageDocBodySchema,
|
|
56551
|
+
changelog: PackageDocBodySchema
|
|
56552
|
+
});
|
|
56058
56553
|
var SearchResultSchema = object({
|
|
56059
56554
|
name: string(),
|
|
56060
56555
|
version: string(),
|
|
@@ -56273,7 +56768,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56273
56768
|
}), object({ success: literal(true) }), {
|
|
56274
56769
|
kind: "mutation",
|
|
56275
56770
|
auth: "admin"
|
|
56276
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56771
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56772
|
+
name: string().min(1),
|
|
56773
|
+
version: string().min(1).optional()
|
|
56774
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56277
56775
|
kind: "mutation",
|
|
56278
56776
|
auth: "admin"
|
|
56279
56777
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56332,27 +56830,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56332
56830
|
*/
|
|
56333
56831
|
var AirQualitySensorStatusSchema = object({
|
|
56334
56832
|
/** Carbon dioxide concentration in ppm. */
|
|
56335
|
-
co2Ppm: number().min(0).optional(),
|
|
56833
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56336
56834
|
/** Total volatile organic compounds in ppb. */
|
|
56337
|
-
vocPpb: number().min(0).optional(),
|
|
56835
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56338
56836
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56339
|
-
pm25: number().min(0).optional(),
|
|
56837
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56340
56838
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56341
|
-
pm10: number().min(0).optional(),
|
|
56839
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56342
56840
|
/** Composite AQI value (typically 0..500). */
|
|
56343
|
-
aqi: number().optional(),
|
|
56841
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56344
56842
|
/** Ms epoch when the slice was last updated. */
|
|
56345
|
-
lastFetchedAt: number()
|
|
56346
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56347
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56348
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56349
|
-
* per slice is unambiguous. */
|
|
56350
|
-
unit: string().optional(),
|
|
56351
|
-
/** Suggested decimal places for numeric display.
|
|
56352
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56353
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56354
|
-
* auto-formatting when absent. */
|
|
56355
|
-
precision: number().int().min(0).max(10).optional()
|
|
56843
|
+
lastFetchedAt: number()
|
|
56356
56844
|
});
|
|
56357
56845
|
var airQualitySensorCapability = {
|
|
56358
56846
|
name: "air-quality-sensor",
|
|
@@ -56389,12 +56877,12 @@ var airQualitySensorCapability = {
|
|
|
56389
56877
|
},
|
|
56390
56878
|
pm25: {
|
|
56391
56879
|
kind: "gauge",
|
|
56392
|
-
unit: "
|
|
56880
|
+
unit: "µg/m³",
|
|
56393
56881
|
deadband: 1
|
|
56394
56882
|
},
|
|
56395
56883
|
pm10: {
|
|
56396
56884
|
kind: "gauge",
|
|
56397
|
-
unit: "
|
|
56885
|
+
unit: "µg/m³",
|
|
56398
56886
|
deadband: 1
|
|
56399
56887
|
},
|
|
56400
56888
|
aqi: {
|
|
@@ -56412,22 +56900,13 @@ var airQualitySensorCapability = {
|
|
|
56412
56900
|
* entries with `device_class: illuminance`.
|
|
56413
56901
|
*/
|
|
56414
56902
|
var AmbientLightSensorStatusSchema = object({
|
|
56415
|
-
/** Current illuminance in lux (lx). */
|
|
56416
|
-
lux: number().min(0).meta({
|
|
56417
|
-
|
|
56903
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
56904
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
56905
|
+
precision: 0,
|
|
56418
56906
|
label: "Illuminance"
|
|
56419
|
-
}),
|
|
56907
|
+
})),
|
|
56420
56908
|
/** Ms epoch when the slice was last updated. */
|
|
56421
|
-
lastFetchedAt: number()
|
|
56422
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56423
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56424
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56425
|
-
unit: string().optional(),
|
|
56426
|
-
/** Suggested decimal places for numeric display.
|
|
56427
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56428
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56429
|
-
* auto-formatting when absent. */
|
|
56430
|
-
precision: number().int().min(0).max(10).optional()
|
|
56909
|
+
lastFetchedAt: number()
|
|
56431
56910
|
});
|
|
56432
56911
|
var ambientLightSensorCapability = {
|
|
56433
56912
|
name: "ambient-light-sensor",
|
|
@@ -56459,12 +56938,7 @@ var ambientLightSensorCapability = {
|
|
|
56459
56938
|
} } },
|
|
56460
56939
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56461
56940
|
* whether persisting is worth a SQLite commit. */
|
|
56462
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56463
|
-
customize: {
|
|
56464
|
-
version: 1,
|
|
56465
|
-
advanced: "derive",
|
|
56466
|
-
targets: []
|
|
56467
|
-
}
|
|
56941
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56468
56942
|
};
|
|
56469
56943
|
/**
|
|
56470
56944
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56691,10 +57165,7 @@ var BatteryStatusSchema = object({
|
|
|
56691
57165
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56692
57166
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56693
57167
|
*/
|
|
56694
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56695
|
-
unit: "%",
|
|
56696
|
-
label: "Charge"
|
|
56697
|
-
}),
|
|
57168
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56698
57169
|
/**
|
|
56699
57170
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56700
57171
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56721,7 +57192,14 @@ var BatteryStatusSchema = object({
|
|
|
56721
57192
|
*/
|
|
56722
57193
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56723
57194
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56724
|
-
lastUpdated: number(),
|
|
57195
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57196
|
+
/**
|
|
57197
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57198
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57199
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57200
|
+
* `numeric-sensor` on the same device.
|
|
57201
|
+
*/
|
|
57202
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56725
57203
|
/**
|
|
56726
57204
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56727
57205
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56773,7 +57251,6 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56773
57251
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56774
57252
|
var batteryCustomize = {
|
|
56775
57253
|
version: 1,
|
|
56776
|
-
advanced: "derive",
|
|
56777
57254
|
targets: [{
|
|
56778
57255
|
id: "percentage",
|
|
56779
57256
|
cardinality: "scalar",
|
|
@@ -56782,7 +57259,7 @@ var batteryCustomize = {
|
|
|
56782
57259
|
stateField: "percentage"
|
|
56783
57260
|
},
|
|
56784
57261
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56785
|
-
apply: "add
|
|
57262
|
+
apply: "add",
|
|
56786
57263
|
path: "percentage",
|
|
56787
57264
|
sources: [{
|
|
56788
57265
|
kind: "field",
|
|
@@ -56903,10 +57380,16 @@ onStatusChanged: { data: object({
|
|
|
56903
57380
|
/**
|
|
56904
57381
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
56905
57382
|
*/
|
|
56906
|
-
history: { fields: {
|
|
56907
|
-
|
|
56908
|
-
|
|
56909
|
-
|
|
57383
|
+
history: { fields: {
|
|
57384
|
+
percentage: {
|
|
57385
|
+
kind: "gauge",
|
|
57386
|
+
unit: "%"
|
|
57387
|
+
},
|
|
57388
|
+
volts: {
|
|
57389
|
+
kind: "gauge",
|
|
57390
|
+
unit: "V"
|
|
57391
|
+
}
|
|
57392
|
+
} },
|
|
56910
57393
|
customize: batteryCustomize,
|
|
56911
57394
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56912
57395
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -56953,12 +57436,7 @@ var binaryCapability = {
|
|
|
56953
57436
|
history: { fields: { on: { kind: "boolean" } } },
|
|
56954
57437
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56955
57438
|
* whether persisting is worth a SQLite commit. */
|
|
56956
|
-
volatileStateFields: ["lastChangedAt"]
|
|
56957
|
-
customize: {
|
|
56958
|
-
version: 1,
|
|
56959
|
-
advanced: "derive",
|
|
56960
|
-
targets: []
|
|
56961
|
-
}
|
|
57439
|
+
volatileStateFields: ["lastChangedAt"]
|
|
56962
57440
|
};
|
|
56963
57441
|
/**
|
|
56964
57442
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -56974,7 +57452,7 @@ var binaryCapability = {
|
|
|
56974
57452
|
*/
|
|
56975
57453
|
var BrightnessStatusSchema = object({
|
|
56976
57454
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56977
|
-
percentage: number().min(0).max(100),
|
|
57455
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56978
57456
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56979
57457
|
lastChangedAt: number()
|
|
56980
57458
|
});
|
|
@@ -57445,21 +57923,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57445
57923
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57446
57924
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57447
57925
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57448
|
-
target: number().nullable(),
|
|
57926
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57449
57927
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57450
57928
|
* in `heat_cool` mode. */
|
|
57451
|
-
targetHigh: number().nullable(),
|
|
57929
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57452
57930
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57453
57931
|
* in `heat_cool` mode. */
|
|
57454
|
-
targetLow: number().nullable(),
|
|
57932
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57455
57933
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57456
57934
|
* humidity control. */
|
|
57457
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57935
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57458
57936
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57459
57937
|
* the device's internal sensor. */
|
|
57460
|
-
currentTemp: number().nullable(),
|
|
57938
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57461
57939
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57462
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57940
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57463
57941
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57464
57942
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57465
57943
|
swingVertical: boolean().nullable(),
|
|
@@ -57467,11 +57945,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57467
57945
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57468
57946
|
swingHorizontal: boolean().nullable(),
|
|
57469
57947
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57470
|
-
minTemp: number().nullable().optional(),
|
|
57948
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57471
57949
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57472
|
-
maxTemp: number().nullable().optional(),
|
|
57950
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57473
57951
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57474
|
-
tempStep: number().positive().nullable().optional(),
|
|
57952
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57475
57953
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57476
57954
|
lastFetchedAt: number()
|
|
57477
57955
|
});
|
|
@@ -57613,17 +58091,17 @@ var climateControlCapability = {
|
|
|
57613
58091
|
* modes to expose in the picker without a slice fetch.
|
|
57614
58092
|
*/
|
|
57615
58093
|
var RgbTripletSchema = object({
|
|
57616
|
-
r: number().int().min(0).max(255),
|
|
57617
|
-
g: number().int().min(0).max(255),
|
|
57618
|
-
b: number().int().min(0).max(255)
|
|
58094
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58095
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58096
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57619
58097
|
});
|
|
57620
58098
|
var HsvTripletSchema = object({
|
|
57621
58099
|
/** Hue in degrees, 0..360. */
|
|
57622
|
-
h: number().min(0).max(360),
|
|
58100
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57623
58101
|
/** Saturation as 0..100 inclusive. */
|
|
57624
|
-
s: number().min(0).max(100),
|
|
58102
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57625
58103
|
/** Value/brightness as 0..100 inclusive. */
|
|
57626
|
-
v: number().min(0).max(100)
|
|
58104
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57627
58105
|
});
|
|
57628
58106
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57629
58107
|
object({
|
|
@@ -57652,7 +58130,7 @@ var ColorStatusSchema = object({
|
|
|
57652
58130
|
/** Populated when `mode === 'hsv'`. */
|
|
57653
58131
|
hsv: HsvTripletSchema.optional(),
|
|
57654
58132
|
/** Populated when `mode === 'mired'`. */
|
|
57655
|
-
mireds: number().int().optional(),
|
|
58133
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57656
58134
|
/** Ms epoch of the last operator-driven change. */
|
|
57657
58135
|
lastChangedAt: number()
|
|
57658
58136
|
});
|
|
@@ -57859,18 +58337,12 @@ _enum([
|
|
|
57859
58337
|
function consumableKindOf(item) {
|
|
57860
58338
|
return item.kind ?? "wear";
|
|
57861
58339
|
}
|
|
57862
|
-
/**
|
|
57863
|
-
|
|
57864
|
-
|
|
57865
|
-
"days",
|
|
57866
|
-
"hours",
|
|
57867
|
-
"cycles"
|
|
57868
|
-
]);
|
|
57869
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57870
|
-
* days). `value` null = unknown (D393). */
|
|
58340
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58341
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58342
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57871
58343
|
var ConsumableRemainingSchema = object({
|
|
57872
|
-
value: number().min(0).nullable(),
|
|
57873
|
-
|
|
58344
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58345
|
+
kind: ConsumableRemainingKindSchema
|
|
57874
58346
|
});
|
|
57875
58347
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
57876
58348
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -57883,7 +58355,7 @@ var ConsumableItemSchema = object({
|
|
|
57883
58355
|
/** Display name. */
|
|
57884
58356
|
label: string().min(1),
|
|
57885
58357
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57886
|
-
level: number().min(0).max(100).nullable(),
|
|
58358
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57887
58359
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57888
58360
|
status: ConsumableStatusSchema.nullable(),
|
|
57889
58361
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57965,8 +58437,8 @@ var consumablesCustomize = {
|
|
|
57965
58437
|
transforms: [{ kind: "identity" }]
|
|
57966
58438
|
}],
|
|
57967
58439
|
literals: [{
|
|
57968
|
-
path: "remaining.
|
|
57969
|
-
values: [...
|
|
58440
|
+
path: "remaining.kind",
|
|
58441
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
57970
58442
|
}]
|
|
57971
58443
|
},
|
|
57972
58444
|
{
|
|
@@ -58095,7 +58567,6 @@ reset: method(object({
|
|
|
58095
58567
|
},
|
|
58096
58568
|
"remaining.value": {
|
|
58097
58569
|
kind: "gauge",
|
|
58098
|
-
unitFrom: "remaining.unit",
|
|
58099
58570
|
deadband: 1,
|
|
58100
58571
|
displayName: "Remaining"
|
|
58101
58572
|
}
|
|
@@ -58165,10 +58636,9 @@ var contactCapability = {
|
|
|
58165
58636
|
* (empty array for the other kinds). It lives in the slice because
|
|
58166
58637
|
* HA `select.*` entities may update their options at runtime.
|
|
58167
58638
|
*
|
|
58168
|
-
*
|
|
58169
|
-
*
|
|
58170
|
-
*
|
|
58171
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
58639
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
58640
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
58641
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58172
58642
|
*/
|
|
58173
58643
|
var ControlStatusSchema = object({
|
|
58174
58644
|
kind: _enum([
|
|
@@ -58180,39 +58650,17 @@ var ControlStatusSchema = object({
|
|
|
58180
58650
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58181
58651
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58182
58652
|
* or time-only — HA accepts all three forms). */
|
|
58183
|
-
value: union([number(), string()]),
|
|
58653
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58184
58654
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58185
58655
|
options: array(string()),
|
|
58186
58656
|
/** Ms epoch when the slice was last updated. */
|
|
58187
58657
|
lastChangedAt: number(),
|
|
58188
|
-
/**
|
|
58189
|
-
|
|
58190
|
-
|
|
58191
|
-
|
|
58192
|
-
/**
|
|
58193
|
-
|
|
58194
|
-
min: number().optional(),
|
|
58195
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58196
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58197
|
-
max: number().optional(),
|
|
58198
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58199
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58200
|
-
step: number().optional(),
|
|
58201
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58202
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58203
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58204
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58205
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58206
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58207
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58208
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58209
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58210
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58211
|
-
format: _enum([
|
|
58212
|
-
"date",
|
|
58213
|
-
"time",
|
|
58214
|
-
"datetime"
|
|
58215
|
-
]).optional()
|
|
58658
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58659
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58660
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58661
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58662
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58663
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58216
58664
|
});
|
|
58217
58665
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58218
58666
|
object({
|
|
@@ -58278,9 +58726,9 @@ var CoverStatusSchema = object({
|
|
|
58278
58726
|
]),
|
|
58279
58727
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58280
58728
|
* no intermediate position surface. */
|
|
58281
|
-
position: number().min(0).max(100).nullable(),
|
|
58729
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58282
58730
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58283
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58731
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58284
58732
|
/** Ms epoch when the slice was last updated. */
|
|
58285
58733
|
lastChangedAt: number()
|
|
58286
58734
|
});
|
|
@@ -58383,9 +58831,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58383
58831
|
var DayNightStatusSchema = object({
|
|
58384
58832
|
mode: DayNightModeSchema,
|
|
58385
58833
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58386
|
-
sensitivity: number().optional(),
|
|
58834
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58387
58835
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58388
|
-
switchDelaySec: number().optional(),
|
|
58836
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58389
58837
|
lastFetchedAt: number()
|
|
58390
58838
|
});
|
|
58391
58839
|
/**
|
|
@@ -58603,11 +59051,11 @@ var DishwasherStatusSchema = object({
|
|
|
58603
59051
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58604
59052
|
availablePrograms: array(string()),
|
|
58605
59053
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58606
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59054
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58607
59055
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58608
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59056
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58609
59057
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58610
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59058
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58611
59059
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58612
59060
|
doorOpen: boolean().nullable(),
|
|
58613
59061
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58631,7 +59079,7 @@ var DishwasherStatusSchema = object({
|
|
|
58631
59079
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58632
59080
|
machineCareDue: boolean().nullable(),
|
|
58633
59081
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58634
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59082
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58635
59083
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58636
59084
|
halfLoad: boolean().nullable(),
|
|
58637
59085
|
hygienePlus: boolean().nullable(),
|
|
@@ -58646,7 +59094,7 @@ var DishwasherStatusSchema = object({
|
|
|
58646
59094
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58647
59095
|
activeEvents: array(string()),
|
|
58648
59096
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58649
|
-
errorCode: number().nullable(),
|
|
59097
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58650
59098
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58651
59099
|
errorLabel: string().nullable(),
|
|
58652
59100
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58877,7 +59325,7 @@ var DoorbellStatusSchema = object({
|
|
|
58877
59325
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58878
59326
|
lastPressedAt: number().nullable(),
|
|
58879
59327
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58880
|
-
pressCountSinceStart: number()
|
|
59328
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58881
59329
|
});
|
|
58882
59330
|
var DoorbellPressEventSchema = object({
|
|
58883
59331
|
deviceId: number(),
|
|
@@ -58942,17 +59390,7 @@ onPressed: {
|
|
|
58942
59390
|
history: "none",
|
|
58943
59391
|
customize: doorbellCustomize
|
|
58944
59392
|
};
|
|
58945
|
-
|
|
58946
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
58947
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
58948
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
58949
|
-
* The option set is stable across observations; it is persisted in the
|
|
58950
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
58951
|
-
* stored in `sourceInfo`.
|
|
58952
|
-
*/
|
|
58953
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
58954
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
58955
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
59393
|
+
_enum([
|
|
58956
59394
|
"date",
|
|
58957
59395
|
"time",
|
|
58958
59396
|
"datetime"
|
|
@@ -58960,12 +59398,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
58960
59398
|
var EnumSensorStatusSchema = object({
|
|
58961
59399
|
value: string(),
|
|
58962
59400
|
/**
|
|
58963
|
-
* Set
|
|
58964
|
-
* as
|
|
58965
|
-
*
|
|
58966
|
-
* a time-only sensor → `'time'`.
|
|
59401
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
59402
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
59403
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
58967
59404
|
*/
|
|
58968
|
-
|
|
59405
|
+
timestamp: boolean().optional(),
|
|
58969
59406
|
/** Ms epoch when the slice was last updated. */
|
|
58970
59407
|
lastFetchedAt: number()
|
|
58971
59408
|
});
|
|
@@ -58992,11 +59429,11 @@ var enumSensorCapability = {
|
|
|
58992
59429
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
58993
59430
|
* operation state, an HVAC action). The option set is per device, so the
|
|
58994
59431
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
58995
|
-
* `
|
|
59432
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
58996
59433
|
*/
|
|
58997
59434
|
history: { fields: { value: {
|
|
58998
59435
|
kind: "enum",
|
|
58999
|
-
skipWhenSet: "
|
|
59436
|
+
skipWhenSet: "timestamp"
|
|
59000
59437
|
} } },
|
|
59001
59438
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59002
59439
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59016,13 +59453,13 @@ var EventFireSchema = object({
|
|
|
59016
59453
|
deviceId: number(),
|
|
59017
59454
|
eventType: string(),
|
|
59018
59455
|
data: record(string(), unknown()).nullable(),
|
|
59019
|
-
timestamp: number(),
|
|
59020
|
-
seq: number()
|
|
59456
|
+
timestamp: number().meta(readingMeta("none")),
|
|
59457
|
+
seq: number().meta(readingMeta("count"))
|
|
59021
59458
|
});
|
|
59022
59459
|
var EventEmitterStatusSchema = object({
|
|
59023
59460
|
eventTypes: array(string()),
|
|
59024
59461
|
lastEvent: EventFireSchema.nullable(),
|
|
59025
|
-
eventCountSinceStart: number()
|
|
59462
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59026
59463
|
});
|
|
59027
59464
|
var eventEmitterCapability = {
|
|
59028
59465
|
name: "event-emitter",
|
|
@@ -59435,10 +59872,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59435
59872
|
var FanControlStatusSchema = object({
|
|
59436
59873
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59437
59874
|
* speed surface (single-speed fan). */
|
|
59438
|
-
percentage: number().min(0).max(100).nullable(),
|
|
59875
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59439
59876
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59440
59877
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59441
|
-
percentageStep: number().positive().optional(),
|
|
59878
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59442
59879
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59443
59880
|
* — empty string when no preset is active or supported. */
|
|
59444
59881
|
preset: string(),
|
|
@@ -59559,7 +59996,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59559
59996
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59560
59997
|
model: string().nullable(),
|
|
59561
59998
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59562
|
-
channelCount: number().nullable(),
|
|
59999
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59563
60000
|
/**
|
|
59564
60001
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59565
60002
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59682,9 +60119,91 @@ var gasCapability = {
|
|
|
59682
60119
|
* whether persisting is worth a SQLite commit. */
|
|
59683
60120
|
volatileStateFields: ["lastChangedAt"]
|
|
59684
60121
|
};
|
|
60122
|
+
var GroupCommandsSchema = object({
|
|
60123
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60124
|
+
results: array(object({
|
|
60125
|
+
deviceId: number().int().nonnegative(),
|
|
60126
|
+
cap: string().min(1),
|
|
60127
|
+
method: string().min(1),
|
|
60128
|
+
ok: boolean(),
|
|
60129
|
+
error: string().optional(),
|
|
60130
|
+
/** Ms epoch of the attempt. */
|
|
60131
|
+
at: number()
|
|
60132
|
+
})) });
|
|
60133
|
+
var groupCommandsCapability = {
|
|
60134
|
+
name: "group-commands",
|
|
60135
|
+
scope: "device",
|
|
60136
|
+
deviceNative: true,
|
|
60137
|
+
mode: "singleton",
|
|
60138
|
+
deviceTypes: [DeviceType.Switch, DeviceType.Light],
|
|
60139
|
+
methods: {},
|
|
60140
|
+
status: {
|
|
60141
|
+
schema: GroupCommandsSchema,
|
|
60142
|
+
kind: "push"
|
|
60143
|
+
},
|
|
60144
|
+
runtimeState: GroupCommandsSchema,
|
|
60145
|
+
/**
|
|
60146
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
60147
|
+
* failure would outlive the command that caused it.
|
|
60148
|
+
*
|
|
60149
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60150
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60151
|
+
*/
|
|
60152
|
+
durability: "session",
|
|
60153
|
+
history: "none"
|
|
60154
|
+
};
|
|
60155
|
+
/**
|
|
60156
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60157
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60158
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60159
|
+
* series that later statistics read is the output cap's own history block.
|
|
60160
|
+
*/
|
|
60161
|
+
var GroupStatusSchema = object({
|
|
60162
|
+
/** Members whose current value entered the aggregate. */
|
|
60163
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60164
|
+
precision: 0,
|
|
60165
|
+
label: "Reporting"
|
|
60166
|
+
})),
|
|
60167
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60168
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60169
|
+
precision: 0,
|
|
60170
|
+
label: "Excluded"
|
|
60171
|
+
})),
|
|
60172
|
+
/** `included` + `excluded`. */
|
|
60173
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60174
|
+
precision: 0,
|
|
60175
|
+
label: "Members"
|
|
60176
|
+
}))
|
|
60177
|
+
});
|
|
60178
|
+
var groupStatusCapability = {
|
|
60179
|
+
name: "group-status",
|
|
60180
|
+
scope: "device",
|
|
60181
|
+
deviceNative: true,
|
|
60182
|
+
mode: "singleton",
|
|
60183
|
+
deviceTypes: [
|
|
60184
|
+
DeviceType.Sensor,
|
|
60185
|
+
DeviceType.Switch,
|
|
60186
|
+
DeviceType.Light
|
|
60187
|
+
],
|
|
60188
|
+
methods: {},
|
|
60189
|
+
status: {
|
|
60190
|
+
schema: GroupStatusSchema,
|
|
60191
|
+
kind: "push"
|
|
60192
|
+
},
|
|
60193
|
+
runtimeState: GroupStatusSchema,
|
|
60194
|
+
/**
|
|
60195
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60196
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60197
|
+
*
|
|
60198
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60199
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60200
|
+
*/
|
|
60201
|
+
durability: "session",
|
|
60202
|
+
history: "none"
|
|
60203
|
+
};
|
|
59685
60204
|
var HeatingValveStatusSchema = object({
|
|
59686
60205
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59687
|
-
position: number().min(0).max(100).nullable(),
|
|
60206
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59688
60207
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59689
60208
|
lastFetchedAt: number()
|
|
59690
60209
|
});
|
|
@@ -59727,9 +60246,9 @@ var HumidifierStatusSchema = object({
|
|
|
59727
60246
|
/** Whether the humidifier is currently on. */
|
|
59728
60247
|
on: boolean(),
|
|
59729
60248
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59730
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60249
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59731
60250
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59732
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60251
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59733
60252
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59734
60253
|
* device has no mode surface. */
|
|
59735
60254
|
mode: string().nullable(),
|
|
@@ -59739,9 +60258,9 @@ var HumidifierStatusSchema = object({
|
|
|
59739
60258
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59740
60259
|
action: string().nullable(),
|
|
59741
60260
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59742
|
-
minHumidity: number().nullable(),
|
|
60261
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59743
60262
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59744
|
-
maxHumidity: number().nullable(),
|
|
60263
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59745
60264
|
/** Ms epoch when the slice was last updated. */
|
|
59746
60265
|
lastChangedAt: number()
|
|
59747
60266
|
});
|
|
@@ -59811,22 +60330,13 @@ var humidifierCapability = {
|
|
|
59811
60330
|
* `sourceInfo`.
|
|
59812
60331
|
*/
|
|
59813
60332
|
var HumiditySensorStatusSchema = object({
|
|
59814
|
-
/** Current relative humidity, 0..100. */
|
|
59815
|
-
percent: number().min(0).max(100).meta({
|
|
59816
|
-
|
|
60333
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60334
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60335
|
+
precision: 0,
|
|
59817
60336
|
label: "Humidity"
|
|
59818
|
-
}),
|
|
60337
|
+
})),
|
|
59819
60338
|
/** Ms epoch when the slice was last updated. */
|
|
59820
|
-
lastFetchedAt: number()
|
|
59821
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59822
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59823
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59824
|
-
unit: string().optional(),
|
|
59825
|
-
/** Suggested decimal places for numeric display.
|
|
59826
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59827
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59828
|
-
* auto-formatting when absent. */
|
|
59829
|
-
precision: number().int().min(0).max(10).optional()
|
|
60339
|
+
lastFetchedAt: number()
|
|
59830
60340
|
});
|
|
59831
60341
|
var humiditySensorCapability = {
|
|
59832
60342
|
name: "humidity-sensor",
|
|
@@ -59857,12 +60367,7 @@ var humiditySensorCapability = {
|
|
|
59857
60367
|
} } },
|
|
59858
60368
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59859
60369
|
* whether persisting is worth a SQLite commit. */
|
|
59860
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
59861
|
-
customize: {
|
|
59862
|
-
version: 1,
|
|
59863
|
-
advanced: "derive",
|
|
59864
|
-
targets: []
|
|
59865
|
-
}
|
|
60370
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
59866
60371
|
};
|
|
59867
60372
|
/**
|
|
59868
60373
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -59883,7 +60388,7 @@ var ImageStatusSchema = object({
|
|
|
59883
60388
|
* entity exposes no `entity_picture` (yet). */
|
|
59884
60389
|
url: string().nullable(),
|
|
59885
60390
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
59886
|
-
lastUpdated: number().nullable()
|
|
60391
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
59887
60392
|
});
|
|
59888
60393
|
var imageCapability = {
|
|
59889
60394
|
name: "image",
|
|
@@ -59971,19 +60476,19 @@ var NormalizedRangeSchema = object({
|
|
|
59971
60476
|
*/
|
|
59972
60477
|
var ImageSettingsStatusSchema = object({
|
|
59973
60478
|
/** Normalized 0–100. */
|
|
59974
|
-
brightness: number().optional(),
|
|
60479
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
59975
60480
|
/** Normalized 0–100. */
|
|
59976
|
-
contrast: number().optional(),
|
|
60481
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
59977
60482
|
/** Normalized 0–100. */
|
|
59978
|
-
saturation: number().optional(),
|
|
60483
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
59979
60484
|
/** Normalized 0–100. */
|
|
59980
|
-
sharpness: number().optional(),
|
|
60485
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
59981
60486
|
mirror: boolean().optional(),
|
|
59982
60487
|
flip: boolean().optional(),
|
|
59983
60488
|
rotate: ImageRotateSchema.optional(),
|
|
59984
60489
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
59985
60490
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
59986
|
-
warmth: number().optional(),
|
|
60491
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
59987
60492
|
exposureMode: ExposureModeSchema.optional(),
|
|
59988
60493
|
backlightMode: BacklightModeSchema.optional(),
|
|
59989
60494
|
lastFetchedAt: number()
|
|
@@ -60262,10 +60767,10 @@ var IntercomAbilitySchema = object({
|
|
|
60262
60767
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60263
60768
|
codecs: array(string()),
|
|
60264
60769
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60265
|
-
sampleRate: number(),
|
|
60770
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60266
60771
|
duplex: _enum(["half", "full"]),
|
|
60267
60772
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60268
|
-
maxBacklogMs: number()
|
|
60773
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60269
60774
|
});
|
|
60270
60775
|
var IntercomStatusSchema = object({
|
|
60271
60776
|
/** True while a talk session is open. */
|
|
@@ -60492,13 +60997,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60492
60997
|
activity: LawnMowerActivitySchema,
|
|
60493
60998
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60494
60999
|
* reading. */
|
|
60495
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61000
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60496
61001
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60497
61002
|
* task is active / progress is unavailable. */
|
|
60498
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61003
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60499
61004
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60500
61005
|
* or null when unknown. */
|
|
60501
|
-
currentCode: number().nullable(),
|
|
61006
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60502
61007
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60503
61008
|
currentCodeLabel: string().nullable(),
|
|
60504
61009
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61031,7 +61536,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61031
61536
|
state: MediaPlayerStateSchema,
|
|
61032
61537
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61033
61538
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61034
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
61539
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61035
61540
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61036
61541
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61037
61542
|
isMuted: boolean().nullable(),
|
|
@@ -61044,10 +61549,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61044
61549
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61045
61550
|
/** Current playback position in ms. Null when not seekable or
|
|
61046
61551
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61047
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
61552
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61048
61553
|
/** Total duration of the current media in ms. Null when unknown
|
|
61049
61554
|
* (live stream) or nothing is playing. */
|
|
61050
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
61555
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61051
61556
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61052
61557
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61053
61558
|
shuffle: boolean().nullable(),
|
|
@@ -61356,7 +61861,7 @@ var motionCustomize = {
|
|
|
61356
61861
|
eventName: "onMotionChanged"
|
|
61357
61862
|
},
|
|
61358
61863
|
deviceTypes: [DeviceType.Camera],
|
|
61359
|
-
apply: "
|
|
61864
|
+
apply: "add",
|
|
61360
61865
|
applyAuthority: {
|
|
61361
61866
|
kind: "camera-sensors",
|
|
61362
61867
|
timeoutField: "motionCooldownMs"
|
|
@@ -61428,7 +61933,7 @@ var MotionStatusSchema = object({
|
|
|
61428
61933
|
* it, every provider seeded it at boot, and every session left it
|
|
61429
61934
|
* `detected: true` after its detach.
|
|
61430
61935
|
*/
|
|
61431
|
-
autoClearAfterMs: number().nullable()
|
|
61936
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61432
61937
|
});
|
|
61433
61938
|
/**
|
|
61434
61939
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61465,12 +61970,18 @@ var motionCapability = {
|
|
|
61465
61970
|
methods: {
|
|
61466
61971
|
/**
|
|
61467
61972
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
61468
|
-
* for consumers that don't need the full status object
|
|
61469
|
-
*
|
|
61470
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
61471
|
-
* consumer.
|
|
61973
|
+
* for consumers that don't need the full status object. A composed
|
|
61974
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
61472
61975
|
*/
|
|
61473
61976
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
61977
|
+
/**
|
|
61978
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
61979
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
61980
|
+
*/
|
|
61981
|
+
composedMethods: { isDetected: {
|
|
61982
|
+
kind: "slice",
|
|
61983
|
+
field: "detected"
|
|
61984
|
+
} },
|
|
61474
61985
|
events: {
|
|
61475
61986
|
/**
|
|
61476
61987
|
* Fires every time the runner transitions a camera between
|
|
@@ -61610,7 +62121,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61610
62121
|
* the grid region(s). */
|
|
61611
62122
|
var MotionZoneStatusSchema = object({
|
|
61612
62123
|
enabled: boolean(),
|
|
61613
|
-
sensitivity: number(),
|
|
62124
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61614
62125
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61615
62126
|
regions: array(MotionZoneRegionSchema),
|
|
61616
62127
|
lastFetchedAt: number()
|
|
@@ -62117,7 +62628,7 @@ var NavigationStatusSchema = object({
|
|
|
62117
62628
|
following: boolean(),
|
|
62118
62629
|
flash: boolean(),
|
|
62119
62630
|
lightMode: NavigationLightModeSchema,
|
|
62120
|
-
lightLevel: number().min(40).max(100),
|
|
62631
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62121
62632
|
/** Ms epoch when the slice was last updated. */
|
|
62122
62633
|
lastChangedAt: number()
|
|
62123
62634
|
});
|
|
@@ -62251,13 +62762,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62251
62762
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62252
62763
|
* SKIP a null rather than coerce it.
|
|
62253
62764
|
*/
|
|
62254
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
62765
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62255
62766
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62256
|
-
rssiDbm: number().optional(),
|
|
62767
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62257
62768
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62258
62769
|
ssid: string().optional(),
|
|
62259
62770
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62260
|
-
lastUpdated: number()
|
|
62771
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62261
62772
|
});
|
|
62262
62773
|
/** The slice a provider seeds before its first read: nothing is known yet. */
|
|
62263
62774
|
var NETWORK_LINK_UNKNOWN = {
|
|
@@ -62653,7 +63164,7 @@ var NotifierStatusSchema = object({
|
|
|
62653
63164
|
lastError: string().nullable(),
|
|
62654
63165
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62655
63166
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62656
|
-
queueDepth: number().int().nonnegative(),
|
|
63167
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62657
63168
|
/** Per-feature capability matrix — authoritative source for the
|
|
62658
63169
|
* compose-form field gating. */
|
|
62659
63170
|
supports: NotifierSupportsSchema
|
|
@@ -62745,11 +63256,9 @@ onSent: { data: object({
|
|
|
62745
63256
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62746
63257
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62747
63258
|
*
|
|
62748
|
-
* The
|
|
62749
|
-
*
|
|
62750
|
-
*
|
|
62751
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62752
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63259
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63260
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63261
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62753
63262
|
*
|
|
62754
63263
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62755
63264
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62758,15 +63267,8 @@ onSent: { data: object({
|
|
|
62758
63267
|
* numeric values land here.
|
|
62759
63268
|
*/
|
|
62760
63269
|
var NumericSensorStatusSchema = object({
|
|
62761
|
-
|
|
62762
|
-
|
|
62763
|
-
* Populated live from the upstream source on each state push.
|
|
62764
|
-
* Absent for unitless sensors. */
|
|
62765
|
-
unit: string().optional(),
|
|
62766
|
-
/** Suggested decimal places for numeric display.
|
|
62767
|
-
* Populated live from the upstream source when provided.
|
|
62768
|
-
* Falls back to auto-formatting when absent. */
|
|
62769
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63270
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63271
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62770
63272
|
/** Ms epoch when the slice was last updated. */
|
|
62771
63273
|
lastFetchedAt: number()
|
|
62772
63274
|
});
|
|
@@ -62790,11 +63292,11 @@ var numericSensorCapability = {
|
|
|
62790
63292
|
*/
|
|
62791
63293
|
durability: "restored",
|
|
62792
63294
|
/**
|
|
62793
|
-
* History (D850): recorded series. The unit is
|
|
63295
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63296
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62794
63297
|
*/
|
|
62795
63298
|
history: { fields: { value: {
|
|
62796
63299
|
kind: "gauge",
|
|
62797
|
-
unitFrom: "unit",
|
|
62798
63300
|
minIntervalMs: 3e4
|
|
62799
63301
|
} } },
|
|
62800
63302
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -63086,23 +63588,26 @@ var PetFeederStatusSchema = object({
|
|
|
63086
63588
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
63087
63589
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
63088
63590
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
63089
|
-
foodLevel: number().nullable(),
|
|
63591
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
63090
63592
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63091
63593
|
* single-hopper models. */
|
|
63092
|
-
food1: number().nullable(),
|
|
63594
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63093
63595
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63094
63596
|
* single-hopper models. */
|
|
63095
|
-
food2: number().nullable(),
|
|
63597
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63096
63598
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63097
63599
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63098
63600
|
* below the feeder's low threshold. */
|
|
63099
63601
|
lowFood: boolean(),
|
|
63100
63602
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63101
63603
|
* device has no battery reading. */
|
|
63102
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63103
|
-
/**
|
|
63104
|
-
*
|
|
63105
|
-
|
|
63604
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63605
|
+
/**
|
|
63606
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
63607
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
63608
|
+
* model has no desiccant sensor.
|
|
63609
|
+
*/
|
|
63610
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63106
63611
|
/** True while a feed is in progress. */
|
|
63107
63612
|
feeding: boolean(),
|
|
63108
63613
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63113,7 +63618,7 @@ var PetFeederStatusSchema = object({
|
|
|
63113
63618
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63114
63619
|
error: string().nullable(),
|
|
63115
63620
|
/** Raw device error code (0 / null = no error). */
|
|
63116
|
-
errorCode: number().nullable(),
|
|
63621
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63117
63622
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63118
63623
|
isDualHopper: boolean(),
|
|
63119
63624
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63123,7 +63628,7 @@ var PetFeederStatusSchema = object({
|
|
|
63123
63628
|
/** Play a chime when dispensing. */
|
|
63124
63629
|
feedSound: boolean(),
|
|
63125
63630
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63126
|
-
volume: number(),
|
|
63631
|
+
volume: number().meta(readingMeta("none")),
|
|
63127
63632
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63128
63633
|
lastFetchedAt: number()
|
|
63129
63634
|
});
|
|
@@ -63242,7 +63747,7 @@ var petFeederCapability = {
|
|
|
63242
63747
|
},
|
|
63243
63748
|
desiccantLeftDays: {
|
|
63244
63749
|
kind: "gauge",
|
|
63245
|
-
unit: "
|
|
63750
|
+
unit: "s"
|
|
63246
63751
|
}
|
|
63247
63752
|
} }
|
|
63248
63753
|
};
|
|
@@ -63643,36 +64148,19 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63643
64148
|
*/
|
|
63644
64149
|
var PowerMeterStatusSchema = object({
|
|
63645
64150
|
/** Instantaneous power draw in watts. */
|
|
63646
|
-
watts: number().optional().meta({
|
|
63647
|
-
unit: "W",
|
|
63648
|
-
label: "Power"
|
|
63649
|
-
}),
|
|
64151
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63650
64152
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63651
|
-
kwhTotal: number().optional().meta({
|
|
63652
|
-
unit: "kWh",
|
|
63653
|
-
label: "Energy"
|
|
63654
|
-
}),
|
|
64153
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63655
64154
|
/** Voltage in volts. */
|
|
63656
|
-
volts: number().optional(),
|
|
64155
|
+
volts: number().optional().meta(readingMeta("voltage")),
|
|
63657
64156
|
/** Current in amperes. */
|
|
63658
|
-
amps: number().optional(),
|
|
63659
|
-
/** Apparent power in volt-amperes
|
|
63660
|
-
va: number().optional(),
|
|
64157
|
+
amps: number().optional().meta(readingMeta("current")),
|
|
64158
|
+
/** Apparent power in volt-amperes. */
|
|
64159
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63661
64160
|
/** Power factor (0..1) if reported. */
|
|
63662
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
64161
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63663
64162
|
/** Ms epoch when the slice was last updated. */
|
|
63664
|
-
lastFetchedAt: number()
|
|
63665
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63666
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63667
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63668
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63669
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63670
|
-
unit: string().optional(),
|
|
63671
|
-
/** Suggested decimal places for numeric display.
|
|
63672
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63673
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63674
|
-
* auto-formatting when absent. */
|
|
63675
|
-
precision: number().int().min(0).max(10).optional()
|
|
64163
|
+
lastFetchedAt: number()
|
|
63676
64164
|
});
|
|
63677
64165
|
var powerMeterCapability = {
|
|
63678
64166
|
name: "power-meter",
|
|
@@ -63736,12 +64224,7 @@ var powerMeterCapability = {
|
|
|
63736
64224
|
} },
|
|
63737
64225
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63738
64226
|
* whether persisting is worth a SQLite commit. */
|
|
63739
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
63740
|
-
customize: {
|
|
63741
|
-
version: 1,
|
|
63742
|
-
advanced: "derive",
|
|
63743
|
-
targets: []
|
|
63744
|
-
}
|
|
64227
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
63745
64228
|
};
|
|
63746
64229
|
/**
|
|
63747
64230
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63761,11 +64244,11 @@ var powerMeterCapability = {
|
|
|
63761
64244
|
*/
|
|
63762
64245
|
var GpsLocationSchema = object({
|
|
63763
64246
|
/** Latitude in decimal degrees, -90..90. */
|
|
63764
|
-
latitude: number().min(-90).max(90),
|
|
64247
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63765
64248
|
/** Longitude in decimal degrees, -180..180. */
|
|
63766
|
-
longitude: number().min(-180).max(180),
|
|
64249
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63767
64250
|
/** Reported accuracy in meters (lower = better). */
|
|
63768
|
-
accuracyMeters: number().nonnegative()
|
|
64251
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63769
64252
|
});
|
|
63770
64253
|
var PresenceStatusSchema = object({
|
|
63771
64254
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63777,7 +64260,7 @@ var PresenceStatusSchema = object({
|
|
|
63777
64260
|
gps: GpsLocationSchema.nullable(),
|
|
63778
64261
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63779
64262
|
* when not reported. */
|
|
63780
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64263
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63781
64264
|
/** Ms epoch when the slice was last updated. */
|
|
63782
64265
|
lastChangedAt: number()
|
|
63783
64266
|
});
|
|
@@ -63827,19 +64310,10 @@ var presenceCapability = {
|
|
|
63827
64310
|
* `sourceInfo`.
|
|
63828
64311
|
*/
|
|
63829
64312
|
var PressureSensorStatusSchema = object({
|
|
63830
|
-
/** Current pressure in hPa. */
|
|
63831
|
-
hpa: number(),
|
|
64313
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64314
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63832
64315
|
/** Ms epoch when the slice was last updated. */
|
|
63833
|
-
lastFetchedAt: number()
|
|
63834
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63835
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63836
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63837
|
-
unit: string().optional(),
|
|
63838
|
-
/** Suggested decimal places for numeric display.
|
|
63839
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63840
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63841
|
-
* auto-formatting when absent. */
|
|
63842
|
-
precision: number().int().min(0).max(10).optional()
|
|
64316
|
+
lastFetchedAt: number()
|
|
63843
64317
|
});
|
|
63844
64318
|
var pressureSensorCapability = {
|
|
63845
64319
|
name: "pressure-sensor",
|
|
@@ -64253,8 +64727,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64253
64727
|
}), _void(), { kind: "mutation" });
|
|
64254
64728
|
var PtzAutotrackSettingsSchema = object({
|
|
64255
64729
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64256
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64257
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
64730
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
64731
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64258
64732
|
});
|
|
64259
64733
|
/**
|
|
64260
64734
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64416,7 +64890,7 @@ var RunningStateStatusSchema = object({
|
|
|
64416
64890
|
/** null = unknown — never coerced to false (D393). */
|
|
64417
64891
|
running: boolean().nullable(),
|
|
64418
64892
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64419
|
-
since: number().nullable(),
|
|
64893
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64420
64894
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64421
64895
|
phase: string().nullable(),
|
|
64422
64896
|
/** null until a reading has been published (D393). */
|
|
@@ -64431,7 +64905,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64431
64905
|
/** Generic Customize target for the running boolean (D936). */
|
|
64432
64906
|
var runningCustomize = {
|
|
64433
64907
|
version: 1,
|
|
64434
|
-
advanced: "derive",
|
|
64435
64908
|
targets: [{
|
|
64436
64909
|
id: "running",
|
|
64437
64910
|
cardinality: "scalar",
|
|
@@ -64451,7 +64924,7 @@ var runningCustomize = {
|
|
|
64451
64924
|
DeviceType.Thermostat,
|
|
64452
64925
|
DeviceType.PetFeeder
|
|
64453
64926
|
],
|
|
64454
|
-
apply: "add
|
|
64927
|
+
apply: "add",
|
|
64455
64928
|
path: "running",
|
|
64456
64929
|
sources: [
|
|
64457
64930
|
{
|
|
@@ -65715,9 +66188,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65715
66188
|
*/
|
|
65716
66189
|
var RecordWindowSchema = object({
|
|
65717
66190
|
trigger: RecordTriggerSchema,
|
|
65718
|
-
day: number().int().min(0).max(6),
|
|
65719
|
-
startMinute: number().int().min(0).max(1439),
|
|
65720
|
-
endMinute: number().int().min(1).max(1440)
|
|
66191
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
66192
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
66193
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65721
66194
|
});
|
|
65722
66195
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65723
66196
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65793,10 +66266,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65793
66266
|
/** Master "record to the card at all" switch. */
|
|
65794
66267
|
enabled: boolean().nullable(),
|
|
65795
66268
|
overwriteWhenFull: boolean().nullable(),
|
|
65796
|
-
preRecordSec: number().nullable(),
|
|
65797
|
-
postRecordSec: number().nullable(),
|
|
66269
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66270
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65798
66271
|
/** Length of one recorded file, in minutes. */
|
|
65799
|
-
segmentMinutes: number().nullable(),
|
|
66272
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65800
66273
|
/** The primary track's weekly windows, flattened. */
|
|
65801
66274
|
windows: array(RecordWindowSchema),
|
|
65802
66275
|
/**
|
|
@@ -65812,7 +66285,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65812
66285
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65813
66286
|
* writable.
|
|
65814
66287
|
*/
|
|
65815
|
-
unreadableWindows: number(),
|
|
66288
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65816
66289
|
/**
|
|
65817
66290
|
* The camera is scheduled to record and has NO usable storage.
|
|
65818
66291
|
*
|
|
@@ -66657,7 +67130,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66657
67130
|
url: string().optional(),
|
|
66658
67131
|
codec: string().optional(),
|
|
66659
67132
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66660
|
-
fps: number().positive().optional(),
|
|
67133
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66661
67134
|
label: string().optional(),
|
|
66662
67135
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66663
67136
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66744,18 +67217,18 @@ var StreamProfileSchema = _enum([
|
|
|
66744
67217
|
]);
|
|
66745
67218
|
/** The current encoding config of one stream profile. */
|
|
66746
67219
|
var StreamProfileConfigSchema = object({
|
|
66747
|
-
width: number(),
|
|
66748
|
-
height: number(),
|
|
67220
|
+
width: number().meta(readingMeta("none")),
|
|
67221
|
+
height: number().meta(readingMeta("none")),
|
|
66749
67222
|
codec: _enum(["h264", "h265"]),
|
|
66750
|
-
framerate: number(),
|
|
66751
|
-
bitrate: number(),
|
|
67223
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67224
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66752
67225
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66753
67226
|
encoderProfile: _enum([
|
|
66754
67227
|
"high",
|
|
66755
67228
|
"main",
|
|
66756
67229
|
"baseline"
|
|
66757
67230
|
]).optional(),
|
|
66758
|
-
gop: number().optional(),
|
|
67231
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66759
67232
|
/**
|
|
66760
67233
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66761
67234
|
*
|
|
@@ -66976,12 +67449,7 @@ var switchCapability = {
|
|
|
66976
67449
|
label: "On",
|
|
66977
67450
|
kind: "boolean"
|
|
66978
67451
|
}
|
|
66979
|
-
}] }
|
|
66980
|
-
customize: {
|
|
66981
|
-
version: 1,
|
|
66982
|
-
advanced: "derive",
|
|
66983
|
-
targets: []
|
|
66984
|
-
}
|
|
67452
|
+
}] }
|
|
66985
67453
|
};
|
|
66986
67454
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66987
67455
|
function hasControlCharacter(value) {
|
|
@@ -67564,35 +68032,21 @@ var tamperCapability = {
|
|
|
67564
68032
|
* entries with `device_class: temperature` and any future native
|
|
67565
68033
|
* thermometer.
|
|
67566
68034
|
*
|
|
67567
|
-
*
|
|
67568
|
-
*
|
|
67569
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67570
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67571
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67572
|
-
* `sourceInfo`.
|
|
68035
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
68036
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67573
68037
|
*
|
|
67574
68038
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67575
68039
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67576
68040
|
* changed" steady state.
|
|
67577
68041
|
*/
|
|
67578
68042
|
var TemperatureSensorStatusSchema = object({
|
|
67579
|
-
/** Current temperature in Celsius. */
|
|
67580
|
-
celsius: number().meta({
|
|
67581
|
-
|
|
68043
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68044
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
68045
|
+
precision: 1,
|
|
67582
68046
|
label: "Temperature"
|
|
67583
|
-
}),
|
|
68047
|
+
})),
|
|
67584
68048
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67585
|
-
lastFetchedAt: number()
|
|
67586
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67587
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67588
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67589
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67590
|
-
unit: string().optional(),
|
|
67591
|
-
/** Suggested decimal places for numeric display.
|
|
67592
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67593
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67594
|
-
* auto-formatting when absent. */
|
|
67595
|
-
precision: number().int().min(0).max(10).optional()
|
|
68049
|
+
lastFetchedAt: number()
|
|
67596
68050
|
});
|
|
67597
68051
|
var temperatureSensorCapability = {
|
|
67598
68052
|
name: "temperature-sensor",
|
|
@@ -67623,12 +68077,7 @@ var temperatureSensorCapability = {
|
|
|
67623
68077
|
} } },
|
|
67624
68078
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67625
68079
|
* whether persisting is worth a SQLite commit. */
|
|
67626
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67627
|
-
customize: {
|
|
67628
|
-
version: 1,
|
|
67629
|
-
advanced: "derive",
|
|
67630
|
-
targets: []
|
|
67631
|
-
}
|
|
68080
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67632
68081
|
};
|
|
67633
68082
|
/**
|
|
67634
68083
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67911,16 +68360,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67911
68360
|
]),
|
|
67912
68361
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67913
68362
|
* reading. */
|
|
67914
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68363
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67915
68364
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67916
68365
|
* the vacuum has no speed control. */
|
|
67917
68366
|
fanSpeed: string().nullable(),
|
|
67918
68367
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67919
68368
|
availableFanSpeeds: array(string()),
|
|
67920
68369
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67921
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68370
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67922
68371
|
/** Current error code (0 / null = no error). */
|
|
67923
|
-
errorCode: number().nullable(),
|
|
68372
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67924
68373
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67925
68374
|
errorLabel: string().nullable(),
|
|
67926
68375
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67998,7 +68447,7 @@ var ValveStatusSchema = object({
|
|
|
67998
68447
|
]),
|
|
67999
68448
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
68000
68449
|
* intermediate position surface. */
|
|
68001
|
-
position: number().min(0).max(100).nullable(),
|
|
68450
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68002
68451
|
/** Ms epoch when the slice was last updated. */
|
|
68003
68452
|
lastChangedAt: number()
|
|
68004
68453
|
});
|
|
@@ -68106,9 +68555,9 @@ var vibrationCapability = {
|
|
|
68106
68555
|
*/
|
|
68107
68556
|
var WaterHeaterStatusSchema = object({
|
|
68108
68557
|
/** Current measured temperature. Null when not reported. */
|
|
68109
|
-
currentTemp: number().nullable(),
|
|
68558
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68110
68559
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68111
|
-
targetTemp: number().nullable(),
|
|
68560
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68112
68561
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68113
68562
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68114
68563
|
* device reports an unknown state. */
|
|
@@ -68119,9 +68568,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68119
68568
|
* has no away surface. */
|
|
68120
68569
|
away: boolean().nullable(),
|
|
68121
68570
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68122
|
-
minTemp: number().nullable(),
|
|
68571
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68123
68572
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68124
|
-
maxTemp: number().nullable(),
|
|
68573
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68125
68574
|
/** Ms epoch when the slice was last updated. */
|
|
68126
68575
|
lastChangedAt: number()
|
|
68127
68576
|
});
|
|
@@ -68206,25 +68655,18 @@ var waterHeaterCapability = {
|
|
|
68206
68655
|
* Forecast deferred — current conditions only for v1.
|
|
68207
68656
|
*/
|
|
68208
68657
|
var WeatherStatusSchema = object({
|
|
68209
|
-
/** Verbatim
|
|
68210
|
-
* when no condition has been reported yet. */
|
|
68658
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68211
68659
|
condition: string().nullable(),
|
|
68212
|
-
/** Current temperature in
|
|
68213
|
-
temperature: number().nullable(),
|
|
68214
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68215
|
-
temperatureUnit: string().nullable(),
|
|
68660
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
68661
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68216
68662
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68217
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68218
|
-
/** Barometric pressure in
|
|
68219
|
-
pressure: number().nullable(),
|
|
68220
|
-
/**
|
|
68221
|
-
|
|
68222
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68223
|
-
windSpeed: number().nullable(),
|
|
68224
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68225
|
-
windSpeedUnit: string().nullable(),
|
|
68663
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
68664
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
68665
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
68666
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
68667
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68226
68668
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68227
|
-
windBearing: number().nullable(),
|
|
68669
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68228
68670
|
/** Ms epoch when the slice was last updated. */
|
|
68229
68671
|
lastFetchedAt: number()
|
|
68230
68672
|
});
|
|
@@ -68252,12 +68694,12 @@ var weatherCapability = {
|
|
|
68252
68694
|
*/
|
|
68253
68695
|
durability: "session",
|
|
68254
68696
|
/**
|
|
68255
|
-
* History (D850): recorded series.
|
|
68697
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68256
68698
|
*/
|
|
68257
68699
|
history: { fields: {
|
|
68258
68700
|
temperature: {
|
|
68259
68701
|
kind: "gauge",
|
|
68260
|
-
|
|
68702
|
+
unit: "°C",
|
|
68261
68703
|
deadband: .2
|
|
68262
68704
|
},
|
|
68263
68705
|
humidity: {
|
|
@@ -68267,12 +68709,12 @@ var weatherCapability = {
|
|
|
68267
68709
|
},
|
|
68268
68710
|
pressure: {
|
|
68269
68711
|
kind: "gauge",
|
|
68270
|
-
|
|
68712
|
+
unit: "hPa",
|
|
68271
68713
|
deadband: .5
|
|
68272
68714
|
},
|
|
68273
68715
|
windSpeed: {
|
|
68274
68716
|
kind: "gauge",
|
|
68275
|
-
|
|
68717
|
+
unit: "m/s",
|
|
68276
68718
|
deadband: .5
|
|
68277
68719
|
}
|
|
68278
68720
|
} }
|
|
@@ -69203,6 +69645,404 @@ function runningFromLawnMower(activity, previous, fetchedAt, transitionAt) {
|
|
|
69203
69645
|
if (activity === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
69204
69646
|
return nativeSlice(false, activity, previous, transitionAtMs, fetchedAt, null);
|
|
69205
69647
|
}
|
|
69648
|
+
/**
|
|
69649
|
+
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
69650
|
+
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
69651
|
+
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
69652
|
+
* decimals). K derives from `°C = K − 273.15`.
|
|
69653
|
+
*/
|
|
69654
|
+
var UNIT_TABLE = {
|
|
69655
|
+
"°C": {
|
|
69656
|
+
dimension: "temperature",
|
|
69657
|
+
factor: 1,
|
|
69658
|
+
offset: 0
|
|
69659
|
+
},
|
|
69660
|
+
"°F": {
|
|
69661
|
+
dimension: "temperature",
|
|
69662
|
+
factor: 5 / 9,
|
|
69663
|
+
offset: -160 / 9
|
|
69664
|
+
},
|
|
69665
|
+
K: {
|
|
69666
|
+
dimension: "temperature",
|
|
69667
|
+
factor: 1,
|
|
69668
|
+
offset: -273.15
|
|
69669
|
+
},
|
|
69670
|
+
hPa: {
|
|
69671
|
+
dimension: "pressure",
|
|
69672
|
+
factor: 1,
|
|
69673
|
+
offset: 0
|
|
69674
|
+
},
|
|
69675
|
+
kPa: {
|
|
69676
|
+
dimension: "pressure",
|
|
69677
|
+
factor: 10,
|
|
69678
|
+
offset: 0
|
|
69679
|
+
},
|
|
69680
|
+
Pa: {
|
|
69681
|
+
dimension: "pressure",
|
|
69682
|
+
factor: .01,
|
|
69683
|
+
offset: 0
|
|
69684
|
+
},
|
|
69685
|
+
mbar: {
|
|
69686
|
+
dimension: "pressure",
|
|
69687
|
+
factor: 1,
|
|
69688
|
+
offset: 0
|
|
69689
|
+
},
|
|
69690
|
+
bar: {
|
|
69691
|
+
dimension: "pressure",
|
|
69692
|
+
factor: 1e3,
|
|
69693
|
+
offset: 0
|
|
69694
|
+
},
|
|
69695
|
+
inHg: {
|
|
69696
|
+
dimension: "pressure",
|
|
69697
|
+
factor: 33.8639,
|
|
69698
|
+
offset: 0
|
|
69699
|
+
},
|
|
69700
|
+
mmHg: {
|
|
69701
|
+
dimension: "pressure",
|
|
69702
|
+
factor: 1.33322,
|
|
69703
|
+
offset: 0
|
|
69704
|
+
},
|
|
69705
|
+
psi: {
|
|
69706
|
+
dimension: "pressure",
|
|
69707
|
+
factor: 68.9476,
|
|
69708
|
+
offset: 0
|
|
69709
|
+
},
|
|
69710
|
+
"m/s": {
|
|
69711
|
+
dimension: "speed",
|
|
69712
|
+
factor: 1,
|
|
69713
|
+
offset: 0
|
|
69714
|
+
},
|
|
69715
|
+
"km/h": {
|
|
69716
|
+
dimension: "speed",
|
|
69717
|
+
factor: 1 / 3.6,
|
|
69718
|
+
offset: 0
|
|
69719
|
+
},
|
|
69720
|
+
mph: {
|
|
69721
|
+
dimension: "speed",
|
|
69722
|
+
factor: .44704,
|
|
69723
|
+
offset: 0
|
|
69724
|
+
},
|
|
69725
|
+
kn: {
|
|
69726
|
+
dimension: "speed",
|
|
69727
|
+
factor: .514444,
|
|
69728
|
+
offset: 0
|
|
69729
|
+
},
|
|
69730
|
+
"mm/h": {
|
|
69731
|
+
dimension: "precipitation-rate",
|
|
69732
|
+
factor: 1,
|
|
69733
|
+
offset: 0
|
|
69734
|
+
},
|
|
69735
|
+
"in/h": {
|
|
69736
|
+
dimension: "precipitation-rate",
|
|
69737
|
+
factor: 25.4,
|
|
69738
|
+
offset: 0
|
|
69739
|
+
},
|
|
69740
|
+
m: {
|
|
69741
|
+
dimension: "length",
|
|
69742
|
+
factor: 1,
|
|
69743
|
+
offset: 0
|
|
69744
|
+
},
|
|
69745
|
+
mm: {
|
|
69746
|
+
dimension: "length",
|
|
69747
|
+
factor: .001,
|
|
69748
|
+
offset: 0
|
|
69749
|
+
},
|
|
69750
|
+
cm: {
|
|
69751
|
+
dimension: "length",
|
|
69752
|
+
factor: .01,
|
|
69753
|
+
offset: 0
|
|
69754
|
+
},
|
|
69755
|
+
km: {
|
|
69756
|
+
dimension: "length",
|
|
69757
|
+
factor: 1e3,
|
|
69758
|
+
offset: 0
|
|
69759
|
+
},
|
|
69760
|
+
in: {
|
|
69761
|
+
dimension: "length",
|
|
69762
|
+
factor: .0254,
|
|
69763
|
+
offset: 0
|
|
69764
|
+
},
|
|
69765
|
+
ft: {
|
|
69766
|
+
dimension: "length",
|
|
69767
|
+
factor: .3048,
|
|
69768
|
+
offset: 0
|
|
69769
|
+
},
|
|
69770
|
+
mi: {
|
|
69771
|
+
dimension: "length",
|
|
69772
|
+
factor: 1609.344,
|
|
69773
|
+
offset: 0
|
|
69774
|
+
},
|
|
69775
|
+
"m²": {
|
|
69776
|
+
dimension: "area",
|
|
69777
|
+
factor: 1,
|
|
69778
|
+
offset: 0
|
|
69779
|
+
},
|
|
69780
|
+
lx: {
|
|
69781
|
+
dimension: "illuminance",
|
|
69782
|
+
factor: 1,
|
|
69783
|
+
offset: 0
|
|
69784
|
+
},
|
|
69785
|
+
"W/m²": {
|
|
69786
|
+
dimension: "irradiance",
|
|
69787
|
+
factor: 1,
|
|
69788
|
+
offset: 0
|
|
69789
|
+
},
|
|
69790
|
+
W: {
|
|
69791
|
+
dimension: "power",
|
|
69792
|
+
factor: 1,
|
|
69793
|
+
offset: 0
|
|
69794
|
+
},
|
|
69795
|
+
kW: {
|
|
69796
|
+
dimension: "power",
|
|
69797
|
+
factor: 1e3,
|
|
69798
|
+
offset: 0
|
|
69799
|
+
},
|
|
69800
|
+
VA: {
|
|
69801
|
+
dimension: "apparent-power",
|
|
69802
|
+
factor: 1,
|
|
69803
|
+
offset: 0
|
|
69804
|
+
},
|
|
69805
|
+
Wh: {
|
|
69806
|
+
dimension: "energy",
|
|
69807
|
+
factor: 1,
|
|
69808
|
+
offset: 0
|
|
69809
|
+
},
|
|
69810
|
+
kWh: {
|
|
69811
|
+
dimension: "energy",
|
|
69812
|
+
factor: 1e3,
|
|
69813
|
+
offset: 0
|
|
69814
|
+
},
|
|
69815
|
+
MWh: {
|
|
69816
|
+
dimension: "energy",
|
|
69817
|
+
factor: 1e6,
|
|
69818
|
+
offset: 0
|
|
69819
|
+
},
|
|
69820
|
+
V: {
|
|
69821
|
+
dimension: "voltage",
|
|
69822
|
+
factor: 1,
|
|
69823
|
+
offset: 0
|
|
69824
|
+
},
|
|
69825
|
+
mV: {
|
|
69826
|
+
dimension: "voltage",
|
|
69827
|
+
factor: .001,
|
|
69828
|
+
offset: 0
|
|
69829
|
+
},
|
|
69830
|
+
A: {
|
|
69831
|
+
dimension: "current",
|
|
69832
|
+
factor: 1,
|
|
69833
|
+
offset: 0
|
|
69834
|
+
},
|
|
69835
|
+
mA: {
|
|
69836
|
+
dimension: "current",
|
|
69837
|
+
factor: .001,
|
|
69838
|
+
offset: 0
|
|
69839
|
+
},
|
|
69840
|
+
ppm: {
|
|
69841
|
+
dimension: "concentration-volume",
|
|
69842
|
+
factor: 1,
|
|
69843
|
+
offset: 0
|
|
69844
|
+
},
|
|
69845
|
+
ppb: {
|
|
69846
|
+
dimension: "concentration-volume",
|
|
69847
|
+
factor: .001,
|
|
69848
|
+
offset: 0
|
|
69849
|
+
},
|
|
69850
|
+
"µg/m³": {
|
|
69851
|
+
dimension: "concentration-mass",
|
|
69852
|
+
factor: 1,
|
|
69853
|
+
offset: 0
|
|
69854
|
+
},
|
|
69855
|
+
"mg/m³": {
|
|
69856
|
+
dimension: "concentration-mass",
|
|
69857
|
+
factor: 1e3,
|
|
69858
|
+
offset: 0
|
|
69859
|
+
},
|
|
69860
|
+
kg: {
|
|
69861
|
+
dimension: "mass",
|
|
69862
|
+
factor: 1,
|
|
69863
|
+
offset: 0
|
|
69864
|
+
},
|
|
69865
|
+
g: {
|
|
69866
|
+
dimension: "mass",
|
|
69867
|
+
factor: .001,
|
|
69868
|
+
offset: 0
|
|
69869
|
+
},
|
|
69870
|
+
lb: {
|
|
69871
|
+
dimension: "mass",
|
|
69872
|
+
factor: .453592,
|
|
69873
|
+
offset: 0
|
|
69874
|
+
},
|
|
69875
|
+
oz: {
|
|
69876
|
+
dimension: "mass",
|
|
69877
|
+
factor: .0283495,
|
|
69878
|
+
offset: 0
|
|
69879
|
+
},
|
|
69880
|
+
"%": {
|
|
69881
|
+
dimension: "percentage",
|
|
69882
|
+
factor: 1,
|
|
69883
|
+
offset: 0
|
|
69884
|
+
},
|
|
69885
|
+
L: {
|
|
69886
|
+
dimension: "volume",
|
|
69887
|
+
factor: 1,
|
|
69888
|
+
offset: 0
|
|
69889
|
+
},
|
|
69890
|
+
mL: {
|
|
69891
|
+
dimension: "volume",
|
|
69892
|
+
factor: .001,
|
|
69893
|
+
offset: 0
|
|
69894
|
+
},
|
|
69895
|
+
gal: {
|
|
69896
|
+
dimension: "volume",
|
|
69897
|
+
factor: 3.785411784,
|
|
69898
|
+
offset: 0
|
|
69899
|
+
},
|
|
69900
|
+
s: {
|
|
69901
|
+
dimension: "duration",
|
|
69902
|
+
factor: 1,
|
|
69903
|
+
offset: 0
|
|
69904
|
+
},
|
|
69905
|
+
ms: {
|
|
69906
|
+
dimension: "duration",
|
|
69907
|
+
factor: .001,
|
|
69908
|
+
offset: 0
|
|
69909
|
+
},
|
|
69910
|
+
min: {
|
|
69911
|
+
dimension: "duration",
|
|
69912
|
+
factor: 60,
|
|
69913
|
+
offset: 0
|
|
69914
|
+
},
|
|
69915
|
+
h: {
|
|
69916
|
+
dimension: "duration",
|
|
69917
|
+
factor: 3600,
|
|
69918
|
+
offset: 0
|
|
69919
|
+
},
|
|
69920
|
+
d: {
|
|
69921
|
+
dimension: "duration",
|
|
69922
|
+
factor: 86400,
|
|
69923
|
+
offset: 0
|
|
69924
|
+
},
|
|
69925
|
+
B: {
|
|
69926
|
+
dimension: "information",
|
|
69927
|
+
factor: 1,
|
|
69928
|
+
offset: 0
|
|
69929
|
+
},
|
|
69930
|
+
KiB: {
|
|
69931
|
+
dimension: "information",
|
|
69932
|
+
factor: 1024,
|
|
69933
|
+
offset: 0
|
|
69934
|
+
},
|
|
69935
|
+
MiB: {
|
|
69936
|
+
dimension: "information",
|
|
69937
|
+
factor: 1024 ** 2,
|
|
69938
|
+
offset: 0
|
|
69939
|
+
},
|
|
69940
|
+
GiB: {
|
|
69941
|
+
dimension: "information",
|
|
69942
|
+
factor: 1024 ** 3,
|
|
69943
|
+
offset: 0
|
|
69944
|
+
},
|
|
69945
|
+
TiB: {
|
|
69946
|
+
dimension: "information",
|
|
69947
|
+
factor: 1024 ** 4,
|
|
69948
|
+
offset: 0
|
|
69949
|
+
},
|
|
69950
|
+
kB: {
|
|
69951
|
+
dimension: "information",
|
|
69952
|
+
factor: 1e3,
|
|
69953
|
+
offset: 0
|
|
69954
|
+
},
|
|
69955
|
+
MB: {
|
|
69956
|
+
dimension: "information",
|
|
69957
|
+
factor: 1e6,
|
|
69958
|
+
offset: 0
|
|
69959
|
+
},
|
|
69960
|
+
GB: {
|
|
69961
|
+
dimension: "information",
|
|
69962
|
+
factor: 1e9,
|
|
69963
|
+
offset: 0
|
|
69964
|
+
},
|
|
69965
|
+
"°": {
|
|
69966
|
+
dimension: "angle",
|
|
69967
|
+
factor: 1,
|
|
69968
|
+
offset: 0
|
|
69969
|
+
},
|
|
69970
|
+
dBFS: {
|
|
69971
|
+
dimension: "sound-level",
|
|
69972
|
+
factor: 1,
|
|
69973
|
+
offset: 0
|
|
69974
|
+
},
|
|
69975
|
+
dBm: {
|
|
69976
|
+
dimension: "signal-level",
|
|
69977
|
+
factor: 1,
|
|
69978
|
+
offset: 0
|
|
69979
|
+
},
|
|
69980
|
+
mired: {
|
|
69981
|
+
dimension: "colour-temperature",
|
|
69982
|
+
factor: 1,
|
|
69983
|
+
offset: 0
|
|
69984
|
+
},
|
|
69985
|
+
kbps: {
|
|
69986
|
+
dimension: "bitrate",
|
|
69987
|
+
factor: 1,
|
|
69988
|
+
offset: 0
|
|
69989
|
+
},
|
|
69990
|
+
Mbps: {
|
|
69991
|
+
dimension: "bitrate",
|
|
69992
|
+
factor: 1e3,
|
|
69993
|
+
offset: 0
|
|
69994
|
+
},
|
|
69995
|
+
fps: {
|
|
69996
|
+
dimension: "rate",
|
|
69997
|
+
factor: 1,
|
|
69998
|
+
offset: 0
|
|
69999
|
+
}
|
|
70000
|
+
};
|
|
70001
|
+
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
70002
|
+
function specFor(unit) {
|
|
70003
|
+
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
70004
|
+
}
|
|
70005
|
+
/** The dimension a unit belongs to, or `undefined` for an unknown unit. */
|
|
70006
|
+
function unitDimension(unit) {
|
|
70007
|
+
return specFor(unit)?.dimension;
|
|
70008
|
+
}
|
|
70009
|
+
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
70010
|
+
function toCanonical(value, spec) {
|
|
70011
|
+
return value * spec.factor + spec.offset;
|
|
70012
|
+
}
|
|
70013
|
+
/** Canonical-unit value → the unit described by `spec`. */
|
|
70014
|
+
function fromCanonical(canonical, spec) {
|
|
70015
|
+
return (canonical - spec.offset) / spec.factor;
|
|
70016
|
+
}
|
|
70017
|
+
/**
|
|
70018
|
+
* Graceful variant for the render path: returns the converted value, or
|
|
70019
|
+
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
70020
|
+
* Never throws — a render caller falls back to the raw value + source unit.
|
|
70021
|
+
*/
|
|
70022
|
+
function tryConvertUnit(value, from, to) {
|
|
70023
|
+
if (from === to) return value;
|
|
70024
|
+
const fromSpec = specFor(from);
|
|
70025
|
+
if (!fromSpec) return void 0;
|
|
70026
|
+
const toSpec = specFor(to);
|
|
70027
|
+
if (!toSpec) return void 0;
|
|
70028
|
+
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
70029
|
+
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
70030
|
+
}
|
|
70031
|
+
/**
|
|
70032
|
+
* Every known unit spelling in a dimension (table insertion order — canonical
|
|
70033
|
+
* unit first). Powers the UI's same-dimension unit picker.
|
|
70034
|
+
*/
|
|
70035
|
+
/**
|
|
70036
|
+
* Convert a difference, not a reading. Affine units (°F) shift an absolute
|
|
70037
|
+
* value by their offset; a step of 1°F is 5/9°C, so the offset is cancelled.
|
|
70038
|
+
*/
|
|
70039
|
+
function tryConvertDelta(value, from, to) {
|
|
70040
|
+
if (from === to) return value;
|
|
70041
|
+
const origin = tryConvertUnit(0, from, to);
|
|
70042
|
+
const shifted = tryConvertUnit(value, from, to);
|
|
70043
|
+
if (origin === void 0 || shifted === void 0) return void 0;
|
|
70044
|
+
return shifted - origin;
|
|
70045
|
+
}
|
|
69206
70046
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
69207
70047
|
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;
|
|
69208
70048
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
@@ -69533,6 +70373,8 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69533
70373
|
featureProbe: featureProbeCapability,
|
|
69534
70374
|
flood: floodCapability,
|
|
69535
70375
|
gas: gasCapability,
|
|
70376
|
+
groupCommands: groupCommandsCapability,
|
|
70377
|
+
groupStatus: groupStatusCapability,
|
|
69536
70378
|
heatingValve: heatingValveCapability,
|
|
69537
70379
|
humidifier: humidifierCapability,
|
|
69538
70380
|
humiditySensor: humiditySensorCapability,
|
|
@@ -70925,6 +71767,13 @@ Object.freeze({
|
|
|
70925
71767
|
access: "view",
|
|
70926
71768
|
role: "admin"
|
|
70927
71769
|
},
|
|
71770
|
+
"addons.getPackageDocs": {
|
|
71771
|
+
capName: "addons",
|
|
71772
|
+
capScope: "system",
|
|
71773
|
+
addonId: null,
|
|
71774
|
+
access: "view",
|
|
71775
|
+
role: "admin"
|
|
71776
|
+
},
|
|
70928
71777
|
"addons.getVersions": {
|
|
70929
71778
|
capName: "addons",
|
|
70930
71779
|
capScope: "system",
|
|
@@ -74033,6 +74882,20 @@ Object.freeze({
|
|
|
74033
74882
|
access: "view",
|
|
74034
74883
|
role: "viewer"
|
|
74035
74884
|
},
|
|
74885
|
+
"groupCommands.getStatus": {
|
|
74886
|
+
capName: "group-commands",
|
|
74887
|
+
capScope: "device",
|
|
74888
|
+
addonId: null,
|
|
74889
|
+
access: "view",
|
|
74890
|
+
role: "viewer"
|
|
74891
|
+
},
|
|
74892
|
+
"groupStatus.getStatus": {
|
|
74893
|
+
capName: "group-status",
|
|
74894
|
+
capScope: "device",
|
|
74895
|
+
addonId: null,
|
|
74896
|
+
access: "view",
|
|
74897
|
+
role: "viewer"
|
|
74898
|
+
},
|
|
74036
74899
|
"heatingValve.getStatus": {
|
|
74037
74900
|
capName: "heating-valve",
|
|
74038
74901
|
capScope: "device",
|
|
@@ -83855,6 +84718,37 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83855
84718
|
icon: "flame"
|
|
83856
84719
|
}]
|
|
83857
84720
|
},
|
|
84721
|
+
"group-commands": {
|
|
84722
|
+
scope: "device",
|
|
84723
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84724
|
+
},
|
|
84725
|
+
"group-status": {
|
|
84726
|
+
scope: "device",
|
|
84727
|
+
noun: t("Group", "Gruppo"),
|
|
84728
|
+
state: [
|
|
84729
|
+
{
|
|
84730
|
+
kind: "numeric",
|
|
84731
|
+
field: "included",
|
|
84732
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84733
|
+
label: t("Reporting", "Rispondono"),
|
|
84734
|
+
icon: "users"
|
|
84735
|
+
},
|
|
84736
|
+
{
|
|
84737
|
+
kind: "numeric",
|
|
84738
|
+
field: "excluded",
|
|
84739
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84740
|
+
label: t("Excluded", "Esclusi"),
|
|
84741
|
+
icon: "users"
|
|
84742
|
+
},
|
|
84743
|
+
{
|
|
84744
|
+
kind: "numeric",
|
|
84745
|
+
field: "total",
|
|
84746
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84747
|
+
label: t("Members", "Membri"),
|
|
84748
|
+
icon: "sigma"
|
|
84749
|
+
}
|
|
84750
|
+
]
|
|
84751
|
+
},
|
|
83858
84752
|
"humidity-sensor": {
|
|
83859
84753
|
scope: "device",
|
|
83860
84754
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83888,7 +84782,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83888
84782
|
field: "value",
|
|
83889
84783
|
quantity: t("the reading", "il valore"),
|
|
83890
84784
|
label: t("Reading", "Valore"),
|
|
83891
|
-
unitField: "unit",
|
|
83892
84785
|
icon: "gauge"
|
|
83893
84786
|
}]
|
|
83894
84787
|
},
|
|
@@ -84024,7 +84917,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84024
84917
|
field: "temperature",
|
|
84025
84918
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
84026
84919
|
label: t("Temperature", "Temperatura"),
|
|
84027
|
-
|
|
84920
|
+
unit: "°C",
|
|
84028
84921
|
icon: "thermometer"
|
|
84029
84922
|
},
|
|
84030
84923
|
{
|
|
@@ -84040,7 +84933,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84040
84933
|
field: "windSpeed",
|
|
84041
84934
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
84042
84935
|
label: t("Wind", "Vento"),
|
|
84043
|
-
|
|
84936
|
+
unit: "m/s",
|
|
84044
84937
|
icon: "wind"
|
|
84045
84938
|
},
|
|
84046
84939
|
{
|
|
@@ -84048,7 +84941,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84048
84941
|
field: "pressure",
|
|
84049
84942
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
84050
84943
|
label: t("Pressure", "Pressione"),
|
|
84051
|
-
|
|
84944
|
+
unit: "hPa",
|
|
84052
84945
|
icon: "gauge"
|
|
84053
84946
|
}
|
|
84054
84947
|
]
|
|
@@ -85321,6 +86214,16 @@ Object.freeze({
|
|
|
85321
86214
|
form: "single",
|
|
85322
86215
|
optional: false
|
|
85323
86216
|
}],
|
|
86217
|
+
"groupCommands.getStatus": [{
|
|
86218
|
+
name: "deviceId",
|
|
86219
|
+
form: "single",
|
|
86220
|
+
optional: false
|
|
86221
|
+
}],
|
|
86222
|
+
"groupStatus.getStatus": [{
|
|
86223
|
+
name: "deviceId",
|
|
86224
|
+
form: "single",
|
|
86225
|
+
optional: false
|
|
86226
|
+
}],
|
|
85324
86227
|
"heatingValve.getStatus": [{
|
|
85325
86228
|
name: "deviceId",
|
|
85326
86229
|
form: "single",
|
|
@@ -87305,6 +88208,8 @@ new Map(Object.entries({
|
|
|
87305
88208
|
"detection-blind": "device-events",
|
|
87306
88209
|
"motion-noisy": "device-events",
|
|
87307
88210
|
"motion-calm": "device-events",
|
|
88211
|
+
"package-llm-silent": "device-events",
|
|
88212
|
+
"package-llm-answered": "device-events",
|
|
87308
88213
|
"recording-stalled": "device-events",
|
|
87309
88214
|
"recording-healthy": "device-events",
|
|
87310
88215
|
"recording-degraded": "device-events",
|
|
@@ -87388,6 +88293,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
87388
88293
|
label: "Motion without a subject",
|
|
87389
88294
|
kinds: ["motion-noisy", "motion-calm"]
|
|
87390
88295
|
},
|
|
88296
|
+
{
|
|
88297
|
+
id: "package-llm",
|
|
88298
|
+
family: "device-events",
|
|
88299
|
+
label: "Package confirm",
|
|
88300
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
88301
|
+
},
|
|
87391
88302
|
{
|
|
87392
88303
|
id: "recording",
|
|
87393
88304
|
family: "device-events",
|
|
@@ -87569,6 +88480,8 @@ var DEVICE_EVENTS = [
|
|
|
87569
88480
|
"detection-blind",
|
|
87570
88481
|
"motion-noisy",
|
|
87571
88482
|
"motion-calm",
|
|
88483
|
+
"package-llm-silent",
|
|
88484
|
+
"package-llm-answered",
|
|
87572
88485
|
"recording-stalled",
|
|
87573
88486
|
"recording-healthy",
|
|
87574
88487
|
"recording-degraded",
|
|
@@ -87837,6 +88750,15 @@ new Map([
|
|
|
87837
88750
|
snapshotLabel: "Cameras with constant motion now",
|
|
87838
88751
|
snapshotSection: null
|
|
87839
88752
|
},
|
|
88753
|
+
{
|
|
88754
|
+
id: "package-llm-confirm",
|
|
88755
|
+
family: "device-events",
|
|
88756
|
+
label: "Package confirm (not answering / answering again)",
|
|
88757
|
+
bad: ["package-llm-silent"],
|
|
88758
|
+
recovery: ["package-llm-answered"],
|
|
88759
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88760
|
+
snapshotSection: null
|
|
88761
|
+
},
|
|
87840
88762
|
{
|
|
87841
88763
|
id: "recording-health",
|
|
87842
88764
|
family: "device-events",
|
|
@@ -88413,6 +89335,96 @@ DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
|
88413
89335
|
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
88414
89336
|
DEFAULT_NATIVE_LEASE_SETTINGS.sceneBudgetMb;
|
|
88415
89337
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
89338
|
+
/**
|
|
89339
|
+
* Convert an upstream number into the stored base of its quantity (D944 §4).
|
|
89340
|
+
* An unknown unit or a unit from another dimension is a refusal: the caller
|
|
89341
|
+
* logs it and publishes null (D393). This function never guesses.
|
|
89342
|
+
*/
|
|
89343
|
+
var DIMENSION_QUANTITY = {
|
|
89344
|
+
temperature: "temperature",
|
|
89345
|
+
pressure: "pressure",
|
|
89346
|
+
speed: "speed",
|
|
89347
|
+
"precipitation-rate": "precipitation-rate",
|
|
89348
|
+
length: "length",
|
|
89349
|
+
area: "area",
|
|
89350
|
+
illuminance: "illuminance",
|
|
89351
|
+
irradiance: "irradiance",
|
|
89352
|
+
power: "power",
|
|
89353
|
+
"apparent-power": "apparent-power",
|
|
89354
|
+
energy: "energy",
|
|
89355
|
+
voltage: "voltage",
|
|
89356
|
+
current: "current",
|
|
89357
|
+
"concentration-volume": "concentration-volume",
|
|
89358
|
+
"concentration-mass": "concentration-mass",
|
|
89359
|
+
mass: "mass",
|
|
89360
|
+
percentage: "percentage",
|
|
89361
|
+
volume: "volume",
|
|
89362
|
+
duration: "duration",
|
|
89363
|
+
information: "information",
|
|
89364
|
+
angle: "angle",
|
|
89365
|
+
"sound-level": "sound-level",
|
|
89366
|
+
"signal-level": "signal-level",
|
|
89367
|
+
"colour-temperature": "colour-temperature",
|
|
89368
|
+
bitrate: "bitrate",
|
|
89369
|
+
rate: "rate"
|
|
89370
|
+
};
|
|
89371
|
+
/**
|
|
89372
|
+
* Quantity implied by a unit symbol. `ppb` and `ms` are the two symbols
|
|
89373
|
+
* whose stored base is not the dimension's canonical unit. `mm` is length;
|
|
89374
|
+
* precipitation is chosen by the caller (a device class), not by the symbol.
|
|
89375
|
+
*/
|
|
89376
|
+
function quantityFromUnit(rawUnit) {
|
|
89377
|
+
const unit = normalizeUnit(rawUnit);
|
|
89378
|
+
if (unit === void 0) return void 0;
|
|
89379
|
+
if (unit === "ppb") return "concentration-ppb";
|
|
89380
|
+
if (unit === "ms") return "duration-ms";
|
|
89381
|
+
const dimension = unitDimension(unit);
|
|
89382
|
+
if (dimension === void 0) return void 0;
|
|
89383
|
+
return DIMENSION_QUANTITY[dimension];
|
|
89384
|
+
}
|
|
89385
|
+
function ingestReading(input) {
|
|
89386
|
+
if (!Number.isFinite(input.value)) return {
|
|
89387
|
+
ok: false,
|
|
89388
|
+
reason: "non-finite"
|
|
89389
|
+
};
|
|
89390
|
+
if (input.quantity === "device") return {
|
|
89391
|
+
ok: false,
|
|
89392
|
+
reason: "unknown-unit"
|
|
89393
|
+
};
|
|
89394
|
+
const raw = input.rawUnit?.trim();
|
|
89395
|
+
if (raw === void 0 || raw.length === 0) return {
|
|
89396
|
+
ok: true,
|
|
89397
|
+
value: input.value
|
|
89398
|
+
};
|
|
89399
|
+
const unit = normalizeUnit(raw);
|
|
89400
|
+
if (unit === void 0) return {
|
|
89401
|
+
ok: false,
|
|
89402
|
+
reason: "unknown-unit"
|
|
89403
|
+
};
|
|
89404
|
+
const base = baseUnitOf(input.quantity);
|
|
89405
|
+
if (base === void 0) {
|
|
89406
|
+
if (unitDimension(unit) !== void 0) return {
|
|
89407
|
+
ok: false,
|
|
89408
|
+
reason: "cross-dimension"
|
|
89409
|
+
};
|
|
89410
|
+
return {
|
|
89411
|
+
ok: false,
|
|
89412
|
+
reason: "unknown-unit"
|
|
89413
|
+
};
|
|
89414
|
+
}
|
|
89415
|
+
const converted = tryConvertUnit(input.value, unit, base);
|
|
89416
|
+
if (converted === void 0) return unitDimension(unit) === void 0 ? {
|
|
89417
|
+
ok: false,
|
|
89418
|
+
reason: "unknown-unit"
|
|
89419
|
+
} : {
|
|
89420
|
+
ok: false,
|
|
89421
|
+
reason: "cross-dimension"
|
|
89422
|
+
};
|
|
89423
|
+
return {
|
|
89424
|
+
ok: true,
|
|
89425
|
+
value: converted
|
|
89426
|
+
};
|
|
89427
|
+
}
|
|
88416
89428
|
var MB = 1024 * 1024;
|
|
88417
89429
|
1024 * MB, 3072 * MB;
|
|
88418
89430
|
//#endregion
|
|
@@ -191109,7 +192121,7 @@ var CONSUMABLES_COLD_START = {
|
|
|
191109
192121
|
lastFetchedAt: 0
|
|
191110
192122
|
};
|
|
191111
192123
|
function itemEqual(a, b) {
|
|
191112
|
-
return a.key === b.key && a.label === b.label && a.level === b.level && a.status === b.status && a.lastResetAt === b.lastResetAt && a.resettable === b.resettable && a.kind === b.kind && a.remaining?.value === b.remaining?.value && a.remaining?.
|
|
192124
|
+
return a.key === b.key && a.label === b.label && a.level === b.level && a.status === b.status && a.lastResetAt === b.lastResetAt && a.resettable === b.resettable && a.kind === b.kind && a.remaining?.value === b.remaining?.value && a.remaining?.kind === b.remaining?.kind;
|
|
191113
192125
|
}
|
|
191114
192126
|
function itemsEqual(a, b) {
|
|
191115
192127
|
return a.length === b.length && a.every((item, i) => {
|
|
@@ -191807,6 +192819,40 @@ var DreameMowerSubstateDevice = class extends DreameChildDevice {
|
|
|
191807
192819
|
}
|
|
191808
192820
|
};
|
|
191809
192821
|
//#endregion
|
|
192822
|
+
//#region src/dreame-reading.ts
|
|
192823
|
+
/** Catalog unit → the quantity stored on the device. `times` is a count. */
|
|
192824
|
+
function dreameQuantity(unit) {
|
|
192825
|
+
if (unit === void 0 || unit.length === 0) return "none";
|
|
192826
|
+
if (unit === "times") return "count";
|
|
192827
|
+
const learned = quantityFromUnit(unit);
|
|
192828
|
+
if (learned === void 0 || learned === "device") return null;
|
|
192829
|
+
return learned;
|
|
192830
|
+
}
|
|
192831
|
+
/** Upstream number → base. A count ignores the word `times`. */
|
|
192832
|
+
function dreameToBase(value, unit, quantity) {
|
|
192833
|
+
const result = ingestReading({
|
|
192834
|
+
value,
|
|
192835
|
+
rawUnit: quantity === "count" ? void 0 : unit,
|
|
192836
|
+
quantity
|
|
192837
|
+
});
|
|
192838
|
+
return result.ok ? result.value : null;
|
|
192839
|
+
}
|
|
192840
|
+
/** Base number → the unit the robot still speaks. */
|
|
192841
|
+
function dreameToUpstream(value, unit, quantity) {
|
|
192842
|
+
const base = baseUnitOf(quantity);
|
|
192843
|
+
const upstream = unit === void 0 ? void 0 : normalizeUnit(unit);
|
|
192844
|
+
if (base === void 0 || upstream === void 0 || upstream === base) return value;
|
|
192845
|
+
return tryConvertUnit(value, base, upstream) ?? null;
|
|
192846
|
+
}
|
|
192847
|
+
/** A step is a difference, so an affine offset must not move it. */
|
|
192848
|
+
function dreameStep(step, unit, quantity) {
|
|
192849
|
+
if (step === void 0) return void 0;
|
|
192850
|
+
const base = baseUnitOf(quantity);
|
|
192851
|
+
const from = unit === void 0 ? void 0 : normalizeUnit(unit);
|
|
192852
|
+
if (base === void 0 || from === void 0 || from === base) return step;
|
|
192853
|
+
return tryConvertDelta(step, from, base);
|
|
192854
|
+
}
|
|
192855
|
+
//#endregion
|
|
191810
192856
|
//#region src/devices/dreame-number-device.ts
|
|
191811
192857
|
var CAP_NAME$5 = "control";
|
|
191812
192858
|
/** Persisted config for a generic number child: the shared Dreame child config
|
|
@@ -191831,22 +192877,25 @@ var dreameNumberSchema = dreameChildSchema.extend({
|
|
|
191831
192877
|
var DreameNumberDevice = class extends DreameChildDevice {
|
|
191832
192878
|
#siid;
|
|
191833
192879
|
#piid;
|
|
191834
|
-
#min;
|
|
191835
|
-
#max;
|
|
191836
|
-
#step;
|
|
191837
192880
|
#unit;
|
|
192881
|
+
#quantity;
|
|
192882
|
+
#baseMin;
|
|
192883
|
+
#baseMax;
|
|
192884
|
+
#baseStep;
|
|
191838
192885
|
constructor(ctx) {
|
|
191839
192886
|
super(ctx, DeviceRole.NumericControl);
|
|
191840
192887
|
const cfg = dreameNumberSchema.parse(ctx.persistedConfig ?? {});
|
|
191841
192888
|
this.#siid = cfg.siid;
|
|
191842
192889
|
this.#piid = cfg.piid;
|
|
191843
|
-
this.#min = cfg.min;
|
|
191844
|
-
this.#max = cfg.max;
|
|
191845
|
-
this.#step = cfg.step;
|
|
191846
192890
|
this.#unit = cfg.unit;
|
|
192891
|
+
this.#quantity = dreameQuantity(cfg.unit);
|
|
192892
|
+
this.#baseMin = this.#toBase(cfg.min) ?? cfg.min;
|
|
192893
|
+
this.#baseMax = this.#toBase(cfg.max) ?? cfg.max;
|
|
192894
|
+
this.#baseStep = this.#quantity === null ? cfg.step : dreameStep(cfg.step, cfg.unit, this.#quantity);
|
|
191847
192895
|
this.updateSourceInfo({
|
|
191848
192896
|
id: `${this.dreameDeviceId}:number:${cfg.siid}-${cfg.piid}`,
|
|
191849
|
-
system: "dreame"
|
|
192897
|
+
system: "dreame",
|
|
192898
|
+
...this.#quantity !== null ? { quantity: this.#quantity } : {}
|
|
191850
192899
|
});
|
|
191851
192900
|
}
|
|
191852
192901
|
/** Read the configured property's numeric value, or null when absent. */
|
|
@@ -191854,41 +192903,68 @@ var DreameNumberDevice = class extends DreameChildDevice {
|
|
|
191854
192903
|
const v = this.resolveHandle()?.getProperty(this.#siid, this.#piid)?.value;
|
|
191855
192904
|
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
191856
192905
|
}
|
|
191857
|
-
#
|
|
192906
|
+
#toBase(value) {
|
|
192907
|
+
if (this.#quantity === null) return null;
|
|
192908
|
+
return dreameToBase(value, this.#unit, this.#quantity);
|
|
192909
|
+
}
|
|
192910
|
+
#slice(upstream) {
|
|
192911
|
+
const value = this.#toBase(upstream);
|
|
192912
|
+
if (value === null) {
|
|
192913
|
+
this.ctx.logger.warn("numeric reading refused", {
|
|
192914
|
+
tags: { deviceId: this.id },
|
|
192915
|
+
meta: {
|
|
192916
|
+
quantity: this.#quantity ?? "device",
|
|
192917
|
+
unit: this.#unit ?? "",
|
|
192918
|
+
reason: "unknown-unit"
|
|
192919
|
+
}
|
|
192920
|
+
});
|
|
192921
|
+
return null;
|
|
192922
|
+
}
|
|
191858
192923
|
return {
|
|
191859
192924
|
kind: "numeric",
|
|
191860
192925
|
value,
|
|
191861
192926
|
options: [],
|
|
191862
192927
|
lastChangedAt: Date.now(),
|
|
191863
|
-
min: this.#
|
|
191864
|
-
max: this.#
|
|
191865
|
-
step: this.#
|
|
191866
|
-
...this.#unit !== void 0 ? { unit: this.#unit } : {}
|
|
192928
|
+
min: this.#baseMin,
|
|
192929
|
+
max: this.#baseMax,
|
|
192930
|
+
...this.#baseStep !== void 0 ? { step: this.#baseStep } : {}
|
|
191867
192931
|
};
|
|
191868
192932
|
}
|
|
191869
192933
|
registerControlCap() {
|
|
191870
192934
|
this.ctx.registerNativeCap(controlCapability, {
|
|
191871
|
-
getStatus: async () => this.runtimeState.getCapState(CAP_NAME$5) ??
|
|
192935
|
+
getStatus: async () => this.runtimeState.getCapState(CAP_NAME$5) ?? {
|
|
192936
|
+
kind: "numeric",
|
|
192937
|
+
value: 0,
|
|
192938
|
+
options: [],
|
|
192939
|
+
lastChangedAt: 0
|
|
192940
|
+
},
|
|
191872
192941
|
setValue: async ({ control }) => {
|
|
191873
192942
|
if (control.kind !== "numeric") throw new Error(`DreameNumberDevice: expected a numeric value (device=${this.dreameDeviceId}, ${this.#siid}/${this.#piid})`);
|
|
192943
|
+
if (this.#quantity === null) throw new Error(`DreameNumberDevice: unknown unit (device=${this.dreameDeviceId}, ${this.#siid}/${this.#piid})`);
|
|
191874
192944
|
const handle = this.resolveHandle();
|
|
191875
192945
|
if (handle === null) throw new Error(`DreameNumberDevice: handle unavailable (device=${this.dreameDeviceId}, ${this.#siid}/${this.#piid})`);
|
|
191876
|
-
const
|
|
192946
|
+
const upstream = dreameToUpstream(Math.min(this.#baseMax, Math.max(this.#baseMin, control.value)), this.#unit, this.#quantity);
|
|
192947
|
+
if (upstream === null) throw new Error(`DreameNumberDevice: cannot convert back (device=${this.dreameDeviceId}, ${this.#siid}/${this.#piid})`);
|
|
191877
192948
|
await handle.setProperty({
|
|
191878
192949
|
siid: this.#siid,
|
|
191879
192950
|
piid: this.#piid,
|
|
191880
|
-
value:
|
|
192951
|
+
value: upstream
|
|
191881
192952
|
});
|
|
191882
|
-
|
|
192953
|
+
const slice = this.#slice(upstream);
|
|
192954
|
+
if (slice !== null) this.runtimeState.setCapState(CAP_NAME$5, slice);
|
|
191883
192955
|
}
|
|
191884
192956
|
});
|
|
191885
|
-
|
|
192957
|
+
const initial = this.#read();
|
|
192958
|
+
const slice = initial === null ? null : this.#slice(initial);
|
|
192959
|
+
if (slice !== null) this.runtimeState.setCapState(CAP_NAME$5, slice);
|
|
191886
192960
|
}
|
|
191887
192961
|
recomputeSlice() {
|
|
191888
192962
|
const value = this.#read();
|
|
191889
192963
|
if (value === null) return;
|
|
191890
|
-
|
|
191891
|
-
|
|
192964
|
+
const slice = this.#slice(value);
|
|
192965
|
+
if (slice === null) return;
|
|
192966
|
+
if (this.runtimeState.getCapState(CAP_NAME$5)?.value === slice.value) return;
|
|
192967
|
+
this.runtimeState.setCapState(CAP_NAME$5, slice);
|
|
191892
192968
|
}
|
|
191893
192969
|
};
|
|
191894
192970
|
//#endregion
|
|
@@ -191919,9 +192995,11 @@ var DreameNumericSensorDevice = class extends DreameChildDevice {
|
|
|
191919
192995
|
this.#siid = cfg.siid;
|
|
191920
192996
|
this.#piid = cfg.piid;
|
|
191921
192997
|
this.#unit = cfg.unit;
|
|
192998
|
+
const quantity = dreameQuantity(cfg.unit);
|
|
191922
192999
|
this.updateSourceInfo({
|
|
191923
193000
|
id: `${this.dreameDeviceId}:sensor:${cfg.siid}-${cfg.piid}`,
|
|
191924
|
-
system: "dreame"
|
|
193001
|
+
system: "dreame",
|
|
193002
|
+
...quantity !== null ? { quantity } : {}
|
|
191925
193003
|
});
|
|
191926
193004
|
}
|
|
191927
193005
|
/** Read the configured property's numeric value from the shared handle, or null. */
|
|
@@ -191930,22 +193008,51 @@ var DreameNumericSensorDevice = class extends DreameChildDevice {
|
|
|
191930
193008
|
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
191931
193009
|
}
|
|
191932
193010
|
#slice(value) {
|
|
193011
|
+
const quantity = dreameQuantity(this.#unit);
|
|
193012
|
+
if (quantity === null) {
|
|
193013
|
+
this.ctx.logger.warn("numeric reading refused", {
|
|
193014
|
+
tags: { deviceId: this.id },
|
|
193015
|
+
meta: {
|
|
193016
|
+
quantity: "device",
|
|
193017
|
+
unit: this.#unit ?? "",
|
|
193018
|
+
reason: "unknown-unit"
|
|
193019
|
+
}
|
|
193020
|
+
});
|
|
193021
|
+
return null;
|
|
193022
|
+
}
|
|
193023
|
+
const stored = dreameToBase(value, this.#unit, quantity);
|
|
193024
|
+
if (stored === null) {
|
|
193025
|
+
this.ctx.logger.warn("numeric reading refused", {
|
|
193026
|
+
tags: { deviceId: this.id },
|
|
193027
|
+
meta: {
|
|
193028
|
+
quantity,
|
|
193029
|
+
unit: this.#unit ?? "",
|
|
193030
|
+
reason: "unknown-unit"
|
|
193031
|
+
}
|
|
193032
|
+
});
|
|
193033
|
+
return null;
|
|
193034
|
+
}
|
|
191933
193035
|
return {
|
|
191934
|
-
value,
|
|
191935
|
-
...this.#unit !== void 0 ? { unit: this.#unit } : {},
|
|
193036
|
+
value: stored,
|
|
191936
193037
|
lastFetchedAt: Date.now()
|
|
191937
193038
|
};
|
|
191938
193039
|
}
|
|
191939
193040
|
registerControlCap() {
|
|
191940
|
-
this.ctx.registerNativeCap(numericSensorCapability, { getStatus: async () => this.runtimeState.getCapState(CAP_NAME$4) ??
|
|
193041
|
+
this.ctx.registerNativeCap(numericSensorCapability, { getStatus: async () => this.runtimeState.getCapState(CAP_NAME$4) ?? {
|
|
193042
|
+
value: 0,
|
|
193043
|
+
lastFetchedAt: 0
|
|
193044
|
+
} });
|
|
191941
193045
|
const initial = this.#readValue();
|
|
191942
|
-
|
|
193046
|
+
const slice = initial === null ? null : this.#slice(initial);
|
|
193047
|
+
if (slice !== null) this.runtimeState.setCapState(CAP_NAME$4, slice);
|
|
191943
193048
|
}
|
|
191944
193049
|
recomputeSlice() {
|
|
191945
193050
|
const value = this.#readValue();
|
|
191946
193051
|
if (value === null) return;
|
|
191947
|
-
|
|
191948
|
-
|
|
193052
|
+
const slice = this.#slice(value);
|
|
193053
|
+
if (slice === null) return;
|
|
193054
|
+
if (this.runtimeState.getCapState(CAP_NAME$4)?.value === slice.value) return;
|
|
193055
|
+
this.runtimeState.setCapState(CAP_NAME$4, slice);
|
|
191949
193056
|
}
|
|
191950
193057
|
};
|
|
191951
193058
|
//#endregion
|