@camstack/addon-provider-homeassistant 1.2.625 → 1.2.627
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/dist/addon.js +268 -119
- package/dist/addon.mjs +268 -119
- package/dist/{dist-DvZEnx9C.mjs → dist-BFnk4bwH.mjs} +1314 -497
- package/dist/{dist-oNUlRdur.js → dist-CRwUHjY7.js} +1349 -496
- package/dist/ha-export/ha-export.addon.js +30 -19
- package/dist/ha-export/ha-export.addon.mjs +30 -19
- package/package.json +1 -1
|
@@ -5567,7 +5567,7 @@ var ZodIssueCode = {
|
|
|
5567
5567
|
var ZodFirstPartyTypeKind;
|
|
5568
5568
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5569
5569
|
//#endregion
|
|
5570
|
-
//#region ../types/dist/sleep-
|
|
5570
|
+
//#region ../types/dist/sleep-B81gwQuR.mjs
|
|
5571
5571
|
/**
|
|
5572
5572
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5573
5573
|
* window to float samples (D455).
|
|
@@ -8309,6 +8309,102 @@ function defineEntryKind(name, spec) {
|
|
|
8309
8309
|
if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
|
|
8310
8310
|
return defined;
|
|
8311
8311
|
}
|
|
8312
|
+
var READING_QUANTITIES = [
|
|
8313
|
+
"temperature",
|
|
8314
|
+
"pressure",
|
|
8315
|
+
"speed",
|
|
8316
|
+
"precipitation",
|
|
8317
|
+
"precipitation-rate",
|
|
8318
|
+
"length",
|
|
8319
|
+
"area",
|
|
8320
|
+
"illuminance",
|
|
8321
|
+
"irradiance",
|
|
8322
|
+
"power",
|
|
8323
|
+
"energy",
|
|
8324
|
+
"voltage",
|
|
8325
|
+
"current",
|
|
8326
|
+
"apparent-power",
|
|
8327
|
+
"humidity",
|
|
8328
|
+
"percentage",
|
|
8329
|
+
"concentration-volume",
|
|
8330
|
+
"concentration-mass",
|
|
8331
|
+
"concentration-ppb",
|
|
8332
|
+
"volume",
|
|
8333
|
+
"duration",
|
|
8334
|
+
"duration-ms",
|
|
8335
|
+
"information",
|
|
8336
|
+
"sound-level",
|
|
8337
|
+
"signal-level",
|
|
8338
|
+
"colour-temperature",
|
|
8339
|
+
"angle",
|
|
8340
|
+
"bitrate",
|
|
8341
|
+
"rate",
|
|
8342
|
+
"mass",
|
|
8343
|
+
"index",
|
|
8344
|
+
"ratio",
|
|
8345
|
+
"count",
|
|
8346
|
+
"none",
|
|
8347
|
+
"device"
|
|
8348
|
+
];
|
|
8349
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8350
|
+
var QUANTITY_SET = new Set(READING_QUANTITIES);
|
|
8351
|
+
function isReadingQuantity(value) {
|
|
8352
|
+
return typeof value === "string" && QUANTITY_SET.has(value);
|
|
8353
|
+
}
|
|
8354
|
+
/**
|
|
8355
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
8356
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
8357
|
+
*/
|
|
8358
|
+
var QUANTITY_BASE = {
|
|
8359
|
+
temperature: "°C",
|
|
8360
|
+
pressure: "hPa",
|
|
8361
|
+
speed: "m/s",
|
|
8362
|
+
precipitation: "mm",
|
|
8363
|
+
"precipitation-rate": "mm/h",
|
|
8364
|
+
length: "m",
|
|
8365
|
+
area: "m²",
|
|
8366
|
+
illuminance: "lx",
|
|
8367
|
+
irradiance: "W/m²",
|
|
8368
|
+
power: "W",
|
|
8369
|
+
energy: "kWh",
|
|
8370
|
+
voltage: "V",
|
|
8371
|
+
current: "A",
|
|
8372
|
+
"apparent-power": "VA",
|
|
8373
|
+
humidity: "%",
|
|
8374
|
+
percentage: "%",
|
|
8375
|
+
"concentration-volume": "ppm",
|
|
8376
|
+
"concentration-mass": "µg/m³",
|
|
8377
|
+
"concentration-ppb": "ppb",
|
|
8378
|
+
volume: "L",
|
|
8379
|
+
duration: "s",
|
|
8380
|
+
"duration-ms": "ms",
|
|
8381
|
+
information: "B",
|
|
8382
|
+
"sound-level": "dBFS",
|
|
8383
|
+
"signal-level": "dBm",
|
|
8384
|
+
"colour-temperature": "mired",
|
|
8385
|
+
angle: "°",
|
|
8386
|
+
bitrate: "kbps",
|
|
8387
|
+
rate: "fps",
|
|
8388
|
+
mass: "kg",
|
|
8389
|
+
index: "none",
|
|
8390
|
+
ratio: "none",
|
|
8391
|
+
count: "none",
|
|
8392
|
+
none: "none",
|
|
8393
|
+
device: "device"
|
|
8394
|
+
};
|
|
8395
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
8396
|
+
function baseUnitOf(quantity) {
|
|
8397
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
8398
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
8399
|
+
return symbol;
|
|
8400
|
+
}
|
|
8401
|
+
function readingMeta(quantity, extras) {
|
|
8402
|
+
return {
|
|
8403
|
+
quantity,
|
|
8404
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8405
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8406
|
+
};
|
|
8407
|
+
}
|
|
8312
8408
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
8313
8409
|
var CamProfileSchema = _enum([
|
|
8314
8410
|
"high",
|
|
@@ -8336,8 +8432,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8336
8432
|
"derived"
|
|
8337
8433
|
]);
|
|
8338
8434
|
var CamStreamResolutionSchema = object({
|
|
8339
|
-
width: number().int().positive(),
|
|
8340
|
-
height: number().int().positive()
|
|
8435
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8436
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8341
8437
|
});
|
|
8342
8438
|
var CameraStreamSchema = object({
|
|
8343
8439
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8914,6 +9010,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
8914
9010
|
"filesystem-browse",
|
|
8915
9011
|
"flood",
|
|
8916
9012
|
"gas",
|
|
9013
|
+
"group-status",
|
|
8917
9014
|
"heating-valve",
|
|
8918
9015
|
"humidifier",
|
|
8919
9016
|
"humidity-sensor",
|
|
@@ -9043,14 +9140,6 @@ Object.freeze({
|
|
|
9043
9140
|
{
|
|
9044
9141
|
"path": "aqi",
|
|
9045
9142
|
"valueType": "number"
|
|
9046
|
-
},
|
|
9047
|
-
{
|
|
9048
|
-
"path": "unit",
|
|
9049
|
-
"valueType": "string"
|
|
9050
|
-
},
|
|
9051
|
-
{
|
|
9052
|
-
"path": "precision",
|
|
9053
|
-
"valueType": "number"
|
|
9054
9143
|
}
|
|
9055
9144
|
],
|
|
9056
9145
|
"alarm-panel": [
|
|
@@ -9086,20 +9175,10 @@ Object.freeze({
|
|
|
9086
9175
|
"valueType": "boolean"
|
|
9087
9176
|
}
|
|
9088
9177
|
],
|
|
9089
|
-
"ambient-light-sensor": [
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
},
|
|
9094
|
-
{
|
|
9095
|
-
"path": "unit",
|
|
9096
|
-
"valueType": "string"
|
|
9097
|
-
},
|
|
9098
|
-
{
|
|
9099
|
-
"path": "precision",
|
|
9100
|
-
"valueType": "number"
|
|
9101
|
-
}
|
|
9102
|
-
],
|
|
9178
|
+
"ambient-light-sensor": [{
|
|
9179
|
+
"path": "lux",
|
|
9180
|
+
"valueType": "number"
|
|
9181
|
+
}],
|
|
9103
9182
|
"audio-metrics": [
|
|
9104
9183
|
{
|
|
9105
9184
|
"path": "ts",
|
|
@@ -9179,6 +9258,10 @@ Object.freeze({
|
|
|
9179
9258
|
"path": "lastUpdated",
|
|
9180
9259
|
"valueType": "number"
|
|
9181
9260
|
},
|
|
9261
|
+
{
|
|
9262
|
+
"path": "volts",
|
|
9263
|
+
"valueType": "number"
|
|
9264
|
+
},
|
|
9182
9265
|
{
|
|
9183
9266
|
"path": "lastContactAt",
|
|
9184
9267
|
"valueType": "number"
|
|
@@ -9421,10 +9504,6 @@ Object.freeze({
|
|
|
9421
9504
|
"datetime"
|
|
9422
9505
|
]
|
|
9423
9506
|
},
|
|
9424
|
-
{
|
|
9425
|
-
"path": "unit",
|
|
9426
|
-
"valueType": "string"
|
|
9427
|
-
},
|
|
9428
9507
|
{
|
|
9429
9508
|
"path": "min",
|
|
9430
9509
|
"valueType": "number"
|
|
@@ -9436,19 +9515,6 @@ Object.freeze({
|
|
|
9436
9515
|
{
|
|
9437
9516
|
"path": "step",
|
|
9438
9517
|
"valueType": "number"
|
|
9439
|
-
},
|
|
9440
|
-
{
|
|
9441
|
-
"path": "precision",
|
|
9442
|
-
"valueType": "number"
|
|
9443
|
-
},
|
|
9444
|
-
{
|
|
9445
|
-
"path": "format",
|
|
9446
|
-
"valueType": "enum",
|
|
9447
|
-
"enumValues": [
|
|
9448
|
-
"date",
|
|
9449
|
-
"time",
|
|
9450
|
-
"datetime"
|
|
9451
|
-
]
|
|
9452
9518
|
}
|
|
9453
9519
|
],
|
|
9454
9520
|
"cover": [
|
|
@@ -9689,13 +9755,8 @@ Object.freeze({
|
|
|
9689
9755
|
"path": "value",
|
|
9690
9756
|
"valueType": "string"
|
|
9691
9757
|
}, {
|
|
9692
|
-
"path": "
|
|
9693
|
-
"valueType": "
|
|
9694
|
-
"enumValues": [
|
|
9695
|
-
"date",
|
|
9696
|
-
"time",
|
|
9697
|
-
"datetime"
|
|
9698
|
-
]
|
|
9758
|
+
"path": "timestamp",
|
|
9759
|
+
"valueType": "boolean"
|
|
9699
9760
|
}],
|
|
9700
9761
|
"event-emitter": [
|
|
9701
9762
|
{
|
|
@@ -9768,6 +9829,20 @@ Object.freeze({
|
|
|
9768
9829
|
"path": "detected",
|
|
9769
9830
|
"valueType": "boolean"
|
|
9770
9831
|
}],
|
|
9832
|
+
"group-status": [
|
|
9833
|
+
{
|
|
9834
|
+
"path": "included",
|
|
9835
|
+
"valueType": "number"
|
|
9836
|
+
},
|
|
9837
|
+
{
|
|
9838
|
+
"path": "excluded",
|
|
9839
|
+
"valueType": "number"
|
|
9840
|
+
},
|
|
9841
|
+
{
|
|
9842
|
+
"path": "total",
|
|
9843
|
+
"valueType": "number"
|
|
9844
|
+
}
|
|
9845
|
+
],
|
|
9771
9846
|
"heating-valve": [{
|
|
9772
9847
|
"path": "position",
|
|
9773
9848
|
"valueType": "number"
|
|
@@ -9802,20 +9877,10 @@ Object.freeze({
|
|
|
9802
9877
|
"valueType": "number"
|
|
9803
9878
|
}
|
|
9804
9879
|
],
|
|
9805
|
-
"humidity-sensor": [
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
},
|
|
9810
|
-
{
|
|
9811
|
-
"path": "unit",
|
|
9812
|
-
"valueType": "string"
|
|
9813
|
-
},
|
|
9814
|
-
{
|
|
9815
|
-
"path": "precision",
|
|
9816
|
-
"valueType": "number"
|
|
9817
|
-
}
|
|
9818
|
-
],
|
|
9880
|
+
"humidity-sensor": [{
|
|
9881
|
+
"path": "percent",
|
|
9882
|
+
"valueType": "number"
|
|
9883
|
+
}],
|
|
9819
9884
|
"image": [{
|
|
9820
9885
|
"path": "url",
|
|
9821
9886
|
"valueType": "string"
|
|
@@ -10154,20 +10219,10 @@ Object.freeze({
|
|
|
10154
10219
|
"valueType": "boolean"
|
|
10155
10220
|
}
|
|
10156
10221
|
],
|
|
10157
|
-
"numeric-sensor": [
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
},
|
|
10162
|
-
{
|
|
10163
|
-
"path": "unit",
|
|
10164
|
-
"valueType": "string"
|
|
10165
|
-
},
|
|
10166
|
-
{
|
|
10167
|
-
"path": "precision",
|
|
10168
|
-
"valueType": "number"
|
|
10169
|
-
}
|
|
10170
|
-
],
|
|
10222
|
+
"numeric-sensor": [{
|
|
10223
|
+
"path": "value",
|
|
10224
|
+
"valueType": "number"
|
|
10225
|
+
}],
|
|
10171
10226
|
"pet-feeder": [
|
|
10172
10227
|
{
|
|
10173
10228
|
"path": "foodLevel",
|
|
@@ -10259,14 +10314,6 @@ Object.freeze({
|
|
|
10259
10314
|
{
|
|
10260
10315
|
"path": "powerFactor",
|
|
10261
10316
|
"valueType": "number"
|
|
10262
|
-
},
|
|
10263
|
-
{
|
|
10264
|
-
"path": "unit",
|
|
10265
|
-
"valueType": "string"
|
|
10266
|
-
},
|
|
10267
|
-
{
|
|
10268
|
-
"path": "precision",
|
|
10269
|
-
"valueType": "number"
|
|
10270
10317
|
}
|
|
10271
10318
|
],
|
|
10272
10319
|
"presence": [
|
|
@@ -10295,20 +10342,10 @@ Object.freeze({
|
|
|
10295
10342
|
"valueType": "number"
|
|
10296
10343
|
}
|
|
10297
10344
|
],
|
|
10298
|
-
"pressure-sensor": [
|
|
10299
|
-
|
|
10300
|
-
|
|
10301
|
-
|
|
10302
|
-
},
|
|
10303
|
-
{
|
|
10304
|
-
"path": "unit",
|
|
10305
|
-
"valueType": "string"
|
|
10306
|
-
},
|
|
10307
|
-
{
|
|
10308
|
-
"path": "precision",
|
|
10309
|
-
"valueType": "number"
|
|
10310
|
-
}
|
|
10311
|
-
],
|
|
10345
|
+
"pressure-sensor": [{
|
|
10346
|
+
"path": "hpa",
|
|
10347
|
+
"valueType": "number"
|
|
10348
|
+
}],
|
|
10312
10349
|
"privacy-mask": [{
|
|
10313
10350
|
"path": "enabled",
|
|
10314
10351
|
"valueType": "boolean"
|
|
@@ -10619,20 +10656,10 @@ Object.freeze({
|
|
|
10619
10656
|
"path": "tampered",
|
|
10620
10657
|
"valueType": "boolean"
|
|
10621
10658
|
}],
|
|
10622
|
-
"temperature-sensor": [
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
},
|
|
10627
|
-
{
|
|
10628
|
-
"path": "unit",
|
|
10629
|
-
"valueType": "string"
|
|
10630
|
-
},
|
|
10631
|
-
{
|
|
10632
|
-
"path": "precision",
|
|
10633
|
-
"valueType": "number"
|
|
10634
|
-
}
|
|
10635
|
-
],
|
|
10659
|
+
"temperature-sensor": [{
|
|
10660
|
+
"path": "celsius",
|
|
10661
|
+
"valueType": "number"
|
|
10662
|
+
}],
|
|
10636
10663
|
"update": [
|
|
10637
10664
|
{
|
|
10638
10665
|
"path": "currentVersion",
|
|
@@ -10743,10 +10770,6 @@ Object.freeze({
|
|
|
10743
10770
|
"path": "temperature",
|
|
10744
10771
|
"valueType": "number"
|
|
10745
10772
|
},
|
|
10746
|
-
{
|
|
10747
|
-
"path": "temperatureUnit",
|
|
10748
|
-
"valueType": "string"
|
|
10749
|
-
},
|
|
10750
10773
|
{
|
|
10751
10774
|
"path": "humidity",
|
|
10752
10775
|
"valueType": "number"
|
|
@@ -10755,18 +10778,10 @@ Object.freeze({
|
|
|
10755
10778
|
"path": "pressure",
|
|
10756
10779
|
"valueType": "number"
|
|
10757
10780
|
},
|
|
10758
|
-
{
|
|
10759
|
-
"path": "pressureUnit",
|
|
10760
|
-
"valueType": "string"
|
|
10761
|
-
},
|
|
10762
10781
|
{
|
|
10763
10782
|
"path": "windSpeed",
|
|
10764
10783
|
"valueType": "number"
|
|
10765
10784
|
},
|
|
10766
|
-
{
|
|
10767
|
-
"path": "windSpeedUnit",
|
|
10768
|
-
"valueType": "string"
|
|
10769
|
-
},
|
|
10770
10785
|
{
|
|
10771
10786
|
"path": "windBearing",
|
|
10772
10787
|
"valueType": "number"
|
|
@@ -11169,7 +11184,7 @@ function errMsg(err) {
|
|
|
11169
11184
|
return String(err);
|
|
11170
11185
|
}
|
|
11171
11186
|
//#endregion
|
|
11172
|
-
//#region ../types/dist/composition-
|
|
11187
|
+
//#region ../types/dist/composition-B85l9j1M.mjs
|
|
11173
11188
|
/**
|
|
11174
11189
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
11175
11190
|
*
|
|
@@ -11924,15 +11939,67 @@ function validateExpressionSource(src) {
|
|
|
11924
11939
|
}
|
|
11925
11940
|
return null;
|
|
11926
11941
|
}
|
|
11927
|
-
/**
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11942
|
+
/**
|
|
11943
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
11944
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
11945
|
+
* `composition.ts` (D659).
|
|
11946
|
+
*/
|
|
11931
11947
|
var CompositionSourceRefSchema = object({
|
|
11932
11948
|
/** The owning addon; `stableId` is unique only within it. */
|
|
11933
11949
|
addonId: string().min(1),
|
|
11934
11950
|
stableId: string().min(1)
|
|
11935
11951
|
});
|
|
11952
|
+
var GROUP_TEMPLATE_IDS = [
|
|
11953
|
+
"temperature",
|
|
11954
|
+
"humidity",
|
|
11955
|
+
"pressure",
|
|
11956
|
+
"illuminance",
|
|
11957
|
+
"power",
|
|
11958
|
+
"energy",
|
|
11959
|
+
"battery",
|
|
11960
|
+
"numeric",
|
|
11961
|
+
"motion",
|
|
11962
|
+
"contact",
|
|
11963
|
+
"leak",
|
|
11964
|
+
"smoke",
|
|
11965
|
+
"occupancy",
|
|
11966
|
+
"binary"
|
|
11967
|
+
];
|
|
11968
|
+
var NUMERIC_AGGREGATES = [
|
|
11969
|
+
"mean",
|
|
11970
|
+
"median",
|
|
11971
|
+
"min",
|
|
11972
|
+
"max",
|
|
11973
|
+
"sum"
|
|
11974
|
+
];
|
|
11975
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
11976
|
+
var AGGREGATE_REDUCERS = [
|
|
11977
|
+
"mean",
|
|
11978
|
+
"median",
|
|
11979
|
+
"min",
|
|
11980
|
+
"max",
|
|
11981
|
+
"sum",
|
|
11982
|
+
"any",
|
|
11983
|
+
"all"
|
|
11984
|
+
];
|
|
11985
|
+
var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
|
|
11986
|
+
var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
|
|
11987
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
11988
|
+
var HelperMemberSchema = object({
|
|
11989
|
+
source: CompositionSourceRefSchema,
|
|
11990
|
+
cap: string().min(1),
|
|
11991
|
+
fieldPath: string().min(1)
|
|
11992
|
+
});
|
|
11993
|
+
var HelperSpecSchema = discriminatedUnion("kind", [object({
|
|
11994
|
+
kind: literal("group"),
|
|
11995
|
+
templateId: GroupTemplateIdSchema,
|
|
11996
|
+
aggregate: AggregateReducerSchema,
|
|
11997
|
+
members: array(HelperMemberSchema).min(1).max(64)
|
|
11998
|
+
})]);
|
|
11999
|
+
/** A composed device's stableId is this prefix plus the block id. */
|
|
12000
|
+
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
12001
|
+
/** Longest snippet a `code` source may carry (slice 4). */
|
|
12002
|
+
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
11936
12003
|
/** One field of one capability of one source device. */
|
|
11937
12004
|
var CompositionFieldReadSchema = object({
|
|
11938
12005
|
source: CompositionSourceRefSchema,
|
|
@@ -11976,7 +12043,33 @@ var CompositionCodeSourceSchema = object({
|
|
|
11976
12043
|
var CompositionFieldSourceSchema = discriminatedUnion("kind", [
|
|
11977
12044
|
CompositionFromSourceSchema,
|
|
11978
12045
|
CompositionExpressionSourceSchema,
|
|
11979
|
-
CompositionCodeSourceSchema
|
|
12046
|
+
CompositionCodeSourceSchema,
|
|
12047
|
+
object({
|
|
12048
|
+
kind: literal("aggregate"),
|
|
12049
|
+
reducer: _enum([
|
|
12050
|
+
"mean",
|
|
12051
|
+
"median",
|
|
12052
|
+
"min",
|
|
12053
|
+
"max",
|
|
12054
|
+
"sum",
|
|
12055
|
+
"any",
|
|
12056
|
+
"all"
|
|
12057
|
+
]),
|
|
12058
|
+
reads: array(CompositionFieldReadSchema).min(1).max(64),
|
|
12059
|
+
/** `value` is the reading; the others are the member counts. */
|
|
12060
|
+
publish: _enum([
|
|
12061
|
+
"value",
|
|
12062
|
+
"included",
|
|
12063
|
+
"excluded",
|
|
12064
|
+
"total"
|
|
12065
|
+
]),
|
|
12066
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
12067
|
+
empty: _enum([
|
|
12068
|
+
"null",
|
|
12069
|
+
"omit",
|
|
12070
|
+
"offline"
|
|
12071
|
+
])
|
|
12072
|
+
})
|
|
11980
12073
|
]);
|
|
11981
12074
|
var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
|
|
11982
12075
|
kind: literal("forward"),
|
|
@@ -12022,7 +12115,13 @@ var CompositionSchema = object({
|
|
|
12022
12115
|
kind: literal("existing"),
|
|
12023
12116
|
device: CompositionSourceRefSchema
|
|
12024
12117
|
})]),
|
|
12025
|
-
features: array(CompositionFeatureSchema).min(1).max(16)
|
|
12118
|
+
features: array(CompositionFeatureSchema).min(1).max(16),
|
|
12119
|
+
/**
|
|
12120
|
+
* Present when the block is a helper template. Absent on a free
|
|
12121
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
12122
|
+
* never the compiled features.
|
|
12123
|
+
*/
|
|
12124
|
+
helper: HelperSpecSchema.optional()
|
|
12026
12125
|
}).superRefine((composition, ctx) => {
|
|
12027
12126
|
const seen = /* @__PURE__ */ new Set();
|
|
12028
12127
|
composition.features.forEach((feature, index) => {
|
|
@@ -18442,7 +18541,11 @@ var CompositionProblemSchema = object({
|
|
|
18442
18541
|
"item-field-reserved",
|
|
18443
18542
|
"target-missing",
|
|
18444
18543
|
"target-unreadable",
|
|
18445
|
-
"not-replaceable"
|
|
18544
|
+
"not-replaceable",
|
|
18545
|
+
"native-capability-replace",
|
|
18546
|
+
"mixed-quantity",
|
|
18547
|
+
"helper-mismatch",
|
|
18548
|
+
"member-constraint"
|
|
18446
18549
|
]),
|
|
18447
18550
|
path: string(),
|
|
18448
18551
|
message: string()
|
|
@@ -18463,7 +18566,8 @@ var CompositionUnavailableModeSchema = _enum([
|
|
|
18463
18566
|
"null",
|
|
18464
18567
|
"offline",
|
|
18465
18568
|
"unknown",
|
|
18466
|
-
"release"
|
|
18569
|
+
"release",
|
|
18570
|
+
"omit"
|
|
18467
18571
|
]);
|
|
18468
18572
|
/**
|
|
18469
18573
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -18500,9 +18604,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
18500
18604
|
reads: array(CompositionFieldReadSchema)
|
|
18501
18605
|
});
|
|
18502
18606
|
/**
|
|
18503
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
18504
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
18505
|
-
*
|
|
18607
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
18608
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
18609
|
+
* Replacing a capability the device already serves is refused
|
|
18610
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
18611
|
+
* wire for a claim the hub already holds.
|
|
18506
18612
|
*/
|
|
18507
18613
|
var CompositionFeatureModeSchema = _enum([
|
|
18508
18614
|
"new",
|
|
@@ -18675,6 +18781,235 @@ Object.freeze({
|
|
|
18675
18781
|
result: ["number", "null"]
|
|
18676
18782
|
}
|
|
18677
18783
|
});
|
|
18784
|
+
/**
|
|
18785
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18786
|
+
* Data, not a form default written into the block.
|
|
18787
|
+
*/
|
|
18788
|
+
var NOW = {
|
|
18789
|
+
fieldPath: "lastFetchedAt",
|
|
18790
|
+
expr: "now"
|
|
18791
|
+
};
|
|
18792
|
+
var CHANGED = {
|
|
18793
|
+
fieldPath: "lastChangedAt",
|
|
18794
|
+
expr: "now"
|
|
18795
|
+
};
|
|
18796
|
+
function numeric(input) {
|
|
18797
|
+
return {
|
|
18798
|
+
...input,
|
|
18799
|
+
family: "numeric",
|
|
18800
|
+
deviceType: DeviceType.Sensor,
|
|
18801
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18802
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18803
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18804
|
+
accept: [{
|
|
18805
|
+
cap: input.outputCap,
|
|
18806
|
+
fieldPath: input.outputField
|
|
18807
|
+
}]
|
|
18808
|
+
};
|
|
18809
|
+
}
|
|
18810
|
+
function binary(input) {
|
|
18811
|
+
return {
|
|
18812
|
+
...input,
|
|
18813
|
+
family: "binary",
|
|
18814
|
+
deviceType: DeviceType.Sensor,
|
|
18815
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18816
|
+
quantity: "none",
|
|
18817
|
+
baseUnit: void 0,
|
|
18818
|
+
aggregates: BINARY_AGGREGATES,
|
|
18819
|
+
empty: "offline"
|
|
18820
|
+
};
|
|
18821
|
+
}
|
|
18822
|
+
var GROUP_TEMPLATES = [
|
|
18823
|
+
numeric({
|
|
18824
|
+
id: "temperature",
|
|
18825
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18826
|
+
role: DeviceRole.TemperatureSensor,
|
|
18827
|
+
outputCap: "temperature-sensor",
|
|
18828
|
+
outputField: "celsius",
|
|
18829
|
+
quantity: "temperature",
|
|
18830
|
+
defaultAggregate: "mean",
|
|
18831
|
+
empty: "null",
|
|
18832
|
+
companions: [NOW]
|
|
18833
|
+
}),
|
|
18834
|
+
numeric({
|
|
18835
|
+
id: "humidity",
|
|
18836
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18837
|
+
role: DeviceRole.HumiditySensor,
|
|
18838
|
+
outputCap: "humidity-sensor",
|
|
18839
|
+
outputField: "percent",
|
|
18840
|
+
quantity: "humidity",
|
|
18841
|
+
defaultAggregate: "mean",
|
|
18842
|
+
empty: "null",
|
|
18843
|
+
companions: [NOW]
|
|
18844
|
+
}),
|
|
18845
|
+
numeric({
|
|
18846
|
+
id: "pressure",
|
|
18847
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18848
|
+
role: DeviceRole.PressureSensor,
|
|
18849
|
+
outputCap: "pressure-sensor",
|
|
18850
|
+
outputField: "hpa",
|
|
18851
|
+
quantity: "pressure",
|
|
18852
|
+
defaultAggregate: "mean",
|
|
18853
|
+
empty: "null",
|
|
18854
|
+
companions: [NOW]
|
|
18855
|
+
}),
|
|
18856
|
+
numeric({
|
|
18857
|
+
id: "illuminance",
|
|
18858
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18859
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18860
|
+
outputCap: "ambient-light-sensor",
|
|
18861
|
+
outputField: "lux",
|
|
18862
|
+
quantity: "illuminance",
|
|
18863
|
+
defaultAggregate: "mean",
|
|
18864
|
+
empty: "null",
|
|
18865
|
+
companions: [NOW]
|
|
18866
|
+
}),
|
|
18867
|
+
numeric({
|
|
18868
|
+
id: "power",
|
|
18869
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18870
|
+
role: DeviceRole.PowerSensor,
|
|
18871
|
+
outputCap: "power-meter",
|
|
18872
|
+
outputField: "watts",
|
|
18873
|
+
quantity: "power",
|
|
18874
|
+
defaultAggregate: "sum",
|
|
18875
|
+
empty: "omit",
|
|
18876
|
+
companions: [NOW]
|
|
18877
|
+
}),
|
|
18878
|
+
numeric({
|
|
18879
|
+
id: "energy",
|
|
18880
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18881
|
+
role: DeviceRole.EnergySensor,
|
|
18882
|
+
outputCap: "power-meter",
|
|
18883
|
+
outputField: "kwhTotal",
|
|
18884
|
+
quantity: "energy",
|
|
18885
|
+
defaultAggregate: "sum",
|
|
18886
|
+
empty: "omit",
|
|
18887
|
+
companions: [NOW]
|
|
18888
|
+
}),
|
|
18889
|
+
numeric({
|
|
18890
|
+
id: "battery",
|
|
18891
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18892
|
+
role: DeviceRole.BatterySensor,
|
|
18893
|
+
outputCap: "battery",
|
|
18894
|
+
outputField: "percentage",
|
|
18895
|
+
quantity: "percentage",
|
|
18896
|
+
defaultAggregate: "mean",
|
|
18897
|
+
empty: "null",
|
|
18898
|
+
companions: [
|
|
18899
|
+
{
|
|
18900
|
+
fieldPath: "charging",
|
|
18901
|
+
expr: "\"unknown\""
|
|
18902
|
+
},
|
|
18903
|
+
{
|
|
18904
|
+
fieldPath: "sleeping",
|
|
18905
|
+
expr: "false"
|
|
18906
|
+
},
|
|
18907
|
+
{
|
|
18908
|
+
fieldPath: "lastUpdated",
|
|
18909
|
+
expr: "now"
|
|
18910
|
+
}
|
|
18911
|
+
]
|
|
18912
|
+
}),
|
|
18913
|
+
numeric({
|
|
18914
|
+
id: "numeric",
|
|
18915
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18916
|
+
role: DeviceRole.NumericSensor,
|
|
18917
|
+
outputCap: "numeric-sensor",
|
|
18918
|
+
outputField: "value",
|
|
18919
|
+
quantity: "device",
|
|
18920
|
+
defaultAggregate: "mean",
|
|
18921
|
+
empty: "null",
|
|
18922
|
+
companions: [NOW]
|
|
18923
|
+
}),
|
|
18924
|
+
binary({
|
|
18925
|
+
id: "motion",
|
|
18926
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18927
|
+
role: DeviceRole.MotionSensor,
|
|
18928
|
+
outputCap: "motion",
|
|
18929
|
+
outputField: "detected",
|
|
18930
|
+
defaultAggregate: "any",
|
|
18931
|
+
accept: [{
|
|
18932
|
+
cap: "motion",
|
|
18933
|
+
fieldPath: "detected"
|
|
18934
|
+
}],
|
|
18935
|
+
companions: [{
|
|
18936
|
+
fieldPath: "lastDetectedAt",
|
|
18937
|
+
expr: "null"
|
|
18938
|
+
}, {
|
|
18939
|
+
fieldPath: "autoClearAfterMs",
|
|
18940
|
+
expr: "null"
|
|
18941
|
+
}]
|
|
18942
|
+
}),
|
|
18943
|
+
binary({
|
|
18944
|
+
id: "contact",
|
|
18945
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18946
|
+
role: DeviceRole.ContactSensor,
|
|
18947
|
+
outputCap: "contact",
|
|
18948
|
+
outputField: "entryOpen",
|
|
18949
|
+
defaultAggregate: "any",
|
|
18950
|
+
accept: [{
|
|
18951
|
+
cap: "contact",
|
|
18952
|
+
fieldPath: "entryOpen"
|
|
18953
|
+
}],
|
|
18954
|
+
companions: [CHANGED]
|
|
18955
|
+
}),
|
|
18956
|
+
binary({
|
|
18957
|
+
id: "leak",
|
|
18958
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18959
|
+
role: DeviceRole.LeakSensor,
|
|
18960
|
+
outputCap: "flood",
|
|
18961
|
+
outputField: "flooded",
|
|
18962
|
+
defaultAggregate: "any",
|
|
18963
|
+
accept: [{
|
|
18964
|
+
cap: "flood",
|
|
18965
|
+
fieldPath: "flooded"
|
|
18966
|
+
}],
|
|
18967
|
+
companions: [CHANGED]
|
|
18968
|
+
}),
|
|
18969
|
+
binary({
|
|
18970
|
+
id: "smoke",
|
|
18971
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18972
|
+
role: DeviceRole.SmokeSensor,
|
|
18973
|
+
outputCap: "smoke",
|
|
18974
|
+
outputField: "detected",
|
|
18975
|
+
defaultAggregate: "any",
|
|
18976
|
+
accept: [{
|
|
18977
|
+
cap: "smoke",
|
|
18978
|
+
fieldPath: "detected"
|
|
18979
|
+
}],
|
|
18980
|
+
companions: [CHANGED]
|
|
18981
|
+
}),
|
|
18982
|
+
binary({
|
|
18983
|
+
id: "occupancy",
|
|
18984
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18985
|
+
role: DeviceRole.BinarySensor,
|
|
18986
|
+
outputCap: "binary",
|
|
18987
|
+
outputField: "on",
|
|
18988
|
+
defaultAggregate: "any",
|
|
18989
|
+
accept: [{
|
|
18990
|
+
cap: "motion",
|
|
18991
|
+
fieldPath: "detected"
|
|
18992
|
+
}, {
|
|
18993
|
+
cap: "binary",
|
|
18994
|
+
fieldPath: "on"
|
|
18995
|
+
}],
|
|
18996
|
+
companions: [CHANGED]
|
|
18997
|
+
}),
|
|
18998
|
+
binary({
|
|
18999
|
+
id: "binary",
|
|
19000
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
19001
|
+
role: DeviceRole.BinarySensor,
|
|
19002
|
+
outputCap: "binary",
|
|
19003
|
+
outputField: "on",
|
|
19004
|
+
defaultAggregate: "any",
|
|
19005
|
+
accept: [{
|
|
19006
|
+
cap: "binary",
|
|
19007
|
+
fieldPath: "on"
|
|
19008
|
+
}],
|
|
19009
|
+
companions: [CHANGED]
|
|
19010
|
+
})
|
|
19011
|
+
];
|
|
19012
|
+
new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18678
19013
|
`${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
|
|
18679
19014
|
/**
|
|
18680
19015
|
* What a composition may BUILD on a device type (G2, D676): the caps a new
|
|
@@ -20535,12 +20870,12 @@ function parseAdminBase(baseUrl) {
|
|
|
20535
20870
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20536
20871
|
* in-place so dispatch keeps working.
|
|
20537
20872
|
*
|
|
20538
|
-
* **
|
|
20539
|
-
*
|
|
20540
|
-
*
|
|
20541
|
-
*
|
|
20542
|
-
* (`ha-domain-mapping`)
|
|
20543
|
-
* stored after that point.
|
|
20873
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
20874
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
20875
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
20876
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
20877
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
20878
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20544
20879
|
*
|
|
20545
20880
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20546
20881
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20554,6 +20889,14 @@ var SourceInfoSchema = object({
|
|
|
20554
20889
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20555
20890
|
* Used to detect rename when `id` changes. */
|
|
20556
20891
|
uniqueId: string().optional(),
|
|
20892
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
20893
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
20894
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
20895
|
+
dateTimeShape: _enum([
|
|
20896
|
+
"date",
|
|
20897
|
+
"time",
|
|
20898
|
+
"datetime"
|
|
20899
|
+
]).optional(),
|
|
20557
20900
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20558
20901
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20559
20902
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -20638,9 +20981,38 @@ function normalizeUnit(raw) {
|
|
|
20638
20981
|
if (lower === "mph") return "mph";
|
|
20639
20982
|
if (lower === "m/s") return "m/s";
|
|
20640
20983
|
if (lower === "m") return "m";
|
|
20984
|
+
if (lower === "m²" || lower === "m2") return "m²";
|
|
20985
|
+
if (lower === "mm") return "mm";
|
|
20986
|
+
if (lower === "cm") return "cm";
|
|
20641
20987
|
if (lower === "km") return "km";
|
|
20988
|
+
if (lower === "in" || lower === "inch" || lower === "inches") return "in";
|
|
20989
|
+
if (lower === "ft" || lower === "foot" || lower === "feet") return "ft";
|
|
20642
20990
|
if (lower === "kg") return "kg";
|
|
20643
20991
|
if (lower === "g") return "g";
|
|
20992
|
+
if (lower === "l" || lower === "liter" || lower === "litre" || lower === "liters" || lower === "litres") return "L";
|
|
20993
|
+
if (lower === "ml") return "mL";
|
|
20994
|
+
if (lower === "gal" || lower === "gallon" || lower === "gallons") return "gal";
|
|
20995
|
+
if (lower === "s" || lower === "sec" || lower === "second" || lower === "seconds") return "s";
|
|
20996
|
+
if (lower === "ms") return "ms";
|
|
20997
|
+
if (lower === "min" || lower === "minute" || lower === "minutes") return "min";
|
|
20998
|
+
if (lower === "h" || lower === "hr" || lower === "hour" || lower === "hours") return "h";
|
|
20999
|
+
if (lower === "d" || lower === "day" || lower === "days") return "d";
|
|
21000
|
+
if (lower === "b" || lower === "byte" || lower === "bytes") return "B";
|
|
21001
|
+
if (lower === "kib") return "KiB";
|
|
21002
|
+
if (lower === "mib") return "MiB";
|
|
21003
|
+
if (lower === "gib") return "GiB";
|
|
21004
|
+
if (lower === "tib") return "TiB";
|
|
21005
|
+
if (lower === "kb") return "kB";
|
|
21006
|
+
if (lower === "mb") return "MB";
|
|
21007
|
+
if (lower === "gb") return "GB";
|
|
21008
|
+
if (lower === "dbm") return "dBm";
|
|
21009
|
+
if (lower === "dbfs") return "dBFS";
|
|
21010
|
+
if (lower === "inhg") return "inHg";
|
|
21011
|
+
if (lower === "mm/h") return "mm/h";
|
|
21012
|
+
if (lower === "w/m²" || lower === "w/m2") return "W/m²";
|
|
21013
|
+
if (lower === "°" || lower === "deg" || lower === "degree" || lower === "degrees") return "°";
|
|
21014
|
+
if (lower === "kbps") return "kbps";
|
|
21015
|
+
if (lower === "fps") return "fps";
|
|
20644
21016
|
return trimmed;
|
|
20645
21017
|
}
|
|
20646
21018
|
/**
|
|
@@ -41745,7 +42117,8 @@ method(object({
|
|
|
41745
42117
|
"enum"
|
|
41746
42118
|
]),
|
|
41747
42119
|
enumValues: array(string()).optional(),
|
|
41748
|
-
item: boolean().optional()
|
|
42120
|
+
item: boolean().optional(),
|
|
42121
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41749
42122
|
})).readonly(),
|
|
41750
42123
|
itemArray: object({
|
|
41751
42124
|
path: string(),
|
|
@@ -45611,8 +45984,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
45611
45984
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
45612
45985
|
var MaskGridShapeSchema = object({
|
|
45613
45986
|
kind: literal("grid"),
|
|
45614
|
-
gridWidth: number(),
|
|
45615
|
-
gridHeight: number(),
|
|
45987
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
45988
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
45616
45989
|
cells: array(boolean())
|
|
45617
45990
|
});
|
|
45618
45991
|
discriminatedUnion("kind", [
|
|
@@ -57180,27 +57553,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
57180
57553
|
*/
|
|
57181
57554
|
var AirQualitySensorStatusSchema = object({
|
|
57182
57555
|
/** Carbon dioxide concentration in ppm. */
|
|
57183
|
-
co2Ppm: number().min(0).optional(),
|
|
57556
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
57184
57557
|
/** Total volatile organic compounds in ppb. */
|
|
57185
|
-
vocPpb: number().min(0).optional(),
|
|
57558
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
57186
57559
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
57187
|
-
pm25: number().min(0).optional(),
|
|
57560
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
57188
57561
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
57189
|
-
pm10: number().min(0).optional(),
|
|
57562
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
57190
57563
|
/** Composite AQI value (typically 0..500). */
|
|
57191
|
-
aqi: number().optional(),
|
|
57564
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
57192
57565
|
/** Ms epoch when the slice was last updated. */
|
|
57193
|
-
lastFetchedAt: number()
|
|
57194
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
57195
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
57196
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
57197
|
-
* per slice is unambiguous. */
|
|
57198
|
-
unit: string().optional(),
|
|
57199
|
-
/** Suggested decimal places for numeric display.
|
|
57200
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57201
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57202
|
-
* auto-formatting when absent. */
|
|
57203
|
-
precision: number().int().min(0).max(10).optional()
|
|
57566
|
+
lastFetchedAt: number()
|
|
57204
57567
|
});
|
|
57205
57568
|
var airQualitySensorCapability = {
|
|
57206
57569
|
name: "air-quality-sensor",
|
|
@@ -57237,12 +57600,12 @@ var airQualitySensorCapability = {
|
|
|
57237
57600
|
},
|
|
57238
57601
|
pm25: {
|
|
57239
57602
|
kind: "gauge",
|
|
57240
|
-
unit: "
|
|
57603
|
+
unit: "µg/m³",
|
|
57241
57604
|
deadband: 1
|
|
57242
57605
|
},
|
|
57243
57606
|
pm10: {
|
|
57244
57607
|
kind: "gauge",
|
|
57245
|
-
unit: "
|
|
57608
|
+
unit: "µg/m³",
|
|
57246
57609
|
deadband: 1
|
|
57247
57610
|
},
|
|
57248
57611
|
aqi: {
|
|
@@ -57260,22 +57623,13 @@ var airQualitySensorCapability = {
|
|
|
57260
57623
|
* entries with `device_class: illuminance`.
|
|
57261
57624
|
*/
|
|
57262
57625
|
var AmbientLightSensorStatusSchema = object({
|
|
57263
|
-
/** Current illuminance in lux (lx). */
|
|
57264
|
-
lux: number().min(0).meta({
|
|
57265
|
-
|
|
57626
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
57627
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
57628
|
+
precision: 0,
|
|
57266
57629
|
label: "Illuminance"
|
|
57267
|
-
}),
|
|
57630
|
+
})),
|
|
57268
57631
|
/** Ms epoch when the slice was last updated. */
|
|
57269
|
-
lastFetchedAt: number()
|
|
57270
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
57271
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
57272
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
57273
|
-
unit: string().optional(),
|
|
57274
|
-
/** Suggested decimal places for numeric display.
|
|
57275
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
57276
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
57277
|
-
* auto-formatting when absent. */
|
|
57278
|
-
precision: number().int().min(0).max(10).optional()
|
|
57632
|
+
lastFetchedAt: number()
|
|
57279
57633
|
});
|
|
57280
57634
|
var ambientLightSensorCapability = {
|
|
57281
57635
|
name: "ambient-light-sensor",
|
|
@@ -57307,12 +57661,7 @@ var ambientLightSensorCapability = {
|
|
|
57307
57661
|
} } },
|
|
57308
57662
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57309
57663
|
* whether persisting is worth a SQLite commit. */
|
|
57310
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
57311
|
-
customize: {
|
|
57312
|
-
version: 1,
|
|
57313
|
-
advanced: "derive",
|
|
57314
|
-
targets: []
|
|
57315
|
-
}
|
|
57664
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
57316
57665
|
};
|
|
57317
57666
|
/**
|
|
57318
57667
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -57539,10 +57888,7 @@ var BatteryStatusSchema = object({
|
|
|
57539
57888
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
57540
57889
|
* declines to band a non-finite reading, which is the correct shape.
|
|
57541
57890
|
*/
|
|
57542
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
57543
|
-
unit: "%",
|
|
57544
|
-
label: "Charge"
|
|
57545
|
-
}),
|
|
57891
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
57546
57892
|
/**
|
|
57547
57893
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
57548
57894
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -57569,7 +57915,14 @@ var BatteryStatusSchema = object({
|
|
|
57569
57915
|
*/
|
|
57570
57916
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
57571
57917
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
57572
|
-
lastUpdated: number(),
|
|
57918
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
57919
|
+
/**
|
|
57920
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
57921
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
57922
|
+
* that only report charge. A second reading on this cap, not a second
|
|
57923
|
+
* `numeric-sensor` on the same device.
|
|
57924
|
+
*/
|
|
57925
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
57573
57926
|
/**
|
|
57574
57927
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
57575
57928
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -57621,7 +57974,6 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
57621
57974
|
/** Generic Customize target for the percentage reading (D936). */
|
|
57622
57975
|
var batteryCustomize = {
|
|
57623
57976
|
version: 1,
|
|
57624
|
-
advanced: "derive",
|
|
57625
57977
|
targets: [{
|
|
57626
57978
|
id: "percentage",
|
|
57627
57979
|
cardinality: "scalar",
|
|
@@ -57630,7 +57982,7 @@ var batteryCustomize = {
|
|
|
57630
57982
|
stateField: "percentage"
|
|
57631
57983
|
},
|
|
57632
57984
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
57633
|
-
apply: "add
|
|
57985
|
+
apply: "add",
|
|
57634
57986
|
path: "percentage",
|
|
57635
57987
|
sources: [{
|
|
57636
57988
|
kind: "field",
|
|
@@ -57751,10 +58103,16 @@ onStatusChanged: { data: object({
|
|
|
57751
58103
|
/**
|
|
57752
58104
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
57753
58105
|
*/
|
|
57754
|
-
history: { fields: {
|
|
57755
|
-
|
|
57756
|
-
|
|
57757
|
-
|
|
58106
|
+
history: { fields: {
|
|
58107
|
+
percentage: {
|
|
58108
|
+
kind: "gauge",
|
|
58109
|
+
unit: "%"
|
|
58110
|
+
},
|
|
58111
|
+
volts: {
|
|
58112
|
+
kind: "gauge",
|
|
58113
|
+
unit: "V"
|
|
58114
|
+
}
|
|
58115
|
+
} },
|
|
57758
58116
|
customize: batteryCustomize,
|
|
57759
58117
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57760
58118
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -57801,12 +58159,7 @@ var binaryCapability = {
|
|
|
57801
58159
|
history: { fields: { on: { kind: "boolean" } } },
|
|
57802
58160
|
/** Clock fields: written, but excluded from the compare that decides
|
|
57803
58161
|
* whether persisting is worth a SQLite commit. */
|
|
57804
|
-
volatileStateFields: ["lastChangedAt"]
|
|
57805
|
-
customize: {
|
|
57806
|
-
version: 1,
|
|
57807
|
-
advanced: "derive",
|
|
57808
|
-
targets: []
|
|
57809
|
-
}
|
|
58162
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57810
58163
|
};
|
|
57811
58164
|
/**
|
|
57812
58165
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57822,7 +58175,7 @@ var binaryCapability = {
|
|
|
57822
58175
|
*/
|
|
57823
58176
|
var BrightnessStatusSchema = object({
|
|
57824
58177
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57825
|
-
percentage: number().min(0).max(100),
|
|
58178
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57826
58179
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57827
58180
|
lastChangedAt: number()
|
|
57828
58181
|
});
|
|
@@ -58303,21 +58656,21 @@ var ClimateControlStatusSchema = object({
|
|
|
58303
58656
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
58304
58657
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
58305
58658
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
58306
|
-
target: number().nullable(),
|
|
58659
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
58307
58660
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
58308
58661
|
* in `heat_cool` mode. */
|
|
58309
|
-
targetHigh: number().nullable(),
|
|
58662
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
58310
58663
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
58311
58664
|
* in `heat_cool` mode. */
|
|
58312
|
-
targetLow: number().nullable(),
|
|
58665
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
58313
58666
|
/** Target relative humidity (0..100). Null when the device has no
|
|
58314
58667
|
* humidity control. */
|
|
58315
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
58668
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58316
58669
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
58317
58670
|
* the device's internal sensor. */
|
|
58318
|
-
currentTemp: number().nullable(),
|
|
58671
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
58319
58672
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
58320
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
58673
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
58321
58674
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
58322
58675
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
58323
58676
|
swingVertical: boolean().nullable(),
|
|
@@ -58325,11 +58678,11 @@ var ClimateControlStatusSchema = object({
|
|
|
58325
58678
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
58326
58679
|
swingHorizontal: boolean().nullable(),
|
|
58327
58680
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58328
|
-
minTemp: number().nullable().optional(),
|
|
58681
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58329
58682
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
58330
|
-
maxTemp: number().nullable().optional(),
|
|
58683
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
58331
58684
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
58332
|
-
tempStep: number().positive().nullable().optional(),
|
|
58685
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
58333
58686
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
58334
58687
|
lastFetchedAt: number()
|
|
58335
58688
|
});
|
|
@@ -58471,17 +58824,17 @@ var climateControlCapability = {
|
|
|
58471
58824
|
* modes to expose in the picker without a slice fetch.
|
|
58472
58825
|
*/
|
|
58473
58826
|
var RgbTripletSchema = object({
|
|
58474
|
-
r: number().int().min(0).max(255),
|
|
58475
|
-
g: number().int().min(0).max(255),
|
|
58476
|
-
b: number().int().min(0).max(255)
|
|
58827
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58828
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
58829
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
58477
58830
|
});
|
|
58478
58831
|
var HsvTripletSchema = object({
|
|
58479
58832
|
/** Hue in degrees, 0..360. */
|
|
58480
|
-
h: number().min(0).max(360),
|
|
58833
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
58481
58834
|
/** Saturation as 0..100 inclusive. */
|
|
58482
|
-
s: number().min(0).max(100),
|
|
58835
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
58483
58836
|
/** Value/brightness as 0..100 inclusive. */
|
|
58484
|
-
v: number().min(0).max(100)
|
|
58837
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
58485
58838
|
});
|
|
58486
58839
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
58487
58840
|
object({
|
|
@@ -58510,7 +58863,7 @@ var ColorStatusSchema = object({
|
|
|
58510
58863
|
/** Populated when `mode === 'hsv'`. */
|
|
58511
58864
|
hsv: HsvTripletSchema.optional(),
|
|
58512
58865
|
/** Populated when `mode === 'mired'`. */
|
|
58513
|
-
mireds: number().int().optional(),
|
|
58866
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
58514
58867
|
/** Ms epoch of the last operator-driven change. */
|
|
58515
58868
|
lastChangedAt: number()
|
|
58516
58869
|
});
|
|
@@ -58719,18 +59072,12 @@ var FORM_OF_KIND = {
|
|
|
58719
59072
|
function consumableFormOf(item) {
|
|
58720
59073
|
return item.form ?? FORM_OF_KIND[consumableKindOf(item)];
|
|
58721
59074
|
}
|
|
58722
|
-
/**
|
|
58723
|
-
|
|
58724
|
-
|
|
58725
|
-
"days",
|
|
58726
|
-
"hours",
|
|
58727
|
-
"cycles"
|
|
58728
|
-
]);
|
|
58729
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
58730
|
-
* days). `value` null = unknown (D393). */
|
|
59075
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
59076
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
59077
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
58731
59078
|
var ConsumableRemainingSchema = object({
|
|
58732
|
-
value: number().min(0).nullable(),
|
|
58733
|
-
|
|
59079
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
59080
|
+
kind: ConsumableRemainingKindSchema
|
|
58734
59081
|
});
|
|
58735
59082
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
58736
59083
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -58743,7 +59090,7 @@ var ConsumableItemSchema = object({
|
|
|
58743
59090
|
/** Display name. */
|
|
58744
59091
|
label: string().min(1),
|
|
58745
59092
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
58746
|
-
level: number().min(0).max(100).nullable(),
|
|
59093
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58747
59094
|
/** The provider's discrete verdict when known (binary mode). */
|
|
58748
59095
|
status: ConsumableStatusSchema.nullable(),
|
|
58749
59096
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -58825,8 +59172,8 @@ var consumablesCustomize = {
|
|
|
58825
59172
|
transforms: [{ kind: "identity" }]
|
|
58826
59173
|
}],
|
|
58827
59174
|
literals: [{
|
|
58828
|
-
path: "remaining.
|
|
58829
|
-
values: [...
|
|
59175
|
+
path: "remaining.kind",
|
|
59176
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
58830
59177
|
}]
|
|
58831
59178
|
},
|
|
58832
59179
|
{
|
|
@@ -58955,7 +59302,6 @@ reset: method(object({
|
|
|
58955
59302
|
},
|
|
58956
59303
|
"remaining.value": {
|
|
58957
59304
|
kind: "gauge",
|
|
58958
|
-
unitFrom: "remaining.unit",
|
|
58959
59305
|
deadband: 1,
|
|
58960
59306
|
displayName: "Remaining"
|
|
58961
59307
|
}
|
|
@@ -59025,10 +59371,9 @@ var contactCapability = {
|
|
|
59025
59371
|
* (empty array for the other kinds). It lives in the slice because
|
|
59026
59372
|
* HA `select.*` entities may update their options at runtime.
|
|
59027
59373
|
*
|
|
59028
|
-
*
|
|
59029
|
-
*
|
|
59030
|
-
*
|
|
59031
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
59374
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
59375
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
59376
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
59032
59377
|
*/
|
|
59033
59378
|
var ControlStatusSchema = object({
|
|
59034
59379
|
kind: _enum([
|
|
@@ -59040,39 +59385,17 @@ var ControlStatusSchema = object({
|
|
|
59040
59385
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
59041
59386
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
59042
59387
|
* or time-only — HA accepts all three forms). */
|
|
59043
|
-
value: union([number(), string()]),
|
|
59388
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
59044
59389
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
59045
59390
|
options: array(string()),
|
|
59046
59391
|
/** Ms epoch when the slice was last updated. */
|
|
59047
59392
|
lastChangedAt: number(),
|
|
59048
|
-
/**
|
|
59049
|
-
|
|
59050
|
-
|
|
59051
|
-
|
|
59052
|
-
/**
|
|
59053
|
-
|
|
59054
|
-
min: number().optional(),
|
|
59055
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
59056
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
59057
|
-
max: number().optional(),
|
|
59058
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
59059
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
59060
|
-
step: number().optional(),
|
|
59061
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
59062
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
59063
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
59064
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
59065
|
-
precision: number().int().min(0).max(10).optional(),
|
|
59066
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
59067
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
59068
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
59069
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
59070
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
59071
|
-
format: _enum([
|
|
59072
|
-
"date",
|
|
59073
|
-
"time",
|
|
59074
|
-
"datetime"
|
|
59075
|
-
]).optional()
|
|
59393
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
59394
|
+
min: number().optional().meta(readingMeta("device")),
|
|
59395
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
59396
|
+
max: number().optional().meta(readingMeta("device")),
|
|
59397
|
+
/** Step increment, in the device quantity's base unit. */
|
|
59398
|
+
step: number().optional().meta(readingMeta("device"))
|
|
59076
59399
|
});
|
|
59077
59400
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
59078
59401
|
object({
|
|
@@ -59138,9 +59461,9 @@ var CoverStatusSchema = object({
|
|
|
59138
59461
|
]),
|
|
59139
59462
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
59140
59463
|
* no intermediate position surface. */
|
|
59141
|
-
position: number().min(0).max(100).nullable(),
|
|
59464
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59142
59465
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
59143
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
59466
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59144
59467
|
/** Ms epoch when the slice was last updated. */
|
|
59145
59468
|
lastChangedAt: number()
|
|
59146
59469
|
});
|
|
@@ -59243,9 +59566,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
59243
59566
|
var DayNightStatusSchema = object({
|
|
59244
59567
|
mode: DayNightModeSchema,
|
|
59245
59568
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
59246
|
-
sensitivity: number().optional(),
|
|
59569
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
59247
59570
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
59248
|
-
switchDelaySec: number().optional(),
|
|
59571
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
59249
59572
|
lastFetchedAt: number()
|
|
59250
59573
|
});
|
|
59251
59574
|
/**
|
|
@@ -59463,11 +59786,11 @@ var DishwasherStatusSchema = object({
|
|
|
59463
59786
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
59464
59787
|
availablePrograms: array(string()),
|
|
59465
59788
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
59466
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
59789
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59467
59790
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
59468
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
59791
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
59469
59792
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
59470
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
59793
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59471
59794
|
/** True when the door is reported open; null when the door state is not known. */
|
|
59472
59795
|
doorOpen: boolean().nullable(),
|
|
59473
59796
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -59491,7 +59814,7 @@ var DishwasherStatusSchema = object({
|
|
|
59491
59814
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
59492
59815
|
machineCareDue: boolean().nullable(),
|
|
59493
59816
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
59494
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
59817
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
59495
59818
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
59496
59819
|
halfLoad: boolean().nullable(),
|
|
59497
59820
|
hygienePlus: boolean().nullable(),
|
|
@@ -59506,7 +59829,7 @@ var DishwasherStatusSchema = object({
|
|
|
59506
59829
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
59507
59830
|
activeEvents: array(string()),
|
|
59508
59831
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
59509
|
-
errorCode: number().nullable(),
|
|
59832
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
59510
59833
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
59511
59834
|
errorLabel: string().nullable(),
|
|
59512
59835
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -59737,7 +60060,7 @@ var DoorbellStatusSchema = object({
|
|
|
59737
60060
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
59738
60061
|
lastPressedAt: number().nullable(),
|
|
59739
60062
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
59740
|
-
pressCountSinceStart: number()
|
|
60063
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
59741
60064
|
});
|
|
59742
60065
|
var DoorbellPressEventSchema = object({
|
|
59743
60066
|
deviceId: number(),
|
|
@@ -59820,12 +60143,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
59820
60143
|
var EnumSensorStatusSchema = object({
|
|
59821
60144
|
value: string(),
|
|
59822
60145
|
/**
|
|
59823
|
-
* Set
|
|
59824
|
-
* as
|
|
59825
|
-
*
|
|
59826
|
-
* a time-only sensor → `'time'`.
|
|
60146
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
60147
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
60148
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
59827
60149
|
*/
|
|
59828
|
-
|
|
60150
|
+
timestamp: boolean().optional(),
|
|
59829
60151
|
/** Ms epoch when the slice was last updated. */
|
|
59830
60152
|
lastFetchedAt: number()
|
|
59831
60153
|
});
|
|
@@ -59852,11 +60174,11 @@ var enumSensorCapability = {
|
|
|
59852
60174
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59853
60175
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59854
60176
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59855
|
-
* `
|
|
60177
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59856
60178
|
*/
|
|
59857
60179
|
history: { fields: { value: {
|
|
59858
60180
|
kind: "enum",
|
|
59859
|
-
skipWhenSet: "
|
|
60181
|
+
skipWhenSet: "timestamp"
|
|
59860
60182
|
} } },
|
|
59861
60183
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59862
60184
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59876,13 +60198,13 @@ var EventFireSchema = object({
|
|
|
59876
60198
|
deviceId: number(),
|
|
59877
60199
|
eventType: string(),
|
|
59878
60200
|
data: record(string(), unknown()).nullable(),
|
|
59879
|
-
timestamp: number(),
|
|
59880
|
-
seq: number()
|
|
60201
|
+
timestamp: number().meta(readingMeta("none")),
|
|
60202
|
+
seq: number().meta(readingMeta("count"))
|
|
59881
60203
|
});
|
|
59882
60204
|
var EventEmitterStatusSchema = object({
|
|
59883
60205
|
eventTypes: array(string()),
|
|
59884
60206
|
lastEvent: EventFireSchema.nullable(),
|
|
59885
|
-
eventCountSinceStart: number()
|
|
60207
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59886
60208
|
});
|
|
59887
60209
|
var eventEmitterCapability = {
|
|
59888
60210
|
name: "event-emitter",
|
|
@@ -60295,10 +60617,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
60295
60617
|
var FanControlStatusSchema = object({
|
|
60296
60618
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
60297
60619
|
* speed surface (single-speed fan). */
|
|
60298
|
-
percentage: number().min(0).max(100).nullable(),
|
|
60620
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60299
60621
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
60300
60622
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
60301
|
-
percentageStep: number().positive().optional(),
|
|
60623
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
60302
60624
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
60303
60625
|
* — empty string when no preset is active or supported. */
|
|
60304
60626
|
preset: string(),
|
|
@@ -60419,7 +60741,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
60419
60741
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
60420
60742
|
model: string().nullable(),
|
|
60421
60743
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
60422
|
-
channelCount: number().nullable(),
|
|
60744
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
60423
60745
|
/**
|
|
60424
60746
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
60425
60747
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -60542,9 +60864,54 @@ var gasCapability = {
|
|
|
60542
60864
|
* whether persisting is worth a SQLite commit. */
|
|
60543
60865
|
volatileStateFields: ["lastChangedAt"]
|
|
60544
60866
|
};
|
|
60867
|
+
/**
|
|
60868
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
60869
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
60870
|
+
* The reading itself stays on the output capability. History is none — the
|
|
60871
|
+
* series that later statistics read is the output cap's own history block.
|
|
60872
|
+
*/
|
|
60873
|
+
var GroupStatusSchema = object({
|
|
60874
|
+
/** Members whose current value entered the aggregate. */
|
|
60875
|
+
included: number().int().nonnegative().meta(readingMeta("count", {
|
|
60876
|
+
precision: 0,
|
|
60877
|
+
label: "Reporting"
|
|
60878
|
+
})),
|
|
60879
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
60880
|
+
excluded: number().int().nonnegative().meta(readingMeta("count", {
|
|
60881
|
+
precision: 0,
|
|
60882
|
+
label: "Excluded"
|
|
60883
|
+
})),
|
|
60884
|
+
/** `included` + `excluded`. */
|
|
60885
|
+
total: number().int().nonnegative().meta(readingMeta("count", {
|
|
60886
|
+
precision: 0,
|
|
60887
|
+
label: "Members"
|
|
60888
|
+
}))
|
|
60889
|
+
});
|
|
60890
|
+
var groupStatusCapability = {
|
|
60891
|
+
name: "group-status",
|
|
60892
|
+
scope: "device",
|
|
60893
|
+
deviceNative: true,
|
|
60894
|
+
mode: "singleton",
|
|
60895
|
+
deviceTypes: [DeviceType.Sensor],
|
|
60896
|
+
methods: {},
|
|
60897
|
+
status: {
|
|
60898
|
+
schema: GroupStatusSchema,
|
|
60899
|
+
kind: "push"
|
|
60900
|
+
},
|
|
60901
|
+
runtimeState: GroupStatusSchema,
|
|
60902
|
+
/**
|
|
60903
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
60904
|
+
* next source event; a restored count would outlive the readings it named.
|
|
60905
|
+
*
|
|
60906
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
60907
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
60908
|
+
*/
|
|
60909
|
+
durability: "session",
|
|
60910
|
+
history: "none"
|
|
60911
|
+
};
|
|
60545
60912
|
var HeatingValveStatusSchema = object({
|
|
60546
60913
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
60547
|
-
position: number().min(0).max(100).nullable(),
|
|
60914
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60548
60915
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
60549
60916
|
lastFetchedAt: number()
|
|
60550
60917
|
});
|
|
@@ -60587,9 +60954,9 @@ var HumidifierStatusSchema = object({
|
|
|
60587
60954
|
/** Whether the humidifier is currently on. */
|
|
60588
60955
|
on: boolean(),
|
|
60589
60956
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
60590
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
60957
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60591
60958
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
60592
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
60959
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
60593
60960
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
60594
60961
|
* device has no mode surface. */
|
|
60595
60962
|
mode: string().nullable(),
|
|
@@ -60599,9 +60966,9 @@ var HumidifierStatusSchema = object({
|
|
|
60599
60966
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
60600
60967
|
action: string().nullable(),
|
|
60601
60968
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
60602
|
-
minHumidity: number().nullable(),
|
|
60969
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60603
60970
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
60604
|
-
maxHumidity: number().nullable(),
|
|
60971
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
60605
60972
|
/** Ms epoch when the slice was last updated. */
|
|
60606
60973
|
lastChangedAt: number()
|
|
60607
60974
|
});
|
|
@@ -60671,22 +61038,13 @@ var humidifierCapability = {
|
|
|
60671
61038
|
* `sourceInfo`.
|
|
60672
61039
|
*/
|
|
60673
61040
|
var HumiditySensorStatusSchema = object({
|
|
60674
|
-
/** Current relative humidity, 0..100. */
|
|
60675
|
-
percent: number().min(0).max(100).meta({
|
|
60676
|
-
|
|
61041
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
61042
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
61043
|
+
precision: 0,
|
|
60677
61044
|
label: "Humidity"
|
|
60678
|
-
}),
|
|
61045
|
+
})),
|
|
60679
61046
|
/** Ms epoch when the slice was last updated. */
|
|
60680
|
-
lastFetchedAt: number()
|
|
60681
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
60682
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
60683
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
60684
|
-
unit: string().optional(),
|
|
60685
|
-
/** Suggested decimal places for numeric display.
|
|
60686
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
60687
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
60688
|
-
* auto-formatting when absent. */
|
|
60689
|
-
precision: number().int().min(0).max(10).optional()
|
|
61047
|
+
lastFetchedAt: number()
|
|
60690
61048
|
});
|
|
60691
61049
|
var humiditySensorCapability = {
|
|
60692
61050
|
name: "humidity-sensor",
|
|
@@ -60717,12 +61075,7 @@ var humiditySensorCapability = {
|
|
|
60717
61075
|
} } },
|
|
60718
61076
|
/** Clock fields: written, but excluded from the compare that decides
|
|
60719
61077
|
* whether persisting is worth a SQLite commit. */
|
|
60720
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
60721
|
-
customize: {
|
|
60722
|
-
version: 1,
|
|
60723
|
-
advanced: "derive",
|
|
60724
|
-
targets: []
|
|
60725
|
-
}
|
|
61078
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
60726
61079
|
};
|
|
60727
61080
|
/**
|
|
60728
61081
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -60743,7 +61096,7 @@ var ImageStatusSchema = object({
|
|
|
60743
61096
|
* entity exposes no `entity_picture` (yet). */
|
|
60744
61097
|
url: string().nullable(),
|
|
60745
61098
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
60746
|
-
lastUpdated: number().nullable()
|
|
61099
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
60747
61100
|
});
|
|
60748
61101
|
var imageCapability = {
|
|
60749
61102
|
name: "image",
|
|
@@ -60831,19 +61184,19 @@ var NormalizedRangeSchema = object({
|
|
|
60831
61184
|
*/
|
|
60832
61185
|
var ImageSettingsStatusSchema = object({
|
|
60833
61186
|
/** Normalized 0–100. */
|
|
60834
|
-
brightness: number().optional(),
|
|
61187
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60835
61188
|
/** Normalized 0–100. */
|
|
60836
|
-
contrast: number().optional(),
|
|
61189
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60837
61190
|
/** Normalized 0–100. */
|
|
60838
|
-
saturation: number().optional(),
|
|
61191
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60839
61192
|
/** Normalized 0–100. */
|
|
60840
|
-
sharpness: number().optional(),
|
|
61193
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60841
61194
|
mirror: boolean().optional(),
|
|
60842
61195
|
flip: boolean().optional(),
|
|
60843
61196
|
rotate: ImageRotateSchema.optional(),
|
|
60844
61197
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60845
61198
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60846
|
-
warmth: number().optional(),
|
|
61199
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60847
61200
|
exposureMode: ExposureModeSchema.optional(),
|
|
60848
61201
|
backlightMode: BacklightModeSchema.optional(),
|
|
60849
61202
|
lastFetchedAt: number()
|
|
@@ -61122,10 +61475,10 @@ var IntercomAbilitySchema = object({
|
|
|
61122
61475
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
61123
61476
|
codecs: array(string()),
|
|
61124
61477
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
61125
|
-
sampleRate: number(),
|
|
61478
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
61126
61479
|
duplex: _enum(["half", "full"]),
|
|
61127
61480
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
61128
|
-
maxBacklogMs: number()
|
|
61481
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
61129
61482
|
});
|
|
61130
61483
|
var IntercomStatusSchema = object({
|
|
61131
61484
|
/** True while a talk session is open. */
|
|
@@ -61352,13 +61705,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
61352
61705
|
activity: LawnMowerActivitySchema,
|
|
61353
61706
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
61354
61707
|
* reading. */
|
|
61355
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
61708
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61356
61709
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
61357
61710
|
* task is active / progress is unavailable. */
|
|
61358
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
61711
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61359
61712
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
61360
61713
|
* or null when unknown. */
|
|
61361
|
-
currentCode: number().nullable(),
|
|
61714
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
61362
61715
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
61363
61716
|
currentCodeLabel: string().nullable(),
|
|
61364
61717
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61891,7 +62244,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61891
62244
|
state: MediaPlayerStateSchema,
|
|
61892
62245
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61893
62246
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61894
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
62247
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61895
62248
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61896
62249
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61897
62250
|
isMuted: boolean().nullable(),
|
|
@@ -61904,10 +62257,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61904
62257
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61905
62258
|
/** Current playback position in ms. Null when not seekable or
|
|
61906
62259
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61907
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
62260
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61908
62261
|
/** Total duration of the current media in ms. Null when unknown
|
|
61909
62262
|
* (live stream) or nothing is playing. */
|
|
61910
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
62263
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61911
62264
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61912
62265
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61913
62266
|
shuffle: boolean().nullable(),
|
|
@@ -62216,7 +62569,7 @@ var motionCustomize = {
|
|
|
62216
62569
|
eventName: "onMotionChanged"
|
|
62217
62570
|
},
|
|
62218
62571
|
deviceTypes: [DeviceType.Camera],
|
|
62219
|
-
apply: "
|
|
62572
|
+
apply: "add",
|
|
62220
62573
|
applyAuthority: {
|
|
62221
62574
|
kind: "camera-sensors",
|
|
62222
62575
|
timeoutField: "motionCooldownMs"
|
|
@@ -62288,7 +62641,7 @@ var MotionStatusSchema = object({
|
|
|
62288
62641
|
* it, every provider seeded it at boot, and every session left it
|
|
62289
62642
|
* `detected: true` after its detach.
|
|
62290
62643
|
*/
|
|
62291
|
-
autoClearAfterMs: number().nullable()
|
|
62644
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
62292
62645
|
});
|
|
62293
62646
|
/**
|
|
62294
62647
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -62325,12 +62678,18 @@ var motionCapability = {
|
|
|
62325
62678
|
methods: {
|
|
62326
62679
|
/**
|
|
62327
62680
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
62328
|
-
* for consumers that don't need the full status object
|
|
62329
|
-
*
|
|
62330
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
62331
|
-
* consumer.
|
|
62681
|
+
* for consumers that don't need the full status object. A composed
|
|
62682
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
62332
62683
|
*/
|
|
62333
62684
|
isDetected: method(object({ deviceId: number() }), boolean()) },
|
|
62685
|
+
/**
|
|
62686
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
62687
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
62688
|
+
*/
|
|
62689
|
+
composedMethods: { isDetected: {
|
|
62690
|
+
kind: "slice",
|
|
62691
|
+
field: "detected"
|
|
62692
|
+
} },
|
|
62334
62693
|
events: {
|
|
62335
62694
|
/**
|
|
62336
62695
|
* Fires every time the runner transitions a camera between
|
|
@@ -62470,7 +62829,7 @@ var MotionZoneRegionSchema = object({
|
|
|
62470
62829
|
* the grid region(s). */
|
|
62471
62830
|
var MotionZoneStatusSchema = object({
|
|
62472
62831
|
enabled: boolean(),
|
|
62473
|
-
sensitivity: number(),
|
|
62832
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
62474
62833
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
62475
62834
|
regions: array(MotionZoneRegionSchema),
|
|
62476
62835
|
lastFetchedAt: number()
|
|
@@ -62840,7 +63199,7 @@ var NavigationStatusSchema = object({
|
|
|
62840
63199
|
following: boolean(),
|
|
62841
63200
|
flash: boolean(),
|
|
62842
63201
|
lightMode: NavigationLightModeSchema,
|
|
62843
|
-
lightLevel: number().min(40).max(100),
|
|
63202
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62844
63203
|
/** Ms epoch when the slice was last updated. */
|
|
62845
63204
|
lastChangedAt: number()
|
|
62846
63205
|
});
|
|
@@ -62974,13 +63333,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62974
63333
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62975
63334
|
* SKIP a null rather than coerce it.
|
|
62976
63335
|
*/
|
|
62977
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
63336
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62978
63337
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62979
|
-
rssiDbm: number().optional(),
|
|
63338
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62980
63339
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62981
63340
|
ssid: string().optional(),
|
|
62982
63341
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62983
|
-
lastUpdated: number()
|
|
63342
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62984
63343
|
});
|
|
62985
63344
|
var networkLinkCapability = {
|
|
62986
63345
|
name: "network-link",
|
|
@@ -63365,7 +63724,7 @@ var NotifierStatusSchema = object({
|
|
|
63365
63724
|
lastError: string().nullable(),
|
|
63366
63725
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
63367
63726
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
63368
|
-
queueDepth: number().int().nonnegative(),
|
|
63727
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
63369
63728
|
/** Per-feature capability matrix — authoritative source for the
|
|
63370
63729
|
* compose-form field gating. */
|
|
63371
63730
|
supports: NotifierSupportsSchema
|
|
@@ -63457,11 +63816,9 @@ onSent: { data: object({
|
|
|
63457
63816
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
63458
63817
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
63459
63818
|
*
|
|
63460
|
-
* The
|
|
63461
|
-
*
|
|
63462
|
-
*
|
|
63463
|
-
* The UI reads them directly from the slice — they are the single source
|
|
63464
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
63819
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
63820
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
63821
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
63465
63822
|
*
|
|
63466
63823
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
63467
63824
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -63470,15 +63827,8 @@ onSent: { data: object({
|
|
|
63470
63827
|
* numeric values land here.
|
|
63471
63828
|
*/
|
|
63472
63829
|
var NumericSensorStatusSchema = object({
|
|
63473
|
-
|
|
63474
|
-
|
|
63475
|
-
* Populated live from the upstream source on each state push.
|
|
63476
|
-
* Absent for unitless sensors. */
|
|
63477
|
-
unit: string().optional(),
|
|
63478
|
-
/** Suggested decimal places for numeric display.
|
|
63479
|
-
* Populated live from the upstream source when provided.
|
|
63480
|
-
* Falls back to auto-formatting when absent. */
|
|
63481
|
-
precision: number().int().min(0).max(10).optional(),
|
|
63830
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
63831
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
63482
63832
|
/** Ms epoch when the slice was last updated. */
|
|
63483
63833
|
lastFetchedAt: number()
|
|
63484
63834
|
});
|
|
@@ -63502,11 +63852,11 @@ var numericSensorCapability = {
|
|
|
63502
63852
|
*/
|
|
63503
63853
|
durability: "restored",
|
|
63504
63854
|
/**
|
|
63505
|
-
* History (D850): recorded series. The unit is
|
|
63855
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
63856
|
+
* resolved when the series is read — the cap has no single unit.
|
|
63506
63857
|
*/
|
|
63507
63858
|
history: { fields: { value: {
|
|
63508
63859
|
kind: "gauge",
|
|
63509
|
-
unitFrom: "unit",
|
|
63510
63860
|
minIntervalMs: 3e4
|
|
63511
63861
|
} } },
|
|
63512
63862
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -63798,23 +64148,26 @@ var PetFeederStatusSchema = object({
|
|
|
63798
64148
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
63799
64149
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
63800
64150
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
63801
|
-
foodLevel: number().nullable(),
|
|
64151
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
63802
64152
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
63803
64153
|
* single-hopper models. */
|
|
63804
|
-
food1: number().nullable(),
|
|
64154
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
63805
64155
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
63806
64156
|
* single-hopper models. */
|
|
63807
|
-
food2: number().nullable(),
|
|
64157
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
63808
64158
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
63809
64159
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
63810
64160
|
* below the feeder's low threshold. */
|
|
63811
64161
|
lowFood: boolean(),
|
|
63812
64162
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
63813
64163
|
* device has no battery reading. */
|
|
63814
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
63815
|
-
/**
|
|
63816
|
-
*
|
|
63817
|
-
|
|
64164
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64165
|
+
/**
|
|
64166
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
64167
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
64168
|
+
* model has no desiccant sensor.
|
|
64169
|
+
*/
|
|
64170
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
63818
64171
|
/** True while a feed is in progress. */
|
|
63819
64172
|
feeding: boolean(),
|
|
63820
64173
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -63825,7 +64178,7 @@ var PetFeederStatusSchema = object({
|
|
|
63825
64178
|
* with `errorCode` for consumers that want the raw integer. */
|
|
63826
64179
|
error: string().nullable(),
|
|
63827
64180
|
/** Raw device error code (0 / null = no error). */
|
|
63828
|
-
errorCode: number().nullable(),
|
|
64181
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
63829
64182
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
63830
64183
|
isDualHopper: boolean(),
|
|
63831
64184
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63835,7 +64188,7 @@ var PetFeederStatusSchema = object({
|
|
|
63835
64188
|
/** Play a chime when dispensing. */
|
|
63836
64189
|
feedSound: boolean(),
|
|
63837
64190
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63838
|
-
volume: number(),
|
|
64191
|
+
volume: number().meta(readingMeta("none")),
|
|
63839
64192
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63840
64193
|
lastFetchedAt: number()
|
|
63841
64194
|
});
|
|
@@ -63954,7 +64307,7 @@ var petFeederCapability = {
|
|
|
63954
64307
|
},
|
|
63955
64308
|
desiccantLeftDays: {
|
|
63956
64309
|
kind: "gauge",
|
|
63957
|
-
unit: "
|
|
64310
|
+
unit: "s"
|
|
63958
64311
|
}
|
|
63959
64312
|
} }
|
|
63960
64313
|
};
|
|
@@ -64355,36 +64708,19 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
64355
64708
|
*/
|
|
64356
64709
|
var PowerMeterStatusSchema = object({
|
|
64357
64710
|
/** Instantaneous power draw in watts. */
|
|
64358
|
-
watts: number().optional().meta({
|
|
64359
|
-
unit: "W",
|
|
64360
|
-
label: "Power"
|
|
64361
|
-
}),
|
|
64711
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
64362
64712
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
64363
|
-
kwhTotal: number().optional().meta({
|
|
64364
|
-
unit: "kWh",
|
|
64365
|
-
label: "Energy"
|
|
64366
|
-
}),
|
|
64713
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
64367
64714
|
/** Voltage in volts. */
|
|
64368
|
-
volts: number().optional(),
|
|
64715
|
+
volts: number().optional().meta(readingMeta("voltage")),
|
|
64369
64716
|
/** Current in amperes. */
|
|
64370
|
-
amps: number().optional(),
|
|
64371
|
-
/** Apparent power in volt-amperes
|
|
64372
|
-
va: number().optional(),
|
|
64717
|
+
amps: number().optional().meta(readingMeta("current")),
|
|
64718
|
+
/** Apparent power in volt-amperes. */
|
|
64719
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
64373
64720
|
/** Power factor (0..1) if reported. */
|
|
64374
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
64721
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
64375
64722
|
/** Ms epoch when the slice was last updated. */
|
|
64376
|
-
lastFetchedAt: number()
|
|
64377
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
64378
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
64379
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
64380
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
64381
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
64382
|
-
unit: string().optional(),
|
|
64383
|
-
/** Suggested decimal places for numeric display.
|
|
64384
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64385
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64386
|
-
* auto-formatting when absent. */
|
|
64387
|
-
precision: number().int().min(0).max(10).optional()
|
|
64723
|
+
lastFetchedAt: number()
|
|
64388
64724
|
});
|
|
64389
64725
|
var powerMeterCapability = {
|
|
64390
64726
|
name: "power-meter",
|
|
@@ -64448,12 +64784,7 @@ var powerMeterCapability = {
|
|
|
64448
64784
|
} },
|
|
64449
64785
|
/** Clock fields: written, but excluded from the compare that decides
|
|
64450
64786
|
* whether persisting is worth a SQLite commit. */
|
|
64451
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
64452
|
-
customize: {
|
|
64453
|
-
version: 1,
|
|
64454
|
-
advanced: "derive",
|
|
64455
|
-
targets: []
|
|
64456
|
-
}
|
|
64787
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
64457
64788
|
};
|
|
64458
64789
|
/**
|
|
64459
64790
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -64473,11 +64804,11 @@ var powerMeterCapability = {
|
|
|
64473
64804
|
*/
|
|
64474
64805
|
var GpsLocationSchema = object({
|
|
64475
64806
|
/** Latitude in decimal degrees, -90..90. */
|
|
64476
|
-
latitude: number().min(-90).max(90),
|
|
64807
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
64477
64808
|
/** Longitude in decimal degrees, -180..180. */
|
|
64478
|
-
longitude: number().min(-180).max(180),
|
|
64809
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
64479
64810
|
/** Reported accuracy in meters (lower = better). */
|
|
64480
|
-
accuracyMeters: number().nonnegative()
|
|
64811
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
64481
64812
|
});
|
|
64482
64813
|
var PresenceStatusSchema = object({
|
|
64483
64814
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -64489,7 +64820,7 @@ var PresenceStatusSchema = object({
|
|
|
64489
64820
|
gps: GpsLocationSchema.nullable(),
|
|
64490
64821
|
/** Optional battery level of the tracking device (0..100). Null
|
|
64491
64822
|
* when not reported. */
|
|
64492
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
64823
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64493
64824
|
/** Ms epoch when the slice was last updated. */
|
|
64494
64825
|
lastChangedAt: number()
|
|
64495
64826
|
});
|
|
@@ -64539,19 +64870,10 @@ var presenceCapability = {
|
|
|
64539
64870
|
* `sourceInfo`.
|
|
64540
64871
|
*/
|
|
64541
64872
|
var PressureSensorStatusSchema = object({
|
|
64542
|
-
/** Current pressure in hPa. */
|
|
64543
|
-
hpa: number(),
|
|
64873
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
64874
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
64544
64875
|
/** Ms epoch when the slice was last updated. */
|
|
64545
|
-
lastFetchedAt: number()
|
|
64546
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
64547
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
64548
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
64549
|
-
unit: string().optional(),
|
|
64550
|
-
/** Suggested decimal places for numeric display.
|
|
64551
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
64552
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
64553
|
-
* auto-formatting when absent. */
|
|
64554
|
-
precision: number().int().min(0).max(10).optional()
|
|
64876
|
+
lastFetchedAt: number()
|
|
64555
64877
|
});
|
|
64556
64878
|
var pressureSensorCapability = {
|
|
64557
64879
|
name: "pressure-sensor",
|
|
@@ -64965,8 +65287,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64965
65287
|
}), _void(), { kind: "mutation" });
|
|
64966
65288
|
var PtzAutotrackSettingsSchema = object({
|
|
64967
65289
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64968
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64969
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
65290
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
65291
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64970
65292
|
});
|
|
64971
65293
|
/**
|
|
64972
65294
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -65128,7 +65450,7 @@ var RunningStateStatusSchema = object({
|
|
|
65128
65450
|
/** null = unknown — never coerced to false (D393). */
|
|
65129
65451
|
running: boolean().nullable(),
|
|
65130
65452
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
65131
|
-
since: number().nullable(),
|
|
65453
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
65132
65454
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
65133
65455
|
phase: string().nullable(),
|
|
65134
65456
|
/** null until a reading has been published (D393). */
|
|
@@ -65143,7 +65465,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
65143
65465
|
/** Generic Customize target for the running boolean (D936). */
|
|
65144
65466
|
var runningCustomize = {
|
|
65145
65467
|
version: 1,
|
|
65146
|
-
advanced: "derive",
|
|
65147
65468
|
targets: [{
|
|
65148
65469
|
id: "running",
|
|
65149
65470
|
cardinality: "scalar",
|
|
@@ -65163,7 +65484,7 @@ var runningCustomize = {
|
|
|
65163
65484
|
DeviceType.Thermostat,
|
|
65164
65485
|
DeviceType.PetFeeder
|
|
65165
65486
|
],
|
|
65166
|
-
apply: "add
|
|
65487
|
+
apply: "add",
|
|
65167
65488
|
path: "running",
|
|
65168
65489
|
sources: [
|
|
65169
65490
|
{
|
|
@@ -66427,9 +66748,9 @@ var RecordTriggerSchema = _enum([
|
|
|
66427
66748
|
*/
|
|
66428
66749
|
var RecordWindowSchema = object({
|
|
66429
66750
|
trigger: RecordTriggerSchema,
|
|
66430
|
-
day: number().int().min(0).max(6),
|
|
66431
|
-
startMinute: number().int().min(0).max(1439),
|
|
66432
|
-
endMinute: number().int().min(1).max(1440)
|
|
66751
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
66752
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
66753
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
66433
66754
|
});
|
|
66434
66755
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
66435
66756
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -66505,10 +66826,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
66505
66826
|
/** Master "record to the card at all" switch. */
|
|
66506
66827
|
enabled: boolean().nullable(),
|
|
66507
66828
|
overwriteWhenFull: boolean().nullable(),
|
|
66508
|
-
preRecordSec: number().nullable(),
|
|
66509
|
-
postRecordSec: number().nullable(),
|
|
66829
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66830
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
66510
66831
|
/** Length of one recorded file, in minutes. */
|
|
66511
|
-
segmentMinutes: number().nullable(),
|
|
66832
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
66512
66833
|
/** The primary track's weekly windows, flattened. */
|
|
66513
66834
|
windows: array(RecordWindowSchema),
|
|
66514
66835
|
/**
|
|
@@ -66524,7 +66845,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
66524
66845
|
* provider reporting a non-zero count also reports the schedule as not
|
|
66525
66846
|
* writable.
|
|
66526
66847
|
*/
|
|
66527
|
-
unreadableWindows: number(),
|
|
66848
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
66528
66849
|
/**
|
|
66529
66850
|
* The camera is scheduled to record and has NO usable storage.
|
|
66530
66851
|
*
|
|
@@ -67369,7 +67690,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
67369
67690
|
url: string().optional(),
|
|
67370
67691
|
codec: string().optional(),
|
|
67371
67692
|
resolution: CamStreamResolutionSchema.optional(),
|
|
67372
|
-
fps: number().positive().optional(),
|
|
67693
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
67373
67694
|
label: string().optional(),
|
|
67374
67695
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
67375
67696
|
deviceFeatures: array(string()).optional(),
|
|
@@ -67456,18 +67777,18 @@ var StreamProfileSchema = _enum([
|
|
|
67456
67777
|
]);
|
|
67457
67778
|
/** The current encoding config of one stream profile. */
|
|
67458
67779
|
var StreamProfileConfigSchema = object({
|
|
67459
|
-
width: number(),
|
|
67460
|
-
height: number(),
|
|
67780
|
+
width: number().meta(readingMeta("none")),
|
|
67781
|
+
height: number().meta(readingMeta("none")),
|
|
67461
67782
|
codec: _enum(["h264", "h265"]),
|
|
67462
|
-
framerate: number(),
|
|
67463
|
-
bitrate: number(),
|
|
67783
|
+
framerate: number().meta(readingMeta("rate")),
|
|
67784
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
67464
67785
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
67465
67786
|
encoderProfile: _enum([
|
|
67466
67787
|
"high",
|
|
67467
67788
|
"main",
|
|
67468
67789
|
"baseline"
|
|
67469
67790
|
]).optional(),
|
|
67470
|
-
gop: number().optional(),
|
|
67791
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
67471
67792
|
/**
|
|
67472
67793
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
67473
67794
|
*
|
|
@@ -67688,12 +68009,7 @@ var switchCapability = {
|
|
|
67688
68009
|
label: "On",
|
|
67689
68010
|
kind: "boolean"
|
|
67690
68011
|
}
|
|
67691
|
-
}] }
|
|
67692
|
-
customize: {
|
|
67693
|
-
version: 1,
|
|
67694
|
-
advanced: "derive",
|
|
67695
|
-
targets: []
|
|
67696
|
-
}
|
|
68012
|
+
}] }
|
|
67697
68013
|
};
|
|
67698
68014
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
67699
68015
|
function hasControlCharacter(value) {
|
|
@@ -68276,35 +68592,21 @@ var tamperCapability = {
|
|
|
68276
68592
|
* entries with `device_class: temperature` and any future native
|
|
68277
68593
|
* thermometer.
|
|
68278
68594
|
*
|
|
68279
|
-
*
|
|
68280
|
-
*
|
|
68281
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
68282
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
68283
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
68284
|
-
* `sourceInfo`.
|
|
68595
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
68596
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
68285
68597
|
*
|
|
68286
68598
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
68287
68599
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
68288
68600
|
* changed" steady state.
|
|
68289
68601
|
*/
|
|
68290
68602
|
var TemperatureSensorStatusSchema = object({
|
|
68291
|
-
/** Current temperature in Celsius. */
|
|
68292
|
-
celsius: number().meta({
|
|
68293
|
-
|
|
68603
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
68604
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
68605
|
+
precision: 1,
|
|
68294
68606
|
label: "Temperature"
|
|
68295
|
-
}),
|
|
68607
|
+
})),
|
|
68296
68608
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
68297
|
-
lastFetchedAt: number()
|
|
68298
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
68299
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
68300
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
68301
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
68302
|
-
unit: string().optional(),
|
|
68303
|
-
/** Suggested decimal places for numeric display.
|
|
68304
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
68305
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
68306
|
-
* auto-formatting when absent. */
|
|
68307
|
-
precision: number().int().min(0).max(10).optional()
|
|
68609
|
+
lastFetchedAt: number()
|
|
68308
68610
|
});
|
|
68309
68611
|
var temperatureSensorCapability = {
|
|
68310
68612
|
name: "temperature-sensor",
|
|
@@ -68335,12 +68637,7 @@ var temperatureSensorCapability = {
|
|
|
68335
68637
|
} } },
|
|
68336
68638
|
/** Clock fields: written, but excluded from the compare that decides
|
|
68337
68639
|
* whether persisting is worth a SQLite commit. */
|
|
68338
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
68339
|
-
customize: {
|
|
68340
|
-
version: 1,
|
|
68341
|
-
advanced: "derive",
|
|
68342
|
-
targets: []
|
|
68343
|
-
}
|
|
68640
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
68344
68641
|
};
|
|
68345
68642
|
/**
|
|
68346
68643
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -68623,16 +68920,16 @@ var VacuumControlStatusSchema = object({
|
|
|
68623
68920
|
]),
|
|
68624
68921
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
68625
68922
|
* reading. */
|
|
68626
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
68923
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68627
68924
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
68628
68925
|
* the vacuum has no speed control. */
|
|
68629
68926
|
fanSpeed: string().nullable(),
|
|
68630
68927
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
68631
68928
|
availableFanSpeeds: array(string()),
|
|
68632
68929
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
68633
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
68930
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68634
68931
|
/** Current error code (0 / null = no error). */
|
|
68635
|
-
errorCode: number().nullable(),
|
|
68932
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
68636
68933
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
68637
68934
|
errorLabel: string().nullable(),
|
|
68638
68935
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -68710,7 +69007,7 @@ var ValveStatusSchema = object({
|
|
|
68710
69007
|
]),
|
|
68711
69008
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
68712
69009
|
* intermediate position surface. */
|
|
68713
|
-
position: number().min(0).max(100).nullable(),
|
|
69010
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68714
69011
|
/** Ms epoch when the slice was last updated. */
|
|
68715
69012
|
lastChangedAt: number()
|
|
68716
69013
|
});
|
|
@@ -68818,9 +69115,9 @@ var vibrationCapability = {
|
|
|
68818
69115
|
*/
|
|
68819
69116
|
var WaterHeaterStatusSchema = object({
|
|
68820
69117
|
/** Current measured temperature. Null when not reported. */
|
|
68821
|
-
currentTemp: number().nullable(),
|
|
69118
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68822
69119
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
68823
|
-
targetTemp: number().nullable(),
|
|
69120
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68824
69121
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
68825
69122
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
68826
69123
|
* device reports an unknown state. */
|
|
@@ -68831,9 +69128,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
68831
69128
|
* has no away surface. */
|
|
68832
69129
|
away: boolean().nullable(),
|
|
68833
69130
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
68834
|
-
minTemp: number().nullable(),
|
|
69131
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68835
69132
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
68836
|
-
maxTemp: number().nullable(),
|
|
69133
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
68837
69134
|
/** Ms epoch when the slice was last updated. */
|
|
68838
69135
|
lastChangedAt: number()
|
|
68839
69136
|
});
|
|
@@ -68918,25 +69215,18 @@ var waterHeaterCapability = {
|
|
|
68918
69215
|
* Forecast deferred — current conditions only for v1.
|
|
68919
69216
|
*/
|
|
68920
69217
|
var WeatherStatusSchema = object({
|
|
68921
|
-
/** Verbatim
|
|
68922
|
-
* when no condition has been reported yet. */
|
|
69218
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68923
69219
|
condition: string().nullable(),
|
|
68924
|
-
/** Current temperature in
|
|
68925
|
-
temperature: number().nullable(),
|
|
68926
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68927
|
-
temperatureUnit: string().nullable(),
|
|
69220
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
69221
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68928
69222
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68929
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68930
|
-
/** Barometric pressure in
|
|
68931
|
-
pressure: number().nullable(),
|
|
68932
|
-
/**
|
|
68933
|
-
|
|
68934
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68935
|
-
windSpeed: number().nullable(),
|
|
68936
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68937
|
-
windSpeedUnit: string().nullable(),
|
|
69223
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
69224
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
69225
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
69226
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
69227
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68938
69228
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68939
|
-
windBearing: number().nullable(),
|
|
69229
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68940
69230
|
/** Ms epoch when the slice was last updated. */
|
|
68941
69231
|
lastFetchedAt: number()
|
|
68942
69232
|
});
|
|
@@ -68964,12 +69254,12 @@ var weatherCapability = {
|
|
|
68964
69254
|
*/
|
|
68965
69255
|
durability: "session",
|
|
68966
69256
|
/**
|
|
68967
|
-
* History (D850): recorded series.
|
|
69257
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68968
69258
|
*/
|
|
68969
69259
|
history: { fields: {
|
|
68970
69260
|
temperature: {
|
|
68971
69261
|
kind: "gauge",
|
|
68972
|
-
|
|
69262
|
+
unit: "°C",
|
|
68973
69263
|
deadband: .2
|
|
68974
69264
|
},
|
|
68975
69265
|
humidity: {
|
|
@@ -68979,12 +69269,12 @@ var weatherCapability = {
|
|
|
68979
69269
|
},
|
|
68980
69270
|
pressure: {
|
|
68981
69271
|
kind: "gauge",
|
|
68982
|
-
|
|
69272
|
+
unit: "hPa",
|
|
68983
69273
|
deadband: .5
|
|
68984
69274
|
},
|
|
68985
69275
|
windSpeed: {
|
|
68986
69276
|
kind: "gauge",
|
|
68987
|
-
|
|
69277
|
+
unit: "m/s",
|
|
68988
69278
|
deadband: .5
|
|
68989
69279
|
}
|
|
68990
69280
|
} }
|
|
@@ -69922,6 +70212,404 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
|
|
|
69922
70212
|
if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
|
|
69923
70213
|
return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
|
|
69924
70214
|
}
|
|
70215
|
+
/**
|
|
70216
|
+
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
70217
|
+
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
70218
|
+
* `factor = 5/9`, `offset = -160/9` (kept as exact expressions, not rounded
|
|
70219
|
+
* decimals). K derives from `°C = K − 273.15`.
|
|
70220
|
+
*/
|
|
70221
|
+
var UNIT_TABLE = {
|
|
70222
|
+
"°C": {
|
|
70223
|
+
dimension: "temperature",
|
|
70224
|
+
factor: 1,
|
|
70225
|
+
offset: 0
|
|
70226
|
+
},
|
|
70227
|
+
"°F": {
|
|
70228
|
+
dimension: "temperature",
|
|
70229
|
+
factor: 5 / 9,
|
|
70230
|
+
offset: -160 / 9
|
|
70231
|
+
},
|
|
70232
|
+
K: {
|
|
70233
|
+
dimension: "temperature",
|
|
70234
|
+
factor: 1,
|
|
70235
|
+
offset: -273.15
|
|
70236
|
+
},
|
|
70237
|
+
hPa: {
|
|
70238
|
+
dimension: "pressure",
|
|
70239
|
+
factor: 1,
|
|
70240
|
+
offset: 0
|
|
70241
|
+
},
|
|
70242
|
+
kPa: {
|
|
70243
|
+
dimension: "pressure",
|
|
70244
|
+
factor: 10,
|
|
70245
|
+
offset: 0
|
|
70246
|
+
},
|
|
70247
|
+
Pa: {
|
|
70248
|
+
dimension: "pressure",
|
|
70249
|
+
factor: .01,
|
|
70250
|
+
offset: 0
|
|
70251
|
+
},
|
|
70252
|
+
mbar: {
|
|
70253
|
+
dimension: "pressure",
|
|
70254
|
+
factor: 1,
|
|
70255
|
+
offset: 0
|
|
70256
|
+
},
|
|
70257
|
+
bar: {
|
|
70258
|
+
dimension: "pressure",
|
|
70259
|
+
factor: 1e3,
|
|
70260
|
+
offset: 0
|
|
70261
|
+
},
|
|
70262
|
+
inHg: {
|
|
70263
|
+
dimension: "pressure",
|
|
70264
|
+
factor: 33.8639,
|
|
70265
|
+
offset: 0
|
|
70266
|
+
},
|
|
70267
|
+
mmHg: {
|
|
70268
|
+
dimension: "pressure",
|
|
70269
|
+
factor: 1.33322,
|
|
70270
|
+
offset: 0
|
|
70271
|
+
},
|
|
70272
|
+
psi: {
|
|
70273
|
+
dimension: "pressure",
|
|
70274
|
+
factor: 68.9476,
|
|
70275
|
+
offset: 0
|
|
70276
|
+
},
|
|
70277
|
+
"m/s": {
|
|
70278
|
+
dimension: "speed",
|
|
70279
|
+
factor: 1,
|
|
70280
|
+
offset: 0
|
|
70281
|
+
},
|
|
70282
|
+
"km/h": {
|
|
70283
|
+
dimension: "speed",
|
|
70284
|
+
factor: 1 / 3.6,
|
|
70285
|
+
offset: 0
|
|
70286
|
+
},
|
|
70287
|
+
mph: {
|
|
70288
|
+
dimension: "speed",
|
|
70289
|
+
factor: .44704,
|
|
70290
|
+
offset: 0
|
|
70291
|
+
},
|
|
70292
|
+
kn: {
|
|
70293
|
+
dimension: "speed",
|
|
70294
|
+
factor: .514444,
|
|
70295
|
+
offset: 0
|
|
70296
|
+
},
|
|
70297
|
+
"mm/h": {
|
|
70298
|
+
dimension: "precipitation-rate",
|
|
70299
|
+
factor: 1,
|
|
70300
|
+
offset: 0
|
|
70301
|
+
},
|
|
70302
|
+
"in/h": {
|
|
70303
|
+
dimension: "precipitation-rate",
|
|
70304
|
+
factor: 25.4,
|
|
70305
|
+
offset: 0
|
|
70306
|
+
},
|
|
70307
|
+
m: {
|
|
70308
|
+
dimension: "length",
|
|
70309
|
+
factor: 1,
|
|
70310
|
+
offset: 0
|
|
70311
|
+
},
|
|
70312
|
+
mm: {
|
|
70313
|
+
dimension: "length",
|
|
70314
|
+
factor: .001,
|
|
70315
|
+
offset: 0
|
|
70316
|
+
},
|
|
70317
|
+
cm: {
|
|
70318
|
+
dimension: "length",
|
|
70319
|
+
factor: .01,
|
|
70320
|
+
offset: 0
|
|
70321
|
+
},
|
|
70322
|
+
km: {
|
|
70323
|
+
dimension: "length",
|
|
70324
|
+
factor: 1e3,
|
|
70325
|
+
offset: 0
|
|
70326
|
+
},
|
|
70327
|
+
in: {
|
|
70328
|
+
dimension: "length",
|
|
70329
|
+
factor: .0254,
|
|
70330
|
+
offset: 0
|
|
70331
|
+
},
|
|
70332
|
+
ft: {
|
|
70333
|
+
dimension: "length",
|
|
70334
|
+
factor: .3048,
|
|
70335
|
+
offset: 0
|
|
70336
|
+
},
|
|
70337
|
+
mi: {
|
|
70338
|
+
dimension: "length",
|
|
70339
|
+
factor: 1609.344,
|
|
70340
|
+
offset: 0
|
|
70341
|
+
},
|
|
70342
|
+
"m²": {
|
|
70343
|
+
dimension: "area",
|
|
70344
|
+
factor: 1,
|
|
70345
|
+
offset: 0
|
|
70346
|
+
},
|
|
70347
|
+
lx: {
|
|
70348
|
+
dimension: "illuminance",
|
|
70349
|
+
factor: 1,
|
|
70350
|
+
offset: 0
|
|
70351
|
+
},
|
|
70352
|
+
"W/m²": {
|
|
70353
|
+
dimension: "irradiance",
|
|
70354
|
+
factor: 1,
|
|
70355
|
+
offset: 0
|
|
70356
|
+
},
|
|
70357
|
+
W: {
|
|
70358
|
+
dimension: "power",
|
|
70359
|
+
factor: 1,
|
|
70360
|
+
offset: 0
|
|
70361
|
+
},
|
|
70362
|
+
kW: {
|
|
70363
|
+
dimension: "power",
|
|
70364
|
+
factor: 1e3,
|
|
70365
|
+
offset: 0
|
|
70366
|
+
},
|
|
70367
|
+
VA: {
|
|
70368
|
+
dimension: "apparent-power",
|
|
70369
|
+
factor: 1,
|
|
70370
|
+
offset: 0
|
|
70371
|
+
},
|
|
70372
|
+
Wh: {
|
|
70373
|
+
dimension: "energy",
|
|
70374
|
+
factor: 1,
|
|
70375
|
+
offset: 0
|
|
70376
|
+
},
|
|
70377
|
+
kWh: {
|
|
70378
|
+
dimension: "energy",
|
|
70379
|
+
factor: 1e3,
|
|
70380
|
+
offset: 0
|
|
70381
|
+
},
|
|
70382
|
+
MWh: {
|
|
70383
|
+
dimension: "energy",
|
|
70384
|
+
factor: 1e6,
|
|
70385
|
+
offset: 0
|
|
70386
|
+
},
|
|
70387
|
+
V: {
|
|
70388
|
+
dimension: "voltage",
|
|
70389
|
+
factor: 1,
|
|
70390
|
+
offset: 0
|
|
70391
|
+
},
|
|
70392
|
+
mV: {
|
|
70393
|
+
dimension: "voltage",
|
|
70394
|
+
factor: .001,
|
|
70395
|
+
offset: 0
|
|
70396
|
+
},
|
|
70397
|
+
A: {
|
|
70398
|
+
dimension: "current",
|
|
70399
|
+
factor: 1,
|
|
70400
|
+
offset: 0
|
|
70401
|
+
},
|
|
70402
|
+
mA: {
|
|
70403
|
+
dimension: "current",
|
|
70404
|
+
factor: .001,
|
|
70405
|
+
offset: 0
|
|
70406
|
+
},
|
|
70407
|
+
ppm: {
|
|
70408
|
+
dimension: "concentration-volume",
|
|
70409
|
+
factor: 1,
|
|
70410
|
+
offset: 0
|
|
70411
|
+
},
|
|
70412
|
+
ppb: {
|
|
70413
|
+
dimension: "concentration-volume",
|
|
70414
|
+
factor: .001,
|
|
70415
|
+
offset: 0
|
|
70416
|
+
},
|
|
70417
|
+
"µg/m³": {
|
|
70418
|
+
dimension: "concentration-mass",
|
|
70419
|
+
factor: 1,
|
|
70420
|
+
offset: 0
|
|
70421
|
+
},
|
|
70422
|
+
"mg/m³": {
|
|
70423
|
+
dimension: "concentration-mass",
|
|
70424
|
+
factor: 1e3,
|
|
70425
|
+
offset: 0
|
|
70426
|
+
},
|
|
70427
|
+
kg: {
|
|
70428
|
+
dimension: "mass",
|
|
70429
|
+
factor: 1,
|
|
70430
|
+
offset: 0
|
|
70431
|
+
},
|
|
70432
|
+
g: {
|
|
70433
|
+
dimension: "mass",
|
|
70434
|
+
factor: .001,
|
|
70435
|
+
offset: 0
|
|
70436
|
+
},
|
|
70437
|
+
lb: {
|
|
70438
|
+
dimension: "mass",
|
|
70439
|
+
factor: .453592,
|
|
70440
|
+
offset: 0
|
|
70441
|
+
},
|
|
70442
|
+
oz: {
|
|
70443
|
+
dimension: "mass",
|
|
70444
|
+
factor: .0283495,
|
|
70445
|
+
offset: 0
|
|
70446
|
+
},
|
|
70447
|
+
"%": {
|
|
70448
|
+
dimension: "percentage",
|
|
70449
|
+
factor: 1,
|
|
70450
|
+
offset: 0
|
|
70451
|
+
},
|
|
70452
|
+
L: {
|
|
70453
|
+
dimension: "volume",
|
|
70454
|
+
factor: 1,
|
|
70455
|
+
offset: 0
|
|
70456
|
+
},
|
|
70457
|
+
mL: {
|
|
70458
|
+
dimension: "volume",
|
|
70459
|
+
factor: .001,
|
|
70460
|
+
offset: 0
|
|
70461
|
+
},
|
|
70462
|
+
gal: {
|
|
70463
|
+
dimension: "volume",
|
|
70464
|
+
factor: 3.785411784,
|
|
70465
|
+
offset: 0
|
|
70466
|
+
},
|
|
70467
|
+
s: {
|
|
70468
|
+
dimension: "duration",
|
|
70469
|
+
factor: 1,
|
|
70470
|
+
offset: 0
|
|
70471
|
+
},
|
|
70472
|
+
ms: {
|
|
70473
|
+
dimension: "duration",
|
|
70474
|
+
factor: .001,
|
|
70475
|
+
offset: 0
|
|
70476
|
+
},
|
|
70477
|
+
min: {
|
|
70478
|
+
dimension: "duration",
|
|
70479
|
+
factor: 60,
|
|
70480
|
+
offset: 0
|
|
70481
|
+
},
|
|
70482
|
+
h: {
|
|
70483
|
+
dimension: "duration",
|
|
70484
|
+
factor: 3600,
|
|
70485
|
+
offset: 0
|
|
70486
|
+
},
|
|
70487
|
+
d: {
|
|
70488
|
+
dimension: "duration",
|
|
70489
|
+
factor: 86400,
|
|
70490
|
+
offset: 0
|
|
70491
|
+
},
|
|
70492
|
+
B: {
|
|
70493
|
+
dimension: "information",
|
|
70494
|
+
factor: 1,
|
|
70495
|
+
offset: 0
|
|
70496
|
+
},
|
|
70497
|
+
KiB: {
|
|
70498
|
+
dimension: "information",
|
|
70499
|
+
factor: 1024,
|
|
70500
|
+
offset: 0
|
|
70501
|
+
},
|
|
70502
|
+
MiB: {
|
|
70503
|
+
dimension: "information",
|
|
70504
|
+
factor: 1024 ** 2,
|
|
70505
|
+
offset: 0
|
|
70506
|
+
},
|
|
70507
|
+
GiB: {
|
|
70508
|
+
dimension: "information",
|
|
70509
|
+
factor: 1024 ** 3,
|
|
70510
|
+
offset: 0
|
|
70511
|
+
},
|
|
70512
|
+
TiB: {
|
|
70513
|
+
dimension: "information",
|
|
70514
|
+
factor: 1024 ** 4,
|
|
70515
|
+
offset: 0
|
|
70516
|
+
},
|
|
70517
|
+
kB: {
|
|
70518
|
+
dimension: "information",
|
|
70519
|
+
factor: 1e3,
|
|
70520
|
+
offset: 0
|
|
70521
|
+
},
|
|
70522
|
+
MB: {
|
|
70523
|
+
dimension: "information",
|
|
70524
|
+
factor: 1e6,
|
|
70525
|
+
offset: 0
|
|
70526
|
+
},
|
|
70527
|
+
GB: {
|
|
70528
|
+
dimension: "information",
|
|
70529
|
+
factor: 1e9,
|
|
70530
|
+
offset: 0
|
|
70531
|
+
},
|
|
70532
|
+
"°": {
|
|
70533
|
+
dimension: "angle",
|
|
70534
|
+
factor: 1,
|
|
70535
|
+
offset: 0
|
|
70536
|
+
},
|
|
70537
|
+
dBFS: {
|
|
70538
|
+
dimension: "sound-level",
|
|
70539
|
+
factor: 1,
|
|
70540
|
+
offset: 0
|
|
70541
|
+
},
|
|
70542
|
+
dBm: {
|
|
70543
|
+
dimension: "signal-level",
|
|
70544
|
+
factor: 1,
|
|
70545
|
+
offset: 0
|
|
70546
|
+
},
|
|
70547
|
+
mired: {
|
|
70548
|
+
dimension: "colour-temperature",
|
|
70549
|
+
factor: 1,
|
|
70550
|
+
offset: 0
|
|
70551
|
+
},
|
|
70552
|
+
kbps: {
|
|
70553
|
+
dimension: "bitrate",
|
|
70554
|
+
factor: 1,
|
|
70555
|
+
offset: 0
|
|
70556
|
+
},
|
|
70557
|
+
Mbps: {
|
|
70558
|
+
dimension: "bitrate",
|
|
70559
|
+
factor: 1e3,
|
|
70560
|
+
offset: 0
|
|
70561
|
+
},
|
|
70562
|
+
fps: {
|
|
70563
|
+
dimension: "rate",
|
|
70564
|
+
factor: 1,
|
|
70565
|
+
offset: 0
|
|
70566
|
+
}
|
|
70567
|
+
};
|
|
70568
|
+
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
70569
|
+
function specFor(unit) {
|
|
70570
|
+
return Object.hasOwn(UNIT_TABLE, unit) ? UNIT_TABLE[unit] : void 0;
|
|
70571
|
+
}
|
|
70572
|
+
/** The dimension a unit belongs to, or `undefined` for an unknown unit. */
|
|
70573
|
+
function unitDimension(unit) {
|
|
70574
|
+
return specFor(unit)?.dimension;
|
|
70575
|
+
}
|
|
70576
|
+
/** Value in `spec`'s unit → its dimension's canonical unit. */
|
|
70577
|
+
function toCanonical(value, spec) {
|
|
70578
|
+
return value * spec.factor + spec.offset;
|
|
70579
|
+
}
|
|
70580
|
+
/** Canonical-unit value → the unit described by `spec`. */
|
|
70581
|
+
function fromCanonical(canonical, spec) {
|
|
70582
|
+
return (canonical - spec.offset) / spec.factor;
|
|
70583
|
+
}
|
|
70584
|
+
/**
|
|
70585
|
+
* Graceful variant for the render path: returns the converted value, or
|
|
70586
|
+
* `undefined` when the conversion is refused (unknown unit / cross-dimension).
|
|
70587
|
+
* Never throws — a render caller falls back to the raw value + source unit.
|
|
70588
|
+
*/
|
|
70589
|
+
function tryConvertUnit(value, from, to) {
|
|
70590
|
+
if (from === to) return value;
|
|
70591
|
+
const fromSpec = specFor(from);
|
|
70592
|
+
if (!fromSpec) return void 0;
|
|
70593
|
+
const toSpec = specFor(to);
|
|
70594
|
+
if (!toSpec) return void 0;
|
|
70595
|
+
if (fromSpec.dimension !== toSpec.dimension) return void 0;
|
|
70596
|
+
return fromCanonical(toCanonical(value, fromSpec), toSpec);
|
|
70597
|
+
}
|
|
70598
|
+
/**
|
|
70599
|
+
* Every known unit spelling in a dimension (table insertion order — canonical
|
|
70600
|
+
* unit first). Powers the UI's same-dimension unit picker.
|
|
70601
|
+
*/
|
|
70602
|
+
/**
|
|
70603
|
+
* Convert a difference, not a reading. Affine units (°F) shift an absolute
|
|
70604
|
+
* value by their offset; a step of 1°F is 5/9°C, so the offset is cancelled.
|
|
70605
|
+
*/
|
|
70606
|
+
function tryConvertDelta(value, from, to) {
|
|
70607
|
+
if (from === to) return value;
|
|
70608
|
+
const origin = tryConvertUnit(0, from, to);
|
|
70609
|
+
const shifted = tryConvertUnit(value, from, to);
|
|
70610
|
+
if (origin === void 0 || shifted === void 0) return void 0;
|
|
70611
|
+
return shifted - origin;
|
|
70612
|
+
}
|
|
69925
70613
|
SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
|
|
69926
70614
|
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;
|
|
69927
70615
|
String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
|
|
@@ -70252,6 +70940,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
70252
70940
|
featureProbe: featureProbeCapability,
|
|
70253
70941
|
flood: floodCapability,
|
|
70254
70942
|
gas: gasCapability,
|
|
70943
|
+
groupStatus: groupStatusCapability,
|
|
70255
70944
|
heatingValve: heatingValveCapability,
|
|
70256
70945
|
humidifier: humidifierCapability,
|
|
70257
70946
|
humiditySensor: humiditySensorCapability,
|
|
@@ -74736,6 +75425,13 @@ Object.freeze({
|
|
|
74736
75425
|
access: "view",
|
|
74737
75426
|
role: "viewer"
|
|
74738
75427
|
},
|
|
75428
|
+
"groupStatus.getStatus": {
|
|
75429
|
+
capName: "group-status",
|
|
75430
|
+
capScope: "device",
|
|
75431
|
+
addonId: null,
|
|
75432
|
+
access: "view",
|
|
75433
|
+
role: "viewer"
|
|
75434
|
+
},
|
|
74739
75435
|
"heatingValve.getStatus": {
|
|
74740
75436
|
capName: "heating-valve",
|
|
74741
75437
|
capScope: "device",
|
|
@@ -84558,6 +85254,33 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84558
85254
|
icon: "flame"
|
|
84559
85255
|
}]
|
|
84560
85256
|
},
|
|
85257
|
+
"group-status": {
|
|
85258
|
+
scope: "device",
|
|
85259
|
+
noun: t("Group", "Gruppo"),
|
|
85260
|
+
state: [
|
|
85261
|
+
{
|
|
85262
|
+
kind: "numeric",
|
|
85263
|
+
field: "included",
|
|
85264
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
85265
|
+
label: t("Reporting", "Rispondono"),
|
|
85266
|
+
icon: "users"
|
|
85267
|
+
},
|
|
85268
|
+
{
|
|
85269
|
+
kind: "numeric",
|
|
85270
|
+
field: "excluded",
|
|
85271
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
85272
|
+
label: t("Excluded", "Esclusi"),
|
|
85273
|
+
icon: "users"
|
|
85274
|
+
},
|
|
85275
|
+
{
|
|
85276
|
+
kind: "numeric",
|
|
85277
|
+
field: "total",
|
|
85278
|
+
quantity: t("the member count", "il numero di membri"),
|
|
85279
|
+
label: t("Members", "Membri"),
|
|
85280
|
+
icon: "sigma"
|
|
85281
|
+
}
|
|
85282
|
+
]
|
|
85283
|
+
},
|
|
84561
85284
|
"humidity-sensor": {
|
|
84562
85285
|
scope: "device",
|
|
84563
85286
|
noun: t("Humidity", "Umidità"),
|
|
@@ -84591,7 +85314,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84591
85314
|
field: "value",
|
|
84592
85315
|
quantity: t("the reading", "il valore"),
|
|
84593
85316
|
label: t("Reading", "Valore"),
|
|
84594
|
-
unitField: "unit",
|
|
84595
85317
|
icon: "gauge"
|
|
84596
85318
|
}]
|
|
84597
85319
|
},
|
|
@@ -84727,7 +85449,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84727
85449
|
field: "temperature",
|
|
84728
85450
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
84729
85451
|
label: t("Temperature", "Temperatura"),
|
|
84730
|
-
|
|
85452
|
+
unit: "°C",
|
|
84731
85453
|
icon: "thermometer"
|
|
84732
85454
|
},
|
|
84733
85455
|
{
|
|
@@ -84743,7 +85465,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84743
85465
|
field: "windSpeed",
|
|
84744
85466
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
84745
85467
|
label: t("Wind", "Vento"),
|
|
84746
|
-
|
|
85468
|
+
unit: "m/s",
|
|
84747
85469
|
icon: "wind"
|
|
84748
85470
|
},
|
|
84749
85471
|
{
|
|
@@ -84751,7 +85473,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
84751
85473
|
field: "pressure",
|
|
84752
85474
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
84753
85475
|
label: t("Pressure", "Pressione"),
|
|
84754
|
-
|
|
85476
|
+
unit: "hPa",
|
|
84755
85477
|
icon: "gauge"
|
|
84756
85478
|
}
|
|
84757
85479
|
]
|
|
@@ -86024,6 +86746,11 @@ Object.freeze({
|
|
|
86024
86746
|
form: "single",
|
|
86025
86747
|
optional: false
|
|
86026
86748
|
}],
|
|
86749
|
+
"groupStatus.getStatus": [{
|
|
86750
|
+
name: "deviceId",
|
|
86751
|
+
form: "single",
|
|
86752
|
+
optional: false
|
|
86753
|
+
}],
|
|
86027
86754
|
"heatingValve.getStatus": [{
|
|
86028
86755
|
name: "deviceId",
|
|
86029
86756
|
form: "single",
|
|
@@ -89324,6 +90051,96 @@ DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
|
89324
90051
|
DEFAULT_NATIVE_LEASE_SETTINGS.sceneBudgetMb;
|
|
89325
90052
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
89326
90053
|
/**
|
|
90054
|
+
* Convert an upstream number into the stored base of its quantity (D944 §4).
|
|
90055
|
+
* An unknown unit or a unit from another dimension is a refusal: the caller
|
|
90056
|
+
* logs it and publishes null (D393). This function never guesses.
|
|
90057
|
+
*/
|
|
90058
|
+
var DIMENSION_QUANTITY = {
|
|
90059
|
+
temperature: "temperature",
|
|
90060
|
+
pressure: "pressure",
|
|
90061
|
+
speed: "speed",
|
|
90062
|
+
"precipitation-rate": "precipitation-rate",
|
|
90063
|
+
length: "length",
|
|
90064
|
+
area: "area",
|
|
90065
|
+
illuminance: "illuminance",
|
|
90066
|
+
irradiance: "irradiance",
|
|
90067
|
+
power: "power",
|
|
90068
|
+
"apparent-power": "apparent-power",
|
|
90069
|
+
energy: "energy",
|
|
90070
|
+
voltage: "voltage",
|
|
90071
|
+
current: "current",
|
|
90072
|
+
"concentration-volume": "concentration-volume",
|
|
90073
|
+
"concentration-mass": "concentration-mass",
|
|
90074
|
+
mass: "mass",
|
|
90075
|
+
percentage: "percentage",
|
|
90076
|
+
volume: "volume",
|
|
90077
|
+
duration: "duration",
|
|
90078
|
+
information: "information",
|
|
90079
|
+
angle: "angle",
|
|
90080
|
+
"sound-level": "sound-level",
|
|
90081
|
+
"signal-level": "signal-level",
|
|
90082
|
+
"colour-temperature": "colour-temperature",
|
|
90083
|
+
bitrate: "bitrate",
|
|
90084
|
+
rate: "rate"
|
|
90085
|
+
};
|
|
90086
|
+
/**
|
|
90087
|
+
* Quantity implied by a unit symbol. `ppb` and `ms` are the two symbols
|
|
90088
|
+
* whose stored base is not the dimension's canonical unit. `mm` is length;
|
|
90089
|
+
* precipitation is chosen by the caller (a device class), not by the symbol.
|
|
90090
|
+
*/
|
|
90091
|
+
function quantityFromUnit(rawUnit) {
|
|
90092
|
+
const unit = normalizeUnit(rawUnit);
|
|
90093
|
+
if (unit === void 0) return void 0;
|
|
90094
|
+
if (unit === "ppb") return "concentration-ppb";
|
|
90095
|
+
if (unit === "ms") return "duration-ms";
|
|
90096
|
+
const dimension = unitDimension(unit);
|
|
90097
|
+
if (dimension === void 0) return void 0;
|
|
90098
|
+
return DIMENSION_QUANTITY[dimension];
|
|
90099
|
+
}
|
|
90100
|
+
function ingestReading(input) {
|
|
90101
|
+
if (!Number.isFinite(input.value)) return {
|
|
90102
|
+
ok: false,
|
|
90103
|
+
reason: "non-finite"
|
|
90104
|
+
};
|
|
90105
|
+
if (input.quantity === "device") return {
|
|
90106
|
+
ok: false,
|
|
90107
|
+
reason: "unknown-unit"
|
|
90108
|
+
};
|
|
90109
|
+
const raw = input.rawUnit?.trim();
|
|
90110
|
+
if (raw === void 0 || raw.length === 0) return {
|
|
90111
|
+
ok: true,
|
|
90112
|
+
value: input.value
|
|
90113
|
+
};
|
|
90114
|
+
const unit = normalizeUnit(raw);
|
|
90115
|
+
if (unit === void 0) return {
|
|
90116
|
+
ok: false,
|
|
90117
|
+
reason: "unknown-unit"
|
|
90118
|
+
};
|
|
90119
|
+
const base = baseUnitOf(input.quantity);
|
|
90120
|
+
if (base === void 0) {
|
|
90121
|
+
if (unitDimension(unit) !== void 0) return {
|
|
90122
|
+
ok: false,
|
|
90123
|
+
reason: "cross-dimension"
|
|
90124
|
+
};
|
|
90125
|
+
return {
|
|
90126
|
+
ok: false,
|
|
90127
|
+
reason: "unknown-unit"
|
|
90128
|
+
};
|
|
90129
|
+
}
|
|
90130
|
+
const converted = tryConvertUnit(input.value, unit, base);
|
|
90131
|
+
if (converted === void 0) return unitDimension(unit) === void 0 ? {
|
|
90132
|
+
ok: false,
|
|
90133
|
+
reason: "unknown-unit"
|
|
90134
|
+
} : {
|
|
90135
|
+
ok: false,
|
|
90136
|
+
reason: "cross-dimension"
|
|
90137
|
+
};
|
|
90138
|
+
return {
|
|
90139
|
+
ok: true,
|
|
90140
|
+
value: converted
|
|
90141
|
+
};
|
|
90142
|
+
}
|
|
90143
|
+
/**
|
|
89327
90144
|
* Pure fuzzy matcher for adoption location import. Normalized
|
|
89328
90145
|
* case-insensitive Levenshtein similarity, used to reuse an existing
|
|
89329
90146
|
* CamStack location when an imported source location (e.g. an HA area) is
|
|
@@ -89552,6 +90369,12 @@ Object.defineProperty(exports, "automationControlCapability", {
|
|
|
89552
90369
|
return automationControlCapability;
|
|
89553
90370
|
}
|
|
89554
90371
|
});
|
|
90372
|
+
Object.defineProperty(exports, "baseUnitOf", {
|
|
90373
|
+
enumerable: true,
|
|
90374
|
+
get: function() {
|
|
90375
|
+
return baseUnitOf;
|
|
90376
|
+
}
|
|
90377
|
+
});
|
|
89555
90378
|
Object.defineProperty(exports, "batteryCapability", {
|
|
89556
90379
|
enumerable: true,
|
|
89557
90380
|
get: function() {
|
|
@@ -89768,6 +90591,18 @@ Object.defineProperty(exports, "imageCapability", {
|
|
|
89768
90591
|
return imageCapability;
|
|
89769
90592
|
}
|
|
89770
90593
|
});
|
|
90594
|
+
Object.defineProperty(exports, "ingestReading", {
|
|
90595
|
+
enumerable: true,
|
|
90596
|
+
get: function() {
|
|
90597
|
+
return ingestReading;
|
|
90598
|
+
}
|
|
90599
|
+
});
|
|
90600
|
+
Object.defineProperty(exports, "isReadingQuantity", {
|
|
90601
|
+
enumerable: true,
|
|
90602
|
+
get: function() {
|
|
90603
|
+
return isReadingQuantity;
|
|
90604
|
+
}
|
|
90605
|
+
});
|
|
89771
90606
|
Object.defineProperty(exports, "lawnMowerControlCapability", {
|
|
89772
90607
|
enumerable: true,
|
|
89773
90608
|
get: function() {
|
|
@@ -89876,6 +90711,12 @@ Object.defineProperty(exports, "pressureSensorCapability", {
|
|
|
89876
90711
|
return pressureSensorCapability;
|
|
89877
90712
|
}
|
|
89878
90713
|
});
|
|
90714
|
+
Object.defineProperty(exports, "quantityFromUnit", {
|
|
90715
|
+
enumerable: true,
|
|
90716
|
+
get: function() {
|
|
90717
|
+
return quantityFromUnit;
|
|
90718
|
+
}
|
|
90719
|
+
});
|
|
89879
90720
|
Object.defineProperty(exports, "record", {
|
|
89880
90721
|
enumerable: true,
|
|
89881
90722
|
get: function() {
|
|
@@ -89942,6 +90783,18 @@ Object.defineProperty(exports, "temperatureSensorCapability", {
|
|
|
89942
90783
|
return temperatureSensorCapability;
|
|
89943
90784
|
}
|
|
89944
90785
|
});
|
|
90786
|
+
Object.defineProperty(exports, "tryConvertDelta", {
|
|
90787
|
+
enumerable: true,
|
|
90788
|
+
get: function() {
|
|
90789
|
+
return tryConvertDelta;
|
|
90790
|
+
}
|
|
90791
|
+
});
|
|
90792
|
+
Object.defineProperty(exports, "tryConvertUnit", {
|
|
90793
|
+
enumerable: true,
|
|
90794
|
+
get: function() {
|
|
90795
|
+
return tryConvertUnit;
|
|
90796
|
+
}
|
|
90797
|
+
});
|
|
89945
90798
|
Object.defineProperty(exports, "union", {
|
|
89946
90799
|
enumerable: true,
|
|
89947
90800
|
get: function() {
|