@camstack/addon-provider-unraid 0.2.146 → 0.2.148
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +341 -530
- package/dist/addon.mjs +341 -530
- package/package.json +7 -2
package/dist/addon.mjs
CHANGED
|
@@ -5433,7 +5433,7 @@ var ZodIssueCode = {
|
|
|
5433
5433
|
var ZodFirstPartyTypeKind;
|
|
5434
5434
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5435
5435
|
//#endregion
|
|
5436
|
-
//#region ../types/dist/sleep-
|
|
5436
|
+
//#region ../types/dist/sleep-CARd6wZF.mjs
|
|
5437
5437
|
/**
|
|
5438
5438
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5439
5439
|
* window to float samples (D455).
|
|
@@ -7987,6 +7987,52 @@ var RecordKindDeclarationSchema = object({
|
|
|
7987
7987
|
}).strict();
|
|
7988
7988
|
/** The kind names: lower-case, dash separated, short enough for an index name. */
|
|
7989
7989
|
var RecordKindNameSchema = string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
7990
|
+
var READING_QUANTITIES = [
|
|
7991
|
+
"temperature",
|
|
7992
|
+
"pressure",
|
|
7993
|
+
"speed",
|
|
7994
|
+
"precipitation",
|
|
7995
|
+
"precipitation-rate",
|
|
7996
|
+
"length",
|
|
7997
|
+
"area",
|
|
7998
|
+
"illuminance",
|
|
7999
|
+
"irradiance",
|
|
8000
|
+
"power",
|
|
8001
|
+
"energy",
|
|
8002
|
+
"voltage",
|
|
8003
|
+
"current",
|
|
8004
|
+
"apparent-power",
|
|
8005
|
+
"humidity",
|
|
8006
|
+
"percentage",
|
|
8007
|
+
"concentration-volume",
|
|
8008
|
+
"concentration-mass",
|
|
8009
|
+
"concentration-ppb",
|
|
8010
|
+
"volume",
|
|
8011
|
+
"duration",
|
|
8012
|
+
"duration-ms",
|
|
8013
|
+
"information",
|
|
8014
|
+
"sound-level",
|
|
8015
|
+
"signal-level",
|
|
8016
|
+
"colour-temperature",
|
|
8017
|
+
"angle",
|
|
8018
|
+
"bitrate",
|
|
8019
|
+
"rate",
|
|
8020
|
+
"mass",
|
|
8021
|
+
"index",
|
|
8022
|
+
"ratio",
|
|
8023
|
+
"count",
|
|
8024
|
+
"none",
|
|
8025
|
+
"device"
|
|
8026
|
+
];
|
|
8027
|
+
var ReadingQuantitySchema = _enum(READING_QUANTITIES);
|
|
8028
|
+
new Set(READING_QUANTITIES);
|
|
8029
|
+
function readingMeta(quantity, extras) {
|
|
8030
|
+
return {
|
|
8031
|
+
quantity,
|
|
8032
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
8033
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
8034
|
+
};
|
|
8035
|
+
}
|
|
7990
8036
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
7991
8037
|
var CamProfileSchema = _enum([
|
|
7992
8038
|
"high",
|
|
@@ -8014,8 +8060,8 @@ var CamStreamKindSchema = _enum([
|
|
|
8014
8060
|
"derived"
|
|
8015
8061
|
]);
|
|
8016
8062
|
var CamStreamResolutionSchema = object({
|
|
8017
|
-
width: number().int().positive(),
|
|
8018
|
-
height: number().int().positive()
|
|
8063
|
+
width: number().int().positive().meta(readingMeta("none")),
|
|
8064
|
+
height: number().int().positive().meta(readingMeta("none"))
|
|
8019
8065
|
});
|
|
8020
8066
|
var CameraStreamSchema = object({
|
|
8021
8067
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -8662,14 +8708,6 @@ Object.freeze({
|
|
|
8662
8708
|
{
|
|
8663
8709
|
"path": "aqi",
|
|
8664
8710
|
"valueType": "number"
|
|
8665
|
-
},
|
|
8666
|
-
{
|
|
8667
|
-
"path": "unit",
|
|
8668
|
-
"valueType": "string"
|
|
8669
|
-
},
|
|
8670
|
-
{
|
|
8671
|
-
"path": "precision",
|
|
8672
|
-
"valueType": "number"
|
|
8673
8711
|
}
|
|
8674
8712
|
],
|
|
8675
8713
|
"alarm-panel": [
|
|
@@ -8705,20 +8743,10 @@ Object.freeze({
|
|
|
8705
8743
|
"valueType": "boolean"
|
|
8706
8744
|
}
|
|
8707
8745
|
],
|
|
8708
|
-
"ambient-light-sensor": [
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
},
|
|
8713
|
-
{
|
|
8714
|
-
"path": "unit",
|
|
8715
|
-
"valueType": "string"
|
|
8716
|
-
},
|
|
8717
|
-
{
|
|
8718
|
-
"path": "precision",
|
|
8719
|
-
"valueType": "number"
|
|
8720
|
-
}
|
|
8721
|
-
],
|
|
8746
|
+
"ambient-light-sensor": [{
|
|
8747
|
+
"path": "lux",
|
|
8748
|
+
"valueType": "number"
|
|
8749
|
+
}],
|
|
8722
8750
|
"audio-metrics": [
|
|
8723
8751
|
{
|
|
8724
8752
|
"path": "ts",
|
|
@@ -8798,6 +8826,10 @@ Object.freeze({
|
|
|
8798
8826
|
"path": "lastUpdated",
|
|
8799
8827
|
"valueType": "number"
|
|
8800
8828
|
},
|
|
8829
|
+
{
|
|
8830
|
+
"path": "volts",
|
|
8831
|
+
"valueType": "number"
|
|
8832
|
+
},
|
|
8801
8833
|
{
|
|
8802
8834
|
"path": "lastContactAt",
|
|
8803
8835
|
"valueType": "number"
|
|
@@ -9040,10 +9072,6 @@ Object.freeze({
|
|
|
9040
9072
|
"datetime"
|
|
9041
9073
|
]
|
|
9042
9074
|
},
|
|
9043
|
-
{
|
|
9044
|
-
"path": "unit",
|
|
9045
|
-
"valueType": "string"
|
|
9046
|
-
},
|
|
9047
9075
|
{
|
|
9048
9076
|
"path": "min",
|
|
9049
9077
|
"valueType": "number"
|
|
@@ -9055,19 +9083,6 @@ Object.freeze({
|
|
|
9055
9083
|
{
|
|
9056
9084
|
"path": "step",
|
|
9057
9085
|
"valueType": "number"
|
|
9058
|
-
},
|
|
9059
|
-
{
|
|
9060
|
-
"path": "precision",
|
|
9061
|
-
"valueType": "number"
|
|
9062
|
-
},
|
|
9063
|
-
{
|
|
9064
|
-
"path": "format",
|
|
9065
|
-
"valueType": "enum",
|
|
9066
|
-
"enumValues": [
|
|
9067
|
-
"date",
|
|
9068
|
-
"time",
|
|
9069
|
-
"datetime"
|
|
9070
|
-
]
|
|
9071
9086
|
}
|
|
9072
9087
|
],
|
|
9073
9088
|
"cover": [
|
|
@@ -9308,13 +9323,8 @@ Object.freeze({
|
|
|
9308
9323
|
"path": "value",
|
|
9309
9324
|
"valueType": "string"
|
|
9310
9325
|
}, {
|
|
9311
|
-
"path": "
|
|
9312
|
-
"valueType": "
|
|
9313
|
-
"enumValues": [
|
|
9314
|
-
"date",
|
|
9315
|
-
"time",
|
|
9316
|
-
"datetime"
|
|
9317
|
-
]
|
|
9326
|
+
"path": "timestamp",
|
|
9327
|
+
"valueType": "boolean"
|
|
9318
9328
|
}],
|
|
9319
9329
|
"event-emitter": [
|
|
9320
9330
|
{
|
|
@@ -9421,20 +9431,10 @@ Object.freeze({
|
|
|
9421
9431
|
"valueType": "number"
|
|
9422
9432
|
}
|
|
9423
9433
|
],
|
|
9424
|
-
"humidity-sensor": [
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
},
|
|
9429
|
-
{
|
|
9430
|
-
"path": "unit",
|
|
9431
|
-
"valueType": "string"
|
|
9432
|
-
},
|
|
9433
|
-
{
|
|
9434
|
-
"path": "precision",
|
|
9435
|
-
"valueType": "number"
|
|
9436
|
-
}
|
|
9437
|
-
],
|
|
9434
|
+
"humidity-sensor": [{
|
|
9435
|
+
"path": "percent",
|
|
9436
|
+
"valueType": "number"
|
|
9437
|
+
}],
|
|
9438
9438
|
"image": [{
|
|
9439
9439
|
"path": "url",
|
|
9440
9440
|
"valueType": "string"
|
|
@@ -9773,20 +9773,10 @@ Object.freeze({
|
|
|
9773
9773
|
"valueType": "boolean"
|
|
9774
9774
|
}
|
|
9775
9775
|
],
|
|
9776
|
-
"numeric-sensor": [
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
},
|
|
9781
|
-
{
|
|
9782
|
-
"path": "unit",
|
|
9783
|
-
"valueType": "string"
|
|
9784
|
-
},
|
|
9785
|
-
{
|
|
9786
|
-
"path": "precision",
|
|
9787
|
-
"valueType": "number"
|
|
9788
|
-
}
|
|
9789
|
-
],
|
|
9776
|
+
"numeric-sensor": [{
|
|
9777
|
+
"path": "value",
|
|
9778
|
+
"valueType": "number"
|
|
9779
|
+
}],
|
|
9790
9780
|
"pet-feeder": [
|
|
9791
9781
|
{
|
|
9792
9782
|
"path": "foodLevel",
|
|
@@ -9878,14 +9868,6 @@ Object.freeze({
|
|
|
9878
9868
|
{
|
|
9879
9869
|
"path": "powerFactor",
|
|
9880
9870
|
"valueType": "number"
|
|
9881
|
-
},
|
|
9882
|
-
{
|
|
9883
|
-
"path": "unit",
|
|
9884
|
-
"valueType": "string"
|
|
9885
|
-
},
|
|
9886
|
-
{
|
|
9887
|
-
"path": "precision",
|
|
9888
|
-
"valueType": "number"
|
|
9889
9871
|
}
|
|
9890
9872
|
],
|
|
9891
9873
|
"presence": [
|
|
@@ -9914,20 +9896,10 @@ Object.freeze({
|
|
|
9914
9896
|
"valueType": "number"
|
|
9915
9897
|
}
|
|
9916
9898
|
],
|
|
9917
|
-
"pressure-sensor": [
|
|
9918
|
-
|
|
9919
|
-
|
|
9920
|
-
|
|
9921
|
-
},
|
|
9922
|
-
{
|
|
9923
|
-
"path": "unit",
|
|
9924
|
-
"valueType": "string"
|
|
9925
|
-
},
|
|
9926
|
-
{
|
|
9927
|
-
"path": "precision",
|
|
9928
|
-
"valueType": "number"
|
|
9929
|
-
}
|
|
9930
|
-
],
|
|
9899
|
+
"pressure-sensor": [{
|
|
9900
|
+
"path": "hpa",
|
|
9901
|
+
"valueType": "number"
|
|
9902
|
+
}],
|
|
9931
9903
|
"privacy-mask": [{
|
|
9932
9904
|
"path": "enabled",
|
|
9933
9905
|
"valueType": "boolean"
|
|
@@ -10238,20 +10210,10 @@ Object.freeze({
|
|
|
10238
10210
|
"path": "tampered",
|
|
10239
10211
|
"valueType": "boolean"
|
|
10240
10212
|
}],
|
|
10241
|
-
"temperature-sensor": [
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
},
|
|
10246
|
-
{
|
|
10247
|
-
"path": "unit",
|
|
10248
|
-
"valueType": "string"
|
|
10249
|
-
},
|
|
10250
|
-
{
|
|
10251
|
-
"path": "precision",
|
|
10252
|
-
"valueType": "number"
|
|
10253
|
-
}
|
|
10254
|
-
],
|
|
10213
|
+
"temperature-sensor": [{
|
|
10214
|
+
"path": "celsius",
|
|
10215
|
+
"valueType": "number"
|
|
10216
|
+
}],
|
|
10255
10217
|
"update": [
|
|
10256
10218
|
{
|
|
10257
10219
|
"path": "currentVersion",
|
|
@@ -10362,10 +10324,6 @@ Object.freeze({
|
|
|
10362
10324
|
"path": "temperature",
|
|
10363
10325
|
"valueType": "number"
|
|
10364
10326
|
},
|
|
10365
|
-
{
|
|
10366
|
-
"path": "temperatureUnit",
|
|
10367
|
-
"valueType": "string"
|
|
10368
|
-
},
|
|
10369
10327
|
{
|
|
10370
10328
|
"path": "humidity",
|
|
10371
10329
|
"valueType": "number"
|
|
@@ -10374,18 +10332,10 @@ Object.freeze({
|
|
|
10374
10332
|
"path": "pressure",
|
|
10375
10333
|
"valueType": "number"
|
|
10376
10334
|
},
|
|
10377
|
-
{
|
|
10378
|
-
"path": "pressureUnit",
|
|
10379
|
-
"valueType": "string"
|
|
10380
|
-
},
|
|
10381
10335
|
{
|
|
10382
10336
|
"path": "windSpeed",
|
|
10383
10337
|
"valueType": "number"
|
|
10384
10338
|
},
|
|
10385
|
-
{
|
|
10386
|
-
"path": "windSpeedUnit",
|
|
10387
|
-
"valueType": "string"
|
|
10388
|
-
},
|
|
10389
10339
|
{
|
|
10390
10340
|
"path": "windBearing",
|
|
10391
10341
|
"valueType": "number"
|
|
@@ -17863,7 +17813,8 @@ var CompositionProblemSchema = object({
|
|
|
17863
17813
|
"item-field-reserved",
|
|
17864
17814
|
"target-missing",
|
|
17865
17815
|
"target-unreadable",
|
|
17866
|
-
"not-replaceable"
|
|
17816
|
+
"not-replaceable",
|
|
17817
|
+
"native-capability-replace"
|
|
17867
17818
|
]),
|
|
17868
17819
|
path: string(),
|
|
17869
17820
|
message: string()
|
|
@@ -17921,9 +17872,11 @@ var CompositionFieldPlanSchema = object({
|
|
|
17921
17872
|
reads: array(CompositionFieldReadSchema)
|
|
17922
17873
|
});
|
|
17923
17874
|
/**
|
|
17924
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17925
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17926
|
-
*
|
|
17875
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
17876
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
17877
|
+
* Replacing a capability the device already serves is refused
|
|
17878
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
17879
|
+
* wire for a claim the hub already holds.
|
|
17927
17880
|
*/
|
|
17928
17881
|
var CompositionFeatureModeSchema = _enum([
|
|
17929
17882
|
"new",
|
|
@@ -19922,12 +19875,12 @@ function buildDeviceAdminUrl(parts) {
|
|
|
19922
19875
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
19923
19876
|
* in-place so dispatch keeps working.
|
|
19924
19877
|
*
|
|
19925
|
-
* **
|
|
19926
|
-
*
|
|
19927
|
-
*
|
|
19928
|
-
*
|
|
19929
|
-
* (`ha-domain-mapping`)
|
|
19930
|
-
* stored after that point.
|
|
19878
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
19879
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
19880
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
19881
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
19882
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
19883
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
19931
19884
|
*
|
|
19932
19885
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
19933
19886
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -19941,6 +19894,14 @@ var SourceInfoSchema = object({
|
|
|
19941
19894
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
19942
19895
|
* Used to detect rename when `id` changes. */
|
|
19943
19896
|
uniqueId: string().optional(),
|
|
19897
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
19898
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
19899
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
19900
|
+
dateTimeShape: _enum([
|
|
19901
|
+
"date",
|
|
19902
|
+
"time",
|
|
19903
|
+
"datetime"
|
|
19904
|
+
]).optional(),
|
|
19944
19905
|
/** Provider-specific extras that don't fit the structured slots.
|
|
19945
19906
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
19946
19907
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -41045,7 +41006,8 @@ method(object({
|
|
|
41045
41006
|
"enum"
|
|
41046
41007
|
]),
|
|
41047
41008
|
enumValues: array(string()).optional(),
|
|
41048
|
-
item: boolean().optional()
|
|
41009
|
+
item: boolean().optional(),
|
|
41010
|
+
quantity: ReadingQuantitySchema.optional()
|
|
41049
41011
|
})).readonly(),
|
|
41050
41012
|
itemArray: object({
|
|
41051
41013
|
path: string(),
|
|
@@ -44889,8 +44851,8 @@ var MaskPolygonShapeSchema = object({
|
|
|
44889
44851
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
44890
44852
|
var MaskGridShapeSchema = object({
|
|
44891
44853
|
kind: literal("grid"),
|
|
44892
|
-
gridWidth: number(),
|
|
44893
|
-
gridHeight: number(),
|
|
44854
|
+
gridWidth: number().meta(readingMeta("none")),
|
|
44855
|
+
gridHeight: number().meta(readingMeta("none")),
|
|
44894
44856
|
cells: array(boolean())
|
|
44895
44857
|
});
|
|
44896
44858
|
discriminatedUnion("kind", [
|
|
@@ -56370,27 +56332,17 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
|
|
|
56370
56332
|
*/
|
|
56371
56333
|
var AirQualitySensorStatusSchema = object({
|
|
56372
56334
|
/** Carbon dioxide concentration in ppm. */
|
|
56373
|
-
co2Ppm: number().min(0).optional(),
|
|
56335
|
+
co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
56374
56336
|
/** Total volatile organic compounds in ppb. */
|
|
56375
|
-
vocPpb: number().min(0).optional(),
|
|
56337
|
+
vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
56376
56338
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
56377
|
-
pm25: number().min(0).optional(),
|
|
56339
|
+
pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56378
56340
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
56379
|
-
pm10: number().min(0).optional(),
|
|
56341
|
+
pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
56380
56342
|
/** Composite AQI value (typically 0..500). */
|
|
56381
|
-
aqi: number().optional(),
|
|
56343
|
+
aqi: number().optional().meta(readingMeta("index")),
|
|
56382
56344
|
/** Ms epoch when the slice was last updated. */
|
|
56383
|
-
lastFetchedAt: number()
|
|
56384
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
56385
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
56386
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
56387
|
-
* per slice is unambiguous. */
|
|
56388
|
-
unit: string().optional(),
|
|
56389
|
-
/** Suggested decimal places for numeric display.
|
|
56390
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56391
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56392
|
-
* auto-formatting when absent. */
|
|
56393
|
-
precision: number().int().min(0).max(10).optional()
|
|
56345
|
+
lastFetchedAt: number()
|
|
56394
56346
|
});
|
|
56395
56347
|
var airQualitySensorCapability = {
|
|
56396
56348
|
name: "air-quality-sensor",
|
|
@@ -56427,12 +56379,12 @@ var airQualitySensorCapability = {
|
|
|
56427
56379
|
},
|
|
56428
56380
|
pm25: {
|
|
56429
56381
|
kind: "gauge",
|
|
56430
|
-
unit: "
|
|
56382
|
+
unit: "µg/m³",
|
|
56431
56383
|
deadband: 1
|
|
56432
56384
|
},
|
|
56433
56385
|
pm10: {
|
|
56434
56386
|
kind: "gauge",
|
|
56435
|
-
unit: "
|
|
56387
|
+
unit: "µg/m³",
|
|
56436
56388
|
deadband: 1
|
|
56437
56389
|
},
|
|
56438
56390
|
aqi: {
|
|
@@ -56450,22 +56402,13 @@ var airQualitySensorCapability = {
|
|
|
56450
56402
|
* entries with `device_class: illuminance`.
|
|
56451
56403
|
*/
|
|
56452
56404
|
var AmbientLightSensorStatusSchema = object({
|
|
56453
|
-
/** Current illuminance in lux (lx). */
|
|
56454
|
-
lux: number().min(0).meta({
|
|
56455
|
-
|
|
56405
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
56406
|
+
lux: number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
56407
|
+
precision: 0,
|
|
56456
56408
|
label: "Illuminance"
|
|
56457
|
-
}),
|
|
56409
|
+
})),
|
|
56458
56410
|
/** Ms epoch when the slice was last updated. */
|
|
56459
|
-
lastFetchedAt: number()
|
|
56460
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
56461
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
56462
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
56463
|
-
unit: string().optional(),
|
|
56464
|
-
/** Suggested decimal places for numeric display.
|
|
56465
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
56466
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
56467
|
-
* auto-formatting when absent. */
|
|
56468
|
-
precision: number().int().min(0).max(10).optional()
|
|
56411
|
+
lastFetchedAt: number()
|
|
56469
56412
|
});
|
|
56470
56413
|
var ambientLightSensorCapability = {
|
|
56471
56414
|
name: "ambient-light-sensor",
|
|
@@ -56497,12 +56440,7 @@ var ambientLightSensorCapability = {
|
|
|
56497
56440
|
} } },
|
|
56498
56441
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56499
56442
|
* whether persisting is worth a SQLite commit. */
|
|
56500
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
56501
|
-
customize: {
|
|
56502
|
-
version: 1,
|
|
56503
|
-
advanced: "derive",
|
|
56504
|
-
targets: []
|
|
56505
|
-
}
|
|
56443
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
56506
56444
|
};
|
|
56507
56445
|
/**
|
|
56508
56446
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -56729,10 +56667,7 @@ var BatteryStatusSchema = object({
|
|
|
56729
56667
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
56730
56668
|
* declines to band a non-finite reading, which is the correct shape.
|
|
56731
56669
|
*/
|
|
56732
|
-
percentage: number().min(0).max(100).nullable().meta({
|
|
56733
|
-
unit: "%",
|
|
56734
|
-
label: "Charge"
|
|
56735
|
-
}),
|
|
56670
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
56736
56671
|
/**
|
|
56737
56672
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
56738
56673
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -56759,7 +56694,14 @@ var BatteryStatusSchema = object({
|
|
|
56759
56694
|
*/
|
|
56760
56695
|
sleeping: boolean().meta({ label: "Sleeping" }),
|
|
56761
56696
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
56762
|
-
lastUpdated: number(),
|
|
56697
|
+
lastUpdated: number().meta(readingMeta("none")),
|
|
56698
|
+
/**
|
|
56699
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
56700
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
56701
|
+
* that only report charge. A second reading on this cap, not a second
|
|
56702
|
+
* `numeric-sensor` on the same device.
|
|
56703
|
+
*/
|
|
56704
|
+
volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
56763
56705
|
/**
|
|
56764
56706
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
56765
56707
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -56811,7 +56753,6 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
56811
56753
|
/** Generic Customize target for the percentage reading (D936). */
|
|
56812
56754
|
var batteryCustomize = {
|
|
56813
56755
|
version: 1,
|
|
56814
|
-
advanced: "derive",
|
|
56815
56756
|
targets: [{
|
|
56816
56757
|
id: "percentage",
|
|
56817
56758
|
cardinality: "scalar",
|
|
@@ -56820,7 +56761,7 @@ var batteryCustomize = {
|
|
|
56820
56761
|
stateField: "percentage"
|
|
56821
56762
|
},
|
|
56822
56763
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
56823
|
-
apply: "add
|
|
56764
|
+
apply: "add",
|
|
56824
56765
|
path: "percentage",
|
|
56825
56766
|
sources: [{
|
|
56826
56767
|
kind: "field",
|
|
@@ -56941,10 +56882,16 @@ onStatusChanged: { data: object({
|
|
|
56941
56882
|
/**
|
|
56942
56883
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
56943
56884
|
*/
|
|
56944
|
-
history: { fields: {
|
|
56945
|
-
|
|
56946
|
-
|
|
56947
|
-
|
|
56885
|
+
history: { fields: {
|
|
56886
|
+
percentage: {
|
|
56887
|
+
kind: "gauge",
|
|
56888
|
+
unit: "%"
|
|
56889
|
+
},
|
|
56890
|
+
volts: {
|
|
56891
|
+
kind: "gauge",
|
|
56892
|
+
unit: "V"
|
|
56893
|
+
}
|
|
56894
|
+
} },
|
|
56948
56895
|
customize: batteryCustomize,
|
|
56949
56896
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56950
56897
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -56991,12 +56938,7 @@ var binaryCapability = {
|
|
|
56991
56938
|
history: { fields: { on: { kind: "boolean" } } },
|
|
56992
56939
|
/** Clock fields: written, but excluded from the compare that decides
|
|
56993
56940
|
* whether persisting is worth a SQLite commit. */
|
|
56994
|
-
volatileStateFields: ["lastChangedAt"]
|
|
56995
|
-
customize: {
|
|
56996
|
-
version: 1,
|
|
56997
|
-
advanced: "derive",
|
|
56998
|
-
targets: []
|
|
56999
|
-
}
|
|
56941
|
+
volatileStateFields: ["lastChangedAt"]
|
|
57000
56942
|
};
|
|
57001
56943
|
/**
|
|
57002
56944
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -57012,7 +56954,7 @@ var binaryCapability = {
|
|
|
57012
56954
|
*/
|
|
57013
56955
|
var BrightnessStatusSchema = object({
|
|
57014
56956
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
57015
|
-
percentage: number().min(0).max(100),
|
|
56957
|
+
percentage: number().min(0).max(100).meta(readingMeta("percentage")),
|
|
57016
56958
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
57017
56959
|
lastChangedAt: number()
|
|
57018
56960
|
});
|
|
@@ -57483,21 +57425,21 @@ var ClimateControlStatusSchema = object({
|
|
|
57483
57425
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
57484
57426
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
57485
57427
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
57486
|
-
target: number().nullable(),
|
|
57428
|
+
target: number().nullable().meta(readingMeta("temperature")),
|
|
57487
57429
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
57488
57430
|
* in `heat_cool` mode. */
|
|
57489
|
-
targetHigh: number().nullable(),
|
|
57431
|
+
targetHigh: number().nullable().meta(readingMeta("temperature")),
|
|
57490
57432
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
57491
57433
|
* in `heat_cool` mode. */
|
|
57492
|
-
targetLow: number().nullable(),
|
|
57434
|
+
targetLow: number().nullable().meta(readingMeta("temperature")),
|
|
57493
57435
|
/** Target relative humidity (0..100). Null when the device has no
|
|
57494
57436
|
* humidity control. */
|
|
57495
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
57437
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57496
57438
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
57497
57439
|
* the device's internal sensor. */
|
|
57498
|
-
currentTemp: number().nullable(),
|
|
57440
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
57499
57441
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
57500
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
57442
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
57501
57443
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
57502
57444
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
57503
57445
|
swingVertical: boolean().nullable(),
|
|
@@ -57505,11 +57447,11 @@ var ClimateControlStatusSchema = object({
|
|
|
57505
57447
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
57506
57448
|
swingHorizontal: boolean().nullable(),
|
|
57507
57449
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57508
|
-
minTemp: number().nullable().optional(),
|
|
57450
|
+
minTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57509
57451
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
57510
|
-
maxTemp: number().nullable().optional(),
|
|
57452
|
+
maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
|
|
57511
57453
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
57512
|
-
tempStep: number().positive().nullable().optional(),
|
|
57454
|
+
tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
57513
57455
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
57514
57456
|
lastFetchedAt: number()
|
|
57515
57457
|
});
|
|
@@ -57651,17 +57593,17 @@ var climateControlCapability = {
|
|
|
57651
57593
|
* modes to expose in the picker without a slice fetch.
|
|
57652
57594
|
*/
|
|
57653
57595
|
var RgbTripletSchema = object({
|
|
57654
|
-
r: number().int().min(0).max(255),
|
|
57655
|
-
g: number().int().min(0).max(255),
|
|
57656
|
-
b: number().int().min(0).max(255)
|
|
57596
|
+
r: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57597
|
+
g: number().int().min(0).max(255).meta(readingMeta("none")),
|
|
57598
|
+
b: number().int().min(0).max(255).meta(readingMeta("none"))
|
|
57657
57599
|
});
|
|
57658
57600
|
var HsvTripletSchema = object({
|
|
57659
57601
|
/** Hue in degrees, 0..360. */
|
|
57660
|
-
h: number().min(0).max(360),
|
|
57602
|
+
h: number().min(0).max(360).meta(readingMeta("none")),
|
|
57661
57603
|
/** Saturation as 0..100 inclusive. */
|
|
57662
|
-
s: number().min(0).max(100),
|
|
57604
|
+
s: number().min(0).max(100).meta(readingMeta("none")),
|
|
57663
57605
|
/** Value/brightness as 0..100 inclusive. */
|
|
57664
|
-
v: number().min(0).max(100)
|
|
57606
|
+
v: number().min(0).max(100).meta(readingMeta("none"))
|
|
57665
57607
|
});
|
|
57666
57608
|
var ColorInputSchema = discriminatedUnion("mode", [
|
|
57667
57609
|
object({
|
|
@@ -57690,7 +57632,7 @@ var ColorStatusSchema = object({
|
|
|
57690
57632
|
/** Populated when `mode === 'hsv'`. */
|
|
57691
57633
|
hsv: HsvTripletSchema.optional(),
|
|
57692
57634
|
/** Populated when `mode === 'mired'`. */
|
|
57693
|
-
mireds: number().int().optional(),
|
|
57635
|
+
mireds: number().int().optional().meta(readingMeta("colour-temperature")),
|
|
57694
57636
|
/** Ms epoch of the last operator-driven change. */
|
|
57695
57637
|
lastChangedAt: number()
|
|
57696
57638
|
});
|
|
@@ -57885,18 +57827,12 @@ _enum([
|
|
|
57885
57827
|
"empty",
|
|
57886
57828
|
"full"
|
|
57887
57829
|
]);
|
|
57888
|
-
/**
|
|
57889
|
-
|
|
57890
|
-
|
|
57891
|
-
"days",
|
|
57892
|
-
"hours",
|
|
57893
|
-
"cycles"
|
|
57894
|
-
]);
|
|
57895
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
57896
|
-
* days). `value` null = unknown (D393). */
|
|
57830
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
57831
|
+
var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
|
|
57832
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
57897
57833
|
var ConsumableRemainingSchema = object({
|
|
57898
|
-
value: number().min(0).nullable(),
|
|
57899
|
-
|
|
57834
|
+
value: number().min(0).nullable().meta(readingMeta("device")),
|
|
57835
|
+
kind: ConsumableRemainingKindSchema
|
|
57900
57836
|
});
|
|
57901
57837
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
57902
57838
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -57909,7 +57845,7 @@ var ConsumableItemSchema = object({
|
|
|
57909
57845
|
/** Display name. */
|
|
57910
57846
|
label: string().min(1),
|
|
57911
57847
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
57912
|
-
level: number().min(0).max(100).nullable(),
|
|
57848
|
+
level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
57913
57849
|
/** The provider's discrete verdict when known (binary mode). */
|
|
57914
57850
|
status: ConsumableStatusSchema.nullable(),
|
|
57915
57851
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -57991,8 +57927,8 @@ var consumablesCustomize = {
|
|
|
57991
57927
|
transforms: [{ kind: "identity" }]
|
|
57992
57928
|
}],
|
|
57993
57929
|
literals: [{
|
|
57994
|
-
path: "remaining.
|
|
57995
|
-
values: [...
|
|
57930
|
+
path: "remaining.kind",
|
|
57931
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
57996
57932
|
}]
|
|
57997
57933
|
},
|
|
57998
57934
|
{
|
|
@@ -58121,7 +58057,6 @@ reset: method(object({
|
|
|
58121
58057
|
},
|
|
58122
58058
|
"remaining.value": {
|
|
58123
58059
|
kind: "gauge",
|
|
58124
|
-
unitFrom: "remaining.unit",
|
|
58125
58060
|
deadband: 1,
|
|
58126
58061
|
displayName: "Remaining"
|
|
58127
58062
|
}
|
|
@@ -58191,10 +58126,9 @@ var contactCapability = {
|
|
|
58191
58126
|
* (empty array for the other kinds). It lives in the slice because
|
|
58192
58127
|
* HA `select.*` entities may update their options at runtime.
|
|
58193
58128
|
*
|
|
58194
|
-
*
|
|
58195
|
-
*
|
|
58196
|
-
*
|
|
58197
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
58129
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
58130
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
58131
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
58198
58132
|
*/
|
|
58199
58133
|
var ControlStatusSchema = object({
|
|
58200
58134
|
kind: _enum([
|
|
@@ -58206,39 +58140,17 @@ var ControlStatusSchema = object({
|
|
|
58206
58140
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
58207
58141
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
58208
58142
|
* or time-only — HA accepts all three forms). */
|
|
58209
|
-
value: union([number(), string()]),
|
|
58143
|
+
value: union([number().meta(readingMeta("device")), string()]),
|
|
58210
58144
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
58211
58145
|
options: array(string()),
|
|
58212
58146
|
/** Ms epoch when the slice was last updated. */
|
|
58213
58147
|
lastChangedAt: number(),
|
|
58214
|
-
/**
|
|
58215
|
-
|
|
58216
|
-
|
|
58217
|
-
|
|
58218
|
-
/**
|
|
58219
|
-
|
|
58220
|
-
min: number().optional(),
|
|
58221
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
58222
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58223
|
-
max: number().optional(),
|
|
58224
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
58225
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
58226
|
-
step: number().optional(),
|
|
58227
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
58228
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
58229
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
58230
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
58231
|
-
precision: number().int().min(0).max(10).optional(),
|
|
58232
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
58233
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
58234
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
58235
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
58236
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
58237
|
-
format: _enum([
|
|
58238
|
-
"date",
|
|
58239
|
-
"time",
|
|
58240
|
-
"datetime"
|
|
58241
|
-
]).optional()
|
|
58148
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
58149
|
+
min: number().optional().meta(readingMeta("device")),
|
|
58150
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
58151
|
+
max: number().optional().meta(readingMeta("device")),
|
|
58152
|
+
/** Step increment, in the device quantity's base unit. */
|
|
58153
|
+
step: number().optional().meta(readingMeta("device"))
|
|
58242
58154
|
});
|
|
58243
58155
|
var ControlSetValueInputSchema = discriminatedUnion("kind", [
|
|
58244
58156
|
object({
|
|
@@ -58304,9 +58216,9 @@ var CoverStatusSchema = object({
|
|
|
58304
58216
|
]),
|
|
58305
58217
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
58306
58218
|
* no intermediate position surface. */
|
|
58307
|
-
position: number().min(0).max(100).nullable(),
|
|
58219
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58308
58220
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
58309
|
-
tiltPosition: number().min(0).max(100).nullable(),
|
|
58221
|
+
tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58310
58222
|
/** Ms epoch when the slice was last updated. */
|
|
58311
58223
|
lastChangedAt: number()
|
|
58312
58224
|
});
|
|
@@ -58409,9 +58321,9 @@ var NormalizedRangeSchema$1 = object({
|
|
|
58409
58321
|
var DayNightStatusSchema = object({
|
|
58410
58322
|
mode: DayNightModeSchema,
|
|
58411
58323
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
58412
|
-
sensitivity: number().optional(),
|
|
58324
|
+
sensitivity: number().optional().meta(readingMeta("none")),
|
|
58413
58325
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
58414
|
-
switchDelaySec: number().optional(),
|
|
58326
|
+
switchDelaySec: number().optional().meta(readingMeta("duration")),
|
|
58415
58327
|
lastFetchedAt: number()
|
|
58416
58328
|
});
|
|
58417
58329
|
/**
|
|
@@ -58629,11 +58541,11 @@ var DishwasherStatusSchema = object({
|
|
|
58629
58541
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
58630
58542
|
availablePrograms: array(string()),
|
|
58631
58543
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
58632
|
-
remainingSeconds: number().int().nonnegative().nullable(),
|
|
58544
|
+
remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58633
58545
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
58634
|
-
delayedStartSeconds: number().int().nonnegative().nullable(),
|
|
58546
|
+
delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
58635
58547
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
58636
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
58548
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
58637
58549
|
/** True when the door is reported open; null when the door state is not known. */
|
|
58638
58550
|
doorOpen: boolean().nullable(),
|
|
58639
58551
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -58657,7 +58569,7 @@ var DishwasherStatusSchema = object({
|
|
|
58657
58569
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
58658
58570
|
machineCareDue: boolean().nullable(),
|
|
58659
58571
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
58660
|
-
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
58572
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
58661
58573
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
58662
58574
|
halfLoad: boolean().nullable(),
|
|
58663
58575
|
hygienePlus: boolean().nullable(),
|
|
@@ -58672,7 +58584,7 @@ var DishwasherStatusSchema = object({
|
|
|
58672
58584
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
58673
58585
|
activeEvents: array(string()),
|
|
58674
58586
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
58675
|
-
errorCode: number().nullable(),
|
|
58587
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
58676
58588
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
58677
58589
|
errorLabel: string().nullable(),
|
|
58678
58590
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -58884,6 +58796,7 @@ var doorbellCustomize = {
|
|
|
58884
58796
|
applyAuthority: { kind: "composition-claim" },
|
|
58885
58797
|
eventName: "onPressed",
|
|
58886
58798
|
edges: ["rising"],
|
|
58799
|
+
defaultEdge: "rising",
|
|
58887
58800
|
timestampPath: "lastPressedAt",
|
|
58888
58801
|
counterPath: "pressCountSinceStart",
|
|
58889
58802
|
highWater: "composer-advance",
|
|
@@ -58902,7 +58815,7 @@ var DoorbellStatusSchema = object({
|
|
|
58902
58815
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
58903
58816
|
lastPressedAt: number().nullable(),
|
|
58904
58817
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
58905
|
-
pressCountSinceStart: number()
|
|
58818
|
+
pressCountSinceStart: number().meta(readingMeta("count"))
|
|
58906
58819
|
});
|
|
58907
58820
|
var DoorbellPressEventSchema = object({
|
|
58908
58821
|
deviceId: number(),
|
|
@@ -58967,17 +58880,7 @@ onPressed: {
|
|
|
58967
58880
|
history: "none",
|
|
58968
58881
|
customize: doorbellCustomize
|
|
58969
58882
|
};
|
|
58970
|
-
|
|
58971
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
58972
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
58973
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
58974
|
-
* The option set is stable across observations; it is persisted in the
|
|
58975
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
58976
|
-
* stored in `sourceInfo`.
|
|
58977
|
-
*/
|
|
58978
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
58979
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
58980
|
-
var EnumSensorDateTimeFormatSchema = _enum([
|
|
58883
|
+
_enum([
|
|
58981
58884
|
"date",
|
|
58982
58885
|
"time",
|
|
58983
58886
|
"datetime"
|
|
@@ -58985,12 +58888,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
|
|
|
58985
58888
|
var EnumSensorStatusSchema = object({
|
|
58986
58889
|
value: string(),
|
|
58987
58890
|
/**
|
|
58988
|
-
* Set
|
|
58989
|
-
* as
|
|
58990
|
-
*
|
|
58991
|
-
* a time-only sensor → `'time'`.
|
|
58891
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
58892
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
58893
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
58992
58894
|
*/
|
|
58993
|
-
|
|
58895
|
+
timestamp: boolean().optional(),
|
|
58994
58896
|
/** Ms epoch when the slice was last updated. */
|
|
58995
58897
|
lastFetchedAt: number()
|
|
58996
58898
|
});
|
|
@@ -59017,11 +58919,11 @@ var enumSensorCapability = {
|
|
|
59017
58919
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59018
58920
|
* operation state, an HVAC action). The option set is per device, so the
|
|
59019
58921
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59020
|
-
* `
|
|
58922
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
59021
58923
|
*/
|
|
59022
58924
|
history: { fields: { value: {
|
|
59023
58925
|
kind: "enum",
|
|
59024
|
-
skipWhenSet: "
|
|
58926
|
+
skipWhenSet: "timestamp"
|
|
59025
58927
|
} } },
|
|
59026
58928
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59027
58929
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -59041,13 +58943,13 @@ var EventFireSchema = object({
|
|
|
59041
58943
|
deviceId: number(),
|
|
59042
58944
|
eventType: string(),
|
|
59043
58945
|
data: record(string(), unknown()).nullable(),
|
|
59044
|
-
timestamp: number(),
|
|
59045
|
-
seq: number()
|
|
58946
|
+
timestamp: number().meta(readingMeta("none")),
|
|
58947
|
+
seq: number().meta(readingMeta("count"))
|
|
59046
58948
|
});
|
|
59047
58949
|
var EventEmitterStatusSchema = object({
|
|
59048
58950
|
eventTypes: array(string()),
|
|
59049
58951
|
lastEvent: EventFireSchema.nullable(),
|
|
59050
|
-
eventCountSinceStart: number()
|
|
58952
|
+
eventCountSinceStart: number().meta(readingMeta("count"))
|
|
59051
58953
|
});
|
|
59052
58954
|
var eventEmitterCapability = {
|
|
59053
58955
|
name: "event-emitter",
|
|
@@ -59460,10 +59362,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
|
|
|
59460
59362
|
var FanControlStatusSchema = object({
|
|
59461
59363
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
59462
59364
|
* speed surface (single-speed fan). */
|
|
59463
|
-
percentage: number().min(0).max(100).nullable(),
|
|
59365
|
+
percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59464
59366
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
59465
59367
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
59466
|
-
percentageStep: number().positive().optional(),
|
|
59368
|
+
percentageStep: number().positive().optional().meta(readingMeta("percentage")),
|
|
59467
59369
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
59468
59370
|
* — empty string when no preset is active or supported. */
|
|
59469
59371
|
preset: string(),
|
|
@@ -59584,7 +59486,7 @@ var FeatureProbeStatusSchema = object({
|
|
|
59584
59486
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
59585
59487
|
model: string().nullable(),
|
|
59586
59488
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
59587
|
-
channelCount: number().nullable(),
|
|
59489
|
+
channelCount: number().nullable().meta(readingMeta("count")),
|
|
59588
59490
|
/**
|
|
59589
59491
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
59590
59492
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -59709,7 +59611,7 @@ var gasCapability = {
|
|
|
59709
59611
|
};
|
|
59710
59612
|
var HeatingValveStatusSchema = object({
|
|
59711
59613
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
59712
|
-
position: number().min(0).max(100).nullable(),
|
|
59614
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
59713
59615
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
59714
59616
|
lastFetchedAt: number()
|
|
59715
59617
|
});
|
|
@@ -59752,9 +59654,9 @@ var HumidifierStatusSchema = object({
|
|
|
59752
59654
|
/** Whether the humidifier is currently on. */
|
|
59753
59655
|
on: boolean(),
|
|
59754
59656
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
59755
|
-
currentHumidity: number().min(0).max(100).nullable(),
|
|
59657
|
+
currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59756
59658
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
59757
|
-
targetHumidity: number().min(0).max(100).nullable(),
|
|
59659
|
+
targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
59758
59660
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
59759
59661
|
* device has no mode surface. */
|
|
59760
59662
|
mode: string().nullable(),
|
|
@@ -59764,9 +59666,9 @@ var HumidifierStatusSchema = object({
|
|
|
59764
59666
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
59765
59667
|
action: string().nullable(),
|
|
59766
59668
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
59767
|
-
minHumidity: number().nullable(),
|
|
59669
|
+
minHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59768
59670
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
59769
|
-
maxHumidity: number().nullable(),
|
|
59671
|
+
maxHumidity: number().nullable().meta(readingMeta("humidity")),
|
|
59770
59672
|
/** Ms epoch when the slice was last updated. */
|
|
59771
59673
|
lastChangedAt: number()
|
|
59772
59674
|
});
|
|
@@ -59836,22 +59738,13 @@ var humidifierCapability = {
|
|
|
59836
59738
|
* `sourceInfo`.
|
|
59837
59739
|
*/
|
|
59838
59740
|
var HumiditySensorStatusSchema = object({
|
|
59839
|
-
/** Current relative humidity, 0..100. */
|
|
59840
|
-
percent: number().min(0).max(100).meta({
|
|
59841
|
-
|
|
59741
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
59742
|
+
percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
59743
|
+
precision: 0,
|
|
59842
59744
|
label: "Humidity"
|
|
59843
|
-
}),
|
|
59745
|
+
})),
|
|
59844
59746
|
/** Ms epoch when the slice was last updated. */
|
|
59845
|
-
lastFetchedAt: number()
|
|
59846
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
59847
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
59848
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
59849
|
-
unit: string().optional(),
|
|
59850
|
-
/** Suggested decimal places for numeric display.
|
|
59851
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
59852
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
59853
|
-
* auto-formatting when absent. */
|
|
59854
|
-
precision: number().int().min(0).max(10).optional()
|
|
59747
|
+
lastFetchedAt: number()
|
|
59855
59748
|
});
|
|
59856
59749
|
var humiditySensorCapability = {
|
|
59857
59750
|
name: "humidity-sensor",
|
|
@@ -59882,12 +59775,7 @@ var humiditySensorCapability = {
|
|
|
59882
59775
|
} } },
|
|
59883
59776
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59884
59777
|
* whether persisting is worth a SQLite commit. */
|
|
59885
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
59886
|
-
customize: {
|
|
59887
|
-
version: 1,
|
|
59888
|
-
advanced: "derive",
|
|
59889
|
-
targets: []
|
|
59890
|
-
}
|
|
59778
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
59891
59779
|
};
|
|
59892
59780
|
/**
|
|
59893
59781
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -59908,7 +59796,7 @@ var ImageStatusSchema = object({
|
|
|
59908
59796
|
* entity exposes no `entity_picture` (yet). */
|
|
59909
59797
|
url: string().nullable(),
|
|
59910
59798
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
59911
|
-
lastUpdated: number().nullable()
|
|
59799
|
+
lastUpdated: number().nullable().meta(readingMeta("none"))
|
|
59912
59800
|
});
|
|
59913
59801
|
var imageCapability = {
|
|
59914
59802
|
name: "image",
|
|
@@ -59996,19 +59884,19 @@ var NormalizedRangeSchema = object({
|
|
|
59996
59884
|
*/
|
|
59997
59885
|
var ImageSettingsStatusSchema = object({
|
|
59998
59886
|
/** Normalized 0–100. */
|
|
59999
|
-
brightness: number().optional(),
|
|
59887
|
+
brightness: number().optional().meta(readingMeta("none")),
|
|
60000
59888
|
/** Normalized 0–100. */
|
|
60001
|
-
contrast: number().optional(),
|
|
59889
|
+
contrast: number().optional().meta(readingMeta("none")),
|
|
60002
59890
|
/** Normalized 0–100. */
|
|
60003
|
-
saturation: number().optional(),
|
|
59891
|
+
saturation: number().optional().meta(readingMeta("none")),
|
|
60004
59892
|
/** Normalized 0–100. */
|
|
60005
|
-
sharpness: number().optional(),
|
|
59893
|
+
sharpness: number().optional().meta(readingMeta("none")),
|
|
60006
59894
|
mirror: boolean().optional(),
|
|
60007
59895
|
flip: boolean().optional(),
|
|
60008
59896
|
rotate: ImageRotateSchema.optional(),
|
|
60009
59897
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
60010
59898
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
60011
|
-
warmth: number().optional(),
|
|
59899
|
+
warmth: number().optional().meta(readingMeta("none")),
|
|
60012
59900
|
exposureMode: ExposureModeSchema.optional(),
|
|
60013
59901
|
backlightMode: BacklightModeSchema.optional(),
|
|
60014
59902
|
lastFetchedAt: number()
|
|
@@ -60287,10 +60175,10 @@ var IntercomAbilitySchema = object({
|
|
|
60287
60175
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
60288
60176
|
codecs: array(string()),
|
|
60289
60177
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
60290
|
-
sampleRate: number(),
|
|
60178
|
+
sampleRate: number().meta(readingMeta("none")),
|
|
60291
60179
|
duplex: _enum(["half", "full"]),
|
|
60292
60180
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
60293
|
-
maxBacklogMs: number()
|
|
60181
|
+
maxBacklogMs: number().meta(readingMeta("duration-ms"))
|
|
60294
60182
|
});
|
|
60295
60183
|
var IntercomStatusSchema = object({
|
|
60296
60184
|
/** True while a talk session is open. */
|
|
@@ -60517,13 +60405,13 @@ var LawnMowerControlStatusSchema = object({
|
|
|
60517
60405
|
activity: LawnMowerActivitySchema,
|
|
60518
60406
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
60519
60407
|
* reading. */
|
|
60520
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
60408
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60521
60409
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
60522
60410
|
* task is active / progress is unavailable. */
|
|
60523
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
60411
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
60524
60412
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
60525
60413
|
* or null when unknown. */
|
|
60526
|
-
currentCode: number().nullable(),
|
|
60414
|
+
currentCode: number().nullable().meta(readingMeta("none")),
|
|
60527
60415
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
60528
60416
|
currentCodeLabel: string().nullable(),
|
|
60529
60417
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -61056,7 +60944,7 @@ var MediaPlayerStatusSchema = object({
|
|
|
61056
60944
|
state: MediaPlayerStateSchema,
|
|
61057
60945
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
61058
60946
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
61059
|
-
volumeLevel: number().min(0).max(100).nullable(),
|
|
60947
|
+
volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
61060
60948
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
61061
60949
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
61062
60950
|
isMuted: boolean().nullable(),
|
|
@@ -61069,10 +60957,10 @@ var MediaPlayerStatusSchema = object({
|
|
|
61069
60957
|
currentMedia: MediaInfoSchema.nullable(),
|
|
61070
60958
|
/** Current playback position in ms. Null when not seekable or
|
|
61071
60959
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
61072
|
-
positionMs: number().int().nonnegative().nullable(),
|
|
60960
|
+
positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61073
60961
|
/** Total duration of the current media in ms. Null when unknown
|
|
61074
60962
|
* (live stream) or nothing is playing. */
|
|
61075
|
-
durationMs: number().int().nonnegative().nullable(),
|
|
60963
|
+
durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
61076
60964
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
61077
60965
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
61078
60966
|
shuffle: boolean().nullable(),
|
|
@@ -61381,7 +61269,7 @@ var motionCustomize = {
|
|
|
61381
61269
|
eventName: "onMotionChanged"
|
|
61382
61270
|
},
|
|
61383
61271
|
deviceTypes: [DeviceType.Camera],
|
|
61384
|
-
apply: "
|
|
61272
|
+
apply: "add",
|
|
61385
61273
|
applyAuthority: {
|
|
61386
61274
|
kind: "camera-sensors",
|
|
61387
61275
|
timeoutField: "motionCooldownMs"
|
|
@@ -61453,7 +61341,7 @@ var MotionStatusSchema = object({
|
|
|
61453
61341
|
* it, every provider seeded it at boot, and every session left it
|
|
61454
61342
|
* `detected: true` after its detach.
|
|
61455
61343
|
*/
|
|
61456
|
-
autoClearAfterMs: number().nullable()
|
|
61344
|
+
autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
|
|
61457
61345
|
});
|
|
61458
61346
|
/**
|
|
61459
61347
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -61635,7 +61523,7 @@ var MotionZoneRegionSchema = object({
|
|
|
61635
61523
|
* the grid region(s). */
|
|
61636
61524
|
var MotionZoneStatusSchema = object({
|
|
61637
61525
|
enabled: boolean(),
|
|
61638
|
-
sensitivity: number(),
|
|
61526
|
+
sensitivity: number().meta(readingMeta("none")),
|
|
61639
61527
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
61640
61528
|
regions: array(MotionZoneRegionSchema),
|
|
61641
61529
|
lastFetchedAt: number()
|
|
@@ -62005,7 +61893,7 @@ var NavigationStatusSchema = object({
|
|
|
62005
61893
|
following: boolean(),
|
|
62006
61894
|
flash: boolean(),
|
|
62007
61895
|
lightMode: NavigationLightModeSchema,
|
|
62008
|
-
lightLevel: number().min(40).max(100),
|
|
61896
|
+
lightLevel: number().min(40).max(100).meta(readingMeta("none")),
|
|
62009
61897
|
/** Ms epoch when the slice was last updated. */
|
|
62010
61898
|
lastChangedAt: number()
|
|
62011
61899
|
});
|
|
@@ -62139,13 +62027,13 @@ var NetworkLinkStatusSchema = object({
|
|
|
62139
62027
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
62140
62028
|
* SKIP a null rather than coerce it.
|
|
62141
62029
|
*/
|
|
62142
|
-
signalPercent: number().min(0).max(100).nullable(),
|
|
62030
|
+
signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62143
62031
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
62144
|
-
rssiDbm: number().optional(),
|
|
62032
|
+
rssiDbm: number().optional().meta(readingMeta("signal-level")),
|
|
62145
62033
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
62146
62034
|
ssid: string().optional(),
|
|
62147
62035
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62148
|
-
lastUpdated: number()
|
|
62036
|
+
lastUpdated: number().meta(readingMeta("none"))
|
|
62149
62037
|
});
|
|
62150
62038
|
var networkLinkCapability = {
|
|
62151
62039
|
name: "network-link",
|
|
@@ -62530,7 +62418,7 @@ var NotifierStatusSchema = object({
|
|
|
62530
62418
|
lastError: string().nullable(),
|
|
62531
62419
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
62532
62420
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
62533
|
-
queueDepth: number().int().nonnegative(),
|
|
62421
|
+
queueDepth: number().int().nonnegative().meta(readingMeta("count")),
|
|
62534
62422
|
/** Per-feature capability matrix — authoritative source for the
|
|
62535
62423
|
* compose-form field gating. */
|
|
62536
62424
|
supports: NotifierSupportsSchema
|
|
@@ -62622,11 +62510,9 @@ onSent: { data: object({
|
|
|
62622
62510
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
62623
62511
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
62624
62512
|
*
|
|
62625
|
-
* The
|
|
62626
|
-
*
|
|
62627
|
-
*
|
|
62628
|
-
* The UI reads them directly from the slice — they are the single source
|
|
62629
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
62513
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
62514
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
62515
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
62630
62516
|
*
|
|
62631
62517
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
62632
62518
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -62635,15 +62521,8 @@ onSent: { data: object({
|
|
|
62635
62521
|
* numeric values land here.
|
|
62636
62522
|
*/
|
|
62637
62523
|
var NumericSensorStatusSchema = object({
|
|
62638
|
-
|
|
62639
|
-
|
|
62640
|
-
* Populated live from the upstream source on each state push.
|
|
62641
|
-
* Absent for unitless sensors. */
|
|
62642
|
-
unit: string().optional(),
|
|
62643
|
-
/** Suggested decimal places for numeric display.
|
|
62644
|
-
* Populated live from the upstream source when provided.
|
|
62645
|
-
* Falls back to auto-formatting when absent. */
|
|
62646
|
-
precision: number().int().min(0).max(10).optional(),
|
|
62524
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
62525
|
+
value: number().nullable().meta(readingMeta("device")),
|
|
62647
62526
|
/** Ms epoch when the slice was last updated. */
|
|
62648
62527
|
lastFetchedAt: number()
|
|
62649
62528
|
});
|
|
@@ -62667,11 +62546,11 @@ var numericSensorCapability = {
|
|
|
62667
62546
|
*/
|
|
62668
62547
|
durability: "restored",
|
|
62669
62548
|
/**
|
|
62670
|
-
* History (D850): recorded series. The unit is
|
|
62549
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
62550
|
+
* resolved when the series is read — the cap has no single unit.
|
|
62671
62551
|
*/
|
|
62672
62552
|
history: { fields: { value: {
|
|
62673
62553
|
kind: "gauge",
|
|
62674
|
-
unitFrom: "unit",
|
|
62675
62554
|
minIntervalMs: 3e4
|
|
62676
62555
|
} } },
|
|
62677
62556
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -62963,23 +62842,26 @@ var PetFeederStatusSchema = object({
|
|
|
62963
62842
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
62964
62843
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
62965
62844
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
62966
|
-
foodLevel: number().nullable(),
|
|
62845
|
+
foodLevel: number().nullable().meta(readingMeta("none")),
|
|
62967
62846
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
62968
62847
|
* single-hopper models. */
|
|
62969
|
-
food1: number().nullable(),
|
|
62848
|
+
food1: number().nullable().meta(readingMeta("none")),
|
|
62970
62849
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
62971
62850
|
* single-hopper models. */
|
|
62972
|
-
food2: number().nullable(),
|
|
62851
|
+
food2: number().nullable().meta(readingMeta("none")),
|
|
62973
62852
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
62974
62853
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
62975
62854
|
* below the feeder's low threshold. */
|
|
62976
62855
|
lowFood: boolean(),
|
|
62977
62856
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
62978
62857
|
* device has no battery reading. */
|
|
62979
|
-
batteryPower: number().min(0).max(100).nullable(),
|
|
62980
|
-
/**
|
|
62981
|
-
*
|
|
62982
|
-
|
|
62858
|
+
batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
62859
|
+
/**
|
|
62860
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
62861
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
62862
|
+
* model has no desiccant sensor.
|
|
62863
|
+
*/
|
|
62864
|
+
desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
|
|
62983
62865
|
/** True while a feed is in progress. */
|
|
62984
62866
|
feeding: boolean(),
|
|
62985
62867
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -62990,7 +62872,7 @@ var PetFeederStatusSchema = object({
|
|
|
62990
62872
|
* with `errorCode` for consumers that want the raw integer. */
|
|
62991
62873
|
error: string().nullable(),
|
|
62992
62874
|
/** Raw device error code (0 / null = no error). */
|
|
62993
|
-
errorCode: number().nullable(),
|
|
62875
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
62994
62876
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
62995
62877
|
isDualHopper: boolean(),
|
|
62996
62878
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -63000,7 +62882,7 @@ var PetFeederStatusSchema = object({
|
|
|
63000
62882
|
/** Play a chime when dispensing. */
|
|
63001
62883
|
feedSound: boolean(),
|
|
63002
62884
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
63003
|
-
volume: number(),
|
|
62885
|
+
volume: number().meta(readingMeta("none")),
|
|
63004
62886
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
63005
62887
|
lastFetchedAt: number()
|
|
63006
62888
|
});
|
|
@@ -63119,7 +63001,7 @@ var petFeederCapability = {
|
|
|
63119
63001
|
},
|
|
63120
63002
|
desiccantLeftDays: {
|
|
63121
63003
|
kind: "gauge",
|
|
63122
|
-
unit: "
|
|
63004
|
+
unit: "s"
|
|
63123
63005
|
}
|
|
63124
63006
|
} }
|
|
63125
63007
|
};
|
|
@@ -63520,36 +63402,19 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
|
|
|
63520
63402
|
*/
|
|
63521
63403
|
var PowerMeterStatusSchema = object({
|
|
63522
63404
|
/** Instantaneous power draw in watts. */
|
|
63523
|
-
watts: number().optional().meta({
|
|
63524
|
-
unit: "W",
|
|
63525
|
-
label: "Power"
|
|
63526
|
-
}),
|
|
63405
|
+
watts: number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
63527
63406
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
63528
|
-
kwhTotal: number().optional().meta({
|
|
63529
|
-
unit: "kWh",
|
|
63530
|
-
label: "Energy"
|
|
63531
|
-
}),
|
|
63407
|
+
kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
63532
63408
|
/** Voltage in volts. */
|
|
63533
|
-
volts: number().optional(),
|
|
63409
|
+
volts: number().optional().meta(readingMeta("voltage")),
|
|
63534
63410
|
/** Current in amperes. */
|
|
63535
|
-
amps: number().optional(),
|
|
63536
|
-
/** Apparent power in volt-amperes
|
|
63537
|
-
va: number().optional(),
|
|
63411
|
+
amps: number().optional().meta(readingMeta("current")),
|
|
63412
|
+
/** Apparent power in volt-amperes. */
|
|
63413
|
+
va: number().optional().meta(readingMeta("apparent-power")),
|
|
63538
63414
|
/** Power factor (0..1) if reported. */
|
|
63539
|
-
powerFactor: number().min(0).max(1).optional(),
|
|
63415
|
+
powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
63540
63416
|
/** Ms epoch when the slice was last updated. */
|
|
63541
|
-
lastFetchedAt: number()
|
|
63542
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
63543
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
63544
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
63545
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
63546
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
63547
|
-
unit: string().optional(),
|
|
63548
|
-
/** Suggested decimal places for numeric display.
|
|
63549
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63550
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63551
|
-
* auto-formatting when absent. */
|
|
63552
|
-
precision: number().int().min(0).max(10).optional()
|
|
63417
|
+
lastFetchedAt: number()
|
|
63553
63418
|
});
|
|
63554
63419
|
var powerMeterCapability = {
|
|
63555
63420
|
name: "power-meter",
|
|
@@ -63613,12 +63478,7 @@ var powerMeterCapability = {
|
|
|
63613
63478
|
} },
|
|
63614
63479
|
/** Clock fields: written, but excluded from the compare that decides
|
|
63615
63480
|
* whether persisting is worth a SQLite commit. */
|
|
63616
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
63617
|
-
customize: {
|
|
63618
|
-
version: 1,
|
|
63619
|
-
advanced: "derive",
|
|
63620
|
-
targets: []
|
|
63621
|
-
}
|
|
63481
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
63622
63482
|
};
|
|
63623
63483
|
/**
|
|
63624
63484
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -63638,11 +63498,11 @@ var powerMeterCapability = {
|
|
|
63638
63498
|
*/
|
|
63639
63499
|
var GpsLocationSchema = object({
|
|
63640
63500
|
/** Latitude in decimal degrees, -90..90. */
|
|
63641
|
-
latitude: number().min(-90).max(90),
|
|
63501
|
+
latitude: number().min(-90).max(90).meta(readingMeta("angle")),
|
|
63642
63502
|
/** Longitude in decimal degrees, -180..180. */
|
|
63643
|
-
longitude: number().min(-180).max(180),
|
|
63503
|
+
longitude: number().min(-180).max(180).meta(readingMeta("angle")),
|
|
63644
63504
|
/** Reported accuracy in meters (lower = better). */
|
|
63645
|
-
accuracyMeters: number().nonnegative()
|
|
63505
|
+
accuracyMeters: number().nonnegative().meta(readingMeta("length"))
|
|
63646
63506
|
});
|
|
63647
63507
|
var PresenceStatusSchema = object({
|
|
63648
63508
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -63654,7 +63514,7 @@ var PresenceStatusSchema = object({
|
|
|
63654
63514
|
gps: GpsLocationSchema.nullable(),
|
|
63655
63515
|
/** Optional battery level of the tracking device (0..100). Null
|
|
63656
63516
|
* when not reported. */
|
|
63657
|
-
batteryPercent: number().min(0).max(100).nullable(),
|
|
63517
|
+
batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63658
63518
|
/** Ms epoch when the slice was last updated. */
|
|
63659
63519
|
lastChangedAt: number()
|
|
63660
63520
|
});
|
|
@@ -63704,19 +63564,10 @@ var presenceCapability = {
|
|
|
63704
63564
|
* `sourceInfo`.
|
|
63705
63565
|
*/
|
|
63706
63566
|
var PressureSensorStatusSchema = object({
|
|
63707
|
-
/** Current pressure in hPa. */
|
|
63708
|
-
hpa: number(),
|
|
63567
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
63568
|
+
hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
63709
63569
|
/** Ms epoch when the slice was last updated. */
|
|
63710
|
-
lastFetchedAt: number()
|
|
63711
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
63712
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
63713
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
63714
|
-
unit: string().optional(),
|
|
63715
|
-
/** Suggested decimal places for numeric display.
|
|
63716
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
63717
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
63718
|
-
* auto-formatting when absent. */
|
|
63719
|
-
precision: number().int().min(0).max(10).optional()
|
|
63570
|
+
lastFetchedAt: number()
|
|
63720
63571
|
});
|
|
63721
63572
|
var pressureSensorCapability = {
|
|
63722
63573
|
name: "pressure-sensor",
|
|
@@ -64130,8 +63981,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
|
|
|
64130
63981
|
}), _void(), { kind: "mutation" });
|
|
64131
63982
|
var PtzAutotrackSettingsSchema = object({
|
|
64132
63983
|
targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
|
|
64133
|
-
stopDelaySeconds: number().int().min(0).max(300),
|
|
64134
|
-
disappearDelaySeconds: number().int().min(0).max(300)
|
|
63984
|
+
stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
63985
|
+
disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
64135
63986
|
});
|
|
64136
63987
|
/**
|
|
64137
63988
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -64285,7 +64136,7 @@ var RunningStateStatusSchema = object({
|
|
|
64285
64136
|
/** null = unknown — never coerced to false (D393). */
|
|
64286
64137
|
running: boolean().nullable(),
|
|
64287
64138
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
64288
|
-
since: number().nullable(),
|
|
64139
|
+
since: number().nullable().meta(readingMeta("none")),
|
|
64289
64140
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
64290
64141
|
phase: string().nullable(),
|
|
64291
64142
|
/** null until a reading has been published (D393). */
|
|
@@ -64300,7 +64151,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
64300
64151
|
/** Generic Customize target for the running boolean (D936). */
|
|
64301
64152
|
var runningCustomize = {
|
|
64302
64153
|
version: 1,
|
|
64303
|
-
advanced: "derive",
|
|
64304
64154
|
targets: [{
|
|
64305
64155
|
id: "running",
|
|
64306
64156
|
cardinality: "scalar",
|
|
@@ -64320,7 +64170,7 @@ var runningCustomize = {
|
|
|
64320
64170
|
DeviceType.Thermostat,
|
|
64321
64171
|
DeviceType.PetFeeder
|
|
64322
64172
|
],
|
|
64323
|
-
apply: "add
|
|
64173
|
+
apply: "add",
|
|
64324
64174
|
path: "running",
|
|
64325
64175
|
sources: [
|
|
64326
64176
|
{
|
|
@@ -64336,6 +64186,7 @@ var runningCustomize = {
|
|
|
64336
64186
|
requiredUnit: "W",
|
|
64337
64187
|
transforms: [{
|
|
64338
64188
|
kind: "threshold",
|
|
64189
|
+
comparisons: ["gte", "lte"],
|
|
64339
64190
|
comparison: "gte",
|
|
64340
64191
|
defaultThreshold: 5,
|
|
64341
64192
|
defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
|
|
@@ -65583,9 +65434,9 @@ var RecordTriggerSchema = _enum([
|
|
|
65583
65434
|
*/
|
|
65584
65435
|
var RecordWindowSchema = object({
|
|
65585
65436
|
trigger: RecordTriggerSchema,
|
|
65586
|
-
day: number().int().min(0).max(6),
|
|
65587
|
-
startMinute: number().int().min(0).max(1439),
|
|
65588
|
-
endMinute: number().int().min(1).max(1440)
|
|
65437
|
+
day: number().int().min(0).max(6).meta(readingMeta("none")),
|
|
65438
|
+
startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
65439
|
+
endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
65589
65440
|
});
|
|
65590
65441
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
65591
65442
|
var OnboardStorageVolumeSchema = object({
|
|
@@ -65661,10 +65512,10 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65661
65512
|
/** Master "record to the card at all" switch. */
|
|
65662
65513
|
enabled: boolean().nullable(),
|
|
65663
65514
|
overwriteWhenFull: boolean().nullable(),
|
|
65664
|
-
preRecordSec: number().nullable(),
|
|
65665
|
-
postRecordSec: number().nullable(),
|
|
65515
|
+
preRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65516
|
+
postRecordSec: number().nullable().meta(readingMeta("duration")),
|
|
65666
65517
|
/** Length of one recorded file, in minutes. */
|
|
65667
|
-
segmentMinutes: number().nullable(),
|
|
65518
|
+
segmentMinutes: number().nullable().meta(readingMeta("none")),
|
|
65668
65519
|
/** The primary track's weekly windows, flattened. */
|
|
65669
65520
|
windows: array(RecordWindowSchema),
|
|
65670
65521
|
/**
|
|
@@ -65680,7 +65531,7 @@ var RecordingOnboardStatusSchema = object({
|
|
|
65680
65531
|
* provider reporting a non-zero count also reports the schedule as not
|
|
65681
65532
|
* writable.
|
|
65682
65533
|
*/
|
|
65683
|
-
unreadableWindows: number(),
|
|
65534
|
+
unreadableWindows: number().meta(readingMeta("count")),
|
|
65684
65535
|
/**
|
|
65685
65536
|
* The camera is scheduled to record and has NO usable storage.
|
|
65686
65537
|
*
|
|
@@ -66525,7 +66376,7 @@ var CamStreamDescriptorSchema = object({
|
|
|
66525
66376
|
url: string().optional(),
|
|
66526
66377
|
codec: string().optional(),
|
|
66527
66378
|
resolution: CamStreamResolutionSchema.optional(),
|
|
66528
|
-
fps: number().positive().optional(),
|
|
66379
|
+
fps: number().positive().optional().meta(readingMeta("rate")),
|
|
66529
66380
|
label: string().optional(),
|
|
66530
66381
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
66531
66382
|
deviceFeatures: array(string()).optional(),
|
|
@@ -66612,18 +66463,18 @@ var StreamProfileSchema = _enum([
|
|
|
66612
66463
|
]);
|
|
66613
66464
|
/** The current encoding config of one stream profile. */
|
|
66614
66465
|
var StreamProfileConfigSchema = object({
|
|
66615
|
-
width: number(),
|
|
66616
|
-
height: number(),
|
|
66466
|
+
width: number().meta(readingMeta("none")),
|
|
66467
|
+
height: number().meta(readingMeta("none")),
|
|
66617
66468
|
codec: _enum(["h264", "h265"]),
|
|
66618
|
-
framerate: number(),
|
|
66619
|
-
bitrate: number(),
|
|
66469
|
+
framerate: number().meta(readingMeta("rate")),
|
|
66470
|
+
bitrate: number().meta(readingMeta("bitrate")),
|
|
66620
66471
|
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
66621
66472
|
encoderProfile: _enum([
|
|
66622
66473
|
"high",
|
|
66623
66474
|
"main",
|
|
66624
66475
|
"baseline"
|
|
66625
66476
|
]).optional(),
|
|
66626
|
-
gop: number().optional(),
|
|
66477
|
+
gop: number().optional().meta(readingMeta("none")),
|
|
66627
66478
|
/**
|
|
66628
66479
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
66629
66480
|
*
|
|
@@ -66844,12 +66695,7 @@ var switchCapability = {
|
|
|
66844
66695
|
label: "On",
|
|
66845
66696
|
kind: "boolean"
|
|
66846
66697
|
}
|
|
66847
|
-
}] }
|
|
66848
|
-
customize: {
|
|
66849
|
-
version: 1,
|
|
66850
|
-
advanced: "derive",
|
|
66851
|
-
targets: []
|
|
66852
|
-
}
|
|
66698
|
+
}] }
|
|
66853
66699
|
};
|
|
66854
66700
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
66855
66701
|
function hasControlCharacter(value) {
|
|
@@ -67432,35 +67278,21 @@ var tamperCapability = {
|
|
|
67432
67278
|
* entries with `device_class: temperature` and any future native
|
|
67433
67279
|
* thermometer.
|
|
67434
67280
|
*
|
|
67435
|
-
*
|
|
67436
|
-
*
|
|
67437
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
67438
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
67439
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
67440
|
-
* `sourceInfo`.
|
|
67281
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
67282
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
67441
67283
|
*
|
|
67442
67284
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
67443
67285
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
67444
67286
|
* changed" steady state.
|
|
67445
67287
|
*/
|
|
67446
67288
|
var TemperatureSensorStatusSchema = object({
|
|
67447
|
-
/** Current temperature in Celsius. */
|
|
67448
|
-
celsius: number().meta({
|
|
67449
|
-
|
|
67289
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
67290
|
+
celsius: number().nullable().meta(readingMeta("temperature", {
|
|
67291
|
+
precision: 1,
|
|
67450
67292
|
label: "Temperature"
|
|
67451
|
-
}),
|
|
67293
|
+
})),
|
|
67452
67294
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
67453
|
-
lastFetchedAt: number()
|
|
67454
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
67455
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
67456
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
67457
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
67458
|
-
unit: string().optional(),
|
|
67459
|
-
/** Suggested decimal places for numeric display.
|
|
67460
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
67461
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
67462
|
-
* auto-formatting when absent. */
|
|
67463
|
-
precision: number().int().min(0).max(10).optional()
|
|
67295
|
+
lastFetchedAt: number()
|
|
67464
67296
|
});
|
|
67465
67297
|
var temperatureSensorCapability = {
|
|
67466
67298
|
name: "temperature-sensor",
|
|
@@ -67491,12 +67323,7 @@ var temperatureSensorCapability = {
|
|
|
67491
67323
|
} } },
|
|
67492
67324
|
/** Clock fields: written, but excluded from the compare that decides
|
|
67493
67325
|
* whether persisting is worth a SQLite commit. */
|
|
67494
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
67495
|
-
customize: {
|
|
67496
|
-
version: 1,
|
|
67497
|
-
advanced: "derive",
|
|
67498
|
-
targets: []
|
|
67499
|
-
}
|
|
67326
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
67500
67327
|
};
|
|
67501
67328
|
/**
|
|
67502
67329
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -67779,16 +67606,16 @@ var VacuumControlStatusSchema = object({
|
|
|
67779
67606
|
]),
|
|
67780
67607
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
67781
67608
|
* reading. */
|
|
67782
|
-
batteryLevel: number().min(0).max(100).nullable(),
|
|
67609
|
+
batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67783
67610
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
67784
67611
|
* the vacuum has no speed control. */
|
|
67785
67612
|
fanSpeed: string().nullable(),
|
|
67786
67613
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
67787
67614
|
availableFanSpeeds: array(string()),
|
|
67788
67615
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
67789
|
-
progressPercent: number().min(0).max(100).nullable(),
|
|
67616
|
+
progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67790
67617
|
/** Current error code (0 / null = no error). */
|
|
67791
|
-
errorCode: number().nullable(),
|
|
67618
|
+
errorCode: number().nullable().meta(readingMeta("none")),
|
|
67792
67619
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
67793
67620
|
errorLabel: string().nullable(),
|
|
67794
67621
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -67866,7 +67693,7 @@ var ValveStatusSchema = object({
|
|
|
67866
67693
|
]),
|
|
67867
67694
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
67868
67695
|
* intermediate position surface. */
|
|
67869
|
-
position: number().min(0).max(100).nullable(),
|
|
67696
|
+
position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67870
67697
|
/** Ms epoch when the slice was last updated. */
|
|
67871
67698
|
lastChangedAt: number()
|
|
67872
67699
|
});
|
|
@@ -67974,9 +67801,9 @@ var vibrationCapability = {
|
|
|
67974
67801
|
*/
|
|
67975
67802
|
var WaterHeaterStatusSchema = object({
|
|
67976
67803
|
/** Current measured temperature. Null when not reported. */
|
|
67977
|
-
currentTemp: number().nullable(),
|
|
67804
|
+
currentTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67978
67805
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
67979
|
-
targetTemp: number().nullable(),
|
|
67806
|
+
targetTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67980
67807
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
67981
67808
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
67982
67809
|
* device reports an unknown state. */
|
|
@@ -67987,9 +67814,9 @@ var WaterHeaterStatusSchema = object({
|
|
|
67987
67814
|
* has no away surface. */
|
|
67988
67815
|
away: boolean().nullable(),
|
|
67989
67816
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
67990
|
-
minTemp: number().nullable(),
|
|
67817
|
+
minTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67991
67818
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
67992
|
-
maxTemp: number().nullable(),
|
|
67819
|
+
maxTemp: number().nullable().meta(readingMeta("temperature")),
|
|
67993
67820
|
/** Ms epoch when the slice was last updated. */
|
|
67994
67821
|
lastChangedAt: number()
|
|
67995
67822
|
});
|
|
@@ -68074,25 +67901,18 @@ var waterHeaterCapability = {
|
|
|
68074
67901
|
* Forecast deferred — current conditions only for v1.
|
|
68075
67902
|
*/
|
|
68076
67903
|
var WeatherStatusSchema = object({
|
|
68077
|
-
/** Verbatim
|
|
68078
|
-
* when no condition has been reported yet. */
|
|
67904
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
68079
67905
|
condition: string().nullable(),
|
|
68080
|
-
/** Current temperature in
|
|
68081
|
-
temperature: number().nullable(),
|
|
68082
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
68083
|
-
temperatureUnit: string().nullable(),
|
|
67906
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
67907
|
+
temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
68084
67908
|
/** Relative humidity (0..100). Null when not provided. */
|
|
68085
|
-
humidity: number().min(0).max(100).nullable(),
|
|
68086
|
-
/** Barometric pressure in
|
|
68087
|
-
pressure: number().nullable(),
|
|
68088
|
-
/**
|
|
68089
|
-
|
|
68090
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
68091
|
-
windSpeed: number().nullable(),
|
|
68092
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
68093
|
-
windSpeedUnit: string().nullable(),
|
|
67909
|
+
humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
67910
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
67911
|
+
pressure: number().nullable().meta(readingMeta("pressure")),
|
|
67912
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
67913
|
+
windSpeed: number().nullable().meta(readingMeta("speed")),
|
|
68094
67914
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
68095
|
-
windBearing: number().nullable(),
|
|
67915
|
+
windBearing: number().nullable().meta(readingMeta("angle")),
|
|
68096
67916
|
/** Ms epoch when the slice was last updated. */
|
|
68097
67917
|
lastFetchedAt: number()
|
|
68098
67918
|
});
|
|
@@ -68120,12 +67940,12 @@ var weatherCapability = {
|
|
|
68120
67940
|
*/
|
|
68121
67941
|
durability: "session",
|
|
68122
67942
|
/**
|
|
68123
|
-
* History (D850): recorded series.
|
|
67943
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
68124
67944
|
*/
|
|
68125
67945
|
history: { fields: {
|
|
68126
67946
|
temperature: {
|
|
68127
67947
|
kind: "gauge",
|
|
68128
|
-
|
|
67948
|
+
unit: "°C",
|
|
68129
67949
|
deadband: .2
|
|
68130
67950
|
},
|
|
68131
67951
|
humidity: {
|
|
@@ -68135,12 +67955,12 @@ var weatherCapability = {
|
|
|
68135
67955
|
},
|
|
68136
67956
|
pressure: {
|
|
68137
67957
|
kind: "gauge",
|
|
68138
|
-
|
|
67958
|
+
unit: "hPa",
|
|
68139
67959
|
deadband: .5
|
|
68140
67960
|
},
|
|
68141
67961
|
windSpeed: {
|
|
68142
67962
|
kind: "gauge",
|
|
68143
|
-
|
|
67963
|
+
unit: "m/s",
|
|
68144
67964
|
deadband: .5
|
|
68145
67965
|
}
|
|
68146
67966
|
} }
|
|
@@ -80329,7 +80149,7 @@ function t(en, it) {
|
|
|
80329
80149
|
* covers, valves, locks, climate, fans, alarm panels.
|
|
80330
80150
|
*/
|
|
80331
80151
|
var ON = t("On", "Acceso");
|
|
80332
|
-
var PERCENT
|
|
80152
|
+
var PERCENT = t("Percentage", "Percentuale");
|
|
80333
80153
|
var OPEN_CLOSE_STATES = [
|
|
80334
80154
|
{
|
|
80335
80155
|
value: "open",
|
|
@@ -80557,7 +80377,7 @@ var ACTUATOR_CAP_VOCABULARY = {
|
|
|
80557
80377
|
icon: "sun-medium",
|
|
80558
80378
|
openArgs: [{
|
|
80559
80379
|
key: "percentage",
|
|
80560
|
-
label: PERCENT
|
|
80380
|
+
label: PERCENT,
|
|
80561
80381
|
offer: {
|
|
80562
80382
|
kind: "number",
|
|
80563
80383
|
min: 0,
|
|
@@ -83710,7 +83530,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83710
83530
|
field: "value",
|
|
83711
83531
|
quantity: t("the reading", "il valore"),
|
|
83712
83532
|
label: t("Reading", "Valore"),
|
|
83713
|
-
unitField: "unit",
|
|
83714
83533
|
icon: "gauge"
|
|
83715
83534
|
}]
|
|
83716
83535
|
},
|
|
@@ -83846,7 +83665,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83846
83665
|
field: "temperature",
|
|
83847
83666
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
83848
83667
|
label: t("Temperature", "Temperatura"),
|
|
83849
|
-
|
|
83668
|
+
unit: "°C",
|
|
83850
83669
|
icon: "thermometer"
|
|
83851
83670
|
},
|
|
83852
83671
|
{
|
|
@@ -83862,7 +83681,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83862
83681
|
field: "windSpeed",
|
|
83863
83682
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
83864
83683
|
label: t("Wind", "Vento"),
|
|
83865
|
-
|
|
83684
|
+
unit: "m/s",
|
|
83866
83685
|
icon: "wind"
|
|
83867
83686
|
},
|
|
83868
83687
|
{
|
|
@@ -83870,7 +83689,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
83870
83689
|
field: "pressure",
|
|
83871
83690
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
83872
83691
|
label: t("Pressure", "Pressione"),
|
|
83873
|
-
|
|
83692
|
+
unit: "hPa",
|
|
83874
83693
|
icon: "gauge"
|
|
83875
83694
|
}
|
|
83876
83695
|
]
|
|
@@ -87007,6 +86826,11 @@ var PulseOverrideDraftSchema = object({
|
|
|
87007
86826
|
targetId: string().min(1),
|
|
87008
86827
|
enabled: boolean(),
|
|
87009
86828
|
debounceMs: number().nonnegative(),
|
|
86829
|
+
edges: array(_enum([
|
|
86830
|
+
"rising",
|
|
86831
|
+
"button",
|
|
86832
|
+
"native-event"
|
|
86833
|
+
])).min(1).optional(),
|
|
87010
86834
|
sources: array(OverrideSourceSchema).min(1)
|
|
87011
86835
|
});
|
|
87012
86836
|
var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
|
|
@@ -88756,17 +88580,15 @@ function entityIdentity(descriptor) {
|
|
|
88756
88580
|
function slugifyKey(value) {
|
|
88757
88581
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
88758
88582
|
}
|
|
88759
|
-
var PERCENT = "%";
|
|
88760
|
-
var WATT = "W";
|
|
88761
88583
|
/** Clamp a raw percentage into 0..100 (defensive — a hung feed can overshoot). */
|
|
88762
88584
|
function pct(value) {
|
|
88763
88585
|
if (!Number.isFinite(value)) return 0;
|
|
88764
88586
|
return Math.max(0, Math.min(100, value));
|
|
88765
88587
|
}
|
|
88766
|
-
/**
|
|
88767
|
-
function
|
|
88768
|
-
if (!Number.isFinite(
|
|
88769
|
-
return
|
|
88588
|
+
/** A byte count. Negative or non-finite input is an empty reading, not a guess. */
|
|
88589
|
+
function bytes(value) {
|
|
88590
|
+
if (!Number.isFinite(value) || value < 0) return 0;
|
|
88591
|
+
return value;
|
|
88770
88592
|
}
|
|
88771
88593
|
/** Array capacity + parity + CPU + notification-count metric descriptors. */
|
|
88772
88594
|
function arrayMetricDescriptors(snapshot) {
|
|
@@ -88793,8 +88615,7 @@ function arrayMetricDescriptors(snapshot) {
|
|
|
88793
88615
|
role: DeviceRole.NumericSensor,
|
|
88794
88616
|
numeric: {
|
|
88795
88617
|
value: usagePercent,
|
|
88796
|
-
|
|
88797
|
-
precision: 1
|
|
88618
|
+
quantity: "percentage"
|
|
88798
88619
|
}
|
|
88799
88620
|
},
|
|
88800
88621
|
{
|
|
@@ -88805,9 +88626,8 @@ function arrayMetricDescriptors(snapshot) {
|
|
|
88805
88626
|
name: "Array total",
|
|
88806
88627
|
role: DeviceRole.NumericSensor,
|
|
88807
88628
|
numeric: {
|
|
88808
|
-
value:
|
|
88809
|
-
|
|
88810
|
-
precision: 1
|
|
88629
|
+
value: bytes(totalKb * 1024),
|
|
88630
|
+
quantity: "information"
|
|
88811
88631
|
}
|
|
88812
88632
|
},
|
|
88813
88633
|
{
|
|
@@ -88818,9 +88638,8 @@ function arrayMetricDescriptors(snapshot) {
|
|
|
88818
88638
|
name: "Array used",
|
|
88819
88639
|
role: DeviceRole.NumericSensor,
|
|
88820
88640
|
numeric: {
|
|
88821
|
-
value:
|
|
88822
|
-
|
|
88823
|
-
precision: 1
|
|
88641
|
+
value: bytes(usedKb * 1024),
|
|
88642
|
+
quantity: "information"
|
|
88824
88643
|
}
|
|
88825
88644
|
},
|
|
88826
88645
|
{
|
|
@@ -88831,9 +88650,8 @@ function arrayMetricDescriptors(snapshot) {
|
|
|
88831
88650
|
name: "Array free",
|
|
88832
88651
|
role: DeviceRole.NumericSensor,
|
|
88833
88652
|
numeric: {
|
|
88834
|
-
value:
|
|
88835
|
-
|
|
88836
|
-
precision: 1
|
|
88653
|
+
value: bytes(array.capacityKb.free * 1024),
|
|
88654
|
+
quantity: "information"
|
|
88837
88655
|
}
|
|
88838
88656
|
},
|
|
88839
88657
|
{
|
|
@@ -88845,8 +88663,7 @@ function arrayMetricDescriptors(snapshot) {
|
|
|
88845
88663
|
role: DeviceRole.NumericSensor,
|
|
88846
88664
|
numeric: {
|
|
88847
88665
|
value: pct(cpu.percent),
|
|
88848
|
-
|
|
88849
|
-
precision: 1
|
|
88666
|
+
quantity: "percentage"
|
|
88850
88667
|
}
|
|
88851
88668
|
},
|
|
88852
88669
|
{
|
|
@@ -88858,8 +88675,7 @@ function arrayMetricDescriptors(snapshot) {
|
|
|
88858
88675
|
role: DeviceRole.NumericSensor,
|
|
88859
88676
|
numeric: {
|
|
88860
88677
|
value: pct(array.parityCheck?.progress ?? 0),
|
|
88861
|
-
|
|
88862
|
-
precision: 0
|
|
88678
|
+
quantity: "percentage"
|
|
88863
88679
|
}
|
|
88864
88680
|
},
|
|
88865
88681
|
{
|
|
@@ -88871,7 +88687,7 @@ function arrayMetricDescriptors(snapshot) {
|
|
|
88871
88687
|
role: DeviceRole.NumericSensor,
|
|
88872
88688
|
numeric: {
|
|
88873
88689
|
value: Math.max(0, notifications.activeCount),
|
|
88874
|
-
|
|
88690
|
+
quantity: "count"
|
|
88875
88691
|
}
|
|
88876
88692
|
}
|
|
88877
88693
|
];
|
|
@@ -88893,8 +88709,7 @@ function arrayMetricDescriptors(snapshot) {
|
|
|
88893
88709
|
role: DeviceRole.PowerSensor,
|
|
88894
88710
|
numeric: {
|
|
88895
88711
|
value: Math.max(0, cpu.powerW),
|
|
88896
|
-
|
|
88897
|
-
precision: 1
|
|
88712
|
+
quantity: "power"
|
|
88898
88713
|
}
|
|
88899
88714
|
});
|
|
88900
88715
|
return out;
|
|
@@ -88978,8 +88793,7 @@ function diskDescriptors(disks) {
|
|
|
88978
88793
|
role: DeviceRole.NumericSensor,
|
|
88979
88794
|
numeric: {
|
|
88980
88795
|
value: usagePercent,
|
|
88981
|
-
|
|
88982
|
-
precision: 1
|
|
88796
|
+
quantity: "percentage"
|
|
88983
88797
|
}
|
|
88984
88798
|
});
|
|
88985
88799
|
out.push({
|
|
@@ -89018,8 +88832,7 @@ function dockerDescriptors(containers) {
|
|
|
89018
88832
|
role: DeviceRole.NumericSensor,
|
|
89019
88833
|
numeric: {
|
|
89020
88834
|
value: pct(container.cpuPercent),
|
|
89021
|
-
|
|
89022
|
-
precision: 1
|
|
88835
|
+
quantity: "percentage"
|
|
89023
88836
|
}
|
|
89024
88837
|
});
|
|
89025
88838
|
out.push({
|
|
@@ -89031,8 +88844,7 @@ function dockerDescriptors(containers) {
|
|
|
89031
88844
|
role: DeviceRole.NumericSensor,
|
|
89032
88845
|
numeric: {
|
|
89033
88846
|
value: pct(container.memPercent),
|
|
89034
|
-
|
|
89035
|
-
precision: 1
|
|
88847
|
+
quantity: "percentage"
|
|
89036
88848
|
}
|
|
89037
88849
|
});
|
|
89038
88850
|
out.push(buttonDescriptor(`restart_container_${slug}`, `Restart ${container.name}`, {
|
|
@@ -89214,10 +89026,9 @@ var UnraidEntityDevice = class extends BaseDevice {
|
|
|
89214
89026
|
if (numeric === void 0) return;
|
|
89215
89027
|
const slice = {
|
|
89216
89028
|
value: numeric.value,
|
|
89217
|
-
lastFetchedAt: now
|
|
89218
|
-
...numeric.unit !== void 0 ? { unit: numeric.unit } : {},
|
|
89219
|
-
...numeric.precision !== void 0 ? { precision: numeric.precision } : {}
|
|
89029
|
+
lastFetchedAt: now
|
|
89220
89030
|
};
|
|
89031
|
+
if (this.sourceInfo.quantity !== numeric.quantity) this.updateSourceInfo({ quantity: numeric.quantity });
|
|
89221
89032
|
this.runtimeState.setCapState(numericSensorCapability.name, slice);
|
|
89222
89033
|
return;
|
|
89223
89034
|
}
|