@camstack/addon-provider-bosch 0.1.24 → 0.1.26
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 +24 -0
- package/dist/{account-integration-offline-Dcy3K68x.js → account-integration-offline-DAgg2Cgr.js} +1 -1
- package/dist/{account-integration-offline-BPXEESM5.mjs → account-integration-offline-iGgTPuq_.mjs} +1 -1
- package/dist/{dist-QNoZItyP.mjs → dist-Cbcvh8mB.mjs} +1507 -510
- package/dist/{dist-cVQVYhpv.js → dist-DEZDBpGW.js} +1518 -509
- package/dist/home-connect/addon.js +17 -5
- package/dist/home-connect/addon.mjs +17 -5
- package/dist/homecom/addon.js +2 -2
- package/dist/homecom/addon.mjs +2 -2
- package/dist/shc/addon.js +1 -1
- package/dist/shc/addon.mjs +1 -1
- package/package.json +4 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require("node:crypto");
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-CT-hz5Rb.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -325,6 +325,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
325
325
|
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
326
326
|
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
327
327
|
/**
|
|
328
|
+
* A camera's package LLM confirm has failed closed three times in a row
|
|
329
|
+
* (D931, 2026-10-26). One edge per camera until
|
|
330
|
+
* {@link PipelinePackageLlmAnswered}.
|
|
331
|
+
*/
|
|
332
|
+
EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
|
|
333
|
+
/** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
|
|
334
|
+
EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
|
|
335
|
+
/**
|
|
328
336
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
329
337
|
* (a settings change via `setAgentInferenceDevices` /
|
|
330
338
|
* `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
|
|
@@ -5434,7 +5442,7 @@ var ZodIssueCode = {
|
|
|
5434
5442
|
var ZodFirstPartyTypeKind;
|
|
5435
5443
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5436
5444
|
//#endregion
|
|
5437
|
-
//#region ../types/dist/sleep-
|
|
5445
|
+
//#region ../types/dist/sleep-bykKrTgu.mjs
|
|
5438
5446
|
/**
|
|
5439
5447
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5440
5448
|
* window to float samples (D455).
|
|
@@ -7992,6 +8000,99 @@ var RecordKindDeclarationSchema = object({
|
|
|
7992
8000
|
}).strict();
|
|
7993
8001
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
7994
8002
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
8003
|
+
var READING_QUANTITIES = [
|
|
8004
|
+
"temperature",
|
|
8005
|
+
"pressure",
|
|
8006
|
+
"speed",
|
|
8007
|
+
"precipitation",
|
|
8008
|
+
"precipitation-rate",
|
|
8009
|
+
"length",
|
|
8010
|
+
"area",
|
|
8011
|
+
"illuminance",
|
|
8012
|
+
"irradiance",
|
|
8013
|
+
"power",
|
|
8014
|
+
"energy",
|
|
8015
|
+
"voltage",
|
|
8016
|
+
"current",
|
|
8017
|
+
"apparent-power",
|
|
8018
|
+
"humidity",
|
|
8019
|
+
"percentage",
|
|
8020
|
+
"concentration-volume",
|
|
8021
|
+
"concentration-mass",
|
|
8022
|
+
"concentration-ppb",
|
|
8023
|
+
"volume",
|
|
8024
|
+
"duration",
|
|
8025
|
+
"duration-ms",
|
|
8026
|
+
"information",
|
|
8027
|
+
"sound-level",
|
|
8028
|
+
"signal-level",
|
|
8029
|
+
"colour-temperature",
|
|
8030
|
+
"angle",
|
|
8031
|
+
"bitrate",
|
|
8032
|
+
"rate",
|
|
8033
|
+
"mass",
|
|
8034
|
+
"index",
|
|
8035
|
+
"ratio",
|
|
8036
|
+
"count",
|
|
8037
|
+
"none",
|
|
8038
|
+
"device"
|
|
8039
|
+
];
|
|
8040
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8041
|
+
new Set(READING_QUANTITIES);
|
|
8042
|
+
/**
|
|
8043
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8044
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8045
|
+
*/
|
|
8046
|
+
var QUANTITY_BASE = {
|
|
8047
|
+
temperature: "°C",
|
|
8048
|
+
pressure: "hPa",
|
|
8049
|
+
speed: "m/s",
|
|
8050
|
+
precipitation: "mm",
|
|
8051
|
+
"precipitation-rate": "mm/h",
|
|
8052
|
+
length: "m",
|
|
8053
|
+
area: "m²",
|
|
8054
|
+
illuminance: "lx",
|
|
8055
|
+
irradiance: "W/m²",
|
|
8056
|
+
power: "W",
|
|
8057
|
+
energy: "kWh",
|
|
8058
|
+
voltage: "V",
|
|
8059
|
+
current: "A",
|
|
8060
|
+
"apparent-power": "VA",
|
|
8061
|
+
humidity: "%",
|
|
8062
|
+
percentage: "%",
|
|
8063
|
+
"concentration-volume": "ppm",
|
|
8064
|
+
"concentration-mass": "µg/m³",
|
|
8065
|
+
"concentration-ppb": "ppb",
|
|
8066
|
+
volume: "L",
|
|
8067
|
+
duration: "s",
|
|
8068
|
+
"duration-ms": "ms",
|
|
8069
|
+
information: "B",
|
|
8070
|
+
"sound-level": "dBFS",
|
|
8071
|
+
"signal-level": "dBm",
|
|
8072
|
+
"colour-temperature": "mired",
|
|
8073
|
+
angle: "°",
|
|
8074
|
+
bitrate: "kbps",
|
|
8075
|
+
rate: "fps",
|
|
8076
|
+
mass: "kg",
|
|
8077
|
+
index: "none",
|
|
8078
|
+
ratio: "none",
|
|
8079
|
+
count: "none",
|
|
8080
|
+
none: "none",
|
|
8081
|
+
device: "device"
|
|
8082
|
+
};
|
|
8083
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8084
|
+
function baseUnitOf(quantity) {
|
|
8085
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8086
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8087
|
+
return symbol;
|
|
8088
|
+
}
|
|
8089
|
+
function readingMeta(quantity, extras) {
|
|
8090
|
+
return {
|
|
8091
|
+
quantity,
|
|
8092
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8093
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8094
|
+
};
|
|
8095
|
+
}
|
|
7995
8096
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
7996
8097
|
var CamProfileSchema = _enum([
|
|
7997
8098
|
"high",
|
|
@@ -8019,8 +8120,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8019
8120
|
"derived"
|
|
8020
8121
|
]);
|
|
8021
8122
|
var CamStreamResolutionSchema = object({
|
|
8022
|
-
width: number().int().positive(),
|
|
8023
|
-
height: number().int().positive()
|
|
8123
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8124
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8024
8125
|
});
|
|
8025
8126
|
var CameraStreamSchema = object({
|
|
8026
8127
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8560,6 +8661,8 @@ var CAP_NAMES = Object.freeze([
|
|
|
8560
8661
|
"filesystem-browse",
|
|
8561
8662
|
"flood",
|
|
8562
8663
|
"gas",
|
|
8664
|
+
"group-commands",
|
|
8665
|
+
"group-status",
|
|
8563
8666
|
"heating-valve",
|
|
8564
8667
|
"humidifier",
|
|
8565
8668
|
"humidity-sensor",
|
|
@@ -8689,14 +8792,6 @@ Object.freeze({
|
|
|
8689
8792
|
{
|
|
8690
8793
|
"path": "aqi",
|
|
8691
8794
|
"valueType": "number"
|
|
8692
|
-
},
|
|
8693
|
-
{
|
|
8694
|
-
"path": "unit",
|
|
8695
|
-
"valueType": "string"
|
|
8696
|
-
},
|
|
8697
|
-
{
|
|
8698
|
-
"path": "precision",
|
|
8699
|
-
"valueType": "number"
|
|
8700
8795
|
}
|
|
8701
8796
|
],
|
|
8702
8797
|
"alarm-panel": [
|
|
@@ -8732,20 +8827,10 @@ Object.freeze({
|
|
|
8732
8827
|
"valueType": "boolean"
|
|
8733
8828
|
}
|
|
8734
8829
|
],
|
|
8735
|
-
"ambient-light-sensor": [
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
},
|
|
8740
|
-
{
|
|
8741
|
-
"path": "unit",
|
|
8742
|
-
"valueType": "string"
|
|
8743
|
-
},
|
|
8744
|
-
{
|
|
8745
|
-
"path": "precision",
|
|
8746
|
-
"valueType": "number"
|
|
8747
|
-
}
|
|
8748
|
-
],
|
|
8830
|
+
"ambient-light-sensor": [{
|
|
8831
|
+
"path": "lux",
|
|
8832
|
+
"valueType": "number"
|
|
8833
|
+
}],
|
|
8749
8834
|
"audio-metrics": [
|
|
8750
8835
|
{
|
|
8751
8836
|
"path": "ts",
|
|
@@ -8825,6 +8910,10 @@ Object.freeze({
|
|
|
8825
8910
|
"path": "lastUpdated",
|
|
8826
8911
|
"valueType": "number"
|
|
8827
8912
|
},
|
|
8913
|
+
{
|
|
8914
|
+
"path": "volts",
|
|
8915
|
+
"valueType": "number"
|
|
8916
|
+
},
|
|
8828
8917
|
{
|
|
8829
8918
|
"path": "lastContactAt",
|
|
8830
8919
|
"valueType": "number"
|
|
@@ -9067,10 +9156,6 @@ Object.freeze({
|
|
|
9067
9156
|
"datetime"
|
|
9068
9157
|
]
|
|
9069
9158
|
},
|
|
9070
|
-
{
|
|
9071
|
-
"path": "unit",
|
|
9072
|
-
"valueType": "string"
|
|
9073
|
-
},
|
|
9074
9159
|
{
|
|
9075
9160
|
"path": "min",
|
|
9076
9161
|
"valueType": "number"
|
|
@@ -9082,19 +9167,6 @@ Object.freeze({
|
|
|
9082
9167
|
{
|
|
9083
9168
|
"path": "step",
|
|
9084
9169
|
"valueType": "number"
|
|
9085
|
-
},
|
|
9086
|
-
{
|
|
9087
|
-
"path": "precision",
|
|
9088
|
-
"valueType": "number"
|
|
9089
|
-
},
|
|
9090
|
-
{
|
|
9091
|
-
"path": "format",
|
|
9092
|
-
"valueType": "enum",
|
|
9093
|
-
"enumValues": [
|
|
9094
|
-
"date",
|
|
9095
|
-
"time",
|
|
9096
|
-
"datetime"
|
|
9097
|
-
]
|
|
9098
9170
|
}
|
|
9099
9171
|
],
|
|
9100
9172
|
"cover": [
|
|
@@ -9335,13 +9407,8 @@ Object.freeze({
|
|
|
9335
9407
|
"path": "value",
|
|
9336
9408
|
"valueType": "string"
|
|
9337
9409
|
}, {
|
|
9338
|
-
"path": "
|
|
9339
|
-
"valueType": "
|
|
9340
|
-
"enumValues": [
|
|
9341
|
-
"date",
|
|
9342
|
-
"time",
|
|
9343
|
-
"datetime"
|
|
9344
|
-
]
|
|
9410
|
+
"path": "timestamp",
|
|
9411
|
+
"valueType": "boolean"
|
|
9345
9412
|
}],
|
|
9346
9413
|
"event-emitter": [
|
|
9347
9414
|
{
|
|
@@ -9414,6 +9481,20 @@ Object.freeze({
|
|
|
9414
9481
|
"path": "detected",
|
|
9415
9482
|
"valueType": "boolean"
|
|
9416
9483
|
}],
|
|
9484
|
+
"group-status": [
|
|
9485
|
+
{
|
|
9486
|
+
"path": "included",
|
|
9487
|
+
"valueType": "number"
|
|
9488
|
+
},
|
|
9489
|
+
{
|
|
9490
|
+
"path": "excluded",
|
|
9491
|
+
"valueType": "number"
|
|
9492
|
+
},
|
|
9493
|
+
{
|
|
9494
|
+
"path": "total",
|
|
9495
|
+
"valueType": "number"
|
|
9496
|
+
}
|
|
9497
|
+
],
|
|
9417
9498
|
"heating-valve": [{
|
|
9418
9499
|
"path": "position",
|
|
9419
9500
|
"valueType": "number"
|
|
@@ -9448,20 +9529,10 @@ Object.freeze({
|
|
|
9448
9529
|
"valueType": "number"
|
|
9449
9530
|
}
|
|
9450
9531
|
],
|
|
9451
|
-
"humidity-sensor": [
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
},
|
|
9456
|
-
{
|
|
9457
|
-
"path": "unit",
|
|
9458
|
-
"valueType": "string"
|
|
9459
|
-
},
|
|
9460
|
-
{
|
|
9461
|
-
"path": "precision",
|
|
9462
|
-
"valueType": "number"
|
|
9463
|
-
}
|
|
9464
|
-
],
|
|
9532
|
+
"humidity-sensor": [{
|
|
9533
|
+
"path": "percent",
|
|
9534
|
+
"valueType": "number"
|
|
9535
|
+
}],
|
|
9465
9536
|
"image": [{
|
|
9466
9537
|
"path": "url",
|
|
9467
9538
|
"valueType": "string"
|
|
@@ -9800,20 +9871,10 @@ Object.freeze({
|
|
|
9800
9871
|
"valueType": "boolean"
|
|
9801
9872
|
}
|
|
9802
9873
|
],
|
|
9803
|
-
"numeric-sensor": [
|
|
9804
|
-
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
},
|
|
9808
|
-
{
|
|
9809
|
-
"path": "unit",
|
|
9810
|
-
"valueType": "string"
|
|
9811
|
-
},
|
|
9812
|
-
{
|
|
9813
|
-
"path": "precision",
|
|
9814
|
-
"valueType": "number"
|
|
9815
|
-
}
|
|
9816
|
-
],
|
|
9874
|
+
"numeric-sensor": [{
|
|
9875
|
+
"path": "value",
|
|
9876
|
+
"valueType": "number"
|
|
9877
|
+
}],
|
|
9817
9878
|
"pet-feeder": [
|
|
9818
9879
|
{
|
|
9819
9880
|
"path": "foodLevel",
|
|
@@ -9905,14 +9966,6 @@ Object.freeze({
|
|
|
9905
9966
|
{
|
|
9906
9967
|
"path": "powerFactor",
|
|
9907
9968
|
"valueType": "number"
|
|
9908
|
-
},
|
|
9909
|
-
{
|
|
9910
|
-
"path": "unit",
|
|
9911
|
-
"valueType": "string"
|
|
9912
|
-
},
|
|
9913
|
-
{
|
|
9914
|
-
"path": "precision",
|
|
9915
|
-
"valueType": "number"
|
|
9916
9969
|
}
|
|
9917
9970
|
],
|
|
9918
9971
|
"presence": [
|
|
@@ -9941,20 +9994,10 @@ Object.freeze({
|
|
|
9941
9994
|
"valueType": "number"
|
|
9942
9995
|
}
|
|
9943
9996
|
],
|
|
9944
|
-
"pressure-sensor": [
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
9948
|
-
},
|
|
9949
|
-
{
|
|
9950
|
-
"path": "unit",
|
|
9951
|
-
"valueType": "string"
|
|
9952
|
-
},
|
|
9953
|
-
{
|
|
9954
|
-
"path": "precision",
|
|
9955
|
-
"valueType": "number"
|
|
9956
|
-
}
|
|
9957
|
-
],
|
|
9997
|
+
"pressure-sensor": [{
|
|
9998
|
+
"path": "hpa",
|
|
9999
|
+
"valueType": "number"
|
|
10000
|
+
}],
|
|
9958
10001
|
"privacy-mask": [{
|
|
9959
10002
|
"path": "enabled",
|
|
9960
10003
|
"valueType": "boolean"
|
|
@@ -10265,20 +10308,10 @@ Object.freeze({
|
|
|
10265
10308
|
"path": "tampered",
|
|
10266
10309
|
"valueType": "boolean"
|
|
10267
10310
|
}],
|
|
10268
|
-
"temperature-sensor": [
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
},
|
|
10273
|
-
{
|
|
10274
|
-
"path": "unit",
|
|
10275
|
-
"valueType": "string"
|
|
10276
|
-
},
|
|
10277
|
-
{
|
|
10278
|
-
"path": "precision",
|
|
10279
|
-
"valueType": "number"
|
|
10280
|
-
}
|
|
10281
|
-
],
|
|
10311
|
+
"temperature-sensor": [{
|
|
10312
|
+
"path": "celsius",
|
|
10313
|
+
"valueType": "number"
|
|
10314
|
+
}],
|
|
10282
10315
|
"update": [
|
|
10283
10316
|
{
|
|
10284
10317
|
"path": "currentVersion",
|
|
@@ -10389,10 +10422,6 @@ Object.freeze({
|
|
|
10389
10422
|
"path": "temperature",
|
|
10390
10423
|
"valueType": "number"
|
|
10391
10424
|
},
|
|
10392
|
-
{
|
|
10393
|
-
"path": "temperatureUnit",
|
|
10394
|
-
"valueType": "string"
|
|
10395
|
-
},
|
|
10396
10425
|
{
|
|
10397
10426
|
"path": "humidity",
|
|
10398
10427
|
"valueType": "number"
|
|
@@ -10401,18 +10430,10 @@ Object.freeze({
|
|
|
10401
10430
|
"path": "pressure",
|
|
10402
10431
|
"valueType": "number"
|
|
10403
10432
|
},
|
|
10404
|
-
{
|
|
10405
|
-
"path": "pressureUnit",
|
|
10406
|
-
"valueType": "string"
|
|
10407
|
-
},
|
|
10408
10433
|
{
|
|
10409
10434
|
"path": "windSpeed",
|
|
10410
10435
|
"valueType": "number"
|
|
10411
10436
|
},
|
|
10412
|
-
{
|
|
10413
|
-
"path": "windSpeedUnit",
|
|
10414
|
-
"valueType": "string"
|
|
10415
|
-
},
|
|
10416
10437
|
{
|
|
10417
10438
|
"path": "windBearing",
|
|
10418
10439
|
"valueType": "number"
|
|
@@ -10815,7 +10836,7 @@ function errMsg(err) {
|
|
|
10815
10836
|
return String(err);
|
|
10816
10837
|
}
|
|
10817
10838
|
//#endregion
|
|
10818
|
-
//#region ../types/dist/composition-
|
|
10839
|
+
//#region ../types/dist/composition-OhpuespA.mjs
|
|
10819
10840
|
/**
|
|
10820
10841
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
10821
10842
|
*
|
|
@@ -11570,15 +11591,74 @@ function validateExpressionSource(src) {
|
|
|
11570
11591
|
}
|
|
11571
11592
|
return null;
|
|
11572
11593
|
}
|
|
11573
|
-
/**
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11594
|
+
/**
|
|
11595
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11596
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11597
|
+
* `composition.ts` (D659).
|
|
11598
|
+
*/
|
|
11577
11599
|
var CompositionSourceRefSchema = object({
|
|
11578
11600
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11579
11601
|
addonId: string().min(1),
|
|
11580
11602
|
stableId: string().min(1)
|
|
11581
11603
|
});
|
|
11604
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11605
|
+
"temperature",
|
|
11606
|
+
"humidity",
|
|
11607
|
+
"pressure",
|
|
11608
|
+
"illuminance",
|
|
11609
|
+
"power",
|
|
11610
|
+
"energy",
|
|
11611
|
+
"battery",
|
|
11612
|
+
"numeric",
|
|
11613
|
+
"motion",
|
|
11614
|
+
"contact",
|
|
11615
|
+
"leak",
|
|
11616
|
+
"smoke",
|
|
11617
|
+
"occupancy",
|
|
11618
|
+
"binary",
|
|
11619
|
+
"switch",
|
|
11620
|
+
"light"
|
|
11621
|
+
];
|
|
11622
|
+
var NUMERIC_AGGREGATES = [
|
|
11623
|
+
"mean",
|
|
11624
|
+
"median",
|
|
11625
|
+
"min",
|
|
11626
|
+
"max",
|
|
11627
|
+
"sum"
|
|
11628
|
+
];
|
|
11629
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11630
|
+
/** How an actuator group decides it is on. Unknown members never count as off. */
|
|
11631
|
+
var ACTIVE_CRITERIA = ["at-least-one", "all"];
|
|
11632
|
+
var AGGREGATE_REDUCERS = [
|
|
11633
|
+
"mean",
|
|
11634
|
+
"median",
|
|
11635
|
+
"min",
|
|
11636
|
+
"max",
|
|
11637
|
+
"sum",
|
|
11638
|
+
"any",
|
|
11639
|
+
"all"
|
|
11640
|
+
];
|
|
11641
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11642
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11643
|
+
var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
|
|
11644
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11645
|
+
var HelperMemberSchema = object({
|
|
11646
|
+
source: CompositionSourceRefSchema,
|
|
11647
|
+
cap: string().min(1),
|
|
11648
|
+
fieldPath: string().min(1)
|
|
11649
|
+
});
|
|
11650
|
+
var HelperSpecSchema = discriminatedUnion("kind", [object({
|
|
11651
|
+
kind: literal("group"),
|
|
11652
|
+
templateId: GroupTemplateIdSchema,
|
|
11653
|
+
aggregate: AggregateReducerSchema,
|
|
11654
|
+
members: array(HelperMemberSchema).min(1).max(64),
|
|
11655
|
+
/** Actuator groups only. Readings leave this unset. */
|
|
11656
|
+
active: ActiveCriterionSchema.optional()
|
|
11657
|
+
})]);
|
|
11658
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
11659
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
11660
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
11661
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11582
11662
|
/** One field of one capability of one source device. */
|
|
11583
11663
|
var CompositionFieldReadSchema = object({
|
|
11584
11664
|
source: CompositionSourceRefSchema,
|
|
@@ -11622,7 +11702,33 @@ var CompositionCodeSourceSchema = object({
|
|
|
11622
11702
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11623
11703
|
CompositionFromSourceSchema,
|
|
11624
11704
|
CompositionExpressionSourceSchema,
|
|
11625
|
-
CompositionCodeSourceSchema
|
|
11705
|
+
CompositionCodeSourceSchema,
|
|
11706
|
+
object({
|
|
11707
|
+
kind: literal("aggregate"),
|
|
11708
|
+
reducer: _enum([
|
|
11709
|
+
"mean",
|
|
11710
|
+
"median",
|
|
11711
|
+
"min",
|
|
11712
|
+
"max",
|
|
11713
|
+
"sum",
|
|
11714
|
+
"any",
|
|
11715
|
+
"all"
|
|
11716
|
+
]),
|
|
11717
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
11718
|
+
/** `value` is the reading; the others are the member counts. */
|
|
11719
|
+
publish: _enum([
|
|
11720
|
+
"value",
|
|
11721
|
+
"included",
|
|
11722
|
+
"excluded",
|
|
11723
|
+
"total"
|
|
11724
|
+
]),
|
|
11725
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
11726
|
+
empty: _enum([
|
|
11727
|
+
"null",
|
|
11728
|
+
"omit",
|
|
11729
|
+
"offline"
|
|
11730
|
+
])
|
|
11731
|
+
})
|
|
11626
11732
|
]);
|
|
11627
11733
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11628
11734
|
kind: literal("forward"),
|
|
@@ -11668,7 +11774,13 @@ var CompositionSchema = object({
|
|
|
11668
11774
|
kind: literal("existing"),
|
|
11669
11775
|
device: CompositionSourceRefSchema
|
|
11670
11776
|
})]),
|
|
11671
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
11777
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
11778
|
+
/**
|
|
11779
|
+
* Present when the block is a helper template. Absent on a free
|
|
11780
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
11781
|
+
* never the compiled features.
|
|
11782
|
+
*/
|
|
11783
|
+
helper: HelperSpecSchema.optional()
|
|
11672
11784
|
}).superRefine((composition, ctx) => {
|
|
11673
11785
|
const seen = /* @__PURE__ */ new Set();
|
|
11674
11786
|
composition.features.forEach((feature, index) => {
|
|
@@ -17876,7 +17988,11 @@ var CompositionProblemSchema = object({
|
|
|
17876
17988
|
"item-field-reserved",
|
|
17877
17989
|
"target-missing",
|
|
17878
17990
|
"target-unreadable",
|
|
17879
|
-
"not-replaceable"
|
|
17991
|
+
"not-replaceable",
|
|
17992
|
+
"native-capability-replace",
|
|
17993
|
+
"mixed-quantity",
|
|
17994
|
+
"helper-mismatch",
|
|
17995
|
+
"member-constraint"
|
|
17880
17996
|
]),
|
|
17881
17997
|
path: string(),
|
|
17882
17998
|
message: string()
|
|
@@ -17897,7 +18013,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
17897
18013
|
"null",
|
|
17898
18014
|
"offline",
|
|
17899
18015
|
"unknown",
|
|
17900
|
-
"release"
|
|
18016
|
+
"release",
|
|
18017
|
+
"omit"
|
|
17901
18018
|
]);
|
|
17902
18019
|
/**
|
|
17903
18020
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17934,9 +18051,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17934
18051
|
reads: array(CompositionFieldReadSchema)
|
|
17935
18052
|
});
|
|
17936
18053
|
/**
|
|
17937
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17938
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17939
|
-
*
|
|
18054
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18055
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18056
|
+
* Replacing a capability the device already serves is refused
|
|
18057
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18058
|
+
* wire for a claim the hub already holds.
|
|
17940
18059
|
*/
|
|
17941
18060
|
var CompositionFeatureModeSchema = _enum([
|
|
17942
18061
|
"new",
|
|
@@ -18109,6 +18228,275 @@ Object.freeze({
|
|
|
18109
18228
|
result: ["number", "null"]
|
|
18110
18229
|
}
|
|
18111
18230
|
});
|
|
18231
|
+
/**
|
|
18232
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18233
|
+
* Data, not a form default written into the block.
|
|
18234
|
+
*/
|
|
18235
|
+
var NOW = {
|
|
18236
|
+
fieldPath: "lastFetchedAt",
|
|
18237
|
+
expr: "now"
|
|
18238
|
+
};
|
|
18239
|
+
var CHANGED = {
|
|
18240
|
+
fieldPath: "lastChangedAt",
|
|
18241
|
+
expr: "now"
|
|
18242
|
+
};
|
|
18243
|
+
function numeric(input) {
|
|
18244
|
+
return {
|
|
18245
|
+
...input,
|
|
18246
|
+
family: "numeric",
|
|
18247
|
+
deviceType: DeviceType.Sensor,
|
|
18248
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18249
|
+
commandCaps: [],
|
|
18250
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18251
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18252
|
+
accept: [{
|
|
18253
|
+
cap: input.outputCap,
|
|
18254
|
+
fieldPath: input.outputField
|
|
18255
|
+
}]
|
|
18256
|
+
};
|
|
18257
|
+
}
|
|
18258
|
+
function binary(input) {
|
|
18259
|
+
return {
|
|
18260
|
+
...input,
|
|
18261
|
+
family: "binary",
|
|
18262
|
+
deviceType: DeviceType.Sensor,
|
|
18263
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18264
|
+
commandCaps: [],
|
|
18265
|
+
quantity: "none",
|
|
18266
|
+
baseUnit: void 0,
|
|
18267
|
+
aggregates: BINARY_AGGREGATES,
|
|
18268
|
+
empty: "offline"
|
|
18269
|
+
};
|
|
18270
|
+
}
|
|
18271
|
+
var GROUP_TEMPLATES = [
|
|
18272
|
+
numeric({
|
|
18273
|
+
id: "temperature",
|
|
18274
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18275
|
+
role: DeviceRole.TemperatureSensor,
|
|
18276
|
+
outputCap: "temperature-sensor",
|
|
18277
|
+
outputField: "celsius",
|
|
18278
|
+
quantity: "temperature",
|
|
18279
|
+
defaultAggregate: "mean",
|
|
18280
|
+
empty: "null",
|
|
18281
|
+
companions: [NOW]
|
|
18282
|
+
}),
|
|
18283
|
+
numeric({
|
|
18284
|
+
id: "humidity",
|
|
18285
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18286
|
+
role: DeviceRole.HumiditySensor,
|
|
18287
|
+
outputCap: "humidity-sensor",
|
|
18288
|
+
outputField: "percent",
|
|
18289
|
+
quantity: "humidity",
|
|
18290
|
+
defaultAggregate: "mean",
|
|
18291
|
+
empty: "null",
|
|
18292
|
+
companions: [NOW]
|
|
18293
|
+
}),
|
|
18294
|
+
numeric({
|
|
18295
|
+
id: "pressure",
|
|
18296
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18297
|
+
role: DeviceRole.PressureSensor,
|
|
18298
|
+
outputCap: "pressure-sensor",
|
|
18299
|
+
outputField: "hpa",
|
|
18300
|
+
quantity: "pressure",
|
|
18301
|
+
defaultAggregate: "mean",
|
|
18302
|
+
empty: "null",
|
|
18303
|
+
companions: [NOW]
|
|
18304
|
+
}),
|
|
18305
|
+
numeric({
|
|
18306
|
+
id: "illuminance",
|
|
18307
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18308
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18309
|
+
outputCap: "ambient-light-sensor",
|
|
18310
|
+
outputField: "lux",
|
|
18311
|
+
quantity: "illuminance",
|
|
18312
|
+
defaultAggregate: "mean",
|
|
18313
|
+
empty: "null",
|
|
18314
|
+
companions: [NOW]
|
|
18315
|
+
}),
|
|
18316
|
+
numeric({
|
|
18317
|
+
id: "power",
|
|
18318
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18319
|
+
role: DeviceRole.PowerSensor,
|
|
18320
|
+
outputCap: "power-meter",
|
|
18321
|
+
outputField: "watts",
|
|
18322
|
+
quantity: "power",
|
|
18323
|
+
defaultAggregate: "sum",
|
|
18324
|
+
empty: "omit",
|
|
18325
|
+
companions: [NOW]
|
|
18326
|
+
}),
|
|
18327
|
+
numeric({
|
|
18328
|
+
id: "energy",
|
|
18329
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18330
|
+
role: DeviceRole.EnergySensor,
|
|
18331
|
+
outputCap: "power-meter",
|
|
18332
|
+
outputField: "kwhTotal",
|
|
18333
|
+
quantity: "energy",
|
|
18334
|
+
defaultAggregate: "sum",
|
|
18335
|
+
empty: "omit",
|
|
18336
|
+
companions: [NOW]
|
|
18337
|
+
}),
|
|
18338
|
+
numeric({
|
|
18339
|
+
id: "battery",
|
|
18340
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18341
|
+
role: DeviceRole.BatterySensor,
|
|
18342
|
+
outputCap: "battery",
|
|
18343
|
+
outputField: "percentage",
|
|
18344
|
+
quantity: "percentage",
|
|
18345
|
+
defaultAggregate: "mean",
|
|
18346
|
+
empty: "null",
|
|
18347
|
+
companions: [
|
|
18348
|
+
{
|
|
18349
|
+
fieldPath: "charging",
|
|
18350
|
+
expr: "\"unknown\""
|
|
18351
|
+
},
|
|
18352
|
+
{
|
|
18353
|
+
fieldPath: "sleeping",
|
|
18354
|
+
expr: "false"
|
|
18355
|
+
},
|
|
18356
|
+
{
|
|
18357
|
+
fieldPath: "lastUpdated",
|
|
18358
|
+
expr: "now"
|
|
18359
|
+
}
|
|
18360
|
+
]
|
|
18361
|
+
}),
|
|
18362
|
+
numeric({
|
|
18363
|
+
id: "numeric",
|
|
18364
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18365
|
+
role: DeviceRole.NumericSensor,
|
|
18366
|
+
outputCap: "numeric-sensor",
|
|
18367
|
+
outputField: "value",
|
|
18368
|
+
quantity: "device",
|
|
18369
|
+
defaultAggregate: "mean",
|
|
18370
|
+
empty: "null",
|
|
18371
|
+
companions: [NOW]
|
|
18372
|
+
}),
|
|
18373
|
+
binary({
|
|
18374
|
+
id: "motion",
|
|
18375
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18376
|
+
role: DeviceRole.MotionSensor,
|
|
18377
|
+
outputCap: "motion",
|
|
18378
|
+
outputField: "detected",
|
|
18379
|
+
defaultAggregate: "any",
|
|
18380
|
+
accept: [{
|
|
18381
|
+
cap: "motion",
|
|
18382
|
+
fieldPath: "detected"
|
|
18383
|
+
}],
|
|
18384
|
+
companions: [{
|
|
18385
|
+
fieldPath: "lastDetectedAt",
|
|
18386
|
+
expr: "null"
|
|
18387
|
+
}, {
|
|
18388
|
+
fieldPath: "autoClearAfterMs",
|
|
18389
|
+
expr: "null"
|
|
18390
|
+
}]
|
|
18391
|
+
}),
|
|
18392
|
+
binary({
|
|
18393
|
+
id: "contact",
|
|
18394
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18395
|
+
role: DeviceRole.ContactSensor,
|
|
18396
|
+
outputCap: "contact",
|
|
18397
|
+
outputField: "entryOpen",
|
|
18398
|
+
defaultAggregate: "any",
|
|
18399
|
+
accept: [{
|
|
18400
|
+
cap: "contact",
|
|
18401
|
+
fieldPath: "entryOpen"
|
|
18402
|
+
}],
|
|
18403
|
+
companions: [CHANGED]
|
|
18404
|
+
}),
|
|
18405
|
+
binary({
|
|
18406
|
+
id: "leak",
|
|
18407
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18408
|
+
role: DeviceRole.LeakSensor,
|
|
18409
|
+
outputCap: "flood",
|
|
18410
|
+
outputField: "flooded",
|
|
18411
|
+
defaultAggregate: "any",
|
|
18412
|
+
accept: [{
|
|
18413
|
+
cap: "flood",
|
|
18414
|
+
fieldPath: "flooded"
|
|
18415
|
+
}],
|
|
18416
|
+
companions: [CHANGED]
|
|
18417
|
+
}),
|
|
18418
|
+
binary({
|
|
18419
|
+
id: "smoke",
|
|
18420
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18421
|
+
role: DeviceRole.SmokeSensor,
|
|
18422
|
+
outputCap: "smoke",
|
|
18423
|
+
outputField: "detected",
|
|
18424
|
+
defaultAggregate: "any",
|
|
18425
|
+
accept: [{
|
|
18426
|
+
cap: "smoke",
|
|
18427
|
+
fieldPath: "detected"
|
|
18428
|
+
}],
|
|
18429
|
+
companions: [CHANGED]
|
|
18430
|
+
}),
|
|
18431
|
+
binary({
|
|
18432
|
+
id: "occupancy",
|
|
18433
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18434
|
+
role: DeviceRole.BinarySensor,
|
|
18435
|
+
outputCap: "binary",
|
|
18436
|
+
outputField: "on",
|
|
18437
|
+
defaultAggregate: "any",
|
|
18438
|
+
accept: [{
|
|
18439
|
+
cap: "motion",
|
|
18440
|
+
fieldPath: "detected"
|
|
18441
|
+
}, {
|
|
18442
|
+
cap: "binary",
|
|
18443
|
+
fieldPath: "on"
|
|
18444
|
+
}],
|
|
18445
|
+
companions: [CHANGED]
|
|
18446
|
+
}),
|
|
18447
|
+
binary({
|
|
18448
|
+
id: "binary",
|
|
18449
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18450
|
+
role: DeviceRole.BinarySensor,
|
|
18451
|
+
outputCap: "binary",
|
|
18452
|
+
outputField: "on",
|
|
18453
|
+
defaultAggregate: "any",
|
|
18454
|
+
accept: [{
|
|
18455
|
+
cap: "binary",
|
|
18456
|
+
fieldPath: "on"
|
|
18457
|
+
}],
|
|
18458
|
+
companions: [CHANGED]
|
|
18459
|
+
}),
|
|
18460
|
+
actuator({
|
|
18461
|
+
id: "switch",
|
|
18462
|
+
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.",
|
|
18463
|
+
deviceType: DeviceType.Switch,
|
|
18464
|
+
outputCap: "switch",
|
|
18465
|
+
commandCaps: ["switch"]
|
|
18466
|
+
}),
|
|
18467
|
+
actuator({
|
|
18468
|
+
id: "light",
|
|
18469
|
+
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.",
|
|
18470
|
+
deviceType: DeviceType.Light,
|
|
18471
|
+
outputCap: "switch",
|
|
18472
|
+
commandCaps: [
|
|
18473
|
+
"switch",
|
|
18474
|
+
"brightness",
|
|
18475
|
+
"color"
|
|
18476
|
+
]
|
|
18477
|
+
})
|
|
18478
|
+
];
|
|
18479
|
+
function actuator(input) {
|
|
18480
|
+
return {
|
|
18481
|
+
...input,
|
|
18482
|
+
family: "actuator",
|
|
18483
|
+
role: void 0,
|
|
18484
|
+
memberDeviceType: input.deviceType,
|
|
18485
|
+
outputField: "on",
|
|
18486
|
+
quantity: "none",
|
|
18487
|
+
baseUnit: void 0,
|
|
18488
|
+
aggregates: BINARY_AGGREGATES,
|
|
18489
|
+
defaultAggregate: "any",
|
|
18490
|
+
empty: "offline",
|
|
18491
|
+
accept: [{
|
|
18492
|
+
cap: "switch",
|
|
18493
|
+
fieldPath: "on"
|
|
18494
|
+
}],
|
|
18495
|
+
companions: [CHANGED]
|
|
18496
|
+
};
|
|
18497
|
+
}
|
|
18498
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18499
|
+
DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
|
|
18112
18500
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18113
18501
|
/**
|
|
18114
18502
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -19822,12 +20210,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
|
|
|
19822
20210
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19823
20211
|
* in-place so dispatch keeps working.
|
|
19824
20212
|
*
|
|
19825
|
-
* **
|
|
19826
|
-
*
|
|
19827
|
-
*
|
|
19828
|
-
*
|
|
19829
|
-
* (`ha-domain-mapping`)
|
|
19830
|
-
* stored after that point.
|
|
20213
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20214
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20215
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20216
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20217
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20218
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19831
20219
|
*
|
|
19832
20220
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19833
20221
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19841,6 +20229,14 @@ var SourceInfoSchema = object({
|
|
|
19841
20229
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19842
20230
|
* Used to detect rename when `id` changes. */
|
|
19843
20231
|
uniqueId: string().optional(),
|
|
20232
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20233
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20234
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20235
|
+
dateTimeShape: _enum([
|
|
20236
|
+
"date",
|
|
20237
|
+
"time",
|
|
20238
|
+
"datetime"
|
|
20239
|
+
]).optional(),
|
|
19844
20240
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19845
20241
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19846
20242
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -19886,6 +20282,80 @@ function mergeSourceInfo(prev, patch) {
|
|
|
19886
20282
|
return next;
|
|
19887
20283
|
}
|
|
19888
20284
|
/**
|
|
20285
|
+
* Coerce common unit-of-measurement string variants to a canonical form
|
|
20286
|
+
* so the UI's display templates can rely on stable strings. Pure
|
|
20287
|
+
* passthrough for unknown units — kept conservative on purpose, the goal
|
|
20288
|
+
* is to normalise the long tail of HA `unit_of_measurement` values that
|
|
20289
|
+
* have multiple historical spellings (`'°C'` vs `'C'` vs `'celsius'`).
|
|
20290
|
+
*
|
|
20291
|
+
* Extend the map as we encounter real-world data. Returning the raw
|
|
20292
|
+
* input for unknown values is intentional: providers should never
|
|
20293
|
+
* lose information silently here.
|
|
20294
|
+
*/
|
|
20295
|
+
function normalizeUnit(raw) {
|
|
20296
|
+
if (raw == null) return void 0;
|
|
20297
|
+
const trimmed = raw.trim();
|
|
20298
|
+
if (trimmed === "") return void 0;
|
|
20299
|
+
const lower = trimmed.toLowerCase();
|
|
20300
|
+
if (lower === "°c" || lower === "c" || lower === "celsius") return "°C";
|
|
20301
|
+
if (lower === "°f" || lower === "f" || lower === "fahrenheit") return "°F";
|
|
20302
|
+
if (lower === "k" || lower === "kelvin") return "K";
|
|
20303
|
+
if (lower === "%" || lower === "percent" || lower === "percentage") return "%";
|
|
20304
|
+
if (lower === "lx" || lower === "lux") return "lx";
|
|
20305
|
+
if (lower === "hpa" || lower === "hectopascal") return "hPa";
|
|
20306
|
+
if (lower === "kpa") return "kPa";
|
|
20307
|
+
if (lower === "pa") return "Pa";
|
|
20308
|
+
if (lower === "mbar" || lower === "millibar") return "mbar";
|
|
20309
|
+
if (lower === "w" || lower === "watt") return "W";
|
|
20310
|
+
if (lower === "kw" || lower === "kilowatt") return "kW";
|
|
20311
|
+
if (lower === "wh" || lower === "watt-hour") return "Wh";
|
|
20312
|
+
if (lower === "kwh" || lower === "kilowatt-hour") return "kWh";
|
|
20313
|
+
if (lower === "v" || lower === "volt") return "V";
|
|
20314
|
+
if (lower === "a" || lower === "amp" || lower === "ampere") return "A";
|
|
20315
|
+
if (lower === "ma" || lower === "milliampere") return "mA";
|
|
20316
|
+
if (lower === "va") return "VA";
|
|
20317
|
+
if (lower === "ppm") return "ppm";
|
|
20318
|
+
if (lower === "ppb") return "ppb";
|
|
20319
|
+
if (lower === "µg/m³" || lower === "ug/m3" || lower === "µg/m3") return "µg/m³";
|
|
20320
|
+
if (lower === "km/h" || lower === "kph") return "km/h";
|
|
20321
|
+
if (lower === "mph") return "mph";
|
|
20322
|
+
if (lower === "m/s") return "m/s";
|
|
20323
|
+
if (lower === "m") return "m";
|
|
20324
|
+
if (lower === "m²" || lower === "m2") return "m²";
|
|
20325
|
+
if (lower === "mm") return "mm";
|
|
20326
|
+
if (lower === "cm") return "cm";
|
|
20327
|
+
if (lower === "km") return "km";
|
|
20328
|
+
if (lower === "in" || lower === "inch" || lower === "inches") return "in";
|
|
20329
|
+
if (lower === "ft" || lower === "foot" || lower === "feet") return "ft";
|
|
20330
|
+
if (lower === "kg") return "kg";
|
|
20331
|
+
if (lower === "g") return "g";
|
|
20332
|
+
if (lower === "l" || lower === "liter" || lower === "litre" || lower === "liters" || lower === "litres") return "L";
|
|
20333
|
+
if (lower === "ml") return "mL";
|
|
20334
|
+
if (lower === "gal" || lower === "gallon" || lower === "gallons") return "gal";
|
|
20335
|
+
if (lower === "s" || lower === "sec" || lower === "second" || lower === "seconds") return "s";
|
|
20336
|
+
if (lower === "ms") return "ms";
|
|
20337
|
+
if (lower === "min" || lower === "minute" || lower === "minutes") return "min";
|
|
20338
|
+
if (lower === "h" || lower === "hr" || lower === "hour" || lower === "hours") return "h";
|
|
20339
|
+
if (lower === "d" || lower === "day" || lower === "days") return "d";
|
|
20340
|
+
if (lower === "b" || lower === "byte" || lower === "bytes") return "B";
|
|
20341
|
+
if (lower === "kib") return "KiB";
|
|
20342
|
+
if (lower === "mib") return "MiB";
|
|
20343
|
+
if (lower === "gib") return "GiB";
|
|
20344
|
+
if (lower === "tib") return "TiB";
|
|
20345
|
+
if (lower === "kb") return "kB";
|
|
20346
|
+
if (lower === "mb") return "MB";
|
|
20347
|
+
if (lower === "gb") return "GB";
|
|
20348
|
+
if (lower === "dbm") return "dBm";
|
|
20349
|
+
if (lower === "dbfs") return "dBFS";
|
|
20350
|
+
if (lower === "inhg") return "inHg";
|
|
20351
|
+
if (lower === "mm/h") return "mm/h";
|
|
20352
|
+
if (lower === "w/m²" || lower === "w/m2") return "W/m²";
|
|
20353
|
+
if (lower === "°" || lower === "deg" || lower === "degree" || lower === "degrees") return "°";
|
|
20354
|
+
if (lower === "kbps") return "kbps";
|
|
20355
|
+
if (lower === "fps") return "fps";
|
|
20356
|
+
return trimmed;
|
|
20357
|
+
}
|
|
20358
|
+
/**
|
|
19889
20359
|
* Key under which `SourceInfo` lives inside `DeviceMeta.metadata`. The
|
|
19890
20360
|
* blob is a free-form `Record<string, unknown>` shared with hardware-
|
|
19891
20361
|
* identity fields (`manufacturer`, `model`, `firmware`, …); SourceInfo
|
|
@@ -40962,7 +41432,8 @@ method(object({
|
|
|
40962
41432
|
"enum"
|
|
40963
41433
|
]),
|
|
40964
41434
|
enumValues: array(string()).optional(),
|
|
40965
|
-
item: boolean().optional()
|
|
41435
|
+
item: boolean().optional(),
|
|
41436
|
+
quantity: ReadingQuantitySchema.optional()
|
|
40966
41437
|
})).readonly(),
|
|
40967
41438
|
itemArray: object({
|
|
40968
41439
|
path: string(),
|
|
@@ -44806,8 +45277,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44806
45277
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44807
45278
|
var MaskGridShapeSchema = object({
|
|
44808
45279
|
kind: literal("grid"),
|
|
44809
|
-
gridWidth: number(),
|
|
44810
|
-
gridHeight: number(),
|
|
45280
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45281
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44811
45282
|
cells: array(boolean())
|
|
44812
45283
|
});
|
|
44813
45284
|
discriminatedUnion("kind", [
|
|
@@ -44919,6 +45390,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
44919
45390
|
"detection-blind",
|
|
44920
45391
|
"motion-noisy",
|
|
44921
45392
|
"motion-calm",
|
|
45393
|
+
"package-llm-silent",
|
|
45394
|
+
"package-llm-answered",
|
|
44922
45395
|
"recording-stalled",
|
|
44923
45396
|
"recording-healthy",
|
|
44924
45397
|
"recording-degraded",
|
|
@@ -56010,6 +56483,28 @@ var PackageVersionInfoSchema = object({
|
|
|
56010
56483
|
deprecated: string().optional(),
|
|
56011
56484
|
distTags: array(string()).readonly()
|
|
56012
56485
|
});
|
|
56486
|
+
/**
|
|
56487
|
+
* One published document. `ok` is markdown from the registry. `missing` means
|
|
56488
|
+
* the registry answered and the file was not there. `error` is a registry or
|
|
56489
|
+
* tarball failure — never an empty string standing in for either.
|
|
56490
|
+
*/
|
|
56491
|
+
var PackageDocBodySchema = discriminatedUnion("status", [
|
|
56492
|
+
object({
|
|
56493
|
+
status: literal("ok"),
|
|
56494
|
+
markdown: string()
|
|
56495
|
+
}),
|
|
56496
|
+
object({ status: literal("missing") }),
|
|
56497
|
+
object({
|
|
56498
|
+
status: literal("error"),
|
|
56499
|
+
message: string()
|
|
56500
|
+
})
|
|
56501
|
+
]);
|
|
56502
|
+
var PackageDocsSchema = object({
|
|
56503
|
+
name: string(),
|
|
56504
|
+
version: string(),
|
|
56505
|
+
readme: PackageDocBodySchema,
|
|
56506
|
+
changelog: PackageDocBodySchema
|
|
56507
|
+
});
|
|
56013
56508
|
var SearchResultSchema = object({
|
|
56014
56509
|
name: string(),
|
|
56015
56510
|
version: string(),
|
|
@@ -56228,7 +56723,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56228
56723
|
}), object({ success: literal(true) }), {
|
|
56229
56724
|
kind: "mutation",
|
|
56230
56725
|
auth: "admin"
|
|
56231
|
-
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56726
|
+
}), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
|
|
56727
|
+
name: string().min(1),
|
|
56728
|
+
version: string().min(1).optional()
|
|
56729
|
+
}), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
|
|
56232
56730
|
kind: "mutation",
|
|
56233
56731
|
auth: "admin"
|
|
56234
56732
|
}), method(object({ packageName: string() }), object({ success: literal(true) }), {
|
|
@@ -56287,27 +56785,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56287
56785
|
*/
|
|
56288
56786
|
var AirQualitySensorStatusSchema = object({
|
|
56289
56787
|
/** Carbon dioxide concentration in ppm. */
|
|
56290
|
-
co2Ppm: number().min(0).optional(),
|
|
56788
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56291
56789
|
/** Total volatile organic compounds in ppb. */
|
|
56292
|
-
vocPpb: number().min(0).optional(),
|
|
56790
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56293
56791
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56294
|
-
pm25: number().min(0).optional(),
|
|
56792
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56295
56793
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56296
|
-
pm10: number().min(0).optional(),
|
|
56794
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56297
56795
|
/** Composite AQI value (typically 0..500). */
|
|
56298
|
-
aqi: number().optional(),
|
|
56796
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56299
56797
|
/** Ms epoch when the slice was last updated. */
|
|
56300
|
-
lastFetchedAt: number()
|
|
56301
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56302
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56303
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56304
|
-
* per slice is unambiguous. */
|
|
56305
|
-
unit: string().optional(),
|
|
56306
|
-
/** Suggested decimal places for numeric display.
|
|
56307
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56308
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56309
|
-
* auto-formatting when absent. */
|
|
56310
|
-
precision: number().int().min(0).max(10).optional()
|
|
56798
|
+
lastFetchedAt: number()
|
|
56311
56799
|
});
|
|
56312
56800
|
var airQualitySensorCapability = {
|
|
56313
56801
|
name: "air-quality-sensor",
|
|
@@ -56344,12 +56832,12 @@ var airQualitySensorCapability = {
|
|
|
56344
56832
|
},
|
|
56345
56833
|
pm25: {
|
|
56346
56834
|
kind: "gauge",
|
|
56347
|
-
unit: "
|
|
56835
|
+
unit: "µg/m³",
|
|
56348
56836
|
deadband: 1
|
|
56349
56837
|
},
|
|
56350
56838
|
pm10: {
|
|
56351
56839
|
kind: "gauge",
|
|
56352
|
-
unit: "
|
|
56840
|
+
unit: "µg/m³",
|
|
56353
56841
|
deadband: 1
|
|
56354
56842
|
},
|
|
56355
56843
|
aqi: {
|
|
@@ -56367,22 +56855,13 @@ var airQualitySensorCapability = {
|
|
|
56367
56855
|
* entries with `device_class: illuminance`.
|
|
56368
56856
|
*/
|
|
56369
56857
|
var AmbientLightSensorStatusSchema = object({
|
|
56370
|
-
/** Current illuminance in lux (lx). */
|
|
56371
|
-
lux: number().min(0).meta({
|
|
56372
|
-
|
|
56858
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
56859
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
56860
|
+
precision: 0,
|
|
56373
56861
|
label: "Illuminance"
|
|
56374
|
-
}),
|
|
56862
|
+
})),
|
|
56375
56863
|
/** Ms epoch when the slice was last updated. */
|
|
56376
|
-
lastFetchedAt: number()
|
|
56377
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56378
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56379
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56380
|
-
unit: string().optional(),
|
|
56381
|
-
/** Suggested decimal places for numeric display.
|
|
56382
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56383
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56384
|
-
* auto-formatting when absent. */
|
|
56385
|
-
precision: number().int().min(0).max(10).optional()
|
|
56864
|
+
lastFetchedAt: number()
|
|
56386
56865
|
});
|
|
56387
56866
|
var ambientLightSensorCapability = {
|
|
56388
56867
|
name: "ambient-light-sensor",
|
|
@@ -56414,12 +56893,7 @@ var ambientLightSensorCapability = {
|
|
|
56414
56893
|
} } },
|
|
56415
56894
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56416
56895
|
* whether persisting is worth a SQLite commit. */
|
|
56417
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56418
|
-
customize: {
|
|
56419
|
-
version: 1,
|
|
56420
|
-
advanced: "derive",
|
|
56421
|
-
targets: []
|
|
56422
|
-
}
|
|
56896
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56423
56897
|
};
|
|
56424
56898
|
/**
|
|
56425
56899
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56646,10 +57120,7 @@ var BatteryStatusSchema = object({
|
|
|
56646
57120
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56647
57121
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56648
57122
|
*/
|
|
56649
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56650
|
-
unit: "%",
|
|
56651
|
-
label: "Charge"
|
|
56652
|
-
}),
|
|
57123
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56653
57124
|
/**
|
|
56654
57125
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56655
57126
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56676,7 +57147,14 @@ var BatteryStatusSchema = object({
|
|
|
56676
57147
|
*/
|
|
56677
57148
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56678
57149
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56679
|
-
lastUpdated: number(),
|
|
57150
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57151
|
+
/**
|
|
57152
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57153
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57154
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57155
|
+
* `numeric-sensor` on the same device.
|
|
57156
|
+
*/
|
|
57157
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56680
57158
|
/**
|
|
56681
57159
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56682
57160
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56728,7 +57206,6 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56728
57206
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56729
57207
|
var batteryCustomize = {
|
|
56730
57208
|
version: 1,
|
|
56731
|
-
advanced: "derive",
|
|
56732
57209
|
targets: [{
|
|
56733
57210
|
id: "percentage",
|
|
56734
57211
|
cardinality: "scalar",
|
|
@@ -56737,7 +57214,7 @@ var batteryCustomize = {
|
|
|
56737
57214
|
stateField: "percentage"
|
|
56738
57215
|
},
|
|
56739
57216
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56740
|
-
apply: "add
|
|
57217
|
+
apply: "add",
|
|
56741
57218
|
path: "percentage",
|
|
56742
57219
|
sources: [{
|
|
56743
57220
|
kind: "field",
|
|
@@ -56858,10 +57335,16 @@ onStatusChanged: { data: object({
|
|
|
56858
57335
|
/**
|
|
56859
57336
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
56860
57337
|
*/
|
|
56861
|
-
history: { fields: {
|
|
56862
|
-
|
|
56863
|
-
|
|
56864
|
-
|
|
57338
|
+
history: { fields: {
|
|
57339
|
+
percentage: {
|
|
57340
|
+
kind: "gauge",
|
|
57341
|
+
unit: "%"
|
|
57342
|
+
},
|
|
57343
|
+
volts: {
|
|
57344
|
+
kind: "gauge",
|
|
57345
|
+
unit: "V"
|
|
57346
|
+
}
|
|
57347
|
+
} },
|
|
56865
57348
|
customize: batteryCustomize,
|
|
56866
57349
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56867
57350
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -56908,12 +57391,7 @@ var binaryCapability = {
|
|
|
56908
57391
|
history: { fields: { on: { kind: "boolean" } } },
|
|
56909
57392
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56910
57393
|
* whether persisting is worth a SQLite commit. */
|
|
56911
|
-
volatileStateFields: ["lastChangedAt"]
|
|
56912
|
-
customize: {
|
|
56913
|
-
version: 1,
|
|
56914
|
-
advanced: "derive",
|
|
56915
|
-
targets: []
|
|
56916
|
-
}
|
|
57394
|
+
volatileStateFields: ["lastChangedAt"]
|
|
56917
57395
|
};
|
|
56918
57396
|
/**
|
|
56919
57397
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -56929,7 +57407,7 @@ var binaryCapability = {
|
|
|
56929
57407
|
*/
|
|
56930
57408
|
var BrightnessStatusSchema = object({
|
|
56931
57409
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
56932
|
-
percentage: number().min(0).max(100),
|
|
57410
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
56933
57411
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
56934
57412
|
lastChangedAt: number()
|
|
56935
57413
|
});
|
|
@@ -57383,21 +57861,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57383
57861
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57384
57862
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57385
57863
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57386
|
-
target: number().nullable(),
|
|
57864
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57387
57865
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57388
57866
|
* in `heat_cool` mode. */
|
|
57389
|
-
targetHigh: number().nullable(),
|
|
57867
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57390
57868
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57391
57869
|
* in `heat_cool` mode. */
|
|
57392
|
-
targetLow: number().nullable(),
|
|
57870
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57393
57871
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57394
57872
|
* humidity control. */
|
|
57395
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57873
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57396
57874
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57397
57875
|
* the device's internal sensor. */
|
|
57398
|
-
currentTemp: number().nullable(),
|
|
57876
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57399
57877
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57400
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57878
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57401
57879
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57402
57880
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57403
57881
|
swingVertical: boolean().nullable(),
|
|
@@ -57405,11 +57883,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57405
57883
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57406
57884
|
swingHorizontal: boolean().nullable(),
|
|
57407
57885
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57408
|
-
minTemp: number().nullable().optional(),
|
|
57886
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57409
57887
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57410
|
-
maxTemp: number().nullable().optional(),
|
|
57888
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57411
57889
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57412
|
-
tempStep: number().positive().nullable().optional(),
|
|
57890
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57413
57891
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57414
57892
|
lastFetchedAt: number()
|
|
57415
57893
|
});
|
|
@@ -57551,17 +58029,17 @@ var climateControlCapability = {
|
|
|
57551
58029
|
* modes to expose in the picker without a slice fetch.
|
|
57552
58030
|
*/
|
|
57553
58031
|
var RgbTripletSchema = object({
|
|
57554
|
-
r: number().int().min(0).max(255),
|
|
57555
|
-
g: number().int().min(0).max(255),
|
|
57556
|
-
b: number().int().min(0).max(255)
|
|
58032
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58033
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58034
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57557
58035
|
});
|
|
57558
58036
|
var HsvTripletSchema = object({
|
|
57559
58037
|
/** Hue in degrees, 0..360. */
|
|
57560
|
-
h: number().min(0).max(360),
|
|
58038
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57561
58039
|
/** Saturation as 0..100 inclusive. */
|
|
57562
|
-
s: number().min(0).max(100),
|
|
58040
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57563
58041
|
/** Value/brightness as 0..100 inclusive. */
|
|
57564
|
-
v: number().min(0).max(100)
|
|
58042
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57565
58043
|
});
|
|
57566
58044
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57567
58045
|
object({
|
|
@@ -57590,7 +58068,7 @@ var ColorStatusSchema = object({
|
|
|
57590
58068
|
/** Populated when `mode === 'hsv'`. */
|
|
57591
58069
|
hsv: HsvTripletSchema.optional(),
|
|
57592
58070
|
/** Populated when `mode === 'mired'`. */
|
|
57593
|
-
mireds: number().int().optional(),
|
|
58071
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57594
58072
|
/** Ms epoch of the last operator-driven change. */
|
|
57595
58073
|
lastChangedAt: number()
|
|
57596
58074
|
});
|
|
@@ -57793,18 +58271,12 @@ _enum([
|
|
|
57793
58271
|
"empty",
|
|
57794
58272
|
"full"
|
|
57795
58273
|
]);
|
|
57796
|
-
/**
|
|
57797
|
-
|
|
57798
|
-
|
|
57799
|
-
"days",
|
|
57800
|
-
"hours",
|
|
57801
|
-
"cycles"
|
|
57802
|
-
]);
|
|
57803
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57804
|
-
* days). `value` null = unknown (D393). */
|
|
58274
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
58275
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
58276
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57805
58277
|
var ConsumableRemainingSchema = object({
|
|
57806
|
-
value: number().min(0).nullable(),
|
|
57807
|
-
|
|
58278
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
58279
|
+
kind: ConsumableRemainingKindSchema
|
|
57808
58280
|
});
|
|
57809
58281
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
57810
58282
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -57817,7 +58289,7 @@ var ConsumableItemSchema = object({
|
|
|
57817
58289
|
/** Display name. */
|
|
57818
58290
|
label: string().min(1),
|
|
57819
58291
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57820
|
-
level: number().min(0).max(100).nullable(),
|
|
58292
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57821
58293
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57822
58294
|
status: ConsumableStatusSchema.nullable(),
|
|
57823
58295
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57899,8 +58371,8 @@ var consumablesCustomize = {
|
|
|
57899
58371
|
transforms: [{ kind: "identity" }]
|
|
57900
58372
|
}],
|
|
57901
58373
|
literals: [{
|
|
57902
|
-
path: "remaining.
|
|
57903
|
-
values: [...
|
|
58374
|
+
path: "remaining.kind",
|
|
58375
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
57904
58376
|
}]
|
|
57905
58377
|
},
|
|
57906
58378
|
{
|
|
@@ -58029,7 +58501,6 @@ reset: method(object({
|
|
|
58029
58501
|
},
|
|
58030
58502
|
"remaining.value": {
|
|
58031
58503
|
kind: "gauge",
|
|
58032
|
-
unitFrom: "remaining.unit",
|
|
58033
58504
|
deadband: 1,
|
|
58034
58505
|
displayName: "Remaining"
|
|
58035
58506
|
}
|
|
@@ -58099,10 +58570,9 @@ var contactCapability = {
|
|
|
58099
58570
|
* (empty array for the other kinds). It lives in the slice because
|
|
58100
58571
|
* HA `select.*` entities may update their options at runtime.
|
|
58101
58572
|
*
|
|
58102
|
-
*
|
|
58103
|
-
*
|
|
58104
|
-
*
|
|
58105
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
58573
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
58574
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
58575
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58106
58576
|
*/
|
|
58107
58577
|
var ControlStatusSchema = object({
|
|
58108
58578
|
kind: _enum([
|
|
@@ -58114,39 +58584,17 @@ var ControlStatusSchema = object({
|
|
|
58114
58584
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58115
58585
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58116
58586
|
* or time-only — HA accepts all three forms). */
|
|
58117
|
-
value: union([number(), string()]),
|
|
58587
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58118
58588
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58119
58589
|
options: array(string()),
|
|
58120
58590
|
/** Ms epoch when the slice was last updated. */
|
|
58121
58591
|
lastChangedAt: number(),
|
|
58122
|
-
/**
|
|
58123
|
-
|
|
58124
|
-
|
|
58125
|
-
|
|
58126
|
-
/**
|
|
58127
|
-
|
|
58128
|
-
min: number().optional(),
|
|
58129
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58130
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58131
|
-
max: number().optional(),
|
|
58132
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58133
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58134
|
-
step: number().optional(),
|
|
58135
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58136
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58137
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58138
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58139
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58140
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58141
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58142
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58143
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58144
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58145
|
-
format: _enum([
|
|
58146
|
-
"date",
|
|
58147
|
-
"time",
|
|
58148
|
-
"datetime"
|
|
58149
|
-
]).optional()
|
|
58592
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58593
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58594
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58595
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58596
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58597
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58150
58598
|
});
|
|
58151
58599
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58152
58600
|
object({
|
|
@@ -58212,9 +58660,9 @@ var CoverStatusSchema = object({
|
|
|
58212
58660
|
]),
|
|
58213
58661
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58214
58662
|
* no intermediate position surface. */
|
|
58215
|
-
position: number().min(0).max(100).nullable(),
|
|
58663
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58216
58664
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58217
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58665
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58218
58666
|
/** Ms epoch when the slice was last updated. */
|
|
58219
58667
|
lastChangedAt: number()
|
|
58220
58668
|
});
|
|
@@ -58317,9 +58765,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58317
58765
|
var DayNightStatusSchema = object({
|
|
58318
58766
|
mode: DayNightModeSchema,
|
|
58319
58767
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58320
|
-
sensitivity: number().optional(),
|
|
58768
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58321
58769
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58322
|
-
switchDelaySec: number().optional(),
|
|
58770
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58323
58771
|
lastFetchedAt: number()
|
|
58324
58772
|
});
|
|
58325
58773
|
/**
|
|
@@ -58537,11 +58985,11 @@ var DishwasherStatusSchema = object({
|
|
|
58537
58985
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58538
58986
|
availablePrograms: array(string()),
|
|
58539
58987
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58540
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58988
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58541
58989
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58542
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58990
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58543
58991
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58544
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58992
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58545
58993
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58546
58994
|
doorOpen: boolean().nullable(),
|
|
58547
58995
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58565,7 +59013,7 @@ var DishwasherStatusSchema = object({
|
|
|
58565
59013
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58566
59014
|
machineCareDue: boolean().nullable(),
|
|
58567
59015
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58568
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59016
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58569
59017
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58570
59018
|
halfLoad: boolean().nullable(),
|
|
58571
59019
|
hygienePlus: boolean().nullable(),
|
|
@@ -58580,7 +59028,7 @@ var DishwasherStatusSchema = object({
|
|
|
58580
59028
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58581
59029
|
activeEvents: array(string()),
|
|
58582
59030
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58583
|
-
errorCode: number().nullable(),
|
|
59031
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58584
59032
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58585
59033
|
errorLabel: string().nullable(),
|
|
58586
59034
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58811,7 +59259,7 @@ var DoorbellStatusSchema = object({
|
|
|
58811
59259
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58812
59260
|
lastPressedAt: number().nullable(),
|
|
58813
59261
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58814
|
-
pressCountSinceStart: number()
|
|
59262
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58815
59263
|
});
|
|
58816
59264
|
var DoorbellPressEventSchema = object({
|
|
58817
59265
|
deviceId: number(),
|
|
@@ -58876,17 +59324,7 @@ onPressed: {
|
|
|
58876
59324
|
history: "none",
|
|
58877
59325
|
customize: doorbellCustomize
|
|
58878
59326
|
};
|
|
58879
|
-
|
|
58880
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
58881
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
58882
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
58883
|
-
* The option set is stable across observations; it is persisted in the
|
|
58884
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
58885
|
-
* stored in `sourceInfo`.
|
|
58886
|
-
*/
|
|
58887
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
58888
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
58889
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
59327
|
+
_enum([
|
|
58890
59328
|
"date",
|
|
58891
59329
|
"time",
|
|
58892
59330
|
"datetime"
|
|
@@ -58894,12 +59332,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
58894
59332
|
var EnumSensorStatusSchema = object({
|
|
58895
59333
|
value: string(),
|
|
58896
59334
|
/**
|
|
58897
|
-
* Set
|
|
58898
|
-
* as
|
|
58899
|
-
*
|
|
58900
|
-
* a time-only sensor → `'time'`.
|
|
59335
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
59336
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
59337
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
58901
59338
|
*/
|
|
58902
|
-
|
|
59339
|
+
timestamp: boolean().optional(),
|
|
58903
59340
|
/** Ms epoch when the slice was last updated. */
|
|
58904
59341
|
lastFetchedAt: number()
|
|
58905
59342
|
});
|
|
@@ -58926,11 +59363,11 @@ var enumSensorCapability = {
|
|
|
58926
59363
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
58927
59364
|
* operation state, an HVAC action). The option set is per device, so the
|
|
58928
59365
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
58929
|
-
* `
|
|
59366
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
58930
59367
|
*/
|
|
58931
59368
|
history: { fields: { value: {
|
|
58932
59369
|
kind: "enum",
|
|
58933
|
-
skipWhenSet: "
|
|
59370
|
+
skipWhenSet: "timestamp"
|
|
58934
59371
|
} } },
|
|
58935
59372
|
/** Clock fields: written, but excluded from the compare that decides
|
|
58936
59373
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -58950,13 +59387,13 @@ var EventFireSchema = object({
|
|
|
58950
59387
|
deviceId: number(),
|
|
58951
59388
|
eventType: string(),
|
|
58952
59389
|
data: record(string(), unknown()).nullable(),
|
|
58953
|
-
timestamp: number(),
|
|
58954
|
-
seq: number()
|
|
59390
|
+
timestamp: number().meta(readingMeta("none")),
|
|
59391
|
+
seq: number().meta(readingMeta("count"))
|
|
58955
59392
|
});
|
|
58956
59393
|
var EventEmitterStatusSchema = object({
|
|
58957
59394
|
eventTypes: array(string()),
|
|
58958
59395
|
lastEvent: EventFireSchema.nullable(),
|
|
58959
|
-
eventCountSinceStart: number()
|
|
59396
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
58960
59397
|
});
|
|
58961
59398
|
var eventEmitterCapability = {
|
|
58962
59399
|
name: "event-emitter",
|
|
@@ -59369,10 +59806,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59369
59806
|
var FanControlStatusSchema = object({
|
|
59370
59807
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59371
59808
|
* speed surface (single-speed fan). */
|
|
59372
|
-
percentage: number().min(0).max(100).nullable(),
|
|
59809
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59373
59810
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59374
59811
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59375
|
-
percentageStep: number().positive().optional(),
|
|
59812
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59376
59813
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59377
59814
|
* — empty string when no preset is active or supported. */
|
|
59378
59815
|
preset: string(),
|
|
@@ -59493,7 +59930,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59493
59930
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59494
59931
|
model: string().nullable(),
|
|
59495
59932
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59496
|
-
channelCount: number().nullable(),
|
|
59933
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59497
59934
|
/**
|
|
59498
59935
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59499
59936
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59616,9 +60053,91 @@ var gasCapability = {
|
|
|
59616
60053
|
* whether persisting is worth a SQLite commit. */
|
|
59617
60054
|
volatileStateFields: ["lastChangedAt"]
|
|
59618
60055
|
};
|
|
60056
|
+
var GroupCommandsSchema = object({
|
|
60057
|
+
/** One row per member that has been commanded. A later command replaces that member's row. */
|
|
60058
|
+
results: array(object({
|
|
60059
|
+
deviceId: number().int().nonnegative(),
|
|
60060
|
+
cap: string().min(1),
|
|
60061
|
+
method: string().min(1),
|
|
60062
|
+
ok: boolean(),
|
|
60063
|
+
error: string().optional(),
|
|
60064
|
+
/** Ms epoch of the attempt. */
|
|
60065
|
+
at: number()
|
|
60066
|
+
})) });
|
|
60067
|
+
var groupCommandsCapability = {
|
|
60068
|
+
name: "group-commands",
|
|
60069
|
+
scope: "device",
|
|
60070
|
+
deviceNative: true,
|
|
60071
|
+
mode: "singleton",
|
|
60072
|
+
deviceTypes: [DeviceType.Switch, DeviceType.Light],
|
|
60073
|
+
methods: {},
|
|
60074
|
+
status: {
|
|
60075
|
+
schema: GroupCommandsSchema,
|
|
60076
|
+
kind: "push"
|
|
60077
|
+
},
|
|
60078
|
+
runtimeState: GroupCommandsSchema,
|
|
60079
|
+
/**
|
|
60080
|
+
* Runtime-state durability: **session** — the last attempt. A restored
|
|
60081
|
+
* failure would outlive the command that caused it.
|
|
60082
|
+
*
|
|
60083
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60084
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60085
|
+
*/
|
|
60086
|
+
durability: "session",
|
|
60087
|
+
history: "none"
|
|
60088
|
+
};
|
|
60089
|
+
/**
|
|
60090
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60091
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60092
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60093
|
+
* series that later statistics read is the output cap's own history block.
|
|
60094
|
+
*/
|
|
60095
|
+
var GroupStatusSchema = object({
|
|
60096
|
+
/** Members whose current value entered the aggregate. */
|
|
60097
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60098
|
+
precision: 0,
|
|
60099
|
+
label: "Reporting"
|
|
60100
|
+
})),
|
|
60101
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60102
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60103
|
+
precision: 0,
|
|
60104
|
+
label: "Excluded"
|
|
60105
|
+
})),
|
|
60106
|
+
/** `included` + `excluded`. */
|
|
60107
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60108
|
+
precision: 0,
|
|
60109
|
+
label: "Members"
|
|
60110
|
+
}))
|
|
60111
|
+
});
|
|
60112
|
+
var groupStatusCapability = {
|
|
60113
|
+
name: "group-status",
|
|
60114
|
+
scope: "device",
|
|
60115
|
+
deviceNative: true,
|
|
60116
|
+
mode: "singleton",
|
|
60117
|
+
deviceTypes: [
|
|
60118
|
+
DeviceType.Sensor,
|
|
60119
|
+
DeviceType.Switch,
|
|
60120
|
+
DeviceType.Light
|
|
60121
|
+
],
|
|
60122
|
+
methods: {},
|
|
60123
|
+
status: {
|
|
60124
|
+
schema: GroupStatusSchema,
|
|
60125
|
+
kind: "push"
|
|
60126
|
+
},
|
|
60127
|
+
runtimeState: GroupStatusSchema,
|
|
60128
|
+
/**
|
|
60129
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60130
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60131
|
+
*
|
|
60132
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60133
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60134
|
+
*/
|
|
60135
|
+
durability: "session",
|
|
60136
|
+
history: "none"
|
|
60137
|
+
};
|
|
59619
60138
|
var HeatingValveStatusSchema = object({
|
|
59620
60139
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59621
|
-
position: number().min(0).max(100).nullable(),
|
|
60140
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59622
60141
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59623
60142
|
lastFetchedAt: number()
|
|
59624
60143
|
});
|
|
@@ -59661,9 +60180,9 @@ var HumidifierStatusSchema = object({
|
|
|
59661
60180
|
/** Whether the humidifier is currently on. */
|
|
59662
60181
|
on: boolean(),
|
|
59663
60182
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59664
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60183
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59665
60184
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59666
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60185
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59667
60186
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59668
60187
|
* device has no mode surface. */
|
|
59669
60188
|
mode: string().nullable(),
|
|
@@ -59673,9 +60192,9 @@ var HumidifierStatusSchema = object({
|
|
|
59673
60192
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59674
60193
|
action: string().nullable(),
|
|
59675
60194
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59676
|
-
minHumidity: number().nullable(),
|
|
60195
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59677
60196
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59678
|
-
maxHumidity: number().nullable(),
|
|
60197
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59679
60198
|
/** Ms epoch when the slice was last updated. */
|
|
59680
60199
|
lastChangedAt: number()
|
|
59681
60200
|
});
|
|
@@ -59745,22 +60264,13 @@ var humidifierCapability = {
|
|
|
59745
60264
|
* `sourceInfo`.
|
|
59746
60265
|
*/
|
|
59747
60266
|
var HumiditySensorStatusSchema = object({
|
|
59748
|
-
/** Current relative humidity, 0..100. */
|
|
59749
|
-
percent: number().min(0).max(100).meta({
|
|
59750
|
-
|
|
60267
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
60268
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
60269
|
+
precision: 0,
|
|
59751
60270
|
label: "Humidity"
|
|
59752
|
-
}),
|
|
60271
|
+
})),
|
|
59753
60272
|
/** Ms epoch when the slice was last updated. */
|
|
59754
|
-
lastFetchedAt: number()
|
|
59755
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59756
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59757
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59758
|
-
unit: string().optional(),
|
|
59759
|
-
/** Suggested decimal places for numeric display.
|
|
59760
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59761
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59762
|
-
* auto-formatting when absent. */
|
|
59763
|
-
precision: number().int().min(0).max(10).optional()
|
|
60273
|
+
lastFetchedAt: number()
|
|
59764
60274
|
});
|
|
59765
60275
|
var humiditySensorCapability = {
|
|
59766
60276
|
name: "humidity-sensor",
|
|
@@ -59791,12 +60301,7 @@ var humiditySensorCapability = {
|
|
|
59791
60301
|
} } },
|
|
59792
60302
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59793
60303
|
* whether persisting is worth a SQLite commit. */
|
|
59794
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
59795
|
-
customize: {
|
|
59796
|
-
version: 1,
|
|
59797
|
-
advanced: "derive",
|
|
59798
|
-
targets: []
|
|
59799
|
-
}
|
|
60304
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
59800
60305
|
};
|
|
59801
60306
|
/**
|
|
59802
60307
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -59817,7 +60322,7 @@ var ImageStatusSchema = object({
|
|
|
59817
60322
|
* entity exposes no `entity_picture` (yet). */
|
|
59818
60323
|
url: string().nullable(),
|
|
59819
60324
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
59820
|
-
lastUpdated: number().nullable()
|
|
60325
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
59821
60326
|
});
|
|
59822
60327
|
var imageCapability = {
|
|
59823
60328
|
name: "image",
|
|
@@ -59905,19 +60410,19 @@ var NormalizedRangeSchema = object({
|
|
|
59905
60410
|
*/
|
|
59906
60411
|
var ImageSettingsStatusSchema = object({
|
|
59907
60412
|
/** Normalized 0–100. */
|
|
59908
|
-
brightness: number().optional(),
|
|
60413
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
59909
60414
|
/** Normalized 0–100. */
|
|
59910
|
-
contrast: number().optional(),
|
|
60415
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
59911
60416
|
/** Normalized 0–100. */
|
|
59912
|
-
saturation: number().optional(),
|
|
60417
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
59913
60418
|
/** Normalized 0–100. */
|
|
59914
|
-
sharpness: number().optional(),
|
|
60419
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
59915
60420
|
mirror: boolean().optional(),
|
|
59916
60421
|
flip: boolean().optional(),
|
|
59917
60422
|
rotate: ImageRotateSchema.optional(),
|
|
59918
60423
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
59919
60424
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
59920
|
-
warmth: number().optional(),
|
|
60425
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
59921
60426
|
exposureMode: ExposureModeSchema.optional(),
|
|
59922
60427
|
backlightMode: BacklightModeSchema.optional(),
|
|
59923
60428
|
lastFetchedAt: number()
|
|
@@ -60196,10 +60701,10 @@ var IntercomAbilitySchema = object({
|
|
|
60196
60701
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60197
60702
|
codecs: array(string()),
|
|
60198
60703
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60199
|
-
sampleRate: number(),
|
|
60704
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60200
60705
|
duplex: _enum(["half", "full"]),
|
|
60201
60706
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60202
|
-
maxBacklogMs: number()
|
|
60707
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60203
60708
|
});
|
|
60204
60709
|
var IntercomStatusSchema = object({
|
|
60205
60710
|
/** True while a talk session is open. */
|
|
@@ -60426,13 +60931,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60426
60931
|
activity: LawnMowerActivitySchema,
|
|
60427
60932
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60428
60933
|
* reading. */
|
|
60429
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
60934
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60430
60935
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60431
60936
|
* task is active / progress is unavailable. */
|
|
60432
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
60937
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60433
60938
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60434
60939
|
* or null when unknown. */
|
|
60435
|
-
currentCode: number().nullable(),
|
|
60940
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60436
60941
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60437
60942
|
currentCodeLabel: string().nullable(),
|
|
60438
60943
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -60965,7 +61470,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
60965
61470
|
state: MediaPlayerStateSchema,
|
|
60966
61471
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
60967
61472
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
60968
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
61473
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60969
61474
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
60970
61475
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
60971
61476
|
isMuted: boolean().nullable(),
|
|
@@ -60978,10 +61483,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
60978
61483
|
currentMedia: MediaInfoSchema.nullable(),
|
|
60979
61484
|
/** Current playback position in ms. Null when not seekable or
|
|
60980
61485
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
60981
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
61486
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
60982
61487
|
/** Total duration of the current media in ms. Null when unknown
|
|
60983
61488
|
* (live stream) or nothing is playing. */
|
|
60984
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
61489
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
60985
61490
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
60986
61491
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
60987
61492
|
shuffle: boolean().nullable(),
|
|
@@ -61290,7 +61795,7 @@ var motionCustomize = {
|
|
|
61290
61795
|
eventName: "onMotionChanged"
|
|
61291
61796
|
},
|
|
61292
61797
|
deviceTypes: [DeviceType.Camera],
|
|
61293
|
-
apply: "
|
|
61798
|
+
apply: "add",
|
|
61294
61799
|
applyAuthority: {
|
|
61295
61800
|
kind: "camera-sensors",
|
|
61296
61801
|
timeoutField: "motionCooldownMs"
|
|
@@ -61362,7 +61867,7 @@ var MotionStatusSchema = object({
|
|
|
61362
61867
|
* it, every provider seeded it at boot, and every session left it
|
|
61363
61868
|
* `detected: true` after its detach.
|
|
61364
61869
|
*/
|
|
61365
|
-
autoClearAfterMs: number().nullable()
|
|
61870
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61366
61871
|
});
|
|
61367
61872
|
/**
|
|
61368
61873
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61399,12 +61904,18 @@ var motionCapability = {
|
|
|
61399
61904
|
methods: {
|
|
61400
61905
|
/**
|
|
61401
61906
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
61402
|
-
* for consumers that don't need the full status object
|
|
61403
|
-
*
|
|
61404
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
61405
|
-
* consumer.
|
|
61907
|
+
* for consumers that don't need the full status object. A composed
|
|
61908
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
61406
61909
|
*/
|
|
61407
61910
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
61911
|
+
/**
|
|
61912
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
61913
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
61914
|
+
*/
|
|
61915
|
+
composedMethods: { isDetected: {
|
|
61916
|
+
kind: "slice",
|
|
61917
|
+
field: "detected"
|
|
61918
|
+
} },
|
|
61408
61919
|
events: {
|
|
61409
61920
|
/**
|
|
61410
61921
|
* Fires every time the runner transitions a camera between
|
|
@@ -61544,7 +62055,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61544
62055
|
* the grid region(s). */
|
|
61545
62056
|
var MotionZoneStatusSchema = object({
|
|
61546
62057
|
enabled: boolean(),
|
|
61547
|
-
sensitivity: number(),
|
|
62058
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61548
62059
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61549
62060
|
regions: array(MotionZoneRegionSchema),
|
|
61550
62061
|
lastFetchedAt: number()
|
|
@@ -61914,7 +62425,7 @@ var NavigationStatusSchema = object({
|
|
|
61914
62425
|
following: boolean(),
|
|
61915
62426
|
flash: boolean(),
|
|
61916
62427
|
lightMode: NavigationLightModeSchema,
|
|
61917
|
-
lightLevel: number().min(40).max(100),
|
|
62428
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
61918
62429
|
/** Ms epoch when the slice was last updated. */
|
|
61919
62430
|
lastChangedAt: number()
|
|
61920
62431
|
});
|
|
@@ -62048,13 +62559,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62048
62559
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62049
62560
|
* SKIP a null rather than coerce it.
|
|
62050
62561
|
*/
|
|
62051
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
62562
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62052
62563
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62053
|
-
rssiDbm: number().optional(),
|
|
62564
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62054
62565
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62055
62566
|
ssid: string().optional(),
|
|
62056
62567
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62057
|
-
lastUpdated: number()
|
|
62568
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62058
62569
|
});
|
|
62059
62570
|
var networkLinkCapability = {
|
|
62060
62571
|
name: "network-link",
|
|
@@ -62439,7 +62950,7 @@ var NotifierStatusSchema = object({
|
|
|
62439
62950
|
lastError: string().nullable(),
|
|
62440
62951
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62441
62952
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62442
|
-
queueDepth: number().int().nonnegative(),
|
|
62953
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62443
62954
|
/** Per-feature capability matrix — authoritative source for the
|
|
62444
62955
|
* compose-form field gating. */
|
|
62445
62956
|
supports: NotifierSupportsSchema
|
|
@@ -62531,11 +63042,9 @@ onSent: { data: object({
|
|
|
62531
63042
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62532
63043
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62533
63044
|
*
|
|
62534
|
-
* The
|
|
62535
|
-
*
|
|
62536
|
-
*
|
|
62537
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62538
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63045
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63046
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63047
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62539
63048
|
*
|
|
62540
63049
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62541
63050
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62544,15 +63053,8 @@ onSent: { data: object({
|
|
|
62544
63053
|
* numeric values land here.
|
|
62545
63054
|
*/
|
|
62546
63055
|
var NumericSensorStatusSchema = object({
|
|
62547
|
-
|
|
62548
|
-
|
|
62549
|
-
* Populated live from the upstream source on each state push.
|
|
62550
|
-
* Absent for unitless sensors. */
|
|
62551
|
-
unit: string().optional(),
|
|
62552
|
-
/** Suggested decimal places for numeric display.
|
|
62553
|
-
* Populated live from the upstream source when provided.
|
|
62554
|
-
* Falls back to auto-formatting when absent. */
|
|
62555
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63056
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63057
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62556
63058
|
/** Ms epoch when the slice was last updated. */
|
|
62557
63059
|
lastFetchedAt: number()
|
|
62558
63060
|
});
|
|
@@ -62576,11 +63078,11 @@ var numericSensorCapability = {
|
|
|
62576
63078
|
*/
|
|
62577
63079
|
durability: "restored",
|
|
62578
63080
|
/**
|
|
62579
|
-
* History (D850): recorded series. The unit is
|
|
63081
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63082
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62580
63083
|
*/
|
|
62581
63084
|
history: { fields: { value: {
|
|
62582
63085
|
kind: "gauge",
|
|
62583
|
-
unitFrom: "unit",
|
|
62584
63086
|
minIntervalMs: 3e4
|
|
62585
63087
|
} } },
|
|
62586
63088
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -62872,23 +63374,26 @@ var PetFeederStatusSchema = object({
|
|
|
62872
63374
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
62873
63375
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
62874
63376
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
62875
|
-
foodLevel: number().nullable(),
|
|
63377
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62876
63378
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
62877
63379
|
* single-hopper models. */
|
|
62878
|
-
food1: number().nullable(),
|
|
63380
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
62879
63381
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
62880
63382
|
* single-hopper models. */
|
|
62881
|
-
food2: number().nullable(),
|
|
63383
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
62882
63384
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
62883
63385
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
62884
63386
|
* below the feeder's low threshold. */
|
|
62885
63387
|
lowFood: boolean(),
|
|
62886
63388
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
62887
63389
|
* device has no battery reading. */
|
|
62888
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
62889
|
-
/**
|
|
62890
|
-
*
|
|
62891
|
-
|
|
63390
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63391
|
+
/**
|
|
63392
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
63393
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
63394
|
+
* model has no desiccant sensor.
|
|
63395
|
+
*/
|
|
63396
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
62892
63397
|
/** True while a feed is in progress. */
|
|
62893
63398
|
feeding: boolean(),
|
|
62894
63399
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -62899,7 +63404,7 @@ var PetFeederStatusSchema = object({
|
|
|
62899
63404
|
* with `errorCode` for consumers that want the raw integer. */
|
|
62900
63405
|
error: string().nullable(),
|
|
62901
63406
|
/** Raw device error code (0 / null = no error). */
|
|
62902
|
-
errorCode: number().nullable(),
|
|
63407
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
62903
63408
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
62904
63409
|
isDualHopper: boolean(),
|
|
62905
63410
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -62909,7 +63414,7 @@ var PetFeederStatusSchema = object({
|
|
|
62909
63414
|
/** Play a chime when dispensing. */
|
|
62910
63415
|
feedSound: boolean(),
|
|
62911
63416
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
62912
|
-
volume: number(),
|
|
63417
|
+
volume: number().meta(readingMeta("none")),
|
|
62913
63418
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
62914
63419
|
lastFetchedAt: number()
|
|
62915
63420
|
});
|
|
@@ -63028,7 +63533,7 @@ var petFeederCapability = {
|
|
|
63028
63533
|
},
|
|
63029
63534
|
desiccantLeftDays: {
|
|
63030
63535
|
kind: "gauge",
|
|
63031
|
-
unit: "
|
|
63536
|
+
unit: "s"
|
|
63032
63537
|
}
|
|
63033
63538
|
} }
|
|
63034
63539
|
};
|
|
@@ -63429,36 +63934,19 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63429
63934
|
*/
|
|
63430
63935
|
var PowerMeterStatusSchema = object({
|
|
63431
63936
|
/** Instantaneous power draw in watts. */
|
|
63432
|
-
watts: number().optional().meta({
|
|
63433
|
-
unit: "W",
|
|
63434
|
-
label: "Power"
|
|
63435
|
-
}),
|
|
63937
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63436
63938
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63437
|
-
kwhTotal: number().optional().meta({
|
|
63438
|
-
unit: "kWh",
|
|
63439
|
-
label: "Energy"
|
|
63440
|
-
}),
|
|
63939
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63441
63940
|
/** Voltage in volts. */
|
|
63442
|
-
volts: number().optional(),
|
|
63941
|
+
volts: number().optional().meta(readingMeta("voltage")),
|
|
63443
63942
|
/** Current in amperes. */
|
|
63444
|
-
amps: number().optional(),
|
|
63445
|
-
/** Apparent power in volt-amperes
|
|
63446
|
-
va: number().optional(),
|
|
63943
|
+
amps: number().optional().meta(readingMeta("current")),
|
|
63944
|
+
/** Apparent power in volt-amperes. */
|
|
63945
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63447
63946
|
/** Power factor (0..1) if reported. */
|
|
63448
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
63947
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63449
63948
|
/** Ms epoch when the slice was last updated. */
|
|
63450
|
-
lastFetchedAt: number()
|
|
63451
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63452
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63453
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63454
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63455
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63456
|
-
unit: string().optional(),
|
|
63457
|
-
/** Suggested decimal places for numeric display.
|
|
63458
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63459
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63460
|
-
* auto-formatting when absent. */
|
|
63461
|
-
precision: number().int().min(0).max(10).optional()
|
|
63949
|
+
lastFetchedAt: number()
|
|
63462
63950
|
});
|
|
63463
63951
|
var powerMeterCapability = {
|
|
63464
63952
|
name: "power-meter",
|
|
@@ -63522,12 +64010,7 @@ var powerMeterCapability = {
|
|
|
63522
64010
|
} },
|
|
63523
64011
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63524
64012
|
* whether persisting is worth a SQLite commit. */
|
|
63525
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
63526
|
-
customize: {
|
|
63527
|
-
version: 1,
|
|
63528
|
-
advanced: "derive",
|
|
63529
|
-
targets: []
|
|
63530
|
-
}
|
|
64013
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
63531
64014
|
};
|
|
63532
64015
|
/**
|
|
63533
64016
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63547,11 +64030,11 @@ var powerMeterCapability = {
|
|
|
63547
64030
|
*/
|
|
63548
64031
|
var GpsLocationSchema = object({
|
|
63549
64032
|
/** Latitude in decimal degrees, -90..90. */
|
|
63550
|
-
latitude: number().min(-90).max(90),
|
|
64033
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63551
64034
|
/** Longitude in decimal degrees, -180..180. */
|
|
63552
|
-
longitude: number().min(-180).max(180),
|
|
64035
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63553
64036
|
/** Reported accuracy in meters (lower = better). */
|
|
63554
|
-
accuracyMeters: number().nonnegative()
|
|
64037
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63555
64038
|
});
|
|
63556
64039
|
var PresenceStatusSchema = object({
|
|
63557
64040
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63563,7 +64046,7 @@ var PresenceStatusSchema = object({
|
|
|
63563
64046
|
gps: GpsLocationSchema.nullable(),
|
|
63564
64047
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63565
64048
|
* when not reported. */
|
|
63566
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64049
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63567
64050
|
/** Ms epoch when the slice was last updated. */
|
|
63568
64051
|
lastChangedAt: number()
|
|
63569
64052
|
});
|
|
@@ -63613,19 +64096,10 @@ var presenceCapability = {
|
|
|
63613
64096
|
* `sourceInfo`.
|
|
63614
64097
|
*/
|
|
63615
64098
|
var PressureSensorStatusSchema = object({
|
|
63616
|
-
/** Current pressure in hPa. */
|
|
63617
|
-
hpa: number(),
|
|
64099
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64100
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63618
64101
|
/** Ms epoch when the slice was last updated. */
|
|
63619
|
-
lastFetchedAt: number()
|
|
63620
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63621
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63622
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63623
|
-
unit: string().optional(),
|
|
63624
|
-
/** Suggested decimal places for numeric display.
|
|
63625
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63626
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63627
|
-
* auto-formatting when absent. */
|
|
63628
|
-
precision: number().int().min(0).max(10).optional()
|
|
64102
|
+
lastFetchedAt: number()
|
|
63629
64103
|
});
|
|
63630
64104
|
var pressureSensorCapability = {
|
|
63631
64105
|
name: "pressure-sensor",
|
|
@@ -64039,8 +64513,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64039
64513
|
}), _void(), { kind: "mutation" });
|
|
64040
64514
|
var PtzAutotrackSettingsSchema = object({
|
|
64041
64515
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64042
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64043
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
64516
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
64517
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64044
64518
|
});
|
|
64045
64519
|
/**
|
|
64046
64520
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64202,7 +64676,7 @@ var RunningStateStatusSchema = object({
|
|
|
64202
64676
|
/** null = unknown — never coerced to false (D393). */
|
|
64203
64677
|
running: boolean().nullable(),
|
|
64204
64678
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64205
|
-
since: number().nullable(),
|
|
64679
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64206
64680
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64207
64681
|
phase: string().nullable(),
|
|
64208
64682
|
/** null until a reading has been published (D393). */
|
|
@@ -64217,7 +64691,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64217
64691
|
/** Generic Customize target for the running boolean (D936). */
|
|
64218
64692
|
var runningCustomize = {
|
|
64219
64693
|
version: 1,
|
|
64220
|
-
advanced: "derive",
|
|
64221
64694
|
targets: [{
|
|
64222
64695
|
id: "running",
|
|
64223
64696
|
cardinality: "scalar",
|
|
@@ -64237,7 +64710,7 @@ var runningCustomize = {
|
|
|
64237
64710
|
DeviceType.Thermostat,
|
|
64238
64711
|
DeviceType.PetFeeder
|
|
64239
64712
|
],
|
|
64240
|
-
apply: "add
|
|
64713
|
+
apply: "add",
|
|
64241
64714
|
path: "running",
|
|
64242
64715
|
sources: [
|
|
64243
64716
|
{
|
|
@@ -65501,9 +65974,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65501
65974
|
*/
|
|
65502
65975
|
var RecordWindowSchema = object({
|
|
65503
65976
|
trigger: RecordTriggerSchema,
|
|
65504
|
-
day: number().int().min(0).max(6),
|
|
65505
|
-
startMinute: number().int().min(0).max(1439),
|
|
65506
|
-
endMinute: number().int().min(1).max(1440)
|
|
65977
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
65978
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
65979
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65507
65980
|
});
|
|
65508
65981
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65509
65982
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65579,10 +66052,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65579
66052
|
/** Master "record to the card at all" switch. */
|
|
65580
66053
|
enabled: boolean().nullable(),
|
|
65581
66054
|
overwriteWhenFull: boolean().nullable(),
|
|
65582
|
-
preRecordSec: number().nullable(),
|
|
65583
|
-
postRecordSec: number().nullable(),
|
|
66055
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66056
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65584
66057
|
/** Length of one recorded file, in minutes. */
|
|
65585
|
-
segmentMinutes: number().nullable(),
|
|
66058
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65586
66059
|
/** The primary track's weekly windows, flattened. */
|
|
65587
66060
|
windows: array(RecordWindowSchema),
|
|
65588
66061
|
/**
|
|
@@ -65598,7 +66071,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65598
66071
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65599
66072
|
* writable.
|
|
65600
66073
|
*/
|
|
65601
|
-
unreadableWindows: number(),
|
|
66074
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65602
66075
|
/**
|
|
65603
66076
|
* The camera is scheduled to record and has NO usable storage.
|
|
65604
66077
|
*
|
|
@@ -66443,7 +66916,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66443
66916
|
url: string().optional(),
|
|
66444
66917
|
codec: string().optional(),
|
|
66445
66918
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66446
|
-
fps: number().positive().optional(),
|
|
66919
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66447
66920
|
label: string().optional(),
|
|
66448
66921
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66449
66922
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66530,18 +67003,18 @@ var StreamProfileSchema = _enum([
|
|
|
66530
67003
|
]);
|
|
66531
67004
|
/** The current encoding config of one stream profile. */
|
|
66532
67005
|
var StreamProfileConfigSchema = object({
|
|
66533
|
-
width: number(),
|
|
66534
|
-
height: number(),
|
|
67006
|
+
width: number().meta(readingMeta("none")),
|
|
67007
|
+
height: number().meta(readingMeta("none")),
|
|
66535
67008
|
codec: _enum(["h264", "h265"]),
|
|
66536
|
-
framerate: number(),
|
|
66537
|
-
bitrate: number(),
|
|
67009
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67010
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66538
67011
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66539
67012
|
encoderProfile: _enum([
|
|
66540
67013
|
"high",
|
|
66541
67014
|
"main",
|
|
66542
67015
|
"baseline"
|
|
66543
67016
|
]).optional(),
|
|
66544
|
-
gop: number().optional(),
|
|
67017
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66545
67018
|
/**
|
|
66546
67019
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66547
67020
|
*
|
|
@@ -66762,12 +67235,7 @@ var switchCapability = {
|
|
|
66762
67235
|
label: "On",
|
|
66763
67236
|
kind: "boolean"
|
|
66764
67237
|
}
|
|
66765
|
-
}] }
|
|
66766
|
-
customize: {
|
|
66767
|
-
version: 1,
|
|
66768
|
-
advanced: "derive",
|
|
66769
|
-
targets: []
|
|
66770
|
-
}
|
|
67238
|
+
}] }
|
|
66771
67239
|
};
|
|
66772
67240
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66773
67241
|
function hasControlCharacter(value) {
|
|
@@ -67350,35 +67818,21 @@ var tamperCapability = {
|
|
|
67350
67818
|
* entries with `device_class: temperature` and any future native
|
|
67351
67819
|
* thermometer.
|
|
67352
67820
|
*
|
|
67353
|
-
*
|
|
67354
|
-
*
|
|
67355
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67356
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67357
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67358
|
-
* `sourceInfo`.
|
|
67821
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
67822
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67359
67823
|
*
|
|
67360
67824
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67361
67825
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67362
67826
|
* changed" steady state.
|
|
67363
67827
|
*/
|
|
67364
67828
|
var TemperatureSensorStatusSchema = object({
|
|
67365
|
-
/** Current temperature in Celsius. */
|
|
67366
|
-
celsius: number().meta({
|
|
67367
|
-
|
|
67829
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
67830
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
67831
|
+
precision: 1,
|
|
67368
67832
|
label: "Temperature"
|
|
67369
|
-
}),
|
|
67833
|
+
})),
|
|
67370
67834
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67371
|
-
lastFetchedAt: number()
|
|
67372
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67373
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67374
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67375
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67376
|
-
unit: string().optional(),
|
|
67377
|
-
/** Suggested decimal places for numeric display.
|
|
67378
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67379
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67380
|
-
* auto-formatting when absent. */
|
|
67381
|
-
precision: number().int().min(0).max(10).optional()
|
|
67835
|
+
lastFetchedAt: number()
|
|
67382
67836
|
});
|
|
67383
67837
|
var temperatureSensorCapability = {
|
|
67384
67838
|
name: "temperature-sensor",
|
|
@@ -67409,12 +67863,7 @@ var temperatureSensorCapability = {
|
|
|
67409
67863
|
} } },
|
|
67410
67864
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67411
67865
|
* whether persisting is worth a SQLite commit. */
|
|
67412
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67413
|
-
customize: {
|
|
67414
|
-
version: 1,
|
|
67415
|
-
advanced: "derive",
|
|
67416
|
-
targets: []
|
|
67417
|
-
}
|
|
67866
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67418
67867
|
};
|
|
67419
67868
|
/**
|
|
67420
67869
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67697,16 +68146,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67697
68146
|
]),
|
|
67698
68147
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67699
68148
|
* reading. */
|
|
67700
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68149
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67701
68150
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67702
68151
|
* the vacuum has no speed control. */
|
|
67703
68152
|
fanSpeed: string().nullable(),
|
|
67704
68153
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67705
68154
|
availableFanSpeeds: array(string()),
|
|
67706
68155
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67707
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68156
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67708
68157
|
/** Current error code (0 / null = no error). */
|
|
67709
|
-
errorCode: number().nullable(),
|
|
68158
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67710
68159
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67711
68160
|
errorLabel: string().nullable(),
|
|
67712
68161
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67784,7 +68233,7 @@ var ValveStatusSchema = object({
|
|
|
67784
68233
|
]),
|
|
67785
68234
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
67786
68235
|
* intermediate position surface. */
|
|
67787
|
-
position: number().min(0).max(100).nullable(),
|
|
68236
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67788
68237
|
/** Ms epoch when the slice was last updated. */
|
|
67789
68238
|
lastChangedAt: number()
|
|
67790
68239
|
});
|
|
@@ -67892,9 +68341,9 @@ var vibrationCapability = {
|
|
|
67892
68341
|
*/
|
|
67893
68342
|
var WaterHeaterStatusSchema = object({
|
|
67894
68343
|
/** Current measured temperature. Null when not reported. */
|
|
67895
|
-
currentTemp: number().nullable(),
|
|
68344
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67896
68345
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
67897
|
-
targetTemp: number().nullable(),
|
|
68346
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67898
68347
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
67899
68348
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
67900
68349
|
* device reports an unknown state. */
|
|
@@ -67905,9 +68354,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
67905
68354
|
* has no away surface. */
|
|
67906
68355
|
away: boolean().nullable(),
|
|
67907
68356
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
67908
|
-
minTemp: number().nullable(),
|
|
68357
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67909
68358
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
67910
|
-
maxTemp: number().nullable(),
|
|
68359
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67911
68360
|
/** Ms epoch when the slice was last updated. */
|
|
67912
68361
|
lastChangedAt: number()
|
|
67913
68362
|
});
|
|
@@ -67992,25 +68441,18 @@ var waterHeaterCapability = {
|
|
|
67992
68441
|
* Forecast deferred — current conditions only for v1.
|
|
67993
68442
|
*/
|
|
67994
68443
|
var WeatherStatusSchema = object({
|
|
67995
|
-
/** Verbatim
|
|
67996
|
-
* when no condition has been reported yet. */
|
|
68444
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
67997
68445
|
condition: string().nullable(),
|
|
67998
|
-
/** Current temperature in
|
|
67999
|
-
temperature: number().nullable(),
|
|
68000
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68001
|
-
temperatureUnit: string().nullable(),
|
|
68446
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
68447
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68002
68448
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68003
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68004
|
-
/** Barometric pressure in
|
|
68005
|
-
pressure: number().nullable(),
|
|
68006
|
-
/**
|
|
68007
|
-
|
|
68008
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68009
|
-
windSpeed: number().nullable(),
|
|
68010
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68011
|
-
windSpeedUnit: string().nullable(),
|
|
68449
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
68450
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
68451
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
68452
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
68453
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68012
68454
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68013
|
-
windBearing: number().nullable(),
|
|
68455
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68014
68456
|
/** Ms epoch when the slice was last updated. */
|
|
68015
68457
|
lastFetchedAt: number()
|
|
68016
68458
|
});
|
|
@@ -68038,12 +68480,12 @@ var weatherCapability = {
|
|
|
68038
68480
|
*/
|
|
68039
68481
|
durability: "session",
|
|
68040
68482
|
/**
|
|
68041
|
-
* History (D850): recorded series.
|
|
68483
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68042
68484
|
*/
|
|
68043
68485
|
history: { fields: {
|
|
68044
68486
|
temperature: {
|
|
68045
68487
|
kind: "gauge",
|
|
68046
|
-
|
|
68488
|
+
unit: "°C",
|
|
68047
68489
|
deadband: .2
|
|
68048
68490
|
},
|
|
68049
68491
|
humidity: {
|
|
@@ -68053,12 +68495,12 @@ var weatherCapability = {
|
|
|
68053
68495
|
},
|
|
68054
68496
|
pressure: {
|
|
68055
68497
|
kind: "gauge",
|
|
68056
|
-
|
|
68498
|
+
unit: "hPa",
|
|
68057
68499
|
deadband: .5
|
|
68058
68500
|
},
|
|
68059
68501
|
windSpeed: {
|
|
68060
68502
|
kind: "gauge",
|
|
68061
|
-
|
|
68503
|
+
unit: "m/s",
|
|
68062
68504
|
deadband: .5
|
|
68063
68505
|
}
|
|
68064
68506
|
} }
|
|
@@ -68990,6 +69432,389 @@ function runningFromDishwasherOperation(operation, program, previous, fetchedAt,
|
|
|
68990
69432
|
if (operation === "Pause") return nativeSlice(false, "Pause", previous, transitionAtMs, fetchedAt, null);
|
|
68991
69433
|
return nativeSlice(false, operation, previous, transitionAtMs, fetchedAt, null);
|
|
68992
69434
|
}
|
|
69435
|
+
/**
|
|
69436
|
+
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
69437
|
+
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
69438
|
+
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
69439
|
+
* decimals). K derives from `°C = K − 273.15`.
|
|
69440
|
+
*/
|
|
69441
|
+
var UNIT_TABLE = {
|
|
69442
|
+
"°C": {
|
|
69443
|
+
dimension: "temperature",
|
|
69444
|
+
factor: 1,
|
|
69445
|
+
offset: 0
|
|
69446
|
+
},
|
|
69447
|
+
"°F": {
|
|
69448
|
+
dimension: "temperature",
|
|
69449
|
+
factor: 5 / 9,
|
|
69450
|
+
offset: -160 / 9
|
|
69451
|
+
},
|
|
69452
|
+
K: {
|
|
69453
|
+
dimension: "temperature",
|
|
69454
|
+
factor: 1,
|
|
69455
|
+
offset: -273.15
|
|
69456
|
+
},
|
|
69457
|
+
hPa: {
|
|
69458
|
+
dimension: "pressure",
|
|
69459
|
+
factor: 1,
|
|
69460
|
+
offset: 0
|
|
69461
|
+
},
|
|
69462
|
+
kPa: {
|
|
69463
|
+
dimension: "pressure",
|
|
69464
|
+
factor: 10,
|
|
69465
|
+
offset: 0
|
|
69466
|
+
},
|
|
69467
|
+
Pa: {
|
|
69468
|
+
dimension: "pressure",
|
|
69469
|
+
factor: .01,
|
|
69470
|
+
offset: 0
|
|
69471
|
+
},
|
|
69472
|
+
mbar: {
|
|
69473
|
+
dimension: "pressure",
|
|
69474
|
+
factor: 1,
|
|
69475
|
+
offset: 0
|
|
69476
|
+
},
|
|
69477
|
+
bar: {
|
|
69478
|
+
dimension: "pressure",
|
|
69479
|
+
factor: 1e3,
|
|
69480
|
+
offset: 0
|
|
69481
|
+
},
|
|
69482
|
+
inHg: {
|
|
69483
|
+
dimension: "pressure",
|
|
69484
|
+
factor: 33.8639,
|
|
69485
|
+
offset: 0
|
|
69486
|
+
},
|
|
69487
|
+
mmHg: {
|
|
69488
|
+
dimension: "pressure",
|
|
69489
|
+
factor: 1.33322,
|
|
69490
|
+
offset: 0
|
|
69491
|
+
},
|
|
69492
|
+
psi: {
|
|
69493
|
+
dimension: "pressure",
|
|
69494
|
+
factor: 68.9476,
|
|
69495
|
+
offset: 0
|
|
69496
|
+
},
|
|
69497
|
+
"m/s": {
|
|
69498
|
+
dimension: "speed",
|
|
69499
|
+
factor: 1,
|
|
69500
|
+
offset: 0
|
|
69501
|
+
},
|
|
69502
|
+
"km/h": {
|
|
69503
|
+
dimension: "speed",
|
|
69504
|
+
factor: 1 / 3.6,
|
|
69505
|
+
offset: 0
|
|
69506
|
+
},
|
|
69507
|
+
mph: {
|
|
69508
|
+
dimension: "speed",
|
|
69509
|
+
factor: .44704,
|
|
69510
|
+
offset: 0
|
|
69511
|
+
},
|
|
69512
|
+
kn: {
|
|
69513
|
+
dimension: "speed",
|
|
69514
|
+
factor: .514444,
|
|
69515
|
+
offset: 0
|
|
69516
|
+
},
|
|
69517
|
+
"mm/h": {
|
|
69518
|
+
dimension: "precipitation-rate",
|
|
69519
|
+
factor: 1,
|
|
69520
|
+
offset: 0
|
|
69521
|
+
},
|
|
69522
|
+
"in/h": {
|
|
69523
|
+
dimension: "precipitation-rate",
|
|
69524
|
+
factor: 25.4,
|
|
69525
|
+
offset: 0
|
|
69526
|
+
},
|
|
69527
|
+
m: {
|
|
69528
|
+
dimension: "length",
|
|
69529
|
+
factor: 1,
|
|
69530
|
+
offset: 0
|
|
69531
|
+
},
|
|
69532
|
+
mm: {
|
|
69533
|
+
dimension: "length",
|
|
69534
|
+
factor: .001,
|
|
69535
|
+
offset: 0
|
|
69536
|
+
},
|
|
69537
|
+
cm: {
|
|
69538
|
+
dimension: "length",
|
|
69539
|
+
factor: .01,
|
|
69540
|
+
offset: 0
|
|
69541
|
+
},
|
|
69542
|
+
km: {
|
|
69543
|
+
dimension: "length",
|
|
69544
|
+
factor: 1e3,
|
|
69545
|
+
offset: 0
|
|
69546
|
+
},
|
|
69547
|
+
in: {
|
|
69548
|
+
dimension: "length",
|
|
69549
|
+
factor: .0254,
|
|
69550
|
+
offset: 0
|
|
69551
|
+
},
|
|
69552
|
+
ft: {
|
|
69553
|
+
dimension: "length",
|
|
69554
|
+
factor: .3048,
|
|
69555
|
+
offset: 0
|
|
69556
|
+
},
|
|
69557
|
+
mi: {
|
|
69558
|
+
dimension: "length",
|
|
69559
|
+
factor: 1609.344,
|
|
69560
|
+
offset: 0
|
|
69561
|
+
},
|
|
69562
|
+
"m²": {
|
|
69563
|
+
dimension: "area",
|
|
69564
|
+
factor: 1,
|
|
69565
|
+
offset: 0
|
|
69566
|
+
},
|
|
69567
|
+
lx: {
|
|
69568
|
+
dimension: "illuminance",
|
|
69569
|
+
factor: 1,
|
|
69570
|
+
offset: 0
|
|
69571
|
+
},
|
|
69572
|
+
"W/m²": {
|
|
69573
|
+
dimension: "irradiance",
|
|
69574
|
+
factor: 1,
|
|
69575
|
+
offset: 0
|
|
69576
|
+
},
|
|
69577
|
+
W: {
|
|
69578
|
+
dimension: "power",
|
|
69579
|
+
factor: 1,
|
|
69580
|
+
offset: 0
|
|
69581
|
+
},
|
|
69582
|
+
kW: {
|
|
69583
|
+
dimension: "power",
|
|
69584
|
+
factor: 1e3,
|
|
69585
|
+
offset: 0
|
|
69586
|
+
},
|
|
69587
|
+
VA: {
|
|
69588
|
+
dimension: "apparent-power",
|
|
69589
|
+
factor: 1,
|
|
69590
|
+
offset: 0
|
|
69591
|
+
},
|
|
69592
|
+
Wh: {
|
|
69593
|
+
dimension: "energy",
|
|
69594
|
+
factor: 1,
|
|
69595
|
+
offset: 0
|
|
69596
|
+
},
|
|
69597
|
+
kWh: {
|
|
69598
|
+
dimension: "energy",
|
|
69599
|
+
factor: 1e3,
|
|
69600
|
+
offset: 0
|
|
69601
|
+
},
|
|
69602
|
+
MWh: {
|
|
69603
|
+
dimension: "energy",
|
|
69604
|
+
factor: 1e6,
|
|
69605
|
+
offset: 0
|
|
69606
|
+
},
|
|
69607
|
+
V: {
|
|
69608
|
+
dimension: "voltage",
|
|
69609
|
+
factor: 1,
|
|
69610
|
+
offset: 0
|
|
69611
|
+
},
|
|
69612
|
+
mV: {
|
|
69613
|
+
dimension: "voltage",
|
|
69614
|
+
factor: .001,
|
|
69615
|
+
offset: 0
|
|
69616
|
+
},
|
|
69617
|
+
A: {
|
|
69618
|
+
dimension: "current",
|
|
69619
|
+
factor: 1,
|
|
69620
|
+
offset: 0
|
|
69621
|
+
},
|
|
69622
|
+
mA: {
|
|
69623
|
+
dimension: "current",
|
|
69624
|
+
factor: .001,
|
|
69625
|
+
offset: 0
|
|
69626
|
+
},
|
|
69627
|
+
ppm: {
|
|
69628
|
+
dimension: "concentration-volume",
|
|
69629
|
+
factor: 1,
|
|
69630
|
+
offset: 0
|
|
69631
|
+
},
|
|
69632
|
+
ppb: {
|
|
69633
|
+
dimension: "concentration-volume",
|
|
69634
|
+
factor: .001,
|
|
69635
|
+
offset: 0
|
|
69636
|
+
},
|
|
69637
|
+
"µg/m³": {
|
|
69638
|
+
dimension: "concentration-mass",
|
|
69639
|
+
factor: 1,
|
|
69640
|
+
offset: 0
|
|
69641
|
+
},
|
|
69642
|
+
"mg/m³": {
|
|
69643
|
+
dimension: "concentration-mass",
|
|
69644
|
+
factor: 1e3,
|
|
69645
|
+
offset: 0
|
|
69646
|
+
},
|
|
69647
|
+
kg: {
|
|
69648
|
+
dimension: "mass",
|
|
69649
|
+
factor: 1,
|
|
69650
|
+
offset: 0
|
|
69651
|
+
},
|
|
69652
|
+
g: {
|
|
69653
|
+
dimension: "mass",
|
|
69654
|
+
factor: .001,
|
|
69655
|
+
offset: 0
|
|
69656
|
+
},
|
|
69657
|
+
lb: {
|
|
69658
|
+
dimension: "mass",
|
|
69659
|
+
factor: .453592,
|
|
69660
|
+
offset: 0
|
|
69661
|
+
},
|
|
69662
|
+
oz: {
|
|
69663
|
+
dimension: "mass",
|
|
69664
|
+
factor: .0283495,
|
|
69665
|
+
offset: 0
|
|
69666
|
+
},
|
|
69667
|
+
"%": {
|
|
69668
|
+
dimension: "percentage",
|
|
69669
|
+
factor: 1,
|
|
69670
|
+
offset: 0
|
|
69671
|
+
},
|
|
69672
|
+
L: {
|
|
69673
|
+
dimension: "volume",
|
|
69674
|
+
factor: 1,
|
|
69675
|
+
offset: 0
|
|
69676
|
+
},
|
|
69677
|
+
mL: {
|
|
69678
|
+
dimension: "volume",
|
|
69679
|
+
factor: .001,
|
|
69680
|
+
offset: 0
|
|
69681
|
+
},
|
|
69682
|
+
gal: {
|
|
69683
|
+
dimension: "volume",
|
|
69684
|
+
factor: 3.785411784,
|
|
69685
|
+
offset: 0
|
|
69686
|
+
},
|
|
69687
|
+
s: {
|
|
69688
|
+
dimension: "duration",
|
|
69689
|
+
factor: 1,
|
|
69690
|
+
offset: 0
|
|
69691
|
+
},
|
|
69692
|
+
ms: {
|
|
69693
|
+
dimension: "duration",
|
|
69694
|
+
factor: .001,
|
|
69695
|
+
offset: 0
|
|
69696
|
+
},
|
|
69697
|
+
min: {
|
|
69698
|
+
dimension: "duration",
|
|
69699
|
+
factor: 60,
|
|
69700
|
+
offset: 0
|
|
69701
|
+
},
|
|
69702
|
+
h: {
|
|
69703
|
+
dimension: "duration",
|
|
69704
|
+
factor: 3600,
|
|
69705
|
+
offset: 0
|
|
69706
|
+
},
|
|
69707
|
+
d: {
|
|
69708
|
+
dimension: "duration",
|
|
69709
|
+
factor: 86400,
|
|
69710
|
+
offset: 0
|
|
69711
|
+
},
|
|
69712
|
+
B: {
|
|
69713
|
+
dimension: "information",
|
|
69714
|
+
factor: 1,
|
|
69715
|
+
offset: 0
|
|
69716
|
+
},
|
|
69717
|
+
KiB: {
|
|
69718
|
+
dimension: "information",
|
|
69719
|
+
factor: 1024,
|
|
69720
|
+
offset: 0
|
|
69721
|
+
},
|
|
69722
|
+
MiB: {
|
|
69723
|
+
dimension: "information",
|
|
69724
|
+
factor: 1024 ** 2,
|
|
69725
|
+
offset: 0
|
|
69726
|
+
},
|
|
69727
|
+
GiB: {
|
|
69728
|
+
dimension: "information",
|
|
69729
|
+
factor: 1024 ** 3,
|
|
69730
|
+
offset: 0
|
|
69731
|
+
},
|
|
69732
|
+
TiB: {
|
|
69733
|
+
dimension: "information",
|
|
69734
|
+
factor: 1024 ** 4,
|
|
69735
|
+
offset: 0
|
|
69736
|
+
},
|
|
69737
|
+
kB: {
|
|
69738
|
+
dimension: "information",
|
|
69739
|
+
factor: 1e3,
|
|
69740
|
+
offset: 0
|
|
69741
|
+
},
|
|
69742
|
+
MB: {
|
|
69743
|
+
dimension: "information",
|
|
69744
|
+
factor: 1e6,
|
|
69745
|
+
offset: 0
|
|
69746
|
+
},
|
|
69747
|
+
GB: {
|
|
69748
|
+
dimension: "information",
|
|
69749
|
+
factor: 1e9,
|
|
69750
|
+
offset: 0
|
|
69751
|
+
},
|
|
69752
|
+
"°": {
|
|
69753
|
+
dimension: "angle",
|
|
69754
|
+
factor: 1,
|
|
69755
|
+
offset: 0
|
|
69756
|
+
},
|
|
69757
|
+
dBFS: {
|
|
69758
|
+
dimension: "sound-level",
|
|
69759
|
+
factor: 1,
|
|
69760
|
+
offset: 0
|
|
69761
|
+
},
|
|
69762
|
+
dBm: {
|
|
69763
|
+
dimension: "signal-level",
|
|
69764
|
+
factor: 1,
|
|
69765
|
+
offset: 0
|
|
69766
|
+
},
|
|
69767
|
+
mired: {
|
|
69768
|
+
dimension: "colour-temperature",
|
|
69769
|
+
factor: 1,
|
|
69770
|
+
offset: 0
|
|
69771
|
+
},
|
|
69772
|
+
kbps: {
|
|
69773
|
+
dimension: "bitrate",
|
|
69774
|
+
factor: 1,
|
|
69775
|
+
offset: 0
|
|
69776
|
+
},
|
|
69777
|
+
Mbps: {
|
|
69778
|
+
dimension: "bitrate",
|
|
69779
|
+
factor: 1e3,
|
|
69780
|
+
offset: 0
|
|
69781
|
+
},
|
|
69782
|
+
fps: {
|
|
69783
|
+
dimension: "rate",
|
|
69784
|
+
factor: 1,
|
|
69785
|
+
offset: 0
|
|
69786
|
+
}
|
|
69787
|
+
};
|
|
69788
|
+
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
69789
|
+
function specFor(unit) {
|
|
69790
|
+
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
69791
|
+
}
|
|
69792
|
+
/** The dimension a unit belongs to, or `undefined` for an unknown unit. */
|
|
69793
|
+
function unitDimension(unit) {
|
|
69794
|
+
return specFor(unit)?.dimension;
|
|
69795
|
+
}
|
|
69796
|
+
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
69797
|
+
function toCanonical(value, spec) {
|
|
69798
|
+
return value * spec.factor + spec.offset;
|
|
69799
|
+
}
|
|
69800
|
+
/** Canonical-unit value → the unit described by `spec`. */
|
|
69801
|
+
function fromCanonical(canonical, spec) {
|
|
69802
|
+
return (canonical - spec.offset) / spec.factor;
|
|
69803
|
+
}
|
|
69804
|
+
/**
|
|
69805
|
+
* Graceful variant for the render path: returns the converted value, or
|
|
69806
|
+
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
69807
|
+
* Never throws — a render caller falls back to the raw value + source unit.
|
|
69808
|
+
*/
|
|
69809
|
+
function tryConvertUnit(value, from, to) {
|
|
69810
|
+
if (from === to) return value;
|
|
69811
|
+
const fromSpec = specFor(from);
|
|
69812
|
+
if (!fromSpec) return void 0;
|
|
69813
|
+
const toSpec = specFor(to);
|
|
69814
|
+
if (!toSpec) return void 0;
|
|
69815
|
+
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
69816
|
+
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
69817
|
+
}
|
|
68993
69818
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
68994
69819
|
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;
|
|
68995
69820
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
@@ -69320,6 +70145,8 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
69320
70145
|
featureProbe: featureProbeCapability,
|
|
69321
70146
|
flood: floodCapability,
|
|
69322
70147
|
gas: gasCapability,
|
|
70148
|
+
groupCommands: groupCommandsCapability,
|
|
70149
|
+
groupStatus: groupStatusCapability,
|
|
69323
70150
|
heatingValve: heatingValveCapability,
|
|
69324
70151
|
humidifier: humidifierCapability,
|
|
69325
70152
|
humiditySensor: humiditySensorCapability,
|
|
@@ -70696,6 +71523,13 @@ Object.freeze({
|
|
|
70696
71523
|
access: "view",
|
|
70697
71524
|
role: "admin"
|
|
70698
71525
|
},
|
|
71526
|
+
"addons.getPackageDocs": {
|
|
71527
|
+
capName: "addons",
|
|
71528
|
+
capScope: "system",
|
|
71529
|
+
addonId: null,
|
|
71530
|
+
access: "view",
|
|
71531
|
+
role: "admin"
|
|
71532
|
+
},
|
|
70699
71533
|
"addons.getVersions": {
|
|
70700
71534
|
capName: "addons",
|
|
70701
71535
|
capScope: "system",
|
|
@@ -73804,6 +74638,20 @@ Object.freeze({
|
|
|
73804
74638
|
access: "view",
|
|
73805
74639
|
role: "viewer"
|
|
73806
74640
|
},
|
|
74641
|
+
"groupCommands.getStatus": {
|
|
74642
|
+
capName: "group-commands",
|
|
74643
|
+
capScope: "device",
|
|
74644
|
+
addonId: null,
|
|
74645
|
+
access: "view",
|
|
74646
|
+
role: "viewer"
|
|
74647
|
+
},
|
|
74648
|
+
"groupStatus.getStatus": {
|
|
74649
|
+
capName: "group-status",
|
|
74650
|
+
capScope: "device",
|
|
74651
|
+
addonId: null,
|
|
74652
|
+
access: "view",
|
|
74653
|
+
role: "viewer"
|
|
74654
|
+
},
|
|
73807
74655
|
"heatingValve.getStatus": {
|
|
73808
74656
|
capName: "heating-valve",
|
|
73809
74657
|
capScope: "device",
|
|
@@ -83626,6 +84474,37 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83626
84474
|
icon: "flame"
|
|
83627
84475
|
}]
|
|
83628
84476
|
},
|
|
84477
|
+
"group-commands": {
|
|
84478
|
+
scope: "device",
|
|
84479
|
+
noun: t("Group command", "Comando di gruppo")
|
|
84480
|
+
},
|
|
84481
|
+
"group-status": {
|
|
84482
|
+
scope: "device",
|
|
84483
|
+
noun: t("Group", "Gruppo"),
|
|
84484
|
+
state: [
|
|
84485
|
+
{
|
|
84486
|
+
kind: "numeric",
|
|
84487
|
+
field: "included",
|
|
84488
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
84489
|
+
label: t("Reporting", "Rispondono"),
|
|
84490
|
+
icon: "users"
|
|
84491
|
+
},
|
|
84492
|
+
{
|
|
84493
|
+
kind: "numeric",
|
|
84494
|
+
field: "excluded",
|
|
84495
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
84496
|
+
label: t("Excluded", "Esclusi"),
|
|
84497
|
+
icon: "users"
|
|
84498
|
+
},
|
|
84499
|
+
{
|
|
84500
|
+
kind: "numeric",
|
|
84501
|
+
field: "total",
|
|
84502
|
+
quantity: t("the member count", "il numero di membri"),
|
|
84503
|
+
label: t("Members", "Membri"),
|
|
84504
|
+
icon: "sigma"
|
|
84505
|
+
}
|
|
84506
|
+
]
|
|
84507
|
+
},
|
|
83629
84508
|
"humidity-sensor": {
|
|
83630
84509
|
scope: "device",
|
|
83631
84510
|
noun: t("Humidity", "Umidità"),
|
|
@@ -83659,7 +84538,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83659
84538
|
field: "value",
|
|
83660
84539
|
quantity: t("the reading", "il valore"),
|
|
83661
84540
|
label: t("Reading", "Valore"),
|
|
83662
|
-
unitField: "unit",
|
|
83663
84541
|
icon: "gauge"
|
|
83664
84542
|
}]
|
|
83665
84543
|
},
|
|
@@ -83795,7 +84673,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83795
84673
|
field: "temperature",
|
|
83796
84674
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
83797
84675
|
label: t("Temperature", "Temperatura"),
|
|
83798
|
-
|
|
84676
|
+
unit: "°C",
|
|
83799
84677
|
icon: "thermometer"
|
|
83800
84678
|
},
|
|
83801
84679
|
{
|
|
@@ -83811,7 +84689,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83811
84689
|
field: "windSpeed",
|
|
83812
84690
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
83813
84691
|
label: t("Wind", "Vento"),
|
|
83814
|
-
|
|
84692
|
+
unit: "m/s",
|
|
83815
84693
|
icon: "wind"
|
|
83816
84694
|
},
|
|
83817
84695
|
{
|
|
@@ -83819,7 +84697,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83819
84697
|
field: "pressure",
|
|
83820
84698
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
83821
84699
|
label: t("Pressure", "Pressione"),
|
|
83822
|
-
|
|
84700
|
+
unit: "hPa",
|
|
83823
84701
|
icon: "gauge"
|
|
83824
84702
|
}
|
|
83825
84703
|
]
|
|
@@ -85092,6 +85970,16 @@ Object.freeze({
|
|
|
85092
85970
|
form: "single",
|
|
85093
85971
|
optional: false
|
|
85094
85972
|
}],
|
|
85973
|
+
"groupCommands.getStatus": [{
|
|
85974
|
+
name: "deviceId",
|
|
85975
|
+
form: "single",
|
|
85976
|
+
optional: false
|
|
85977
|
+
}],
|
|
85978
|
+
"groupStatus.getStatus": [{
|
|
85979
|
+
name: "deviceId",
|
|
85980
|
+
form: "single",
|
|
85981
|
+
optional: false
|
|
85982
|
+
}],
|
|
85095
85983
|
"heatingValve.getStatus": [{
|
|
85096
85984
|
name: "deviceId",
|
|
85097
85985
|
form: "single",
|
|
@@ -87076,6 +87964,8 @@ new Map(Object.entries({
|
|
|
87076
87964
|
"detection-blind": "device-events",
|
|
87077
87965
|
"motion-noisy": "device-events",
|
|
87078
87966
|
"motion-calm": "device-events",
|
|
87967
|
+
"package-llm-silent": "device-events",
|
|
87968
|
+
"package-llm-answered": "device-events",
|
|
87079
87969
|
"recording-stalled": "device-events",
|
|
87080
87970
|
"recording-healthy": "device-events",
|
|
87081
87971
|
"recording-degraded": "device-events",
|
|
@@ -87159,6 +88049,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
87159
88049
|
label: "Motion without a subject",
|
|
87160
88050
|
kinds: ["motion-noisy", "motion-calm"]
|
|
87161
88051
|
},
|
|
88052
|
+
{
|
|
88053
|
+
id: "package-llm",
|
|
88054
|
+
family: "device-events",
|
|
88055
|
+
label: "Package confirm",
|
|
88056
|
+
kinds: ["package-llm-silent", "package-llm-answered"]
|
|
88057
|
+
},
|
|
87162
88058
|
{
|
|
87163
88059
|
id: "recording",
|
|
87164
88060
|
family: "device-events",
|
|
@@ -87340,6 +88236,8 @@ var DEVICE_EVENTS = [
|
|
|
87340
88236
|
"detection-blind",
|
|
87341
88237
|
"motion-noisy",
|
|
87342
88238
|
"motion-calm",
|
|
88239
|
+
"package-llm-silent",
|
|
88240
|
+
"package-llm-answered",
|
|
87343
88241
|
"recording-stalled",
|
|
87344
88242
|
"recording-healthy",
|
|
87345
88243
|
"recording-degraded",
|
|
@@ -87608,6 +88506,15 @@ new Map([
|
|
|
87608
88506
|
snapshotLabel: "Cameras with constant motion now",
|
|
87609
88507
|
snapshotSection: null
|
|
87610
88508
|
},
|
|
88509
|
+
{
|
|
88510
|
+
id: "package-llm-confirm",
|
|
88511
|
+
family: "device-events",
|
|
88512
|
+
label: "Package confirm (not answering / answering again)",
|
|
88513
|
+
bad: ["package-llm-silent"],
|
|
88514
|
+
recovery: ["package-llm-answered"],
|
|
88515
|
+
snapshotLabel: "Cameras whose package confirm is not answering",
|
|
88516
|
+
snapshotSection: null
|
|
88517
|
+
},
|
|
87611
88518
|
{
|
|
87612
88519
|
id: "recording-health",
|
|
87613
88520
|
family: "device-events",
|
|
@@ -88184,6 +89091,96 @@ DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
|
88184
89091
|
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
88185
89092
|
DEFAULT_NATIVE_LEASE_SETTINGS.sceneBudgetMb;
|
|
88186
89093
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
89094
|
+
/**
|
|
89095
|
+
* Convert an upstream number into the stored base of its quantity (D944 §4).
|
|
89096
|
+
* An unknown unit or a unit from another dimension is a refusal: the caller
|
|
89097
|
+
* logs it and publishes null (D393). This function never guesses.
|
|
89098
|
+
*/
|
|
89099
|
+
var DIMENSION_QUANTITY = {
|
|
89100
|
+
temperature: "temperature",
|
|
89101
|
+
pressure: "pressure",
|
|
89102
|
+
speed: "speed",
|
|
89103
|
+
"precipitation-rate": "precipitation-rate",
|
|
89104
|
+
length: "length",
|
|
89105
|
+
area: "area",
|
|
89106
|
+
illuminance: "illuminance",
|
|
89107
|
+
irradiance: "irradiance",
|
|
89108
|
+
power: "power",
|
|
89109
|
+
"apparent-power": "apparent-power",
|
|
89110
|
+
energy: "energy",
|
|
89111
|
+
voltage: "voltage",
|
|
89112
|
+
current: "current",
|
|
89113
|
+
"concentration-volume": "concentration-volume",
|
|
89114
|
+
"concentration-mass": "concentration-mass",
|
|
89115
|
+
mass: "mass",
|
|
89116
|
+
percentage: "percentage",
|
|
89117
|
+
volume: "volume",
|
|
89118
|
+
duration: "duration",
|
|
89119
|
+
information: "information",
|
|
89120
|
+
angle: "angle",
|
|
89121
|
+
"sound-level": "sound-level",
|
|
89122
|
+
"signal-level": "signal-level",
|
|
89123
|
+
"colour-temperature": "colour-temperature",
|
|
89124
|
+
bitrate: "bitrate",
|
|
89125
|
+
rate: "rate"
|
|
89126
|
+
};
|
|
89127
|
+
/**
|
|
89128
|
+
* Quantity implied by a unit symbol. `ppb` and `ms` are the two symbols
|
|
89129
|
+
* whose stored base is not the dimension's canonical unit. `mm` is length;
|
|
89130
|
+
* precipitation is chosen by the caller (a device class), not by the symbol.
|
|
89131
|
+
*/
|
|
89132
|
+
function quantityFromUnit(rawUnit) {
|
|
89133
|
+
const unit = normalizeUnit(rawUnit);
|
|
89134
|
+
if (unit === void 0) return void 0;
|
|
89135
|
+
if (unit === "ppb") return "concentration-ppb";
|
|
89136
|
+
if (unit === "ms") return "duration-ms";
|
|
89137
|
+
const dimension = unitDimension(unit);
|
|
89138
|
+
if (dimension === void 0) return void 0;
|
|
89139
|
+
return DIMENSION_QUANTITY[dimension];
|
|
89140
|
+
}
|
|
89141
|
+
function ingestReading(input) {
|
|
89142
|
+
if (!Number.isFinite(input.value)) return {
|
|
89143
|
+
ok: false,
|
|
89144
|
+
reason: "non-finite"
|
|
89145
|
+
};
|
|
89146
|
+
if (input.quantity === "device") return {
|
|
89147
|
+
ok: false,
|
|
89148
|
+
reason: "unknown-unit"
|
|
89149
|
+
};
|
|
89150
|
+
const raw = input.rawUnit?.trim();
|
|
89151
|
+
if (raw === void 0 || raw.length === 0) return {
|
|
89152
|
+
ok: true,
|
|
89153
|
+
value: input.value
|
|
89154
|
+
};
|
|
89155
|
+
const unit = normalizeUnit(raw);
|
|
89156
|
+
if (unit === void 0) return {
|
|
89157
|
+
ok: false,
|
|
89158
|
+
reason: "unknown-unit"
|
|
89159
|
+
};
|
|
89160
|
+
const base = baseUnitOf(input.quantity);
|
|
89161
|
+
if (base === void 0) {
|
|
89162
|
+
if (unitDimension(unit) !== void 0) return {
|
|
89163
|
+
ok: false,
|
|
89164
|
+
reason: "cross-dimension"
|
|
89165
|
+
};
|
|
89166
|
+
return {
|
|
89167
|
+
ok: false,
|
|
89168
|
+
reason: "unknown-unit"
|
|
89169
|
+
};
|
|
89170
|
+
}
|
|
89171
|
+
const converted = tryConvertUnit(input.value, unit, base);
|
|
89172
|
+
if (converted === void 0) return unitDimension(unit) === void 0 ? {
|
|
89173
|
+
ok: false,
|
|
89174
|
+
reason: "unknown-unit"
|
|
89175
|
+
} : {
|
|
89176
|
+
ok: false,
|
|
89177
|
+
reason: "cross-dimension"
|
|
89178
|
+
};
|
|
89179
|
+
return {
|
|
89180
|
+
ok: true,
|
|
89181
|
+
value: converted
|
|
89182
|
+
};
|
|
89183
|
+
}
|
|
88187
89184
|
var MB = 1024 * 1024;
|
|
88188
89185
|
1024 * MB, 3072 * MB;
|
|
88189
89186
|
//#endregion
|
|
@@ -88325,6 +89322,12 @@ Object.defineProperty(exports, "heatingValveCapability", {
|
|
|
88325
89322
|
return heatingValveCapability;
|
|
88326
89323
|
}
|
|
88327
89324
|
});
|
|
89325
|
+
Object.defineProperty(exports, "ingestReading", {
|
|
89326
|
+
enumerable: true,
|
|
89327
|
+
get: function() {
|
|
89328
|
+
return ingestReading;
|
|
89329
|
+
}
|
|
89330
|
+
});
|
|
88328
89331
|
Object.defineProperty(exports, "isSecretMarker", {
|
|
88329
89332
|
enumerable: true,
|
|
88330
89333
|
get: function() {
|
|
@@ -88367,6 +89370,12 @@ Object.defineProperty(exports, "powerMeterCapability", {
|
|
|
88367
89370
|
return powerMeterCapability;
|
|
88368
89371
|
}
|
|
88369
89372
|
});
|
|
89373
|
+
Object.defineProperty(exports, "quantityFromUnit", {
|
|
89374
|
+
enumerable: true,
|
|
89375
|
+
get: function() {
|
|
89376
|
+
return quantityFromUnit;
|
|
89377
|
+
}
|
|
89378
|
+
});
|
|
88370
89379
|
Object.defineProperty(exports, "record", {
|
|
88371
89380
|
enumerable: true,
|
|
88372
89381
|
get: function() {
|