@camstack/addon-training 0.1.82 → 0.1.83

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.
Files changed (20) hide show
  1. package/dist/{MotionZonesSettings-Ca-6XXfI.mjs → MotionZonesSettings-ua7eMlj6.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-BCUM9T8S.mjs → PrivacyMaskSettings-tOwuzUR7.mjs} +2 -2
  3. package/dist/{SceneMonitorEditor-CjJ891SK.mjs → SceneMonitorEditor-D70yDpkr.mjs} +1 -1
  4. package/dist/_stub.js +5358 -5290
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-vEOlZUQt.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-CX_OmaCS.mjs} +3 -3
  6. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CF6J142s.mjs +26 -0
  7. package/dist/{dist-CQOH32eF.mjs → dist-BK5jIqgk.mjs} +273 -422
  8. package/dist/{dist-VJTyi7FX.js → dist-BinKWWJ5.js} +273 -422
  9. package/dist/{hostInit-CvOJdSqn.mjs → hostInit-DR72gpW3.mjs} +2 -2
  10. package/dist/index.js +1 -1
  11. package/dist/orchestrator/training.addon.js +1 -1
  12. package/dist/orchestrator/training.addon.mjs +1 -1
  13. package/dist/{player-overlays-Bk8LUHwl.mjs → player-overlays-DCStC-vp.mjs} +1 -1
  14. package/dist/providers/modal/training-modal.addon.js +1 -1
  15. package/dist/providers/modal/training-modal.addon.mjs +1 -1
  16. package/dist/remoteEntry.js +1 -1
  17. package/dist/{responsive-DkRlf-GQ.mjs → responsive-DsQ48pYk.mjs} +16 -13
  18. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-DNg-tEZh.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-BToJVQAB.mjs} +1 -1
  19. package/package.json +1 -1
  20. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-9NmkfCw8.mjs +0 -26
@@ -5567,7 +5567,7 @@ var ZodIssueCode = {
5567
5567
  var ZodFirstPartyTypeKind;
5568
5568
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5569
5569
  //#endregion
5570
- //#region ../types/dist/sleep-BErAxhul.mjs
5570
+ //#region ../types/dist/sleep-CARd6wZF.mjs
5571
5571
  /**
5572
5572
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5573
5573
  * window to float samples (D455).
@@ -8302,6 +8302,52 @@ function defineEntryKind(name, spec) {
8302
8302
  if (defined === void 0) throw new DeclarationRefusedError(`entry kind "${name}" was not built`);
8303
8303
  return defined;
8304
8304
  }
8305
+ var READING_QUANTITIES = [
8306
+ "temperature",
8307
+ "pressure",
8308
+ "speed",
8309
+ "precipitation",
8310
+ "precipitation-rate",
8311
+ "length",
8312
+ "area",
8313
+ "illuminance",
8314
+ "irradiance",
8315
+ "power",
8316
+ "energy",
8317
+ "voltage",
8318
+ "current",
8319
+ "apparent-power",
8320
+ "humidity",
8321
+ "percentage",
8322
+ "concentration-volume",
8323
+ "concentration-mass",
8324
+ "concentration-ppb",
8325
+ "volume",
8326
+ "duration",
8327
+ "duration-ms",
8328
+ "information",
8329
+ "sound-level",
8330
+ "signal-level",
8331
+ "colour-temperature",
8332
+ "angle",
8333
+ "bitrate",
8334
+ "rate",
8335
+ "mass",
8336
+ "index",
8337
+ "ratio",
8338
+ "count",
8339
+ "none",
8340
+ "device"
8341
+ ];
8342
+ var ReadingQuantitySchema = _enum(READING_QUANTITIES);
8343
+ new Set(READING_QUANTITIES);
8344
+ function readingMeta(quantity, extras) {
8345
+ return {
8346
+ quantity,
8347
+ ...extras?.precision !== void 0 ? { precision: extras.precision } : {},
8348
+ ...extras?.label !== void 0 ? { label: extras.label } : {}
8349
+ };
8350
+ }
8305
8351
  /** Shared Zod schemas used across streaming capabilities. */
8306
8352
  var CamProfileSchema = _enum([
8307
8353
  "high",
@@ -8329,8 +8375,8 @@ var CamStreamKindSchema = _enum([
8329
8375
  "derived"
8330
8376
  ]);
8331
8377
  var CamStreamResolutionSchema = object({
8332
- width: number().int().positive(),
8333
- height: number().int().positive()
8378
+ width: number().int().positive().meta(readingMeta("none")),
8379
+ height: number().int().positive().meta(readingMeta("none"))
8334
8380
  });
8335
8381
  var CameraStreamSchema = object({
8336
8382
  /** Stable, provider-assigned id unique within the (deviceId) scope. */
@@ -8973,14 +9019,6 @@ Object.freeze({
8973
9019
  {
8974
9020
  "path": "aqi",
8975
9021
  "valueType": "number"
8976
- },
8977
- {
8978
- "path": "unit",
8979
- "valueType": "string"
8980
- },
8981
- {
8982
- "path": "precision",
8983
- "valueType": "number"
8984
9022
  }
8985
9023
  ],
8986
9024
  "alarm-panel": [
@@ -9016,20 +9054,10 @@ Object.freeze({
9016
9054
  "valueType": "boolean"
9017
9055
  }
9018
9056
  ],
9019
- "ambient-light-sensor": [
9020
- {
9021
- "path": "lux",
9022
- "valueType": "number"
9023
- },
9024
- {
9025
- "path": "unit",
9026
- "valueType": "string"
9027
- },
9028
- {
9029
- "path": "precision",
9030
- "valueType": "number"
9031
- }
9032
- ],
9057
+ "ambient-light-sensor": [{
9058
+ "path": "lux",
9059
+ "valueType": "number"
9060
+ }],
9033
9061
  "audio-metrics": [
9034
9062
  {
9035
9063
  "path": "ts",
@@ -9109,6 +9137,10 @@ Object.freeze({
9109
9137
  "path": "lastUpdated",
9110
9138
  "valueType": "number"
9111
9139
  },
9140
+ {
9141
+ "path": "volts",
9142
+ "valueType": "number"
9143
+ },
9112
9144
  {
9113
9145
  "path": "lastContactAt",
9114
9146
  "valueType": "number"
@@ -9351,10 +9383,6 @@ Object.freeze({
9351
9383
  "datetime"
9352
9384
  ]
9353
9385
  },
9354
- {
9355
- "path": "unit",
9356
- "valueType": "string"
9357
- },
9358
9386
  {
9359
9387
  "path": "min",
9360
9388
  "valueType": "number"
@@ -9366,19 +9394,6 @@ Object.freeze({
9366
9394
  {
9367
9395
  "path": "step",
9368
9396
  "valueType": "number"
9369
- },
9370
- {
9371
- "path": "precision",
9372
- "valueType": "number"
9373
- },
9374
- {
9375
- "path": "format",
9376
- "valueType": "enum",
9377
- "enumValues": [
9378
- "date",
9379
- "time",
9380
- "datetime"
9381
- ]
9382
9397
  }
9383
9398
  ],
9384
9399
  "cover": [
@@ -9619,13 +9634,8 @@ Object.freeze({
9619
9634
  "path": "value",
9620
9635
  "valueType": "string"
9621
9636
  }, {
9622
- "path": "format",
9623
- "valueType": "enum",
9624
- "enumValues": [
9625
- "date",
9626
- "time",
9627
- "datetime"
9628
- ]
9637
+ "path": "timestamp",
9638
+ "valueType": "boolean"
9629
9639
  }],
9630
9640
  "event-emitter": [
9631
9641
  {
@@ -9732,20 +9742,10 @@ Object.freeze({
9732
9742
  "valueType": "number"
9733
9743
  }
9734
9744
  ],
9735
- "humidity-sensor": [
9736
- {
9737
- "path": "percent",
9738
- "valueType": "number"
9739
- },
9740
- {
9741
- "path": "unit",
9742
- "valueType": "string"
9743
- },
9744
- {
9745
- "path": "precision",
9746
- "valueType": "number"
9747
- }
9748
- ],
9745
+ "humidity-sensor": [{
9746
+ "path": "percent",
9747
+ "valueType": "number"
9748
+ }],
9749
9749
  "image": [{
9750
9750
  "path": "url",
9751
9751
  "valueType": "string"
@@ -10084,20 +10084,10 @@ Object.freeze({
10084
10084
  "valueType": "boolean"
10085
10085
  }
10086
10086
  ],
10087
- "numeric-sensor": [
10088
- {
10089
- "path": "value",
10090
- "valueType": "number"
10091
- },
10092
- {
10093
- "path": "unit",
10094
- "valueType": "string"
10095
- },
10096
- {
10097
- "path": "precision",
10098
- "valueType": "number"
10099
- }
10100
- ],
10087
+ "numeric-sensor": [{
10088
+ "path": "value",
10089
+ "valueType": "number"
10090
+ }],
10101
10091
  "pet-feeder": [
10102
10092
  {
10103
10093
  "path": "foodLevel",
@@ -10189,14 +10179,6 @@ Object.freeze({
10189
10179
  {
10190
10180
  "path": "powerFactor",
10191
10181
  "valueType": "number"
10192
- },
10193
- {
10194
- "path": "unit",
10195
- "valueType": "string"
10196
- },
10197
- {
10198
- "path": "precision",
10199
- "valueType": "number"
10200
10182
  }
10201
10183
  ],
10202
10184
  "presence": [
@@ -10225,20 +10207,10 @@ Object.freeze({
10225
10207
  "valueType": "number"
10226
10208
  }
10227
10209
  ],
10228
- "pressure-sensor": [
10229
- {
10230
- "path": "hpa",
10231
- "valueType": "number"
10232
- },
10233
- {
10234
- "path": "unit",
10235
- "valueType": "string"
10236
- },
10237
- {
10238
- "path": "precision",
10239
- "valueType": "number"
10240
- }
10241
- ],
10210
+ "pressure-sensor": [{
10211
+ "path": "hpa",
10212
+ "valueType": "number"
10213
+ }],
10242
10214
  "privacy-mask": [{
10243
10215
  "path": "enabled",
10244
10216
  "valueType": "boolean"
@@ -10549,20 +10521,10 @@ Object.freeze({
10549
10521
  "path": "tampered",
10550
10522
  "valueType": "boolean"
10551
10523
  }],
10552
- "temperature-sensor": [
10553
- {
10554
- "path": "celsius",
10555
- "valueType": "number"
10556
- },
10557
- {
10558
- "path": "unit",
10559
- "valueType": "string"
10560
- },
10561
- {
10562
- "path": "precision",
10563
- "valueType": "number"
10564
- }
10565
- ],
10524
+ "temperature-sensor": [{
10525
+ "path": "celsius",
10526
+ "valueType": "number"
10527
+ }],
10566
10528
  "update": [
10567
10529
  {
10568
10530
  "path": "currentVersion",
@@ -10673,10 +10635,6 @@ Object.freeze({
10673
10635
  "path": "temperature",
10674
10636
  "valueType": "number"
10675
10637
  },
10676
- {
10677
- "path": "temperatureUnit",
10678
- "valueType": "string"
10679
- },
10680
10638
  {
10681
10639
  "path": "humidity",
10682
10640
  "valueType": "number"
@@ -10685,18 +10643,10 @@ Object.freeze({
10685
10643
  "path": "pressure",
10686
10644
  "valueType": "number"
10687
10645
  },
10688
- {
10689
- "path": "pressureUnit",
10690
- "valueType": "string"
10691
- },
10692
10646
  {
10693
10647
  "path": "windSpeed",
10694
10648
  "valueType": "number"
10695
10649
  },
10696
- {
10697
- "path": "windSpeedUnit",
10698
- "valueType": "string"
10699
- },
10700
10650
  {
10701
10651
  "path": "windBearing",
10702
10652
  "valueType": "number"
@@ -18079,7 +18029,8 @@ var CompositionProblemSchema = object({
18079
18029
  "item-field-reserved",
18080
18030
  "target-missing",
18081
18031
  "target-unreadable",
18082
- "not-replaceable"
18032
+ "not-replaceable",
18033
+ "native-capability-replace"
18083
18034
  ]),
18084
18035
  path: string(),
18085
18036
  message: string()
@@ -18137,9 +18088,11 @@ var CompositionFieldPlanSchema = object({
18137
18088
  reads: array(CompositionFieldReadSchema)
18138
18089
  });
18139
18090
  /**
18140
- * What a feature does to its target (D663): `new` builds a capability on a new
18141
- * device; on an existing device it `add`s a capability the device lacks, or
18142
- * `replace`s named fields of one it has natively.
18091
+ * What a feature does to its target (D663, D944): `new` builds a capability on a
18092
+ * new device; on an existing device it `add`s a capability the device lacks.
18093
+ * Replacing a capability the device already serves is refused
18094
+ * (`native-capability-replace`), not planned. `replace` remains on the claim
18095
+ * wire for a claim the hub already holds.
18143
18096
  */
18144
18097
  var CompositionFeatureModeSchema = _enum([
18145
18098
  "new",
@@ -20025,12 +19978,12 @@ method(object({ deviceId: number().int().nonnegative() }), DeviceAdminLinkSchema
20025
19978
  * providers detect renames by matching `uniqueId` and patch `id`
20026
19979
  * in-place so dispatch keeps working.
20027
19980
  *
20028
- * **Rendering metadata is NOT stored here.** Display fields (`unit`,
20029
- * `precision`) live in the cap STATUS SLICE so they flow live with every
20030
- * state push and are the single source of truth. The `device_class` tag is
20031
- * an HA-specific input that is consumed at the discovery boundary
20032
- * (`ha-domain-mapping`) to derive the CamStack `DeviceRole`; it is never
20033
- * stored after that point.
19981
+ * **Display unit and precision are NOT stored here.** They are a read-time
19982
+ * preference (D944). A polymorphic reading stores its `quantity` here once,
19983
+ * at adopt, and a date/time value stores `dateTimeShape` the same way —
19984
+ * neither is repeated on each sample. The `device_class` tag is an
19985
+ * HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
19986
+ * to derive the CamStack `DeviceRole`; it is never stored after that point.
20034
19987
  *
20035
19988
  * The `raw` escape hatch carries provider-specific attributes that don't
20036
19989
  * fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
@@ -20044,6 +19997,14 @@ var SourceInfoSchema = object({
20044
19997
  /** Immutable upstream identifier when available (HA `unique_id`, … ).
20045
19998
  * Used to detect rename when `id` changes. */
20046
19999
  uniqueId: string().optional(),
20000
+ /** Quantity of a polymorphic reading, written once at adopt (D944). */
20001
+ quantity: ReadingQuantitySchema.optional(),
20002
+ /** Date / time / datetime shape of a string reading, written once at adopt. */
20003
+ dateTimeShape: _enum([
20004
+ "date",
20005
+ "time",
20006
+ "datetime"
20007
+ ]).optional(),
20047
20008
  /** Provider-specific extras that don't fit the structured slots.
20048
20009
  * Whitelist what goes here per provider — do NOT dump entire HA
20049
20010
  * attribute blobs (would explode the meta JSON column). */
@@ -40956,7 +40917,8 @@ method(object({
40956
40917
  "enum"
40957
40918
  ]),
40958
40919
  enumValues: array(string()).optional(),
40959
- item: boolean().optional()
40920
+ item: boolean().optional(),
40921
+ quantity: ReadingQuantitySchema.optional()
40960
40922
  })).readonly(),
40961
40923
  itemArray: object({
40962
40924
  path: string(),
@@ -44756,8 +44718,8 @@ var MaskPolygonShapeSchema = object({
44756
44718
  /** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
44757
44719
  var MaskGridShapeSchema = object({
44758
44720
  kind: literal("grid"),
44759
- gridWidth: number(),
44760
- gridHeight: number(),
44721
+ gridWidth: number().meta(readingMeta("none")),
44722
+ gridHeight: number().meta(readingMeta("none")),
44761
44723
  cells: array(boolean())
44762
44724
  });
44763
44725
  discriminatedUnion("kind", [
@@ -56151,46 +56113,27 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
56151
56113
  }), LogStreamEntrySchema, { kind: "subscription" });
56152
56114
  object({
56153
56115
  /** Carbon dioxide concentration in ppm. */
56154
- co2Ppm: number().min(0).optional(),
56116
+ co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
56155
56117
  /** Total volatile organic compounds in ppb. */
56156
- vocPpb: number().min(0).optional(),
56118
+ vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
56157
56119
  /** Particulate matter ≤ 2.5 μm in µg/m³. */
56158
- pm25: number().min(0).optional(),
56120
+ pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
56159
56121
  /** Particulate matter ≤ 10 μm in µg/m³. */
56160
- pm10: number().min(0).optional(),
56122
+ pm10: number().min(0).optional().meta(readingMeta("concentration-mass")),
56161
56123
  /** Composite AQI value (typically 0..500). */
56162
- aqi: number().optional(),
56124
+ aqi: number().optional().meta(readingMeta("index")),
56163
56125
  /** Ms epoch when the slice was last updated. */
56164
- lastFetchedAt: number(),
56165
- /** Live display unit of the single metric this slice carries (e.g. HA
56166
- * `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
56167
- * upstream `sensor.*` entity surfaces ONE device_class, so one unit
56168
- * per slice is unambiguous. */
56169
- unit: string().optional(),
56170
- /** Suggested decimal places for numeric display.
56171
- * Populated live from the upstream source when provided (e.g. HA
56172
- * `attributes.suggested_display_precision`). Falls back to
56173
- * auto-formatting when absent. */
56174
- precision: number().int().min(0).max(10).optional()
56126
+ lastFetchedAt: number()
56175
56127
  });
56176
56128
  DeviceType.Sensor;
56177
56129
  object({
56178
- /** Current illuminance in lux (lx). */
56179
- lux: number().min(0).meta({
56180
- unit: "lx",
56130
+ /** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
56131
+ lux: number().min(0).nullable().meta(readingMeta("illuminance", {
56132
+ precision: 0,
56181
56133
  label: "Illuminance"
56182
- }),
56134
+ })),
56183
56135
  /** Ms epoch when the slice was last updated. */
56184
- lastFetchedAt: number(),
56185
- /** Live display unit from the upstream source (e.g. HA
56186
- * `attributes.unit_of_measurement`). The UI prefers this over the
56187
- * role's canonical unit. Absent → fall back to the canonical unit. */
56188
- unit: string().optional(),
56189
- /** Suggested decimal places for numeric display.
56190
- * Populated live from the upstream source when provided (e.g. HA
56191
- * `attributes.suggested_display_precision`). Falls back to
56192
- * auto-formatting when absent. */
56193
- precision: number().int().min(0).max(10).optional()
56136
+ lastFetchedAt: number()
56194
56137
  });
56195
56138
  DeviceType.Sensor;
56196
56139
  /**
@@ -56335,10 +56278,7 @@ var BatteryStatusSchema = object({
56335
56278
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
56336
56279
  * declines to band a non-finite reading, which is the correct shape.
56337
56280
  */
56338
- percentage: number().min(0).max(100).nullable().meta({
56339
- unit: "%",
56340
- label: "Charge"
56341
- }),
56281
+ percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
56342
56282
  /**
56343
56283
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
56344
56284
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -56365,7 +56305,14 @@ var BatteryStatusSchema = object({
56365
56305
  */
56366
56306
  sleeping: boolean().meta({ label: "Sleeping" }),
56367
56307
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
56368
- lastUpdated: number(),
56308
+ lastUpdated: number().meta(readingMeta("none")),
56309
+ /**
56310
+ * Battery voltage in volts, for a cell the firmware reports as voltage
56311
+ * rather than a percentage (Ecowitt capacitor packs). Absent on cameras
56312
+ * that only report charge. A second reading on this cap, not a second
56313
+ * `numeric-sensor` on the same device.
56314
+ */
56315
+ volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
56369
56316
  /**
56370
56317
  * Ms epoch of the last time the device PROVED it was reachable — a
56371
56318
  * completed firmware round-trip, an observed wake, or an inbound push
@@ -56425,7 +56372,7 @@ object({
56425
56372
  DeviceType.Sensor;
56426
56373
  object({
56427
56374
  /** Current level as 0..100 inclusive. Firmware-reported. */
56428
- percentage: number().min(0).max(100),
56375
+ percentage: number().min(0).max(100).meta(readingMeta("percentage")),
56429
56376
  /** Ms epoch of the last operator-driven change. Useful for UI freshness. */
56430
56377
  lastChangedAt: number()
56431
56378
  });
@@ -56810,21 +56757,21 @@ object({
56810
56757
  /** Single setpoint in Celsius. Used by single-target modes
56811
56758
  * (heat / cool / dry). Null when the device is in a range mode
56812
56759
  * (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
56813
- target: number().nullable(),
56760
+ target: number().nullable().meta(readingMeta("temperature")),
56814
56761
  /** Upper bound of the dual setpoint in Celsius. Populated only
56815
56762
  * in `heat_cool` mode. */
56816
- targetHigh: number().nullable(),
56763
+ targetHigh: number().nullable().meta(readingMeta("temperature")),
56817
56764
  /** Lower bound of the dual setpoint in Celsius. Populated only
56818
56765
  * in `heat_cool` mode. */
56819
- targetLow: number().nullable(),
56766
+ targetLow: number().nullable().meta(readingMeta("temperature")),
56820
56767
  /** Target relative humidity (0..100). Null when the device has no
56821
56768
  * humidity control. */
56822
- targetHumidity: number().min(0).max(100).nullable(),
56769
+ targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
56823
56770
  /** Current measured temperature in Celsius. Read-only — pushed by
56824
56771
  * the device's internal sensor. */
56825
- currentTemp: number().nullable(),
56772
+ currentTemp: number().nullable().meta(readingMeta("temperature")),
56826
56773
  /** Current measured relative humidity (0..100). Read-only. */
56827
- currentHumidity: number().min(0).max(100).nullable(),
56774
+ currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
56828
56775
  /** Vertical louver swing on/off. Null when the device has no vertical
56829
56776
  * swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
56830
56777
  swingVertical: boolean().nullable(),
@@ -56832,11 +56779,11 @@ object({
56832
56779
  * horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
56833
56780
  swingHorizontal: boolean().nullable(),
56834
56781
  /** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
56835
- minTemp: number().nullable().optional(),
56782
+ minTemp: number().nullable().optional().meta(readingMeta("temperature")),
56836
56783
  /** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
56837
- maxTemp: number().nullable().optional(),
56784
+ maxTemp: number().nullable().optional().meta(readingMeta("temperature")),
56838
56785
  /** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
56839
- tempStep: number().positive().nullable().optional(),
56786
+ tempStep: number().positive().nullable().optional().meta(readingMeta("temperature")),
56840
56787
  /** Ms epoch when the slice was last updated (push or command). */
56841
56788
  lastFetchedAt: number()
56842
56789
  });
@@ -56915,17 +56862,17 @@ DeviceType.Thermostat, DeviceType.Climate, method(object({
56915
56862
  * modes to expose in the picker without a slice fetch.
56916
56863
  */
56917
56864
  var RgbTripletSchema = object({
56918
- r: number().int().min(0).max(255),
56919
- g: number().int().min(0).max(255),
56920
- b: number().int().min(0).max(255)
56865
+ r: number().int().min(0).max(255).meta(readingMeta("none")),
56866
+ g: number().int().min(0).max(255).meta(readingMeta("none")),
56867
+ b: number().int().min(0).max(255).meta(readingMeta("none"))
56921
56868
  });
56922
56869
  var HsvTripletSchema = object({
56923
56870
  /** Hue in degrees, 0..360. */
56924
- h: number().min(0).max(360),
56871
+ h: number().min(0).max(360).meta(readingMeta("none")),
56925
56872
  /** Saturation as 0..100 inclusive. */
56926
- s: number().min(0).max(100),
56873
+ s: number().min(0).max(100).meta(readingMeta("none")),
56927
56874
  /** Value/brightness as 0..100 inclusive. */
56928
- v: number().min(0).max(100)
56875
+ v: number().min(0).max(100).meta(readingMeta("none"))
56929
56876
  });
56930
56877
  var ColorInputSchema = discriminatedUnion("mode", [
56931
56878
  object({
@@ -56954,7 +56901,7 @@ object({
56954
56901
  /** Populated when `mode === 'hsv'`. */
56955
56902
  hsv: HsvTripletSchema.optional(),
56956
56903
  /** Populated when `mode === 'mired'`. */
56957
- mireds: number().int().optional(),
56904
+ mireds: number().int().optional().meta(readingMeta("colour-temperature")),
56958
56905
  /** Ms epoch of the last operator-driven change. */
56959
56906
  lastChangedAt: number()
56960
56907
  });
@@ -57078,18 +57025,12 @@ _enum([
57078
57025
  "empty",
57079
57026
  "full"
57080
57027
  ]);
57081
- /** Units a remaining-life counter is reported in. Closed: the panel renders
57082
- * each. */
57083
- var ConsumableRemainingUnitSchema = _enum([
57084
- "days",
57085
- "hours",
57086
- "cycles"
57087
- ]);
57088
- /** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
57089
- * days). `value` null = unknown (D393). */
57028
+ /** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
57029
+ var ConsumableRemainingKindSchema = _enum(["duration", "count"]);
57030
+ /** Remaining life. `value` null = unknown (D393). Duration is seconds. */
57090
57031
  var ConsumableRemainingSchema = object({
57091
- value: number().min(0).nullable(),
57092
- unit: ConsumableRemainingUnitSchema
57032
+ value: number().min(0).nullable().meta(readingMeta("device")),
57033
+ kind: ConsumableRemainingKindSchema
57093
57034
  });
57094
57035
  var ConsumablesStatusSchema = object({
57095
57036
  items: array(object({
@@ -57098,7 +57039,7 @@ var ConsumablesStatusSchema = object({
57098
57039
  /** Display name. */
57099
57040
  label: string().min(1),
57100
57041
  /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
57101
- level: number().min(0).max(100).nullable(),
57042
+ level: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
57102
57043
  /** The provider's discrete verdict when known (binary mode). */
57103
57044
  status: ConsumableStatusSchema.nullable(),
57104
57045
  /** What the item is — decides whether low or full is bad. Absent = `wear`. */
@@ -57115,7 +57056,7 @@ var ConsumablesStatusSchema = object({
57115
57056
  })),
57116
57057
  lastChangedAt: number()
57117
57058
  });
57118
- Object.values(DeviceType), [...ConsumableRemainingUnitSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
57059
+ Object.values(DeviceType), [...ConsumableRemainingKindSchema.options], [...ConsumableStatusSchema.options], [...ConsumableKindSchema.options], [...ConsumableFormSchema.options];
57119
57060
  Object.values(DeviceType), method(object({
57120
57061
  deviceId: number().int().nonnegative(),
57121
57062
  key: string().min(1)
@@ -57140,39 +57081,17 @@ object({
57140
57081
  /** Current value. Numeric kind → number; select/text/datetime → string.
57141
57082
  * Datetime values are ISO 8601 strings (full timestamp, date-only,
57142
57083
  * or time-only — HA accepts all three forms). */
57143
- value: union([number(), string()]),
57084
+ value: union([number().meta(readingMeta("device")), string()]),
57144
57085
  /** Acceptable values when `kind === 'select'`. Empty for other kinds. */
57145
57086
  options: array(string()),
57146
57087
  /** Ms epoch when the slice was last updated. */
57147
57088
  lastChangedAt: number(),
57148
- /** Display unit-of-measurement (e.g. '°C', '%', 'lx').
57149
- * Populated live from HA `attributes.unit_of_measurement` on each push.
57150
- * Meaningful for `kind === 'numeric'`; absent for other kinds. */
57151
- unit: string().optional(),
57152
- /** Minimum allowed value. Populated live from HA `attributes.min`.
57153
- * Meaningful for `kind === 'numeric'`; absent for other kinds. */
57154
- min: number().optional(),
57155
- /** Maximum allowed value. Populated live from HA `attributes.max`.
57156
- * Meaningful for `kind === 'numeric'`; absent for other kinds. */
57157
- max: number().optional(),
57158
- /** Step increment. Populated live from HA `attributes.step`.
57159
- * Meaningful for `kind === 'numeric'`; absent for other kinds. */
57160
- step: number().optional(),
57161
- /** Suggested decimal places for numeric display. Populated live from HA
57162
- * `attributes.suggested_display_precision`, or derived from `step` when the
57163
- * HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
57164
- * other kinds. Falls back to auto-formatting when absent. */
57165
- precision: number().int().min(0).max(10).optional(),
57166
- /** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
57167
- * 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
57168
- * (UI defaults to 'datetime'). Derived live from the device's HA domain
57169
- * (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
57170
- * `has_date`/`has_time` attributes on each push. */
57171
- format: _enum([
57172
- "date",
57173
- "time",
57174
- "datetime"
57175
- ]).optional()
57089
+ /** Minimum allowed value, in the device quantity's base unit. */
57090
+ min: number().optional().meta(readingMeta("device")),
57091
+ /** Maximum allowed value, in the device quantity's base unit. */
57092
+ max: number().optional().meta(readingMeta("device")),
57093
+ /** Step increment, in the device quantity's base unit. */
57094
+ step: number().optional().meta(readingMeta("device"))
57176
57095
  });
57177
57096
  var ControlSetValueInputSchema = discriminatedUnion("kind", [
57178
57097
  object({
@@ -57210,9 +57129,9 @@ object({
57210
57129
  ]),
57211
57130
  /** 0 = fully closed, 100 = fully open. Null when the device has
57212
57131
  * no intermediate position surface. */
57213
- position: number().min(0).max(100).nullable(),
57132
+ position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
57214
57133
  /** 0 = closed slats, 100 = open slats. Null when no tilt support. */
57215
- tiltPosition: number().min(0).max(100).nullable(),
57134
+ tiltPosition: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
57216
57135
  /** Ms epoch when the slice was last updated. */
57217
57136
  lastChangedAt: number()
57218
57137
  });
@@ -57270,9 +57189,9 @@ var NormalizedRangeSchema$1 = object({
57270
57189
  object({
57271
57190
  mode: DayNightModeSchema,
57272
57191
  /** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
57273
- sensitivity: number().optional(),
57192
+ sensitivity: number().optional().meta(readingMeta("none")),
57274
57193
  /** Delay before the IR-cut filter flips, in seconds. */
57275
- switchDelaySec: number().optional(),
57194
+ switchDelaySec: number().optional().meta(readingMeta("duration")),
57276
57195
  lastFetchedAt: number()
57277
57196
  });
57278
57197
  /**
@@ -57427,11 +57346,11 @@ object({
57427
57346
  /** Feature keys of the programs the appliance currently offers — drives the UI selector. */
57428
57347
  availablePrograms: array(string()),
57429
57348
  /** Seconds remaining on the active cycle, or null when not running / not known. */
57430
- remainingSeconds: number().int().nonnegative().nullable(),
57349
+ remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
57431
57350
  /** Seconds the delayed start is set to (time until the cycle starts), or null. */
57432
- delayedStartSeconds: number().int().nonnegative().nullable(),
57351
+ delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
57433
57352
  /** Cycle completion 0..100, or null when not applicable. */
57434
- progressPercent: number().min(0).max(100).nullable(),
57353
+ progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
57435
57354
  /** True when the door is reported open; null when the door state is not known. */
57436
57355
  doorOpen: boolean().nullable(),
57437
57356
  /** True when the door is latched (locked) during a cycle; null when not reported. */
@@ -57455,7 +57374,7 @@ object({
57455
57374
  /** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
57456
57375
  machineCareDue: boolean().nullable(),
57457
57376
  /** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
57458
- machineCareRemainingRuns: number().int().nonnegative().nullable(),
57377
+ machineCareRemainingRuns: number().int().nonnegative().nullable().meta(readingMeta("count")),
57459
57378
  /** Option states: null when the appliance does not expose the option or has not said. */
57460
57379
  halfLoad: boolean().nullable(),
57461
57380
  hygienePlus: boolean().nullable(),
@@ -57470,7 +57389,7 @@ object({
57470
57389
  /** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
57471
57390
  activeEvents: array(string()),
57472
57391
  /** Numeric error code when the appliance reports one; null otherwise. */
57473
- errorCode: number().nullable(),
57392
+ errorCode: number().nullable().meta(readingMeta("none")),
57474
57393
  /** Name of the raised alert-level event while the appliance is in error; null otherwise. */
57475
57394
  errorLabel: string().nullable(),
57476
57395
  /** Ms epoch of the last value received from the appliance; 0 = never. */
@@ -57616,24 +57535,14 @@ object({
57616
57535
  /** Ms epoch of the last press. null = never observed since this provider started. */
57617
57536
  lastPressedAt: number().nullable(),
57618
57537
  /** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
57619
- pressCountSinceStart: number()
57538
+ pressCountSinceStart: number().meta(readingMeta("count"))
57620
57539
  });
57621
57540
  object({
57622
57541
  deviceId: number(),
57623
57542
  timestamp: number()
57624
57543
  });
57625
57544
  DeviceType.Button, DeviceType.Camera;
57626
- /**
57627
- * Enum-state sensor — a string value picked from a finite option set.
57628
- * Drives HA `sensor` entries with `state_class: enum` (HVAC action
57629
- * states, weather conditions, contact-source channels, mode strings).
57630
- * The option set is stable across observations; it is persisted in the
57631
- * device config blob (via the control slice at adoption) and is NOT
57632
- * stored in `sourceInfo`.
57633
- */
57634
- /** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
57635
- * enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
57636
- var EnumSensorDateTimeFormatSchema = _enum([
57545
+ _enum([
57637
57546
  "date",
57638
57547
  "time",
57639
57548
  "datetime"
@@ -57641,12 +57550,11 @@ var EnumSensorDateTimeFormatSchema = _enum([
57641
57550
  object({
57642
57551
  value: string(),
57643
57552
  /**
57644
- * Set for `DateTimeSensor`-role sensors so the UI renders the ISO `value`
57645
- * as a locale date/time/datetime; absent for plain enum sensors. HA
57646
- * `device_class=timestamp` → `'datetime'`, `device_class=date` → `'date'`,
57647
- * a time-only sensor → `'time'`.
57553
+ * Set when `value` is a timestamp rather than an enum state, so history
57554
+ * does not learn ISO strings as states. The display shape (date / time /
57555
+ * datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
57648
57556
  */
57649
- format: EnumSensorDateTimeFormatSchema.optional(),
57557
+ timestamp: boolean().optional(),
57650
57558
  /** Ms epoch when the slice was last updated. */
57651
57559
  lastFetchedAt: number()
57652
57560
  });
@@ -57665,13 +57573,13 @@ var EventFireSchema = object({
57665
57573
  deviceId: number(),
57666
57574
  eventType: string(),
57667
57575
  data: record(string(), unknown()).nullable(),
57668
- timestamp: number(),
57669
- seq: number()
57576
+ timestamp: number().meta(readingMeta("none")),
57577
+ seq: number().meta(readingMeta("count"))
57670
57578
  });
57671
57579
  object({
57672
57580
  eventTypes: array(string()),
57673
57581
  lastEvent: EventFireSchema.nullable(),
57674
- eventCountSinceStart: number()
57582
+ eventCountSinceStart: number().meta(readingMeta("count"))
57675
57583
  });
57676
57584
  DeviceType.EventEmitter;
57677
57585
  var IdentitySchema = object({
@@ -58060,10 +57968,10 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
58060
57968
  object({
58061
57969
  /** Active speed as 0..100 inclusive. Null when the device has no
58062
57970
  * speed surface (single-speed fan). */
58063
- percentage: number().min(0).max(100).nullable(),
57971
+ percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
58064
57972
  /** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
58065
57973
  * a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
58066
- percentageStep: number().positive().optional(),
57974
+ percentageStep: number().positive().optional().meta(readingMeta("percentage")),
58067
57975
  /** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
58068
57976
  * — empty string when no preset is active or supported. */
58069
57977
  preset: string(),
@@ -58145,7 +58053,7 @@ var FeatureProbeStatusSchema = object({
58145
58053
  /** Camera/firmware model string. `null` when the firmware doesn't expose it. */
58146
58054
  model: string().nullable(),
58147
58055
  /** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
58148
- channelCount: number().nullable(),
58056
+ channelCount: number().nullable().meta(readingMeta("count")),
58149
58057
  /**
58150
58058
  * Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
58151
58059
  * completes — drivers' `getAccessoryChildren()` should treat zero as
@@ -58179,7 +58087,7 @@ object({
58179
58087
  DeviceType.Sensor;
58180
58088
  object({
58181
58089
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58182
- position: number().min(0).max(100).nullable(),
58090
+ position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
58183
58091
  /** Ms epoch when the slice was last updated (push or poll). */
58184
58092
  lastFetchedAt: number()
58185
58093
  });
@@ -58188,9 +58096,9 @@ object({
58188
58096
  /** Whether the humidifier is currently on. */
58189
58097
  on: boolean(),
58190
58098
  /** Current measured relative humidity (0..100). Null when not reported. */
58191
- currentHumidity: number().min(0).max(100).nullable(),
58099
+ currentHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
58192
58100
  /** Target relative humidity (0..100). Null when no setpoint surface. */
58193
- targetHumidity: number().min(0).max(100).nullable(),
58101
+ targetHumidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
58194
58102
  /** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
58195
58103
  * device has no mode surface. */
58196
58104
  mode: string().nullable(),
@@ -58200,9 +58108,9 @@ object({
58200
58108
  * `idle` / `off`). Null when the device doesn't report it. */
58201
58109
  action: string().nullable(),
58202
58110
  /** HA `min_humidity` attribute. Null → UI uses 0. */
58203
- minHumidity: number().nullable(),
58111
+ minHumidity: number().nullable().meta(readingMeta("humidity")),
58204
58112
  /** HA `max_humidity` attribute. Null → UI uses 100. */
58205
- maxHumidity: number().nullable(),
58113
+ maxHumidity: number().nullable().meta(readingMeta("humidity")),
58206
58114
  /** Ms epoch when the slice was last updated. */
58207
58115
  lastChangedAt: number()
58208
58116
  });
@@ -58226,22 +58134,13 @@ DeviceType.Humidifier, method(object({
58226
58134
  auth: "protected"
58227
58135
  });
58228
58136
  object({
58229
- /** Current relative humidity, 0..100. */
58230
- percent: number().min(0).max(100).meta({
58231
- unit: "%",
58137
+ /** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
58138
+ percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
58139
+ precision: 0,
58232
58140
  label: "Humidity"
58233
- }),
58141
+ })),
58234
58142
  /** Ms epoch when the slice was last updated. */
58235
- lastFetchedAt: number(),
58236
- /** Live display unit from the upstream source (e.g. HA
58237
- * `attributes.unit_of_measurement`). The UI prefers this over the
58238
- * role's canonical unit. Absent → fall back to the canonical unit. */
58239
- unit: string().optional(),
58240
- /** Suggested decimal places for numeric display.
58241
- * Populated live from the upstream source when provided (e.g. HA
58242
- * `attributes.suggested_display_precision`). Falls back to
58243
- * auto-formatting when absent. */
58244
- precision: number().int().min(0).max(10).optional()
58143
+ lastFetchedAt: number()
58245
58144
  });
58246
58145
  DeviceType.Sensor, DeviceType.Thermostat;
58247
58146
  object({
@@ -58249,7 +58148,7 @@ object({
58249
58148
  * entity exposes no `entity_picture` (yet). */
58250
58149
  url: string().nullable(),
58251
58150
  /** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
58252
- lastUpdated: number().nullable()
58151
+ lastUpdated: number().nullable().meta(readingMeta("none"))
58253
58152
  });
58254
58153
  DeviceType.Image;
58255
58154
  /**
@@ -58305,19 +58204,19 @@ var NormalizedRangeSchema = object({
58305
58204
  });
58306
58205
  object({
58307
58206
  /** Normalized 0–100. */
58308
- brightness: number().optional(),
58207
+ brightness: number().optional().meta(readingMeta("none")),
58309
58208
  /** Normalized 0–100. */
58310
- contrast: number().optional(),
58209
+ contrast: number().optional().meta(readingMeta("none")),
58311
58210
  /** Normalized 0–100. */
58312
- saturation: number().optional(),
58211
+ saturation: number().optional().meta(readingMeta("none")),
58313
58212
  /** Normalized 0–100. */
58314
- sharpness: number().optional(),
58213
+ sharpness: number().optional().meta(readingMeta("none")),
58315
58214
  mirror: boolean().optional(),
58316
58215
  flip: boolean().optional(),
58317
58216
  rotate: ImageRotateSchema.optional(),
58318
58217
  whiteBalance: WhiteBalanceModeSchema.optional(),
58319
58218
  /** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
58320
- warmth: number().optional(),
58219
+ warmth: number().optional().meta(readingMeta("none")),
58321
58220
  exposureMode: ExposureModeSchema.optional(),
58322
58221
  backlightMode: BacklightModeSchema.optional(),
58323
58222
  lastFetchedAt: number()
@@ -58562,10 +58461,10 @@ var IntercomAbilitySchema = object({
58562
58461
  /** Codecs accepted by firmware, in preference order. Driver-authored strings. */
58563
58462
  codecs: array(string()),
58564
58463
  /** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
58565
- sampleRate: number(),
58464
+ sampleRate: number().meta(readingMeta("none")),
58566
58465
  duplex: _enum(["half", "full"]),
58567
58466
  /** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
58568
- maxBacklogMs: number()
58467
+ maxBacklogMs: number().meta(readingMeta("duration-ms"))
58569
58468
  });
58570
58469
  var IntercomStatusSchema = object({
58571
58470
  /** True while a talk session is open. */
@@ -58676,13 +58575,13 @@ object({
58676
58575
  activity: LawnMowerActivitySchema,
58677
58576
  /** 0..100 battery percentage. Null when the device has no battery
58678
58577
  * reading. */
58679
- batteryLevel: number().min(0).max(100).nullable(),
58578
+ batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
58680
58579
  /** 0..100 mowing-completion percentage of the current task, or null when no
58681
58580
  * task is active / progress is unavailable. */
58682
- progressPercent: number().min(0).max(100).nullable(),
58581
+ progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
58683
58582
  /** Current device/event code (dynamic — mostly status, sometimes an error),
58684
58583
  * or null when unknown. */
58685
- currentCode: number().nullable(),
58584
+ currentCode: number().nullable().meta(readingMeta("none")),
58686
58585
  /** Human label for {@link currentCode}, or null when undecodable. */
58687
58586
  currentCodeLabel: string().nullable(),
58688
58587
  /** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
@@ -59144,7 +59043,7 @@ object({
59144
59043
  state: MediaPlayerStateSchema,
59145
59044
  /** Volume as 0..100 inclusive. Null when the device has no volume
59146
59045
  * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
59147
- volumeLevel: number().min(0).max(100).nullable(),
59046
+ volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59148
59047
  /** Mute toggle distinct from volume=0. Null when no mute surface.
59149
59048
  * Pair with `DeviceFeature.MediaPlayerMute`. */
59150
59049
  isMuted: boolean().nullable(),
@@ -59157,10 +59056,10 @@ object({
59157
59056
  currentMedia: MediaInfoSchema.nullable(),
59158
59057
  /** Current playback position in ms. Null when not seekable or
59159
59058
  * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
59160
- positionMs: number().int().nonnegative().nullable(),
59059
+ positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
59161
59060
  /** Total duration of the current media in ms. Null when unknown
59162
59061
  * (live stream) or nothing is playing. */
59163
- durationMs: number().int().nonnegative().nullable(),
59062
+ durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
59164
59063
  /** Shuffle toggle. Null when no shuffle surface.
59165
59064
  * Pair with `DeviceFeature.MediaPlayerShuffle`. */
59166
59065
  shuffle: boolean().nullable(),
@@ -59460,7 +59359,7 @@ object({
59460
59359
  * it, every provider seeded it at boot, and every session left it
59461
59360
  * `detected: true` after its detach.
59462
59361
  */
59463
- autoClearAfterMs: number().nullable()
59362
+ autoClearAfterMs: number().nullable().meta(readingMeta("duration-ms"))
59464
59363
  });
59465
59364
  /**
59466
59365
  * Payload of `motion.onMotionChanged` event + the corresponding bus
@@ -59510,7 +59409,7 @@ var MotionZoneRegionSchema = object({
59510
59409
  });
59511
59410
  object({
59512
59411
  enabled: boolean(),
59513
- sensitivity: number(),
59412
+ sensitivity: number().meta(readingMeta("none")),
59514
59413
  /** Grid region(s). Today exactly one `grid` shape. */
59515
59414
  regions: array(MotionZoneRegionSchema),
59516
59415
  lastFetchedAt: number()
@@ -59814,7 +59713,7 @@ var NavigationStatusSchema = object({
59814
59713
  following: boolean(),
59815
59714
  flash: boolean(),
59816
59715
  lightMode: NavigationLightModeSchema,
59817
- lightLevel: number().min(40).max(100),
59716
+ lightLevel: number().min(40).max(100).meta(readingMeta("none")),
59818
59717
  /** Ms epoch when the slice was last updated. */
59819
59718
  lastChangedAt: number()
59820
59719
  });
@@ -59860,13 +59759,13 @@ var NetworkLinkStatusSchema = object({
59860
59759
  * one whose reading has not landed must not be drawn at 0 %. Consumers
59861
59760
  * SKIP a null rather than coerce it.
59862
59761
  */
59863
- signalPercent: number().min(0).max(100).nullable(),
59762
+ signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59864
59763
  /** Raw received signal strength in dBm, when the firmware reports one. */
59865
- rssiDbm: number().optional(),
59764
+ rssiDbm: number().optional().meta(readingMeta("signal-level")),
59866
59765
  /** Network name of a wireless link, when the firmware reports it. */
59867
59766
  ssid: string().optional(),
59868
59767
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
59869
- lastUpdated: number()
59768
+ lastUpdated: number().meta(readingMeta("none"))
59870
59769
  });
59871
59770
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.Light, DeviceType.Lock, DeviceType.Siren, object({
59872
59771
  deviceId: number(),
@@ -60185,7 +60084,7 @@ object({
60185
60084
  lastError: string().nullable(),
60186
60085
  /** Number of deliveries currently buffered server-side (rate-limited
60187
60086
  * notifiers may queue). 0 when the provider sends synchronously. */
60188
- queueDepth: number().int().nonnegative(),
60087
+ queueDepth: number().int().nonnegative().meta(readingMeta("count")),
60189
60088
  /** Per-feature capability matrix — authoritative source for the
60190
60089
  * compose-form field gating. */
60191
60090
  supports: NotifierSupportsSchema
@@ -60235,15 +60134,8 @@ DeviceType.Notifier, method(NotifierSendInputSchema, NotifierSendResultSchema, {
60235
60134
  acceptedAt: number()
60236
60135
  });
60237
60136
  object({
60238
- value: number(),
60239
- /** Display unit-of-measurement (e.g. 'dBm', 's', 'rpm', 'steps').
60240
- * Populated live from the upstream source on each state push.
60241
- * Absent for unitless sensors. */
60242
- unit: string().optional(),
60243
- /** Suggested decimal places for numeric display.
60244
- * Populated live from the upstream source when provided.
60245
- * Falls back to auto-formatting when absent. */
60246
- precision: number().int().min(0).max(10).optional(),
60137
+ /** Reading in the device quantity's base unit. `null` when refused (D393). */
60138
+ value: number().nullable().meta(readingMeta("device")),
60247
60139
  /** Ms epoch when the slice was last updated. */
60248
60140
  lastFetchedAt: number()
60249
60141
  });
@@ -60533,23 +60425,26 @@ object({
60533
60425
  /** Food currently in the bowl (grams). Null when the device has not
60534
60426
  * reported a reading yet. On dual-hopper models this is the combined
60535
60427
  * bowl reading; per-hopper levels live in `food1`/`food2`. */
60536
- foodLevel: number().nullable(),
60428
+ foodLevel: number().nullable().meta(readingMeta("none")),
60537
60429
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
60538
60430
  * single-hopper models. */
60539
- food1: number().nullable(),
60431
+ food1: number().nullable().meta(readingMeta("none")),
60540
60432
  /** Hopper-2 food level (grams) on dual-hopper feeders; null on
60541
60433
  * single-hopper models. */
60542
- food2: number().nullable(),
60434
+ food2: number().nullable().meta(readingMeta("none")),
60543
60435
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
60544
60436
  * (`device_class: problem`, on = low). True when the bowl is empty /
60545
60437
  * below the feeder's low threshold. */
60546
60438
  lowFood: boolean(),
60547
60439
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
60548
60440
  * device has no battery reading. */
60549
- batteryPower: number().min(0).max(100).nullable(),
60550
- /** Days of desiccant life remaining. Null when the model has no
60551
- * desiccant sensor. */
60552
- desiccantLeftDays: number().nullable(),
60441
+ batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60442
+ /**
60443
+ * Desiccant life remaining, stored in seconds (duration base, D944).
60444
+ * Providers convert from the days the feeder reports. Null when the
60445
+ * model has no desiccant sensor.
60446
+ */
60447
+ desiccantLeftDays: number().nullable().meta(readingMeta("duration")),
60553
60448
  /** True while a feed is in progress. */
60554
60449
  feeding: boolean(),
60555
60450
  /** Decoded connectivity / power status (HA petkit device-status enum).
@@ -60560,7 +60455,7 @@ object({
60560
60455
  * with `errorCode` for consumers that want the raw integer. */
60561
60456
  error: string().nullable(),
60562
60457
  /** Raw device error code (0 / null = no error). */
60563
- errorCode: number().nullable(),
60458
+ errorCode: number().nullable().meta(readingMeta("none")),
60564
60459
  /** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
60565
60460
  isDualHopper: boolean(),
60566
60461
  /** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
@@ -60570,7 +60465,7 @@ object({
60570
60465
  /** Play a chime when dispensing. */
60571
60466
  feedSound: boolean(),
60572
60467
  /** Speaker / prompt volume level (device-scaled integer). */
60573
- volume: number(),
60468
+ volume: number().meta(readingMeta("none")),
60574
60469
  /** Ms epoch when the slice was last refreshed from the cloud. */
60575
60470
  lastFetchedAt: number()
60576
60471
  });
@@ -61007,36 +60902,19 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
61007
60902
  });
61008
60903
  object({
61009
60904
  /** Instantaneous power draw in watts. */
61010
- watts: number().optional().meta({
61011
- unit: "W",
61012
- label: "Power"
61013
- }),
60905
+ watts: number().optional().meta(readingMeta("power", { label: "Power" })),
61014
60906
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
61015
- kwhTotal: number().optional().meta({
61016
- unit: "kWh",
61017
- label: "Energy"
61018
- }),
60907
+ kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
61019
60908
  /** Voltage in volts. */
61020
- volts: number().optional(),
60909
+ volts: number().optional().meta(readingMeta("voltage")),
61021
60910
  /** Current in amperes. */
61022
- amps: number().optional(),
61023
- /** Apparent power in volt-amperes (W × power-factor reciprocal). */
61024
- va: number().optional(),
60911
+ amps: number().optional().meta(readingMeta("current")),
60912
+ /** Apparent power in volt-amperes. */
60913
+ va: number().optional().meta(readingMeta("apparent-power")),
61025
60914
  /** Power factor (0..1) if reported. */
61026
- powerFactor: number().min(0).max(1).optional(),
60915
+ powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
61027
60916
  /** Ms epoch when the slice was last updated. */
61028
- lastFetchedAt: number(),
61029
- /** Live display unit of the single metric this slice carries (e.g. HA
61030
- * `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
61031
- * Each upstream `sensor.*` entity surfaces ONE device_class, so one
61032
- * unit per slice is unambiguous. The UI prefers this over the role's
61033
- * canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
61034
- unit: string().optional(),
61035
- /** Suggested decimal places for numeric display.
61036
- * Populated live from the upstream source when provided (e.g. HA
61037
- * `attributes.suggested_display_precision`). Falls back to
61038
- * auto-formatting when absent. */
61039
- precision: number().int().min(0).max(10).optional()
60917
+ lastFetchedAt: number()
61040
60918
  });
61041
60919
  DeviceType.Sensor;
61042
60920
  /**
@@ -61057,11 +60935,11 @@ DeviceType.Sensor;
61057
60935
  */
61058
60936
  var GpsLocationSchema = object({
61059
60937
  /** Latitude in decimal degrees, -90..90. */
61060
- latitude: number().min(-90).max(90),
60938
+ latitude: number().min(-90).max(90).meta(readingMeta("angle")),
61061
60939
  /** Longitude in decimal degrees, -180..180. */
61062
- longitude: number().min(-180).max(180),
60940
+ longitude: number().min(-180).max(180).meta(readingMeta("angle")),
61063
60941
  /** Reported accuracy in meters (lower = better). */
61064
- accuracyMeters: number().nonnegative()
60942
+ accuracyMeters: number().nonnegative().meta(readingMeta("length"))
61065
60943
  });
61066
60944
  object({
61067
60945
  /** `home` / `not_home` / any user-defined zone name. */
@@ -61073,25 +60951,16 @@ object({
61073
60951
  gps: GpsLocationSchema.nullable(),
61074
60952
  /** Optional battery level of the tracking device (0..100). Null
61075
60953
  * when not reported. */
61076
- batteryPercent: number().min(0).max(100).nullable(),
60954
+ batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61077
60955
  /** Ms epoch when the slice was last updated. */
61078
60956
  lastChangedAt: number()
61079
60957
  });
61080
60958
  DeviceType.Presence;
61081
60959
  object({
61082
- /** Current pressure in hPa. */
61083
- hpa: number(),
60960
+ /** Current pressure in hPa. `null` when the sample was refused (D393). */
60961
+ hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
61084
60962
  /** Ms epoch when the slice was last updated. */
61085
- lastFetchedAt: number(),
61086
- /** Live display unit from the upstream source (e.g. HA
61087
- * `attributes.unit_of_measurement`). The UI prefers this over the
61088
- * role's canonical unit. Absent → fall back to the canonical unit. */
61089
- unit: string().optional(),
61090
- /** Suggested decimal places for numeric display.
61091
- * Populated live from the upstream source when provided (e.g. HA
61092
- * `attributes.suggested_display_precision`). Falls back to
61093
- * auto-formatting when absent. */
61094
- precision: number().int().min(0).max(10).optional()
60963
+ lastFetchedAt: number()
61095
60964
  });
61096
60965
  DeviceType.Sensor;
61097
60966
  /**
@@ -61424,8 +61293,8 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number() }), _
61424
61293
  }), _void(), { kind: "mutation" });
61425
61294
  var PtzAutotrackSettingsSchema = object({
61426
61295
  targetType: string().describe("Vendor target string (people/vehicle/pet); empty = camera default"),
61427
- stopDelaySeconds: number().int().min(0).max(300),
61428
- disappearDelaySeconds: number().int().min(0).max(300)
61296
+ stopDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration")),
61297
+ disappearDelaySeconds: number().int().min(0).max(300).meta(readingMeta("duration"))
61429
61298
  });
61430
61299
  /**
61431
61300
  * One option the camera advertises as a valid `targetType`. Drivers
@@ -61482,7 +61351,7 @@ object({
61482
61351
  /** null = unknown — never coerced to false (D393). */
61483
61352
  running: boolean().nullable(),
61484
61353
  /** Epoch ms the current boolean began; null while `running` is null. */
61485
- since: number().nullable(),
61354
+ since: number().nullable().meta(readingMeta("none")),
61486
61355
  source: RunningStateSourceSchema.meta({ label: "Source" }),
61487
61356
  phase: string().nullable(),
61488
61357
  /** null until a reading has been published (D393). */
@@ -62680,9 +62549,9 @@ var RecordTriggerSchema = _enum([
62680
62549
  */
62681
62550
  var RecordWindowSchema = object({
62682
62551
  trigger: RecordTriggerSchema,
62683
- day: number().int().min(0).max(6),
62684
- startMinute: number().int().min(0).max(1439),
62685
- endMinute: number().int().min(1).max(1440)
62552
+ day: number().int().min(0).max(6).meta(readingMeta("none")),
62553
+ startMinute: number().int().min(0).max(1439).meta(readingMeta("none")),
62554
+ endMinute: number().int().min(1).max(1440).meta(readingMeta("none"))
62686
62555
  });
62687
62556
  /** Status of one physical volume, as the camera itself describes it. */
62688
62557
  var OnboardStorageVolumeSchema = object({
@@ -62751,10 +62620,10 @@ object({
62751
62620
  /** Master "record to the card at all" switch. */
62752
62621
  enabled: boolean().nullable(),
62753
62622
  overwriteWhenFull: boolean().nullable(),
62754
- preRecordSec: number().nullable(),
62755
- postRecordSec: number().nullable(),
62623
+ preRecordSec: number().nullable().meta(readingMeta("duration")),
62624
+ postRecordSec: number().nullable().meta(readingMeta("duration")),
62756
62625
  /** Length of one recorded file, in minutes. */
62757
- segmentMinutes: number().nullable(),
62626
+ segmentMinutes: number().nullable().meta(readingMeta("none")),
62758
62627
  /** The primary track's weekly windows, flattened. */
62759
62628
  windows: array(RecordWindowSchema),
62760
62629
  /**
@@ -62770,7 +62639,7 @@ object({
62770
62639
  * provider reporting a non-zero count also reports the schedule as not
62771
62640
  * writable.
62772
62641
  */
62773
- unreadableWindows: number(),
62642
+ unreadableWindows: number().meta(readingMeta("count")),
62774
62643
  /**
62775
62644
  * The camera is scheduled to record and has NO usable storage.
62776
62645
  *
@@ -63407,7 +63276,7 @@ var CamStreamDescriptorSchema = object({
63407
63276
  url: string().optional(),
63408
63277
  codec: string().optional(),
63409
63278
  resolution: CamStreamResolutionSchema.optional(),
63410
- fps: number().positive().optional(),
63279
+ fps: number().positive().optional().meta(readingMeta("rate")),
63411
63280
  label: string().optional(),
63412
63281
  /** Device-level features (e.g. `battery-operated`) — drives broker policy. */
63413
63282
  deviceFeatures: array(string()).optional(),
@@ -63437,18 +63306,18 @@ var StreamProfileSchema = _enum([
63437
63306
  ]);
63438
63307
  /** The current encoding config of one stream profile. */
63439
63308
  var StreamProfileConfigSchema = object({
63440
- width: number(),
63441
- height: number(),
63309
+ width: number().meta(readingMeta("none")),
63310
+ height: number().meta(readingMeta("none")),
63442
63311
  codec: _enum(["h264", "h265"]),
63443
- framerate: number(),
63444
- bitrate: number(),
63312
+ framerate: number().meta(readingMeta("rate")),
63313
+ bitrate: number().meta(readingMeta("bitrate")),
63445
63314
  bitrateMode: _enum(["vbr", "cbr"]).optional(),
63446
63315
  encoderProfile: _enum([
63447
63316
  "high",
63448
63317
  "main",
63449
63318
  "baseline"
63450
63319
  ]).optional(),
63451
- gop: number().optional(),
63320
+ gop: number().optional().meta(readingMeta("none")),
63452
63321
  /**
63453
63322
  * Whether THIS profile currently carries an audio track. READ-ONLY here.
63454
63323
  *
@@ -64091,23 +63960,13 @@ object({
64091
63960
  });
64092
63961
  DeviceType.Sensor;
64093
63962
  object({
64094
- /** Current temperature in Celsius. */
64095
- celsius: number().meta({
64096
- unit: "°C",
63963
+ /** Current temperature in Celsius. `null` when the sample was refused (D393). */
63964
+ celsius: number().nullable().meta(readingMeta("temperature", {
63965
+ precision: 1,
64097
63966
  label: "Temperature"
64098
- }),
63967
+ })),
64099
63968
  /** Ms epoch when the slice was last updated (push or poll). */
64100
- lastFetchedAt: number(),
64101
- /** Live display unit from the upstream source (e.g. HA
64102
- * `attributes.unit_of_measurement`). The UI prefers this over the
64103
- * role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
64104
- * Absent → the UI falls back to the role's canonical unit. */
64105
- unit: string().optional(),
64106
- /** Suggested decimal places for numeric display.
64107
- * Populated live from the upstream source when provided (e.g. HA
64108
- * `attributes.suggested_display_precision`). Falls back to
64109
- * auto-formatting when absent. */
64110
- precision: number().int().min(0).max(10).optional()
63969
+ lastFetchedAt: number()
64111
63970
  });
64112
63971
  DeviceType.Sensor, DeviceType.Thermostat;
64113
63972
  /**
@@ -64359,16 +64218,16 @@ object({
64359
64218
  ]),
64360
64219
  /** 0..100 battery percentage. Null when the device has no battery
64361
64220
  * reading. */
64362
- batteryLevel: number().min(0).max(100).nullable(),
64221
+ batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64363
64222
  /** Current fan-speed token (provider-verbatim). Null when unknown or
64364
64223
  * the vacuum has no speed control. */
64365
64224
  fanSpeed: string().nullable(),
64366
64225
  /** Speed tokens the hardware accepts — drives the UI selector. */
64367
64226
  availableFanSpeeds: array(string()),
64368
64227
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64369
- progressPercent: number().min(0).max(100).nullable(),
64228
+ progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64370
64229
  /** Current error code (0 / null = no error). */
64371
- errorCode: number().nullable(),
64230
+ errorCode: number().nullable().meta(readingMeta("none")),
64372
64231
  /** Human label for {@link errorCode}, or null when none / undecodable. */
64373
64232
  errorLabel: string().nullable(),
64374
64233
  /** Ms epoch when the slice was last updated. */
@@ -64407,7 +64266,7 @@ object({
64407
64266
  ]),
64408
64267
  /** 0 = fully closed, 100 = fully open. Null when the device has no
64409
64268
  * intermediate position surface. */
64410
- position: number().min(0).max(100).nullable(),
64269
+ position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64411
64270
  /** Ms epoch when the slice was last updated. */
64412
64271
  lastChangedAt: number()
64413
64272
  });
@@ -64435,9 +64294,9 @@ object({
64435
64294
  DeviceType.Sensor;
64436
64295
  object({
64437
64296
  /** Current measured temperature. Null when not reported. */
64438
- currentTemp: number().nullable(),
64297
+ currentTemp: number().nullable().meta(readingMeta("temperature")),
64439
64298
  /** Target temperature setpoint. Null when no setpoint surface. */
64440
- targetTemp: number().nullable(),
64299
+ targetTemp: number().nullable().meta(readingMeta("temperature")),
64441
64300
  /** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
64442
64301
  * `heat_pump` / `high_demand` / `performance` / `off`). Null when the
64443
64302
  * device reports an unknown state. */
@@ -64448,9 +64307,9 @@ object({
64448
64307
  * has no away surface. */
64449
64308
  away: boolean().nullable(),
64450
64309
  /** HA `min_temp` attribute. Null when not reported. */
64451
- minTemp: number().nullable(),
64310
+ minTemp: number().nullable().meta(readingMeta("temperature")),
64452
64311
  /** HA `max_temp` attribute. Null when not reported. */
64453
- maxTemp: number().nullable(),
64312
+ maxTemp: number().nullable().meta(readingMeta("temperature")),
64454
64313
  /** Ms epoch when the slice was last updated. */
64455
64314
  lastChangedAt: number()
64456
64315
  });
@@ -64474,25 +64333,18 @@ DeviceType.WaterHeater, method(object({
64474
64333
  auth: "protected"
64475
64334
  });
64476
64335
  object({
64477
- /** Verbatim HA condition state (`sunny`, `cloudy`, `rainy`, …). Null
64478
- * when no condition has been reported yet. */
64336
+ /** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
64479
64337
  condition: string().nullable(),
64480
- /** Current temperature in the reported unit. Null when not provided. */
64481
- temperature: number().nullable(),
64482
- /** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
64483
- temperatureUnit: string().nullable(),
64338
+ /** Current temperature in Celsius. Null when not provided or refused. */
64339
+ temperature: number().nullable().meta(readingMeta("temperature", { precision: 1 })),
64484
64340
  /** Relative humidity (0..100). Null when not provided. */
64485
- humidity: number().min(0).max(100).nullable(),
64486
- /** Barometric pressure in the reported unit. Null when not provided. */
64487
- pressure: number().nullable(),
64488
- /** Pressure unit string (e.g. `hPa` / `inHg`). Null when not provided. */
64489
- pressureUnit: string().nullable(),
64490
- /** Wind speed in the reported unit. Null when not provided. */
64491
- windSpeed: number().nullable(),
64492
- /** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
64493
- windSpeedUnit: string().nullable(),
64341
+ humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity")),
64342
+ /** Barometric pressure in hPa. Null when not provided or refused. */
64343
+ pressure: number().nullable().meta(readingMeta("pressure")),
64344
+ /** Wind speed in metres per second. Null when not provided or refused. */
64345
+ windSpeed: number().nullable().meta(readingMeta("speed")),
64494
64346
  /** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
64495
- windBearing: number().nullable(),
64347
+ windBearing: number().nullable().meta(readingMeta("angle")),
64496
64348
  /** Ms epoch when the slice was last updated. */
64497
64349
  lastFetchedAt: number()
64498
64350
  });
@@ -78469,7 +78321,6 @@ var SENSOR_CAP_VOCABULARY = {
78469
78321
  field: "value",
78470
78322
  quantity: t("the reading", "il valore"),
78471
78323
  label: t("Reading", "Valore"),
78472
- unitField: "unit",
78473
78324
  icon: "gauge"
78474
78325
  }]
78475
78326
  },
@@ -78605,7 +78456,7 @@ var SENSOR_CAP_VOCABULARY = {
78605
78456
  field: "temperature",
78606
78457
  quantity: t("the outdoor temperature", "la temperatura esterna"),
78607
78458
  label: t("Temperature", "Temperatura"),
78608
- unitField: "temperatureUnit",
78459
+ unit: "°C",
78609
78460
  icon: "thermometer"
78610
78461
  },
78611
78462
  {
@@ -78621,7 +78472,7 @@ var SENSOR_CAP_VOCABULARY = {
78621
78472
  field: "windSpeed",
78622
78473
  quantity: t("the wind speed", "la velocità del vento"),
78623
78474
  label: t("Wind", "Vento"),
78624
- unitField: "windSpeedUnit",
78475
+ unit: "m/s",
78625
78476
  icon: "wind"
78626
78477
  },
78627
78478
  {
@@ -78629,7 +78480,7 @@ var SENSOR_CAP_VOCABULARY = {
78629
78480
  field: "pressure",
78630
78481
  quantity: t("the air pressure", "la pressione atmosferica"),
78631
78482
  label: t("Pressure", "Pressione"),
78632
- unitField: "pressureUnit",
78483
+ unit: "hPa",
78633
78484
  icon: "gauge"
78634
78485
  }
78635
78486
  ]