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