@camstack/system 1.2.484 → 1.2.486
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/{agent-https-DttPIFry.mjs → agent-https-C4PLR74Z.mjs} +1 -1
- package/dist/{agent-https-CW8aLMDL.js → agent-https-DP-Ds2hU.js} +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +69 -15
- package/dist/builtins/composer/composer.addon.mjs +69 -15
- package/dist/builtins/composer/composition-runtime.d.ts +2 -0
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/composition-sources.d.ts +3 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +53 -28
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +53 -28
- package/dist/builtins/device-history/device-history.addon.d.ts +2 -0
- package/dist/builtins/device-history/device-history.addon.js +248 -4
- package/dist/builtins/device-history/device-history.addon.mjs +248 -4
- package/dist/builtins/device-history/query/history-query.d.ts +5 -1
- package/dist/builtins/device-history/runtime/history-runtime.d.ts +18 -1
- package/dist/builtins/device-history/store/history-schema.d.ts +2 -0
- package/dist/builtins/device-history/store/history-store.d.ts +11 -0
- package/dist/builtins/device-history/store/series-scale.d.ts +37 -0
- package/dist/builtins/device-manager/device-manager.addon.js +3 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +3 -2
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +3 -3
- package/dist/builtins/keychain/index.mjs +3 -3
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +2 -2
- package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
- package/dist/builtins/local-network/local-network.addon.js +2 -2
- package/dist/builtins/local-network/local-network.addon.mjs +2 -2
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/record-entries/index.js +1 -1
- package/dist/builtins/record-entries/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +3 -3
- package/dist/builtins/system-config/system-config.addon.mjs +3 -3
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{composition-sources-DqRPHdtw.js → composition-sources-CN8K2Q91.js} +4 -2
- package/dist/{composition-sources-DEsDonpg.mjs → composition-sources-IxiUkrz1.mjs} +4 -2
- package/dist/{constants-71vf77HY.js → constants-1S7BBGMb.js} +1 -1
- package/dist/{constants-B3FDrBIq.mjs → constants-DLyGFHZ2.mjs} +1 -1
- package/dist/{device-ca-bhz04X_N.mjs → device-ca-Cbf7_R9t.mjs} +1 -1
- package/dist/{device-ca-BDPYXhkH.js → device-ca-DoOFG0nm.js} +1 -1
- package/dist/{dist-k--OhKkO.js → dist-D-d_UWL4.js} +1375 -537
- package/dist/{dist-BT_THdzJ.mjs → dist-HBue971z.mjs} +1364 -538
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/{hub-mdns-ciao-DDgdvcQw.mjs → hub-mdns-ciao-CuEWb6gB.mjs} +2 -2
- package/dist/{hub-mdns-ciao-CGXfhvTk.js → hub-mdns-ciao-dcacrwqd.js} +2 -2
- package/dist/index.js +7 -7
- package/dist/index.mjs +7 -7
- package/dist/{restore-archive-z0XT2g29.mjs → restore-archive-BGBRadFJ.mjs} +1 -1
- package/dist/{restore-archive-B-GiglWt.js → restore-archive-DHdXrKwG.js} +1 -1
- package/dist/{retention-DFkmhjeH.mjs → retention-8uqDWll8.mjs} +1 -1
- package/dist/{retention-DR0_xRTy.js → retention-ChgrkTfz.js} +1 -1
- package/dist/{wal-maintenance-C4cma95b.js → wal-maintenance-BOT7wWvH.js} +0 -0
- package/dist/{wal-maintenance-CVDrL_BD.mjs → wal-maintenance-DubGwqz2.mjs} +0 -0
- package/package.json +1 -1
|
@@ -765,7 +765,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
765
765
|
return EventCategory;
|
|
766
766
|
}({});
|
|
767
767
|
//#endregion
|
|
768
|
-
//#region ../types/dist/sleep-
|
|
768
|
+
//#region ../types/dist/sleep-B81gwQuR.mjs
|
|
769
769
|
/**
|
|
770
770
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
771
771
|
* window to float samples (D455).
|
|
@@ -3801,6 +3801,112 @@ function assertTransactScope(members) {
|
|
|
3801
3801
|
if (missing.length > 0) throw new TransactRefusedError(`no-family: ${missing.map((m) => m.kind).join(", ")} declare no transactFamily; kinds that must agree through transact share one`);
|
|
3802
3802
|
if (new Set(kinds.map((m) => m.declaration.transactFamily)).size > 1) throw new TransactRefusedError(`cross-family: the ops span more than one transactFamily (${kinds.map((m) => `${m.kind}=${String(m.declaration.transactFamily)}`).join(", ")})`);
|
|
3803
3803
|
}
|
|
3804
|
+
var READING_QUANTITIES = [
|
|
3805
|
+
"temperature",
|
|
3806
|
+
"pressure",
|
|
3807
|
+
"speed",
|
|
3808
|
+
"precipitation",
|
|
3809
|
+
"precipitation-rate",
|
|
3810
|
+
"length",
|
|
3811
|
+
"area",
|
|
3812
|
+
"illuminance",
|
|
3813
|
+
"irradiance",
|
|
3814
|
+
"power",
|
|
3815
|
+
"energy",
|
|
3816
|
+
"voltage",
|
|
3817
|
+
"current",
|
|
3818
|
+
"apparent-power",
|
|
3819
|
+
"humidity",
|
|
3820
|
+
"percentage",
|
|
3821
|
+
"concentration-volume",
|
|
3822
|
+
"concentration-mass",
|
|
3823
|
+
"concentration-ppb",
|
|
3824
|
+
"volume",
|
|
3825
|
+
"duration",
|
|
3826
|
+
"duration-ms",
|
|
3827
|
+
"information",
|
|
3828
|
+
"sound-level",
|
|
3829
|
+
"signal-level",
|
|
3830
|
+
"colour-temperature",
|
|
3831
|
+
"angle",
|
|
3832
|
+
"bitrate",
|
|
3833
|
+
"rate",
|
|
3834
|
+
"mass",
|
|
3835
|
+
"index",
|
|
3836
|
+
"ratio",
|
|
3837
|
+
"count",
|
|
3838
|
+
"none",
|
|
3839
|
+
"device"
|
|
3840
|
+
];
|
|
3841
|
+
var ReadingQuantitySchema = zod.z.enum(READING_QUANTITIES);
|
|
3842
|
+
var QUANTITY_SET = new Set(READING_QUANTITIES);
|
|
3843
|
+
function isReadingQuantity(value) {
|
|
3844
|
+
return typeof value === "string" && QUANTITY_SET.has(value);
|
|
3845
|
+
}
|
|
3846
|
+
/**
|
|
3847
|
+
* Stored unit symbol for a quantity. `none` means the number is dimensionless
|
|
3848
|
+
* (or an index / ratio / count). `device` means the cap has no single unit.
|
|
3849
|
+
*/
|
|
3850
|
+
var QUANTITY_BASE = {
|
|
3851
|
+
temperature: "°C",
|
|
3852
|
+
pressure: "hPa",
|
|
3853
|
+
speed: "m/s",
|
|
3854
|
+
precipitation: "mm",
|
|
3855
|
+
"precipitation-rate": "mm/h",
|
|
3856
|
+
length: "m",
|
|
3857
|
+
area: "m²",
|
|
3858
|
+
illuminance: "lx",
|
|
3859
|
+
irradiance: "W/m²",
|
|
3860
|
+
power: "W",
|
|
3861
|
+
energy: "kWh",
|
|
3862
|
+
voltage: "V",
|
|
3863
|
+
current: "A",
|
|
3864
|
+
"apparent-power": "VA",
|
|
3865
|
+
humidity: "%",
|
|
3866
|
+
percentage: "%",
|
|
3867
|
+
"concentration-volume": "ppm",
|
|
3868
|
+
"concentration-mass": "µg/m³",
|
|
3869
|
+
"concentration-ppb": "ppb",
|
|
3870
|
+
volume: "L",
|
|
3871
|
+
duration: "s",
|
|
3872
|
+
"duration-ms": "ms",
|
|
3873
|
+
information: "B",
|
|
3874
|
+
"sound-level": "dBFS",
|
|
3875
|
+
"signal-level": "dBm",
|
|
3876
|
+
"colour-temperature": "mired",
|
|
3877
|
+
angle: "°",
|
|
3878
|
+
bitrate: "kbps",
|
|
3879
|
+
rate: "fps",
|
|
3880
|
+
mass: "kg",
|
|
3881
|
+
index: "none",
|
|
3882
|
+
ratio: "none",
|
|
3883
|
+
count: "none",
|
|
3884
|
+
none: "none",
|
|
3885
|
+
device: "device"
|
|
3886
|
+
};
|
|
3887
|
+
/** The stored unit, or `undefined` when the quantity has no unit symbol. */
|
|
3888
|
+
function baseUnitOf(quantity) {
|
|
3889
|
+
const symbol = QUANTITY_BASE[quantity];
|
|
3890
|
+
if (symbol === "none" || symbol === "device") return void 0;
|
|
3891
|
+
return symbol;
|
|
3892
|
+
}
|
|
3893
|
+
/**
|
|
3894
|
+
* History catalog label for a quantity. Index and ratio keep the labels the
|
|
3895
|
+
* series already used (`count`, `ratio`). A polymorphic reading has no
|
|
3896
|
+
* single label.
|
|
3897
|
+
*/
|
|
3898
|
+
function historyUnitFor(quantity) {
|
|
3899
|
+
if (quantity === "index" || quantity === "count") return "count";
|
|
3900
|
+
if (quantity === "ratio") return "ratio";
|
|
3901
|
+
return baseUnitOf(quantity);
|
|
3902
|
+
}
|
|
3903
|
+
function readingMeta(quantity, extras) {
|
|
3904
|
+
return {
|
|
3905
|
+
quantity,
|
|
3906
|
+
...extras?.precision !== void 0 ? { precision: extras.precision } : {},
|
|
3907
|
+
...extras?.label !== void 0 ? { label: extras.label } : {}
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3804
3910
|
/** Shared Zod schemas used across streaming capabilities. */
|
|
3805
3911
|
var CamProfileSchema = zod.z.enum([
|
|
3806
3912
|
"high",
|
|
@@ -3828,8 +3934,8 @@ var CamStreamKindSchema = zod.z.enum([
|
|
|
3828
3934
|
"derived"
|
|
3829
3935
|
]);
|
|
3830
3936
|
var CamStreamResolutionSchema = zod.z.object({
|
|
3831
|
-
width: zod.z.number().int().positive(),
|
|
3832
|
-
height: zod.z.number().int().positive()
|
|
3937
|
+
width: zod.z.number().int().positive().meta(readingMeta("none")),
|
|
3938
|
+
height: zod.z.number().int().positive().meta(readingMeta("none"))
|
|
3833
3939
|
});
|
|
3834
3940
|
var CameraStreamSchema = zod.z.object({
|
|
3835
3941
|
/** Stable, provider-assigned id unique within the (deviceId) scope. */
|
|
@@ -5077,6 +5183,7 @@ var CAP_NAMES = Object.freeze([
|
|
|
5077
5183
|
"filesystem-browse",
|
|
5078
5184
|
"flood",
|
|
5079
5185
|
"gas",
|
|
5186
|
+
"group-status",
|
|
5080
5187
|
"heating-valve",
|
|
5081
5188
|
"humidifier",
|
|
5082
5189
|
"humidity-sensor",
|
|
@@ -5206,14 +5313,6 @@ Object.freeze({
|
|
|
5206
5313
|
{
|
|
5207
5314
|
"path": "aqi",
|
|
5208
5315
|
"valueType": "number"
|
|
5209
|
-
},
|
|
5210
|
-
{
|
|
5211
|
-
"path": "unit",
|
|
5212
|
-
"valueType": "string"
|
|
5213
|
-
},
|
|
5214
|
-
{
|
|
5215
|
-
"path": "precision",
|
|
5216
|
-
"valueType": "number"
|
|
5217
5316
|
}
|
|
5218
5317
|
],
|
|
5219
5318
|
"alarm-panel": [
|
|
@@ -5249,20 +5348,10 @@ Object.freeze({
|
|
|
5249
5348
|
"valueType": "boolean"
|
|
5250
5349
|
}
|
|
5251
5350
|
],
|
|
5252
|
-
"ambient-light-sensor": [
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
},
|
|
5257
|
-
{
|
|
5258
|
-
"path": "unit",
|
|
5259
|
-
"valueType": "string"
|
|
5260
|
-
},
|
|
5261
|
-
{
|
|
5262
|
-
"path": "precision",
|
|
5263
|
-
"valueType": "number"
|
|
5264
|
-
}
|
|
5265
|
-
],
|
|
5351
|
+
"ambient-light-sensor": [{
|
|
5352
|
+
"path": "lux",
|
|
5353
|
+
"valueType": "number"
|
|
5354
|
+
}],
|
|
5266
5355
|
"audio-metrics": [
|
|
5267
5356
|
{
|
|
5268
5357
|
"path": "ts",
|
|
@@ -5342,6 +5431,10 @@ Object.freeze({
|
|
|
5342
5431
|
"path": "lastUpdated",
|
|
5343
5432
|
"valueType": "number"
|
|
5344
5433
|
},
|
|
5434
|
+
{
|
|
5435
|
+
"path": "volts",
|
|
5436
|
+
"valueType": "number"
|
|
5437
|
+
},
|
|
5345
5438
|
{
|
|
5346
5439
|
"path": "lastContactAt",
|
|
5347
5440
|
"valueType": "number"
|
|
@@ -5584,10 +5677,6 @@ Object.freeze({
|
|
|
5584
5677
|
"datetime"
|
|
5585
5678
|
]
|
|
5586
5679
|
},
|
|
5587
|
-
{
|
|
5588
|
-
"path": "unit",
|
|
5589
|
-
"valueType": "string"
|
|
5590
|
-
},
|
|
5591
5680
|
{
|
|
5592
5681
|
"path": "min",
|
|
5593
5682
|
"valueType": "number"
|
|
@@ -5599,19 +5688,6 @@ Object.freeze({
|
|
|
5599
5688
|
{
|
|
5600
5689
|
"path": "step",
|
|
5601
5690
|
"valueType": "number"
|
|
5602
|
-
},
|
|
5603
|
-
{
|
|
5604
|
-
"path": "precision",
|
|
5605
|
-
"valueType": "number"
|
|
5606
|
-
},
|
|
5607
|
-
{
|
|
5608
|
-
"path": "format",
|
|
5609
|
-
"valueType": "enum",
|
|
5610
|
-
"enumValues": [
|
|
5611
|
-
"date",
|
|
5612
|
-
"time",
|
|
5613
|
-
"datetime"
|
|
5614
|
-
]
|
|
5615
5691
|
}
|
|
5616
5692
|
],
|
|
5617
5693
|
"cover": [
|
|
@@ -5852,13 +5928,8 @@ Object.freeze({
|
|
|
5852
5928
|
"path": "value",
|
|
5853
5929
|
"valueType": "string"
|
|
5854
5930
|
}, {
|
|
5855
|
-
"path": "
|
|
5856
|
-
"valueType": "
|
|
5857
|
-
"enumValues": [
|
|
5858
|
-
"date",
|
|
5859
|
-
"time",
|
|
5860
|
-
"datetime"
|
|
5861
|
-
]
|
|
5931
|
+
"path": "timestamp",
|
|
5932
|
+
"valueType": "boolean"
|
|
5862
5933
|
}],
|
|
5863
5934
|
"event-emitter": [
|
|
5864
5935
|
{
|
|
@@ -5931,6 +6002,20 @@ Object.freeze({
|
|
|
5931
6002
|
"path": "detected",
|
|
5932
6003
|
"valueType": "boolean"
|
|
5933
6004
|
}],
|
|
6005
|
+
"group-status": [
|
|
6006
|
+
{
|
|
6007
|
+
"path": "included",
|
|
6008
|
+
"valueType": "number"
|
|
6009
|
+
},
|
|
6010
|
+
{
|
|
6011
|
+
"path": "excluded",
|
|
6012
|
+
"valueType": "number"
|
|
6013
|
+
},
|
|
6014
|
+
{
|
|
6015
|
+
"path": "total",
|
|
6016
|
+
"valueType": "number"
|
|
6017
|
+
}
|
|
6018
|
+
],
|
|
5934
6019
|
"heating-valve": [{
|
|
5935
6020
|
"path": "position",
|
|
5936
6021
|
"valueType": "number"
|
|
@@ -5965,20 +6050,10 @@ Object.freeze({
|
|
|
5965
6050
|
"valueType": "number"
|
|
5966
6051
|
}
|
|
5967
6052
|
],
|
|
5968
|
-
"humidity-sensor": [
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
},
|
|
5973
|
-
{
|
|
5974
|
-
"path": "unit",
|
|
5975
|
-
"valueType": "string"
|
|
5976
|
-
},
|
|
5977
|
-
{
|
|
5978
|
-
"path": "precision",
|
|
5979
|
-
"valueType": "number"
|
|
5980
|
-
}
|
|
5981
|
-
],
|
|
6053
|
+
"humidity-sensor": [{
|
|
6054
|
+
"path": "percent",
|
|
6055
|
+
"valueType": "number"
|
|
6056
|
+
}],
|
|
5982
6057
|
"image": [{
|
|
5983
6058
|
"path": "url",
|
|
5984
6059
|
"valueType": "string"
|
|
@@ -6317,20 +6392,10 @@ Object.freeze({
|
|
|
6317
6392
|
"valueType": "boolean"
|
|
6318
6393
|
}
|
|
6319
6394
|
],
|
|
6320
|
-
"numeric-sensor": [
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
},
|
|
6325
|
-
{
|
|
6326
|
-
"path": "unit",
|
|
6327
|
-
"valueType": "string"
|
|
6328
|
-
},
|
|
6329
|
-
{
|
|
6330
|
-
"path": "precision",
|
|
6331
|
-
"valueType": "number"
|
|
6332
|
-
}
|
|
6333
|
-
],
|
|
6395
|
+
"numeric-sensor": [{
|
|
6396
|
+
"path": "value",
|
|
6397
|
+
"valueType": "number"
|
|
6398
|
+
}],
|
|
6334
6399
|
"pet-feeder": [
|
|
6335
6400
|
{
|
|
6336
6401
|
"path": "foodLevel",
|
|
@@ -6422,14 +6487,6 @@ Object.freeze({
|
|
|
6422
6487
|
{
|
|
6423
6488
|
"path": "powerFactor",
|
|
6424
6489
|
"valueType": "number"
|
|
6425
|
-
},
|
|
6426
|
-
{
|
|
6427
|
-
"path": "unit",
|
|
6428
|
-
"valueType": "string"
|
|
6429
|
-
},
|
|
6430
|
-
{
|
|
6431
|
-
"path": "precision",
|
|
6432
|
-
"valueType": "number"
|
|
6433
6490
|
}
|
|
6434
6491
|
],
|
|
6435
6492
|
"presence": [
|
|
@@ -6458,20 +6515,10 @@ Object.freeze({
|
|
|
6458
6515
|
"valueType": "number"
|
|
6459
6516
|
}
|
|
6460
6517
|
],
|
|
6461
|
-
"pressure-sensor": [
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
},
|
|
6466
|
-
{
|
|
6467
|
-
"path": "unit",
|
|
6468
|
-
"valueType": "string"
|
|
6469
|
-
},
|
|
6470
|
-
{
|
|
6471
|
-
"path": "precision",
|
|
6472
|
-
"valueType": "number"
|
|
6473
|
-
}
|
|
6474
|
-
],
|
|
6518
|
+
"pressure-sensor": [{
|
|
6519
|
+
"path": "hpa",
|
|
6520
|
+
"valueType": "number"
|
|
6521
|
+
}],
|
|
6475
6522
|
"privacy-mask": [{
|
|
6476
6523
|
"path": "enabled",
|
|
6477
6524
|
"valueType": "boolean"
|
|
@@ -6782,20 +6829,10 @@ Object.freeze({
|
|
|
6782
6829
|
"path": "tampered",
|
|
6783
6830
|
"valueType": "boolean"
|
|
6784
6831
|
}],
|
|
6785
|
-
"temperature-sensor": [
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
},
|
|
6790
|
-
{
|
|
6791
|
-
"path": "unit",
|
|
6792
|
-
"valueType": "string"
|
|
6793
|
-
},
|
|
6794
|
-
{
|
|
6795
|
-
"path": "precision",
|
|
6796
|
-
"valueType": "number"
|
|
6797
|
-
}
|
|
6798
|
-
],
|
|
6832
|
+
"temperature-sensor": [{
|
|
6833
|
+
"path": "celsius",
|
|
6834
|
+
"valueType": "number"
|
|
6835
|
+
}],
|
|
6799
6836
|
"update": [
|
|
6800
6837
|
{
|
|
6801
6838
|
"path": "currentVersion",
|
|
@@ -6906,10 +6943,6 @@ Object.freeze({
|
|
|
6906
6943
|
"path": "temperature",
|
|
6907
6944
|
"valueType": "number"
|
|
6908
6945
|
},
|
|
6909
|
-
{
|
|
6910
|
-
"path": "temperatureUnit",
|
|
6911
|
-
"valueType": "string"
|
|
6912
|
-
},
|
|
6913
6946
|
{
|
|
6914
6947
|
"path": "humidity",
|
|
6915
6948
|
"valueType": "number"
|
|
@@ -6918,18 +6951,10 @@ Object.freeze({
|
|
|
6918
6951
|
"path": "pressure",
|
|
6919
6952
|
"valueType": "number"
|
|
6920
6953
|
},
|
|
6921
|
-
{
|
|
6922
|
-
"path": "pressureUnit",
|
|
6923
|
-
"valueType": "string"
|
|
6924
|
-
},
|
|
6925
6954
|
{
|
|
6926
6955
|
"path": "windSpeed",
|
|
6927
6956
|
"valueType": "number"
|
|
6928
6957
|
},
|
|
6929
|
-
{
|
|
6930
|
-
"path": "windSpeedUnit",
|
|
6931
|
-
"valueType": "string"
|
|
6932
|
-
},
|
|
6933
6958
|
{
|
|
6934
6959
|
"path": "windBearing",
|
|
6935
6960
|
"valueType": "number"
|
|
@@ -7458,7 +7483,7 @@ function errMsg(err) {
|
|
|
7458
7483
|
return String(err);
|
|
7459
7484
|
}
|
|
7460
7485
|
//#endregion
|
|
7461
|
-
//#region ../types/dist/composition-
|
|
7486
|
+
//#region ../types/dist/composition-B85l9j1M.mjs
|
|
7462
7487
|
var AUDIO_ENCODER_BY_CODEC = {
|
|
7463
7488
|
opus: "libopus",
|
|
7464
7489
|
aac: "aac",
|
|
@@ -8976,6 +9001,68 @@ function evaluateExpressionSource(expr, bindingValues, now, opts) {
|
|
|
8976
9001
|
}
|
|
8977
9002
|
}
|
|
8978
9003
|
/**
|
|
9004
|
+
* A composition source identity: `(addonId, stableId)`, never a numeric device
|
|
9005
|
+
* id. Split out so helper schemas can name it without a cycle through
|
|
9006
|
+
* `composition.ts` (D659).
|
|
9007
|
+
*/
|
|
9008
|
+
var CompositionSourceRefSchema = zod.z.object({
|
|
9009
|
+
/** The owning addon; `stableId` is unique only within it. */
|
|
9010
|
+
addonId: zod.z.string().min(1),
|
|
9011
|
+
stableId: zod.z.string().min(1)
|
|
9012
|
+
});
|
|
9013
|
+
var GROUP_TEMPLATE_IDS = [
|
|
9014
|
+
"temperature",
|
|
9015
|
+
"humidity",
|
|
9016
|
+
"pressure",
|
|
9017
|
+
"illuminance",
|
|
9018
|
+
"power",
|
|
9019
|
+
"energy",
|
|
9020
|
+
"battery",
|
|
9021
|
+
"numeric",
|
|
9022
|
+
"motion",
|
|
9023
|
+
"contact",
|
|
9024
|
+
"leak",
|
|
9025
|
+
"smoke",
|
|
9026
|
+
"occupancy",
|
|
9027
|
+
"binary"
|
|
9028
|
+
];
|
|
9029
|
+
var NUMERIC_AGGREGATES = [
|
|
9030
|
+
"mean",
|
|
9031
|
+
"median",
|
|
9032
|
+
"min",
|
|
9033
|
+
"max",
|
|
9034
|
+
"sum"
|
|
9035
|
+
];
|
|
9036
|
+
var BINARY_AGGREGATES = ["any", "all"];
|
|
9037
|
+
var AGGREGATE_REDUCERS = [
|
|
9038
|
+
"mean",
|
|
9039
|
+
"median",
|
|
9040
|
+
"min",
|
|
9041
|
+
"max",
|
|
9042
|
+
"sum",
|
|
9043
|
+
"any",
|
|
9044
|
+
"all"
|
|
9045
|
+
];
|
|
9046
|
+
var GroupTemplateIdSchema = zod.z.enum(GROUP_TEMPLATE_IDS);
|
|
9047
|
+
var AggregateReducerSchema = zod.z.enum(AGGREGATE_REDUCERS);
|
|
9048
|
+
/** One member. The field is stored so occupancy can name motion or binary. */
|
|
9049
|
+
var HelperMemberSchema = zod.z.object({
|
|
9050
|
+
source: CompositionSourceRefSchema,
|
|
9051
|
+
cap: zod.z.string().min(1),
|
|
9052
|
+
fieldPath: zod.z.string().min(1)
|
|
9053
|
+
});
|
|
9054
|
+
/**
|
|
9055
|
+
* Phase 1a is groups only. Math, integral and statistics stay off this union
|
|
9056
|
+
* until the composer can run them — a control must not save a spec it cannot.
|
|
9057
|
+
*/
|
|
9058
|
+
var GroupHelperSpecSchema = zod.z.object({
|
|
9059
|
+
kind: zod.z.literal("group"),
|
|
9060
|
+
templateId: GroupTemplateIdSchema,
|
|
9061
|
+
aggregate: AggregateReducerSchema,
|
|
9062
|
+
members: zod.z.array(HelperMemberSchema).min(1).max(64)
|
|
9063
|
+
});
|
|
9064
|
+
var HelperSpecSchema = zod.z.discriminatedUnion("kind", [GroupHelperSpecSchema]);
|
|
9065
|
+
/**
|
|
8979
9066
|
* A COMPOSITION: a device assembled from other devices' state (D659).
|
|
8980
9067
|
*
|
|
8981
9068
|
* The data half of the composed-devices spec §1. A composition is stored inside
|
|
@@ -9000,11 +9087,6 @@ var COMPOSER_ADDON_ID = "composer";
|
|
|
9000
9087
|
var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
|
|
9001
9088
|
/** Longest snippet a `code` source may carry (slice 4). */
|
|
9002
9089
|
var MAX_COMPOSITION_CODE_LENGTH = 2e4;
|
|
9003
|
-
var CompositionSourceRefSchema = zod.z.object({
|
|
9004
|
-
/** The owning addon; `stableId` is unique only within it. */
|
|
9005
|
-
addonId: zod.z.string().min(1),
|
|
9006
|
-
stableId: zod.z.string().min(1)
|
|
9007
|
-
});
|
|
9008
9090
|
/** One field of one capability of one source device. */
|
|
9009
9091
|
var CompositionFieldReadSchema = zod.z.object({
|
|
9010
9092
|
source: CompositionSourceRefSchema,
|
|
@@ -9047,10 +9129,42 @@ var CompositionCodeSourceSchema = zod.z.object({
|
|
|
9047
9129
|
kind: zod.z.literal("code"),
|
|
9048
9130
|
code: zod.z.string().min(1).max(MAX_COMPOSITION_CODE_LENGTH)
|
|
9049
9131
|
});
|
|
9132
|
+
/**
|
|
9133
|
+
* `aggregate`: a group reducer. Offline and unknown reads are excluded, not
|
|
9134
|
+
* folded in as 0 or false (D944). Free expressions stay `expression` so a
|
|
9135
|
+
* stale member is still included there.
|
|
9136
|
+
*/
|
|
9137
|
+
var CompositionAggregateSourceSchema = zod.z.object({
|
|
9138
|
+
kind: zod.z.literal("aggregate"),
|
|
9139
|
+
reducer: zod.z.enum([
|
|
9140
|
+
"mean",
|
|
9141
|
+
"median",
|
|
9142
|
+
"min",
|
|
9143
|
+
"max",
|
|
9144
|
+
"sum",
|
|
9145
|
+
"any",
|
|
9146
|
+
"all"
|
|
9147
|
+
]),
|
|
9148
|
+
reads: zod.z.array(CompositionFieldReadSchema).min(1).max(64),
|
|
9149
|
+
/** `value` is the reading; the others are the member counts. */
|
|
9150
|
+
publish: zod.z.enum([
|
|
9151
|
+
"value",
|
|
9152
|
+
"included",
|
|
9153
|
+
"excluded",
|
|
9154
|
+
"total"
|
|
9155
|
+
]),
|
|
9156
|
+
/** What a `value` publish does when nobody is included. Counts ignore this. */
|
|
9157
|
+
empty: zod.z.enum([
|
|
9158
|
+
"null",
|
|
9159
|
+
"omit",
|
|
9160
|
+
"offline"
|
|
9161
|
+
])
|
|
9162
|
+
});
|
|
9050
9163
|
var CompositionFieldSourceSchema = zod.z.discriminatedUnion("kind", [
|
|
9051
9164
|
CompositionFromSourceSchema,
|
|
9052
9165
|
CompositionExpressionSourceSchema,
|
|
9053
|
-
CompositionCodeSourceSchema
|
|
9166
|
+
CompositionCodeSourceSchema,
|
|
9167
|
+
CompositionAggregateSourceSchema
|
|
9054
9168
|
]);
|
|
9055
9169
|
/** `forward`: RESERVED for slice 3. Argument mapping arrives there as an additive optional `args`. */
|
|
9056
9170
|
var CompositionForwardCommandSchema = zod.z.object({
|
|
@@ -9115,7 +9229,13 @@ var CompositionExistingTargetSchema = zod.z.object({
|
|
|
9115
9229
|
var CompositionTargetSchema = zod.z.discriminatedUnion("kind", [CompositionNewTargetSchema, CompositionExistingTargetSchema]);
|
|
9116
9230
|
var CompositionSchema = zod.z.object({
|
|
9117
9231
|
target: CompositionTargetSchema,
|
|
9118
|
-
features: zod.z.array(CompositionFeatureSchema).min(1).max(16)
|
|
9232
|
+
features: zod.z.array(CompositionFeatureSchema).min(1).max(16),
|
|
9233
|
+
/**
|
|
9234
|
+
* Present when the block is a helper template. Absent on a free
|
|
9235
|
+
* composition (the room example, device 4603). The editor reads this,
|
|
9236
|
+
* never the compiled features.
|
|
9237
|
+
*/
|
|
9238
|
+
helper: HelperSpecSchema.optional()
|
|
9119
9239
|
}).superRefine((composition, ctx) => {
|
|
9120
9240
|
const seen = /* @__PURE__ */ new Set();
|
|
9121
9241
|
composition.features.forEach((feature, index) => {
|
|
@@ -9162,6 +9282,7 @@ function fieldReads(source) {
|
|
|
9162
9282
|
cap: binding.cap,
|
|
9163
9283
|
fieldPath: binding.fieldPath
|
|
9164
9284
|
}] : []);
|
|
9285
|
+
case "aggregate": return source.reads;
|
|
9165
9286
|
case "code": return [];
|
|
9166
9287
|
}
|
|
9167
9288
|
}
|
|
@@ -17134,6 +17255,17 @@ function unwrapSchema(schema) {
|
|
|
17134
17255
|
while (s instanceof zod.z.ZodNullable || s instanceof zod.z.ZodOptional || s instanceof zod.z.ZodDefault) s = s.unwrap();
|
|
17135
17256
|
return s;
|
|
17136
17257
|
}
|
|
17258
|
+
function isMetaBag(value) {
|
|
17259
|
+
return typeof value === "object" && value !== null;
|
|
17260
|
+
}
|
|
17261
|
+
function metaQuantity(schema) {
|
|
17262
|
+
const bag = zod.z.globalRegistry.get(schema);
|
|
17263
|
+
if (isMetaBag(bag) && isReadingQuantity(bag.quantity)) return bag.quantity;
|
|
17264
|
+
}
|
|
17265
|
+
/** Quantity declared with `readingMeta` on the field or on the unwrapped leaf. */
|
|
17266
|
+
function quantityOfField(schema) {
|
|
17267
|
+
return metaQuantity(schema) ?? metaQuantity(unwrapSchema(schema));
|
|
17268
|
+
}
|
|
17137
17269
|
function leafKind(schema) {
|
|
17138
17270
|
const s = unwrapSchema(schema);
|
|
17139
17271
|
if (s instanceof zod.z.ZodEnum) return {
|
|
@@ -17162,11 +17294,15 @@ function enumerateSchemaFields(schema, prefix = "") {
|
|
|
17162
17294
|
continue;
|
|
17163
17295
|
}
|
|
17164
17296
|
const leaf = leafKind(field);
|
|
17165
|
-
if (leaf)
|
|
17166
|
-
|
|
17167
|
-
|
|
17168
|
-
|
|
17169
|
-
|
|
17297
|
+
if (leaf) {
|
|
17298
|
+
const quantity = quantityOfField(field);
|
|
17299
|
+
out.push({
|
|
17300
|
+
path,
|
|
17301
|
+
kind: leaf.kind,
|
|
17302
|
+
...leaf.enumValues ? { enumValues: leaf.enumValues } : {},
|
|
17303
|
+
...quantity !== void 0 ? { quantity } : {}
|
|
17304
|
+
});
|
|
17305
|
+
}
|
|
17170
17306
|
}
|
|
17171
17307
|
return out;
|
|
17172
17308
|
}
|
|
@@ -17225,7 +17361,7 @@ function requiredTopLevelKeys(schema) {
|
|
|
17225
17361
|
/**
|
|
17226
17362
|
* The proper prefixes of `path` whose schema accepts `undefined`: a required
|
|
17227
17363
|
* leaf under one of them is required only once something writes that parent
|
|
17228
|
-
* (`remaining.
|
|
17364
|
+
* (`remaining.kind` is required only when `remaining` is present).
|
|
17229
17365
|
*/
|
|
17230
17366
|
function optionalAncestors(schema, path) {
|
|
17231
17367
|
const segments = path.split(".");
|
|
@@ -17337,7 +17473,11 @@ var CompositionProblemCodeSchema = zod.z.enum([
|
|
|
17337
17473
|
"item-field-reserved",
|
|
17338
17474
|
"target-missing",
|
|
17339
17475
|
"target-unreadable",
|
|
17340
|
-
"not-replaceable"
|
|
17476
|
+
"not-replaceable",
|
|
17477
|
+
"native-capability-replace",
|
|
17478
|
+
"mixed-quantity",
|
|
17479
|
+
"helper-mismatch",
|
|
17480
|
+
"member-constraint"
|
|
17341
17481
|
]);
|
|
17342
17482
|
/** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
|
|
17343
17483
|
var CompositionProblemSchema = zod.z.object({
|
|
@@ -17361,7 +17501,8 @@ var CompositionUnavailableModeSchema = zod.z.enum([
|
|
|
17361
17501
|
"null",
|
|
17362
17502
|
"offline",
|
|
17363
17503
|
"unknown",
|
|
17364
|
-
"release"
|
|
17504
|
+
"release",
|
|
17505
|
+
"omit"
|
|
17365
17506
|
]);
|
|
17366
17507
|
/**
|
|
17367
17508
|
* `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
|
|
@@ -17403,9 +17544,11 @@ function compositionFieldKey(plan) {
|
|
|
17403
17544
|
return `${plan.cap}.${path}`;
|
|
17404
17545
|
}
|
|
17405
17546
|
/**
|
|
17406
|
-
* What a feature does to its target (D663): `new` builds a capability on a
|
|
17407
|
-
* device; on an existing device it `add`s a capability the device lacks
|
|
17408
|
-
*
|
|
17547
|
+
* What a feature does to its target (D663, D944): `new` builds a capability on a
|
|
17548
|
+
* new device; on an existing device it `add`s a capability the device lacks.
|
|
17549
|
+
* Replacing a capability the device already serves is refused
|
|
17550
|
+
* (`native-capability-replace`), not planned. `replace` remains on the claim
|
|
17551
|
+
* wire for a claim the hub already holds.
|
|
17409
17552
|
*/
|
|
17410
17553
|
var CompositionFeatureModeSchema = zod.z.enum([
|
|
17411
17554
|
"new",
|
|
@@ -17721,6 +17864,24 @@ function inferExpressionKinds(input) {
|
|
|
17721
17864
|
* planner (`composition-items.ts`). Internal to the composition module — NOT
|
|
17722
17865
|
* in the barrel: these are planner internals, not a published contract.
|
|
17723
17866
|
*/
|
|
17867
|
+
function aggregateKinds(source) {
|
|
17868
|
+
if (source.publish !== "value") return {
|
|
17869
|
+
ok: true,
|
|
17870
|
+
kinds: new Set(["number"])
|
|
17871
|
+
};
|
|
17872
|
+
if (source.reducer === "any" || source.reducer === "all") return {
|
|
17873
|
+
ok: true,
|
|
17874
|
+
kinds: new Set(["boolean"])
|
|
17875
|
+
};
|
|
17876
|
+
if (source.empty === "null") return {
|
|
17877
|
+
ok: true,
|
|
17878
|
+
kinds: new Set(["number", "null"])
|
|
17879
|
+
};
|
|
17880
|
+
return {
|
|
17881
|
+
ok: true,
|
|
17882
|
+
kinds: new Set(["number"])
|
|
17883
|
+
};
|
|
17884
|
+
}
|
|
17724
17885
|
function readKinds(read, lookupCap) {
|
|
17725
17886
|
const def = lookupCap(read.cap);
|
|
17726
17887
|
const schema = def?.runtimeState ?? def?.status?.schema;
|
|
@@ -17748,6 +17909,7 @@ function sourceKinds(source, lookupCap) {
|
|
|
17748
17909
|
code: "reserved-variant",
|
|
17749
17910
|
message: "code fields arrive in slice 4"
|
|
17750
17911
|
};
|
|
17912
|
+
if (source.kind === "aggregate") return aggregateKinds(source);
|
|
17751
17913
|
const bindingKinds = /* @__PURE__ */ new Map();
|
|
17752
17914
|
for (const [name, binding] of Object.entries(source.bindings)) {
|
|
17753
17915
|
if (binding.kind === "literal") {
|
|
@@ -17942,6 +18104,379 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
|
|
|
17942
18104
|
};
|
|
17943
18105
|
}
|
|
17944
18106
|
/**
|
|
18107
|
+
* One catalog row per base reading a group helper can build (D944 §3).
|
|
18108
|
+
* Data, not a form default written into the block.
|
|
18109
|
+
*/
|
|
18110
|
+
var NOW = {
|
|
18111
|
+
fieldPath: "lastFetchedAt",
|
|
18112
|
+
expr: "now"
|
|
18113
|
+
};
|
|
18114
|
+
var CHANGED = {
|
|
18115
|
+
fieldPath: "lastChangedAt",
|
|
18116
|
+
expr: "now"
|
|
18117
|
+
};
|
|
18118
|
+
function numeric(input) {
|
|
18119
|
+
return {
|
|
18120
|
+
...input,
|
|
18121
|
+
family: "numeric",
|
|
18122
|
+
deviceType: DeviceType.Sensor,
|
|
18123
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18124
|
+
baseUnit: baseUnitOf(input.quantity),
|
|
18125
|
+
aggregates: NUMERIC_AGGREGATES,
|
|
18126
|
+
accept: [{
|
|
18127
|
+
cap: input.outputCap,
|
|
18128
|
+
fieldPath: input.outputField
|
|
18129
|
+
}]
|
|
18130
|
+
};
|
|
18131
|
+
}
|
|
18132
|
+
function binary(input) {
|
|
18133
|
+
return {
|
|
18134
|
+
...input,
|
|
18135
|
+
family: "binary",
|
|
18136
|
+
deviceType: DeviceType.Sensor,
|
|
18137
|
+
memberDeviceType: DeviceType.Sensor,
|
|
18138
|
+
quantity: "none",
|
|
18139
|
+
baseUnit: void 0,
|
|
18140
|
+
aggregates: BINARY_AGGREGATES,
|
|
18141
|
+
empty: "offline"
|
|
18142
|
+
};
|
|
18143
|
+
}
|
|
18144
|
+
var GROUP_TEMPLATES = [
|
|
18145
|
+
numeric({
|
|
18146
|
+
id: "temperature",
|
|
18147
|
+
summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
|
|
18148
|
+
role: DeviceRole.TemperatureSensor,
|
|
18149
|
+
outputCap: "temperature-sensor",
|
|
18150
|
+
outputField: "celsius",
|
|
18151
|
+
quantity: "temperature",
|
|
18152
|
+
defaultAggregate: "mean",
|
|
18153
|
+
empty: "null",
|
|
18154
|
+
companions: [NOW]
|
|
18155
|
+
}),
|
|
18156
|
+
numeric({
|
|
18157
|
+
id: "humidity",
|
|
18158
|
+
summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18159
|
+
role: DeviceRole.HumiditySensor,
|
|
18160
|
+
outputCap: "humidity-sensor",
|
|
18161
|
+
outputField: "percent",
|
|
18162
|
+
quantity: "humidity",
|
|
18163
|
+
defaultAggregate: "mean",
|
|
18164
|
+
empty: "null",
|
|
18165
|
+
companions: [NOW]
|
|
18166
|
+
}),
|
|
18167
|
+
numeric({
|
|
18168
|
+
id: "pressure",
|
|
18169
|
+
summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
|
|
18170
|
+
role: DeviceRole.PressureSensor,
|
|
18171
|
+
outputCap: "pressure-sensor",
|
|
18172
|
+
outputField: "hpa",
|
|
18173
|
+
quantity: "pressure",
|
|
18174
|
+
defaultAggregate: "mean",
|
|
18175
|
+
empty: "null",
|
|
18176
|
+
companions: [NOW]
|
|
18177
|
+
}),
|
|
18178
|
+
numeric({
|
|
18179
|
+
id: "illuminance",
|
|
18180
|
+
summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
|
|
18181
|
+
role: DeviceRole.AmbientLightSensor,
|
|
18182
|
+
outputCap: "ambient-light-sensor",
|
|
18183
|
+
outputField: "lux",
|
|
18184
|
+
quantity: "illuminance",
|
|
18185
|
+
defaultAggregate: "mean",
|
|
18186
|
+
empty: "null",
|
|
18187
|
+
companions: [NOW]
|
|
18188
|
+
}),
|
|
18189
|
+
numeric({
|
|
18190
|
+
id: "power",
|
|
18191
|
+
summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
|
|
18192
|
+
role: DeviceRole.PowerSensor,
|
|
18193
|
+
outputCap: "power-meter",
|
|
18194
|
+
outputField: "watts",
|
|
18195
|
+
quantity: "power",
|
|
18196
|
+
defaultAggregate: "sum",
|
|
18197
|
+
empty: "omit",
|
|
18198
|
+
companions: [NOW]
|
|
18199
|
+
}),
|
|
18200
|
+
numeric({
|
|
18201
|
+
id: "energy",
|
|
18202
|
+
summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
|
|
18203
|
+
role: DeviceRole.EnergySensor,
|
|
18204
|
+
outputCap: "power-meter",
|
|
18205
|
+
outputField: "kwhTotal",
|
|
18206
|
+
quantity: "energy",
|
|
18207
|
+
defaultAggregate: "sum",
|
|
18208
|
+
empty: "omit",
|
|
18209
|
+
companions: [NOW]
|
|
18210
|
+
}),
|
|
18211
|
+
numeric({
|
|
18212
|
+
id: "battery",
|
|
18213
|
+
summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
|
|
18214
|
+
role: DeviceRole.BatterySensor,
|
|
18215
|
+
outputCap: "battery",
|
|
18216
|
+
outputField: "percentage",
|
|
18217
|
+
quantity: "percentage",
|
|
18218
|
+
defaultAggregate: "mean",
|
|
18219
|
+
empty: "null",
|
|
18220
|
+
companions: [
|
|
18221
|
+
{
|
|
18222
|
+
fieldPath: "charging",
|
|
18223
|
+
expr: "\"unknown\""
|
|
18224
|
+
},
|
|
18225
|
+
{
|
|
18226
|
+
fieldPath: "sleeping",
|
|
18227
|
+
expr: "false"
|
|
18228
|
+
},
|
|
18229
|
+
{
|
|
18230
|
+
fieldPath: "lastUpdated",
|
|
18231
|
+
expr: "now"
|
|
18232
|
+
}
|
|
18233
|
+
]
|
|
18234
|
+
}),
|
|
18235
|
+
numeric({
|
|
18236
|
+
id: "numeric",
|
|
18237
|
+
summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
|
|
18238
|
+
role: DeviceRole.NumericSensor,
|
|
18239
|
+
outputCap: "numeric-sensor",
|
|
18240
|
+
outputField: "value",
|
|
18241
|
+
quantity: "device",
|
|
18242
|
+
defaultAggregate: "mean",
|
|
18243
|
+
empty: "null",
|
|
18244
|
+
companions: [NOW]
|
|
18245
|
+
}),
|
|
18246
|
+
binary({
|
|
18247
|
+
id: "motion",
|
|
18248
|
+
summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
|
|
18249
|
+
role: DeviceRole.MotionSensor,
|
|
18250
|
+
outputCap: "motion",
|
|
18251
|
+
outputField: "detected",
|
|
18252
|
+
defaultAggregate: "any",
|
|
18253
|
+
accept: [{
|
|
18254
|
+
cap: "motion",
|
|
18255
|
+
fieldPath: "detected"
|
|
18256
|
+
}],
|
|
18257
|
+
companions: [{
|
|
18258
|
+
fieldPath: "lastDetectedAt",
|
|
18259
|
+
expr: "null"
|
|
18260
|
+
}, {
|
|
18261
|
+
fieldPath: "autoClearAfterMs",
|
|
18262
|
+
expr: "null"
|
|
18263
|
+
}]
|
|
18264
|
+
}),
|
|
18265
|
+
binary({
|
|
18266
|
+
id: "contact",
|
|
18267
|
+
summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
|
|
18268
|
+
role: DeviceRole.ContactSensor,
|
|
18269
|
+
outputCap: "contact",
|
|
18270
|
+
outputField: "entryOpen",
|
|
18271
|
+
defaultAggregate: "any",
|
|
18272
|
+
accept: [{
|
|
18273
|
+
cap: "contact",
|
|
18274
|
+
fieldPath: "entryOpen"
|
|
18275
|
+
}],
|
|
18276
|
+
companions: [CHANGED]
|
|
18277
|
+
}),
|
|
18278
|
+
binary({
|
|
18279
|
+
id: "leak",
|
|
18280
|
+
summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
|
|
18281
|
+
role: DeviceRole.LeakSensor,
|
|
18282
|
+
outputCap: "flood",
|
|
18283
|
+
outputField: "flooded",
|
|
18284
|
+
defaultAggregate: "any",
|
|
18285
|
+
accept: [{
|
|
18286
|
+
cap: "flood",
|
|
18287
|
+
fieldPath: "flooded"
|
|
18288
|
+
}],
|
|
18289
|
+
companions: [CHANGED]
|
|
18290
|
+
}),
|
|
18291
|
+
binary({
|
|
18292
|
+
id: "smoke",
|
|
18293
|
+
summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
|
|
18294
|
+
role: DeviceRole.SmokeSensor,
|
|
18295
|
+
outputCap: "smoke",
|
|
18296
|
+
outputField: "detected",
|
|
18297
|
+
defaultAggregate: "any",
|
|
18298
|
+
accept: [{
|
|
18299
|
+
cap: "smoke",
|
|
18300
|
+
fieldPath: "detected"
|
|
18301
|
+
}],
|
|
18302
|
+
companions: [CHANGED]
|
|
18303
|
+
}),
|
|
18304
|
+
binary({
|
|
18305
|
+
id: "occupancy",
|
|
18306
|
+
summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
|
|
18307
|
+
role: DeviceRole.BinarySensor,
|
|
18308
|
+
outputCap: "binary",
|
|
18309
|
+
outputField: "on",
|
|
18310
|
+
defaultAggregate: "any",
|
|
18311
|
+
accept: [{
|
|
18312
|
+
cap: "motion",
|
|
18313
|
+
fieldPath: "detected"
|
|
18314
|
+
}, {
|
|
18315
|
+
cap: "binary",
|
|
18316
|
+
fieldPath: "on"
|
|
18317
|
+
}],
|
|
18318
|
+
companions: [CHANGED]
|
|
18319
|
+
}),
|
|
18320
|
+
binary({
|
|
18321
|
+
id: "binary",
|
|
18322
|
+
summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
|
|
18323
|
+
role: DeviceRole.BinarySensor,
|
|
18324
|
+
outputCap: "binary",
|
|
18325
|
+
outputField: "on",
|
|
18326
|
+
defaultAggregate: "any",
|
|
18327
|
+
accept: [{
|
|
18328
|
+
cap: "binary",
|
|
18329
|
+
fieldPath: "on"
|
|
18330
|
+
}],
|
|
18331
|
+
companions: [CHANGED]
|
|
18332
|
+
})
|
|
18333
|
+
];
|
|
18334
|
+
var BY_ID = new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
|
|
18335
|
+
function groupTemplate(id) {
|
|
18336
|
+
return BY_ID.get(id) ?? null;
|
|
18337
|
+
}
|
|
18338
|
+
function sameSource(a, b) {
|
|
18339
|
+
return a.addonId === b.addonId && a.stableId === b.stableId;
|
|
18340
|
+
}
|
|
18341
|
+
function sameMember(a, b) {
|
|
18342
|
+
return sameSource(a.source, b.source) && a.cap === b.cap && a.fieldPath === b.fieldPath;
|
|
18343
|
+
}
|
|
18344
|
+
function accepted(template, member) {
|
|
18345
|
+
return template.accept.some((field) => field.cap === member.cap && field.fieldPath === member.fieldPath);
|
|
18346
|
+
}
|
|
18347
|
+
function memberProblems(template, spec) {
|
|
18348
|
+
return spec.members.flatMap((member, index) => {
|
|
18349
|
+
const at = `helper.members[${index}]`;
|
|
18350
|
+
const problems = [];
|
|
18351
|
+
if (!accepted(template, member)) {
|
|
18352
|
+
const allowed = template.accept.map((field) => `${field.cap}.${field.fieldPath}`).join(" or ");
|
|
18353
|
+
problems.push(problem("member-constraint", at, `a ${template.id} group reads ${allowed}; this member is ${member.cap}.${member.fieldPath}`));
|
|
18354
|
+
}
|
|
18355
|
+
if (spec.members.slice(0, index).some((other) => sameMember(other, member))) problems.push(problem("member-constraint", at, "this member is already in the group"));
|
|
18356
|
+
return problems;
|
|
18357
|
+
});
|
|
18358
|
+
}
|
|
18359
|
+
function aggregateSource(template, spec, reads, publish) {
|
|
18360
|
+
return {
|
|
18361
|
+
kind: "aggregate",
|
|
18362
|
+
reducer: spec.aggregate,
|
|
18363
|
+
reads: [...reads],
|
|
18364
|
+
publish,
|
|
18365
|
+
empty: template.empty
|
|
18366
|
+
};
|
|
18367
|
+
}
|
|
18368
|
+
function expressionSource(expr) {
|
|
18369
|
+
return {
|
|
18370
|
+
kind: "expression",
|
|
18371
|
+
expr,
|
|
18372
|
+
bindings: {}
|
|
18373
|
+
};
|
|
18374
|
+
}
|
|
18375
|
+
function draftOf$1(template, spec) {
|
|
18376
|
+
const reads = spec.members.map((member) => ({
|
|
18377
|
+
source: member.source,
|
|
18378
|
+
cap: member.cap,
|
|
18379
|
+
fieldPath: member.fieldPath
|
|
18380
|
+
}));
|
|
18381
|
+
const companions = Object.fromEntries(template.companions.map((companion) => [companion.fieldPath, expressionSource(companion.expr)]));
|
|
18382
|
+
return {
|
|
18383
|
+
target: {
|
|
18384
|
+
kind: "new",
|
|
18385
|
+
type: template.deviceType,
|
|
18386
|
+
role: template.role
|
|
18387
|
+
},
|
|
18388
|
+
helper: spec,
|
|
18389
|
+
features: [{
|
|
18390
|
+
kind: "fields",
|
|
18391
|
+
cap: template.outputCap,
|
|
18392
|
+
fields: {
|
|
18393
|
+
[template.outputField]: aggregateSource(template, spec, reads, "value"),
|
|
18394
|
+
...companions
|
|
18395
|
+
}
|
|
18396
|
+
}, {
|
|
18397
|
+
kind: "fields",
|
|
18398
|
+
cap: "group-status",
|
|
18399
|
+
fields: {
|
|
18400
|
+
included: aggregateSource(template, spec, reads, "included"),
|
|
18401
|
+
excluded: aggregateSource(template, spec, reads, "excluded"),
|
|
18402
|
+
total: aggregateSource(template, spec, reads, "total")
|
|
18403
|
+
}
|
|
18404
|
+
}]
|
|
18405
|
+
};
|
|
18406
|
+
}
|
|
18407
|
+
function parseDraft(draft) {
|
|
18408
|
+
const parsed = CompositionSchema.safeParse(draft);
|
|
18409
|
+
if (parsed.success) return {
|
|
18410
|
+
ok: true,
|
|
18411
|
+
composition: parsed.data
|
|
18412
|
+
};
|
|
18413
|
+
return {
|
|
18414
|
+
ok: false,
|
|
18415
|
+
problems: [problem("helper-mismatch", "helper", `the template did not compile: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`)]
|
|
18416
|
+
};
|
|
18417
|
+
}
|
|
18418
|
+
/** Compile a group template to a new-device composition. Refusals are named. */
|
|
18419
|
+
function compileHelper(spec) {
|
|
18420
|
+
const template = groupTemplate(spec.templateId);
|
|
18421
|
+
if (template === null) return {
|
|
18422
|
+
ok: false,
|
|
18423
|
+
problems: [problem("member-constraint", "helper.templateId", `unknown template \`${spec.templateId}\``)]
|
|
18424
|
+
};
|
|
18425
|
+
if (!template.aggregates.includes(spec.aggregate)) {
|
|
18426
|
+
const allowed = template.aggregates.join(", ");
|
|
18427
|
+
return {
|
|
18428
|
+
ok: false,
|
|
18429
|
+
problems: [problem("kind-mismatch", "helper.aggregate", `a ${template.id} group aggregates by ${allowed}, not \`${spec.aggregate}\``)]
|
|
18430
|
+
};
|
|
18431
|
+
}
|
|
18432
|
+
const members = memberProblems(template, spec);
|
|
18433
|
+
if (members.length > 0) return {
|
|
18434
|
+
ok: false,
|
|
18435
|
+
problems: members
|
|
18436
|
+
};
|
|
18437
|
+
return parseDraft(draftOf$1(template, spec));
|
|
18438
|
+
}
|
|
18439
|
+
/** The built body, ignoring `helper`, so a save can demand one writer. */
|
|
18440
|
+
function sameHelperBody(stored, compiled) {
|
|
18441
|
+
return JSON.stringify(stored.target) === JSON.stringify(compiled.target) && JSON.stringify(stored.features) === JSON.stringify(compiled.features);
|
|
18442
|
+
}
|
|
18443
|
+
function quantityProblems(spec, facts) {
|
|
18444
|
+
const template = groupTemplate(spec.templateId);
|
|
18445
|
+
if (template === null || template.family !== "numeric") return [];
|
|
18446
|
+
const known = spec.members.flatMap((member, index) => {
|
|
18447
|
+
const quantity = facts.get(compositionSourceKey(member.source))?.quantity;
|
|
18448
|
+
return quantity === void 0 ? [] : [{
|
|
18449
|
+
index,
|
|
18450
|
+
quantity
|
|
18451
|
+
}];
|
|
18452
|
+
});
|
|
18453
|
+
if (template.quantity !== "device") return known.flatMap((member) => member.quantity === template.quantity ? [] : [problem("mixed-quantity", `helper.members[${member.index}]`, `a ${template.id} group is ${template.quantity}${template.baseUnit === void 0 ? "" : ` (${template.baseUnit})`}; this member is ${member.quantity}`)]);
|
|
18454
|
+
const distinct = [...new Set(known.map((member) => member.quantity))];
|
|
18455
|
+
if (distinct.length <= 1) return [];
|
|
18456
|
+
return [problem("mixed-quantity", "helper.members", `a numeric group requires one quantity; members report ${distinct.join(" and ")}`)];
|
|
18457
|
+
}
|
|
18458
|
+
function deviceTypeProblems(spec, facts) {
|
|
18459
|
+
const template = groupTemplate(spec.templateId);
|
|
18460
|
+
if (template === null) return [];
|
|
18461
|
+
return spec.members.flatMap((member, index) => {
|
|
18462
|
+
const deviceType = facts.get(compositionSourceKey(member.source))?.deviceType;
|
|
18463
|
+
if (deviceType === void 0 || deviceType === template.memberDeviceType) return [];
|
|
18464
|
+
return [problem("member-constraint", `helper.members[${index}]`, `a ${template.id} group takes ${template.memberDeviceType} devices; this member is a ${deviceType}`)];
|
|
18465
|
+
});
|
|
18466
|
+
}
|
|
18467
|
+
/**
|
|
18468
|
+
* Problems that refuse a save. No `helper` key means a free composition: this
|
|
18469
|
+
* returns nothing, and expression semantics stay as they are.
|
|
18470
|
+
*/
|
|
18471
|
+
function helperSaveProblems(composition, facts) {
|
|
18472
|
+
const spec = composition.helper;
|
|
18473
|
+
if (spec === void 0) return [];
|
|
18474
|
+
const compiled = compileHelper(spec);
|
|
18475
|
+
if (!compiled.ok) return compiled.problems;
|
|
18476
|
+
if (!sameHelperBody(composition, compiled.composition)) return [problem("helper-mismatch", "helper", "the stored features are not this template — the helper spec is the only writer")];
|
|
18477
|
+
return [...quantityProblems(spec, facts), ...deviceTypeProblems(spec, facts)];
|
|
18478
|
+
}
|
|
18479
|
+
/**
|
|
17945
18480
|
* The field graph across every composition, and the cycles in it (D659).
|
|
17946
18481
|
*
|
|
17947
18482
|
* A node is ONE field of ONE device (`<addon>/<stableId>#<cap>.<field>`); an
|
|
@@ -18146,6 +18681,7 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
|
|
|
18146
18681
|
const role = roleOf(source);
|
|
18147
18682
|
const unavailable = unavailableFor(tf, role, mode, def.name, fieldAt);
|
|
18148
18683
|
if (!unavailable.ok) return refused(unavailable.problem);
|
|
18684
|
+
const omitEmpty = source.kind === "aggregate" && source.publish === "value" && source.empty === "omit";
|
|
18149
18685
|
const plan = {
|
|
18150
18686
|
cap: def.name,
|
|
18151
18687
|
path,
|
|
@@ -18153,7 +18689,7 @@ function planTopLevelField({ def, fields }, field, mode, lookupCap) {
|
|
|
18153
18689
|
kind: tf.kind,
|
|
18154
18690
|
nullable: tf.nullable,
|
|
18155
18691
|
required: tf.required,
|
|
18156
|
-
unavailable: unavailable.unavailable,
|
|
18692
|
+
unavailable: omitEmpty ? "omit" : unavailable.unavailable,
|
|
18157
18693
|
role,
|
|
18158
18694
|
source,
|
|
18159
18695
|
reads: [...fieldReads(source)]
|
|
@@ -18202,6 +18738,9 @@ function isNativeCap(target, cap) {
|
|
|
18202
18738
|
const owner = target.nativeCaps.get(cap);
|
|
18203
18739
|
return owner !== void 0 && owner !== "composer";
|
|
18204
18740
|
}
|
|
18741
|
+
function isPlanProblem(value) {
|
|
18742
|
+
return "code" in value;
|
|
18743
|
+
}
|
|
18205
18744
|
/** The target read, or the refusal that replaces the whole plan when it could not be (D391). */
|
|
18206
18745
|
function planTargetOf(composition, target) {
|
|
18207
18746
|
if (composition.target.kind === "new") return {
|
|
@@ -18217,26 +18756,59 @@ function planTargetOf(composition, target) {
|
|
|
18217
18756
|
found: target
|
|
18218
18757
|
};
|
|
18219
18758
|
}
|
|
18220
|
-
|
|
18759
|
+
var NATIVE_REPLACE_KEPT = new Set([
|
|
18760
|
+
"not-composable",
|
|
18761
|
+
"unknown-capability",
|
|
18762
|
+
"reserved-variant"
|
|
18763
|
+
]);
|
|
18764
|
+
/** A native override is refused, unless the cap cannot be composed at all — that reason stays. */
|
|
18765
|
+
function nativeReplaceOrBlock(refusal, probed) {
|
|
18766
|
+
const kept = probed.problems.filter((item) => NATIVE_REPLACE_KEPT.has(item.code));
|
|
18767
|
+
if (kept.length > 0) return {
|
|
18768
|
+
problems: kept,
|
|
18769
|
+
fields: [],
|
|
18770
|
+
features: [],
|
|
18771
|
+
events: []
|
|
18772
|
+
};
|
|
18773
|
+
return refused(refusal);
|
|
18774
|
+
}
|
|
18775
|
+
function featureTargetOf(target, cap, at) {
|
|
18221
18776
|
if (target.kind === "new") return {
|
|
18222
18777
|
mode: "new",
|
|
18223
18778
|
deviceType: target.type
|
|
18224
18779
|
};
|
|
18780
|
+
if (isNativeCap(target.found, cap)) return problem("native-capability-replace", at, `native-capability-replace: stored override replaces native capability \`${cap}\` on device ${target.found.deviceId} — refused (D944)`);
|
|
18225
18781
|
return {
|
|
18226
|
-
mode:
|
|
18782
|
+
mode: "add",
|
|
18227
18783
|
deviceType: target.found.type
|
|
18228
18784
|
};
|
|
18229
18785
|
}
|
|
18230
18786
|
/**
|
|
18231
18787
|
* The static plan. `target` describes an EXISTING target device (one read);
|
|
18232
|
-
* it is ignored for a new one. On an existing target each feature
|
|
18233
|
-
*
|
|
18788
|
+
* it is ignored for a new one. On an existing target each feature ADDS a cap
|
|
18789
|
+
* the device lacks. A feature that would replace a native capability is
|
|
18790
|
+
* refused by name (D944). A new device is unchanged.
|
|
18234
18791
|
*/
|
|
18235
18792
|
function planComposition(composition, lookupCap, target) {
|
|
18236
18793
|
const planTarget = planTargetOf(composition, target);
|
|
18237
18794
|
if ("code" in planTarget) return refused(planTarget);
|
|
18238
18795
|
const results = composition.features.map((feature, index) => {
|
|
18239
|
-
const
|
|
18796
|
+
const at = `features[${index}]`;
|
|
18797
|
+
if (feature.kind === "passthrough") return refused(problem("reserved-variant", at, `whole-capability passthrough of \`${feature.cap}\` arrives in slice 3`));
|
|
18798
|
+
const featureTarget = featureTargetOf(planTarget, feature.cap, at);
|
|
18799
|
+
if (isPlanProblem(featureTarget)) {
|
|
18800
|
+
if (!compositionFeatureEnabled(feature) || planTarget.kind !== "existing") return {
|
|
18801
|
+
problems: [],
|
|
18802
|
+
fields: [],
|
|
18803
|
+
features: [],
|
|
18804
|
+
events: []
|
|
18805
|
+
};
|
|
18806
|
+
return nativeReplaceOrBlock(featureTarget, planFeature(feature, index, {
|
|
18807
|
+
mode: "add",
|
|
18808
|
+
deviceType: planTarget.found.type
|
|
18809
|
+
}, lookupCap));
|
|
18810
|
+
}
|
|
18811
|
+
const result = planFeature(feature, index, featureTarget, lookupCap);
|
|
18240
18812
|
return compositionFeatureEnabled(feature) ? result : {
|
|
18241
18813
|
problems: result.problems,
|
|
18242
18814
|
fields: [],
|
|
@@ -18377,11 +18949,20 @@ function cycleProblems(composition, ctx, fields, self) {
|
|
|
18377
18949
|
function validateComposition(composition, ctx) {
|
|
18378
18950
|
const plan = planComposition(composition, ctx.lookupCap, ctx.target ?? void 0);
|
|
18379
18951
|
const self = candidateSelf(composition, ctx, plan);
|
|
18380
|
-
const
|
|
18952
|
+
const refusedFeatures = plan.problems.filter((item) => item.code === "native-capability-replace").map((item) => item.path);
|
|
18953
|
+
const cycles = cycleProblems(composition, ctx, plan.fields, self).filter((item) => {
|
|
18954
|
+
if (refusedFeatures.some((at) => item.path === at || item.path.startsWith(`${at}.`))) return false;
|
|
18955
|
+
return refusedFeatures.length === 0 || item.path !== "features";
|
|
18956
|
+
});
|
|
18957
|
+
const facts = new Map([...ctx.sources].flatMap(([key, source]) => source.kind === "found" ? [[key, {
|
|
18958
|
+
deviceType: source.deviceType,
|
|
18959
|
+
quantity: source.quantity
|
|
18960
|
+
}]] : []));
|
|
18381
18961
|
const problems = [
|
|
18382
18962
|
...plan.problems,
|
|
18383
18963
|
...sourceProblems(plan.fields, ctx, self),
|
|
18384
|
-
...cycles
|
|
18964
|
+
...cycles,
|
|
18965
|
+
...helperSaveProblems(composition, facts)
|
|
18385
18966
|
];
|
|
18386
18967
|
return {
|
|
18387
18968
|
ok: problems.length === 0,
|
|
@@ -20894,12 +21475,12 @@ getAdminLink: method(zod.z.object({ deviceId: zod.z.number().int().nonnegative()
|
|
|
20894
21475
|
* providers detect renames by matching `uniqueId` and patch `id`
|
|
20895
21476
|
* in-place so dispatch keeps working.
|
|
20896
21477
|
*
|
|
20897
|
-
* **
|
|
20898
|
-
*
|
|
20899
|
-
*
|
|
20900
|
-
*
|
|
20901
|
-
* (`ha-domain-mapping`)
|
|
20902
|
-
* stored after that point.
|
|
21478
|
+
* **Display unit and precision are NOT stored here.** They are a read-time
|
|
21479
|
+
* preference (D944). A polymorphic reading stores its `quantity` here once,
|
|
21480
|
+
* at adopt, and a date/time value stores `dateTimeShape` the same way —
|
|
21481
|
+
* neither is repeated on each sample. The `device_class` tag is an
|
|
21482
|
+
* HA-specific input consumed at the discovery boundary (`ha-domain-mapping`)
|
|
21483
|
+
* to derive the CamStack `DeviceRole`; it is never stored after that point.
|
|
20903
21484
|
*
|
|
20904
21485
|
* The `raw` escape hatch carries provider-specific attributes that don't
|
|
20905
21486
|
* fit the structured slots (HA `attributes` whitelist, Reolink `deviceCache`
|
|
@@ -20913,6 +21494,14 @@ var SourceInfoSchema = zod.z.object({
|
|
|
20913
21494
|
/** Immutable upstream identifier when available (HA `unique_id`, … ).
|
|
20914
21495
|
* Used to detect rename when `id` changes. */
|
|
20915
21496
|
uniqueId: zod.z.string().optional(),
|
|
21497
|
+
/** Quantity of a polymorphic reading, written once at adopt (D944). */
|
|
21498
|
+
quantity: ReadingQuantitySchema.optional(),
|
|
21499
|
+
/** Date / time / datetime shape of a string reading, written once at adopt. */
|
|
21500
|
+
dateTimeShape: zod.z.enum([
|
|
21501
|
+
"date",
|
|
21502
|
+
"time",
|
|
21503
|
+
"datetime"
|
|
21504
|
+
]).optional(),
|
|
20916
21505
|
/** Provider-specific extras that don't fit the structured slots.
|
|
20917
21506
|
* Whitelist what goes here per provider — do NOT dump entire HA
|
|
20918
21507
|
* attribute blobs (would explode the meta JSON column). */
|
|
@@ -20997,9 +21586,38 @@ function normalizeUnit(raw) {
|
|
|
20997
21586
|
if (lower === "mph") return "mph";
|
|
20998
21587
|
if (lower === "m/s") return "m/s";
|
|
20999
21588
|
if (lower === "m") return "m";
|
|
21589
|
+
if (lower === "m²" || lower === "m2") return "m²";
|
|
21590
|
+
if (lower === "mm") return "mm";
|
|
21591
|
+
if (lower === "cm") return "cm";
|
|
21000
21592
|
if (lower === "km") return "km";
|
|
21593
|
+
if (lower === "in" || lower === "inch" || lower === "inches") return "in";
|
|
21594
|
+
if (lower === "ft" || lower === "foot" || lower === "feet") return "ft";
|
|
21001
21595
|
if (lower === "kg") return "kg";
|
|
21002
21596
|
if (lower === "g") return "g";
|
|
21597
|
+
if (lower === "l" || lower === "liter" || lower === "litre" || lower === "liters" || lower === "litres") return "L";
|
|
21598
|
+
if (lower === "ml") return "mL";
|
|
21599
|
+
if (lower === "gal" || lower === "gallon" || lower === "gallons") return "gal";
|
|
21600
|
+
if (lower === "s" || lower === "sec" || lower === "second" || lower === "seconds") return "s";
|
|
21601
|
+
if (lower === "ms") return "ms";
|
|
21602
|
+
if (lower === "min" || lower === "minute" || lower === "minutes") return "min";
|
|
21603
|
+
if (lower === "h" || lower === "hr" || lower === "hour" || lower === "hours") return "h";
|
|
21604
|
+
if (lower === "d" || lower === "day" || lower === "days") return "d";
|
|
21605
|
+
if (lower === "b" || lower === "byte" || lower === "bytes") return "B";
|
|
21606
|
+
if (lower === "kib") return "KiB";
|
|
21607
|
+
if (lower === "mib") return "MiB";
|
|
21608
|
+
if (lower === "gib") return "GiB";
|
|
21609
|
+
if (lower === "tib") return "TiB";
|
|
21610
|
+
if (lower === "kb") return "kB";
|
|
21611
|
+
if (lower === "mb") return "MB";
|
|
21612
|
+
if (lower === "gb") return "GB";
|
|
21613
|
+
if (lower === "dbm") return "dBm";
|
|
21614
|
+
if (lower === "dbfs") return "dBFS";
|
|
21615
|
+
if (lower === "inhg") return "inHg";
|
|
21616
|
+
if (lower === "mm/h") return "mm/h";
|
|
21617
|
+
if (lower === "w/m²" || lower === "w/m2") return "W/m²";
|
|
21618
|
+
if (lower === "°" || lower === "deg" || lower === "degree" || lower === "degrees") return "°";
|
|
21619
|
+
if (lower === "kbps") return "kbps";
|
|
21620
|
+
if (lower === "fps") return "fps";
|
|
21003
21621
|
return trimmed;
|
|
21004
21622
|
}
|
|
21005
21623
|
/**
|
|
@@ -42261,7 +42879,8 @@ var deviceManagerCapability = {
|
|
|
42261
42879
|
"enum"
|
|
42262
42880
|
]),
|
|
42263
42881
|
enumValues: zod.z.array(zod.z.string()).optional(),
|
|
42264
|
-
item: zod.z.boolean().optional()
|
|
42882
|
+
item: zod.z.boolean().optional(),
|
|
42883
|
+
quantity: ReadingQuantitySchema.optional()
|
|
42265
42884
|
})).readonly(),
|
|
42266
42885
|
itemArray: zod.z.object({
|
|
42267
42886
|
path: zod.z.string(),
|
|
@@ -47526,8 +48145,8 @@ var MaskPolygonShapeSchema = zod.z.object({
|
|
|
47526
48145
|
/** Boolean cell grid — row-major, length === gridWidth*gridHeight. */
|
|
47527
48146
|
var MaskGridShapeSchema = zod.z.object({
|
|
47528
48147
|
kind: zod.z.literal("grid"),
|
|
47529
|
-
gridWidth: zod.z.number(),
|
|
47530
|
-
gridHeight: zod.z.number(),
|
|
48148
|
+
gridWidth: zod.z.number().meta(readingMeta("none")),
|
|
48149
|
+
gridHeight: zod.z.number().meta(readingMeta("none")),
|
|
47531
48150
|
cells: zod.z.array(zod.z.boolean())
|
|
47532
48151
|
});
|
|
47533
48152
|
/** Directed line / tripwire — an ordered list of normalized points (≥2). */
|
|
@@ -62076,27 +62695,17 @@ var addonsCapability = {
|
|
|
62076
62695
|
*/
|
|
62077
62696
|
var AirQualitySensorStatusSchema = zod.z.object({
|
|
62078
62697
|
/** Carbon dioxide concentration in ppm. */
|
|
62079
|
-
co2Ppm: zod.z.number().min(0).optional(),
|
|
62698
|
+
co2Ppm: zod.z.number().min(0).optional().meta(readingMeta("concentration-volume")),
|
|
62080
62699
|
/** Total volatile organic compounds in ppb. */
|
|
62081
|
-
vocPpb: zod.z.number().min(0).optional(),
|
|
62700
|
+
vocPpb: zod.z.number().min(0).optional().meta(readingMeta("concentration-ppb")),
|
|
62082
62701
|
/** Particulate matter ≤ 2.5 μm in µg/m³. */
|
|
62083
|
-
pm25: zod.z.number().min(0).optional(),
|
|
62702
|
+
pm25: zod.z.number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
62084
62703
|
/** Particulate matter ≤ 10 μm in µg/m³. */
|
|
62085
|
-
pm10: zod.z.number().min(0).optional(),
|
|
62704
|
+
pm10: zod.z.number().min(0).optional().meta(readingMeta("concentration-mass")),
|
|
62086
62705
|
/** Composite AQI value (typically 0..500). */
|
|
62087
|
-
aqi: zod.z.number().optional(),
|
|
62706
|
+
aqi: zod.z.number().optional().meta(readingMeta("index")),
|
|
62088
62707
|
/** Ms epoch when the slice was last updated. */
|
|
62089
|
-
lastFetchedAt: zod.z.number()
|
|
62090
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
62091
|
-
* `attributes.unit_of_measurement` → 'ppm' / 'ppb' / 'µg/m³'). Each
|
|
62092
|
-
* upstream `sensor.*` entity surfaces ONE device_class, so one unit
|
|
62093
|
-
* per slice is unambiguous. */
|
|
62094
|
-
unit: zod.z.string().optional(),
|
|
62095
|
-
/** Suggested decimal places for numeric display.
|
|
62096
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
62097
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
62098
|
-
* auto-formatting when absent. */
|
|
62099
|
-
precision: zod.z.number().int().min(0).max(10).optional()
|
|
62708
|
+
lastFetchedAt: zod.z.number()
|
|
62100
62709
|
});
|
|
62101
62710
|
var airQualitySensorCapability = {
|
|
62102
62711
|
name: "air-quality-sensor",
|
|
@@ -62133,12 +62742,12 @@ var airQualitySensorCapability = {
|
|
|
62133
62742
|
},
|
|
62134
62743
|
pm25: {
|
|
62135
62744
|
kind: "gauge",
|
|
62136
|
-
unit: "
|
|
62745
|
+
unit: "µg/m³",
|
|
62137
62746
|
deadband: 1
|
|
62138
62747
|
},
|
|
62139
62748
|
pm10: {
|
|
62140
62749
|
kind: "gauge",
|
|
62141
|
-
unit: "
|
|
62750
|
+
unit: "µg/m³",
|
|
62142
62751
|
deadband: 1
|
|
62143
62752
|
},
|
|
62144
62753
|
aqi: {
|
|
@@ -62156,22 +62765,13 @@ var airQualitySensorCapability = {
|
|
|
62156
62765
|
* entries with `device_class: illuminance`.
|
|
62157
62766
|
*/
|
|
62158
62767
|
var AmbientLightSensorStatusSchema = zod.z.object({
|
|
62159
|
-
/** Current illuminance in lux (lx). */
|
|
62160
|
-
lux: zod.z.number().min(0).meta({
|
|
62161
|
-
|
|
62768
|
+
/** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
|
|
62769
|
+
lux: zod.z.number().min(0).nullable().meta(readingMeta("illuminance", {
|
|
62770
|
+
precision: 0,
|
|
62162
62771
|
label: "Illuminance"
|
|
62163
|
-
}),
|
|
62772
|
+
})),
|
|
62164
62773
|
/** Ms epoch when the slice was last updated. */
|
|
62165
|
-
lastFetchedAt: zod.z.number()
|
|
62166
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
62167
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
62168
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
62169
|
-
unit: zod.z.string().optional(),
|
|
62170
|
-
/** Suggested decimal places for numeric display.
|
|
62171
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
62172
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
62173
|
-
* auto-formatting when absent. */
|
|
62174
|
-
precision: zod.z.number().int().min(0).max(10).optional()
|
|
62774
|
+
lastFetchedAt: zod.z.number()
|
|
62175
62775
|
});
|
|
62176
62776
|
var ambientLightSensorCapability = {
|
|
62177
62777
|
name: "ambient-light-sensor",
|
|
@@ -62203,12 +62803,7 @@ var ambientLightSensorCapability = {
|
|
|
62203
62803
|
} } },
|
|
62204
62804
|
/** Clock fields: written, but excluded from the compare that decides
|
|
62205
62805
|
* whether persisting is worth a SQLite commit. */
|
|
62206
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
62207
|
-
customize: {
|
|
62208
|
-
version: 1,
|
|
62209
|
-
advanced: "derive",
|
|
62210
|
-
targets: []
|
|
62211
|
-
}
|
|
62806
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
62212
62807
|
};
|
|
62213
62808
|
/**
|
|
62214
62809
|
* Per-class audio metrics aggregated over a sliding window.
|
|
@@ -62444,10 +63039,7 @@ var BatteryStatusSchema = zod.z.object({
|
|
|
62444
63039
|
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
62445
63040
|
* declines to band a non-finite reading, which is the correct shape.
|
|
62446
63041
|
*/
|
|
62447
|
-
percentage: zod.z.number().min(0).max(100).nullable().meta({
|
|
62448
|
-
unit: "%",
|
|
62449
|
-
label: "Charge"
|
|
62450
|
-
}),
|
|
63042
|
+
percentage: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
|
|
62451
63043
|
/**
|
|
62452
63044
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
62453
63045
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -62474,7 +63066,14 @@ var BatteryStatusSchema = zod.z.object({
|
|
|
62474
63066
|
*/
|
|
62475
63067
|
sleeping: zod.z.boolean().meta({ label: "Sleeping" }),
|
|
62476
63068
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
62477
|
-
lastUpdated: zod.z.number(),
|
|
63069
|
+
lastUpdated: zod.z.number().meta(readingMeta("none")),
|
|
63070
|
+
/**
|
|
63071
|
+
* Battery voltage in volts, for a cell the firmware reports as voltage
|
|
63072
|
+
* rather than a percentage (Ecowitt capacitor packs). Absent on cameras
|
|
63073
|
+
* that only report charge. A second reading on this cap, not a second
|
|
63074
|
+
* `numeric-sensor` on the same device.
|
|
63075
|
+
*/
|
|
63076
|
+
volts: zod.z.number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
|
|
62478
63077
|
/**
|
|
62479
63078
|
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
62480
63079
|
* completed firmware round-trip, an observed wake, or an inbound push
|
|
@@ -62526,7 +63125,6 @@ var BATTERY_DEVICE_TYPES = [
|
|
|
62526
63125
|
/** Generic Customize target for the percentage reading (D936). */
|
|
62527
63126
|
var batteryCustomize = {
|
|
62528
63127
|
version: 1,
|
|
62529
|
-
advanced: "derive",
|
|
62530
63128
|
targets: [{
|
|
62531
63129
|
id: "percentage",
|
|
62532
63130
|
cardinality: "scalar",
|
|
@@ -62535,7 +63133,7 @@ var batteryCustomize = {
|
|
|
62535
63133
|
stateField: "percentage"
|
|
62536
63134
|
},
|
|
62537
63135
|
deviceTypes: BATTERY_DEVICE_TYPES,
|
|
62538
|
-
apply: "add
|
|
63136
|
+
apply: "add",
|
|
62539
63137
|
path: "percentage",
|
|
62540
63138
|
sources: [{
|
|
62541
63139
|
kind: "field",
|
|
@@ -62656,10 +63254,16 @@ onStatusChanged: { data: zod.z.object({
|
|
|
62656
63254
|
/**
|
|
62657
63255
|
* History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
|
|
62658
63256
|
*/
|
|
62659
|
-
history: { fields: {
|
|
62660
|
-
|
|
62661
|
-
|
|
62662
|
-
|
|
63257
|
+
history: { fields: {
|
|
63258
|
+
percentage: {
|
|
63259
|
+
kind: "gauge",
|
|
63260
|
+
unit: "%"
|
|
63261
|
+
},
|
|
63262
|
+
volts: {
|
|
63263
|
+
kind: "gauge",
|
|
63264
|
+
unit: "V"
|
|
63265
|
+
}
|
|
63266
|
+
} },
|
|
62663
63267
|
customize: batteryCustomize,
|
|
62664
63268
|
/** Clock fields: written, but excluded from the compare that decides
|
|
62665
63269
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -62706,12 +63310,7 @@ var binaryCapability = {
|
|
|
62706
63310
|
history: { fields: { on: { kind: "boolean" } } },
|
|
62707
63311
|
/** Clock fields: written, but excluded from the compare that decides
|
|
62708
63312
|
* whether persisting is worth a SQLite commit. */
|
|
62709
|
-
volatileStateFields: ["lastChangedAt"]
|
|
62710
|
-
customize: {
|
|
62711
|
-
version: 1,
|
|
62712
|
-
advanced: "derive",
|
|
62713
|
-
targets: []
|
|
62714
|
-
}
|
|
63313
|
+
volatileStateFields: ["lastChangedAt"]
|
|
62715
63314
|
};
|
|
62716
63315
|
/**
|
|
62717
63316
|
* Dimmable-light brightness control. Co-exists with `switch` on the
|
|
@@ -62727,7 +63326,7 @@ var binaryCapability = {
|
|
|
62727
63326
|
*/
|
|
62728
63327
|
var BrightnessStatusSchema = zod.z.object({
|
|
62729
63328
|
/** Current level as 0..100 inclusive. Firmware-reported. */
|
|
62730
|
-
percentage: zod.z.number().min(0).max(100),
|
|
63329
|
+
percentage: zod.z.number().min(0).max(100).meta(readingMeta("percentage")),
|
|
62731
63330
|
/** Ms epoch of the last operator-driven change. Useful for UI freshness. */
|
|
62732
63331
|
lastChangedAt: zod.z.number()
|
|
62733
63332
|
});
|
|
@@ -63278,21 +63877,21 @@ var ClimateControlStatusSchema = zod.z.object({
|
|
|
63278
63877
|
/** Single setpoint in Celsius. Used by single-target modes
|
|
63279
63878
|
* (heat / cool / dry). Null when the device is in a range mode
|
|
63280
63879
|
* (`heat_cool`) or has no setpoint at all (`fan_only`/`off`). */
|
|
63281
|
-
target: zod.z.number().nullable(),
|
|
63880
|
+
target: zod.z.number().nullable().meta(readingMeta("temperature")),
|
|
63282
63881
|
/** Upper bound of the dual setpoint in Celsius. Populated only
|
|
63283
63882
|
* in `heat_cool` mode. */
|
|
63284
|
-
targetHigh: zod.z.number().nullable(),
|
|
63883
|
+
targetHigh: zod.z.number().nullable().meta(readingMeta("temperature")),
|
|
63285
63884
|
/** Lower bound of the dual setpoint in Celsius. Populated only
|
|
63286
63885
|
* in `heat_cool` mode. */
|
|
63287
|
-
targetLow: zod.z.number().nullable(),
|
|
63886
|
+
targetLow: zod.z.number().nullable().meta(readingMeta("temperature")),
|
|
63288
63887
|
/** Target relative humidity (0..100). Null when the device has no
|
|
63289
63888
|
* humidity control. */
|
|
63290
|
-
targetHumidity: zod.z.number().min(0).max(100).nullable(),
|
|
63889
|
+
targetHumidity: zod.z.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
63291
63890
|
/** Current measured temperature in Celsius. Read-only — pushed by
|
|
63292
63891
|
* the device's internal sensor. */
|
|
63293
|
-
currentTemp: zod.z.number().nullable(),
|
|
63892
|
+
currentTemp: zod.z.number().nullable().meta(readingMeta("temperature")),
|
|
63294
63893
|
/** Current measured relative humidity (0..100). Read-only. */
|
|
63295
|
-
currentHumidity: zod.z.number().min(0).max(100).nullable(),
|
|
63894
|
+
currentHumidity: zod.z.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
63296
63895
|
/** Vertical louver swing on/off. Null when the device has no vertical
|
|
63297
63896
|
* swing surface (gate with `DeviceFeature.ClimateSwingVertical`). */
|
|
63298
63897
|
swingVertical: zod.z.boolean().nullable(),
|
|
@@ -63300,11 +63899,11 @@ var ClimateControlStatusSchema = zod.z.object({
|
|
|
63300
63899
|
* horizontal swing surface (gate with `DeviceFeature.ClimateSwingHorizontal`). */
|
|
63301
63900
|
swingHorizontal: zod.z.boolean().nullable(),
|
|
63302
63901
|
/** Lowest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
63303
|
-
minTemp: zod.z.number().nullable().optional(),
|
|
63902
|
+
minTemp: zod.z.number().nullable().optional().meta(readingMeta("temperature")),
|
|
63304
63903
|
/** Highest setpoint the device accepts, Celsius. Absent / null = not reported. */
|
|
63305
|
-
maxTemp: zod.z.number().nullable().optional(),
|
|
63904
|
+
maxTemp: zod.z.number().nullable().optional().meta(readingMeta("temperature")),
|
|
63306
63905
|
/** Setpoint granularity, Celsius (0.5, 1). Absent / null = not reported. */
|
|
63307
|
-
tempStep: zod.z.number().positive().nullable().optional(),
|
|
63906
|
+
tempStep: zod.z.number().positive().nullable().optional().meta(readingMeta("temperature")),
|
|
63308
63907
|
/** Ms epoch when the slice was last updated (push or command). */
|
|
63309
63908
|
lastFetchedAt: zod.z.number()
|
|
63310
63909
|
});
|
|
@@ -63446,17 +64045,17 @@ var climateControlCapability = {
|
|
|
63446
64045
|
* modes to expose in the picker without a slice fetch.
|
|
63447
64046
|
*/
|
|
63448
64047
|
var RgbTripletSchema = zod.z.object({
|
|
63449
|
-
r: zod.z.number().int().min(0).max(255),
|
|
63450
|
-
g: zod.z.number().int().min(0).max(255),
|
|
63451
|
-
b: zod.z.number().int().min(0).max(255)
|
|
64048
|
+
r: zod.z.number().int().min(0).max(255).meta(readingMeta("none")),
|
|
64049
|
+
g: zod.z.number().int().min(0).max(255).meta(readingMeta("none")),
|
|
64050
|
+
b: zod.z.number().int().min(0).max(255).meta(readingMeta("none"))
|
|
63452
64051
|
});
|
|
63453
64052
|
var HsvTripletSchema = zod.z.object({
|
|
63454
64053
|
/** Hue in degrees, 0..360. */
|
|
63455
|
-
h: zod.z.number().min(0).max(360),
|
|
64054
|
+
h: zod.z.number().min(0).max(360).meta(readingMeta("none")),
|
|
63456
64055
|
/** Saturation as 0..100 inclusive. */
|
|
63457
|
-
s: zod.z.number().min(0).max(100),
|
|
64056
|
+
s: zod.z.number().min(0).max(100).meta(readingMeta("none")),
|
|
63458
64057
|
/** Value/brightness as 0..100 inclusive. */
|
|
63459
|
-
v: zod.z.number().min(0).max(100)
|
|
64058
|
+
v: zod.z.number().min(0).max(100).meta(readingMeta("none"))
|
|
63460
64059
|
});
|
|
63461
64060
|
var ColorInputSchema = zod.z.discriminatedUnion("mode", [
|
|
63462
64061
|
zod.z.object({
|
|
@@ -63485,7 +64084,7 @@ var ColorStatusSchema = zod.z.object({
|
|
|
63485
64084
|
/** Populated when `mode === 'hsv'`. */
|
|
63486
64085
|
hsv: HsvTripletSchema.optional(),
|
|
63487
64086
|
/** Populated when `mode === 'mired'`. */
|
|
63488
|
-
mireds: zod.z.number().int().optional(),
|
|
64087
|
+
mireds: zod.z.number().int().optional().meta(readingMeta("colour-temperature")),
|
|
63489
64088
|
/** Ms epoch of the last operator-driven change. */
|
|
63490
64089
|
lastChangedAt: zod.z.number()
|
|
63491
64090
|
});
|
|
@@ -63688,18 +64287,12 @@ zod.z.enum([
|
|
|
63688
64287
|
"empty",
|
|
63689
64288
|
"full"
|
|
63690
64289
|
]);
|
|
63691
|
-
/**
|
|
63692
|
-
|
|
63693
|
-
|
|
63694
|
-
"days",
|
|
63695
|
-
"hours",
|
|
63696
|
-
"cycles"
|
|
63697
|
-
]);
|
|
63698
|
-
/** Remaining life as a COUNT, not a percentage (the PetKit desiccant reports
|
|
63699
|
-
* days). `value` null = unknown (D393). */
|
|
64290
|
+
/** Whether `remaining.value` is a duration in seconds or a dimensionless count. */
|
|
64291
|
+
var ConsumableRemainingKindSchema = zod.z.enum(["duration", "count"]);
|
|
64292
|
+
/** Remaining life. `value` null = unknown (D393). Duration is seconds. */
|
|
63700
64293
|
var ConsumableRemainingSchema = zod.z.object({
|
|
63701
|
-
value: zod.z.number().min(0).nullable(),
|
|
63702
|
-
|
|
64294
|
+
value: zod.z.number().min(0).nullable().meta(readingMeta("device")),
|
|
64295
|
+
kind: ConsumableRemainingKindSchema
|
|
63703
64296
|
});
|
|
63704
64297
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
63705
64298
|
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
@@ -63712,7 +64305,7 @@ var ConsumableItemSchema = zod.z.object({
|
|
|
63712
64305
|
/** Display name. */
|
|
63713
64306
|
label: zod.z.string().min(1),
|
|
63714
64307
|
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
63715
|
-
level: zod.z.number().min(0).max(100).nullable(),
|
|
64308
|
+
level: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
63716
64309
|
/** The provider's discrete verdict when known (binary mode). */
|
|
63717
64310
|
status: ConsumableStatusSchema.nullable(),
|
|
63718
64311
|
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
@@ -63794,8 +64387,8 @@ var consumablesCustomize = {
|
|
|
63794
64387
|
transforms: [{ kind: "identity" }]
|
|
63795
64388
|
}],
|
|
63796
64389
|
literals: [{
|
|
63797
|
-
path: "remaining.
|
|
63798
|
-
values: [...
|
|
64390
|
+
path: "remaining.kind",
|
|
64391
|
+
values: [...ConsumableRemainingKindSchema.options]
|
|
63799
64392
|
}]
|
|
63800
64393
|
},
|
|
63801
64394
|
{
|
|
@@ -63924,7 +64517,6 @@ reset: method(zod.z.object({
|
|
|
63924
64517
|
},
|
|
63925
64518
|
"remaining.value": {
|
|
63926
64519
|
kind: "gauge",
|
|
63927
|
-
unitFrom: "remaining.unit",
|
|
63928
64520
|
deadband: 1,
|
|
63929
64521
|
displayName: "Remaining"
|
|
63930
64522
|
}
|
|
@@ -64023,49 +64615,26 @@ var ControlKindSchema = zod.z.enum([
|
|
|
64023
64615
|
* (empty array for the other kinds). It lives in the slice because
|
|
64024
64616
|
* HA `select.*` entities may update their options at runtime.
|
|
64025
64617
|
*
|
|
64026
|
-
*
|
|
64027
|
-
*
|
|
64028
|
-
*
|
|
64029
|
-
* push — consistent with `options` and the sensor-unit approach.
|
|
64618
|
+
* Numeric `min` / `max` / `step` live in the slice and share the device
|
|
64619
|
+
* quantity (`SourceInfo.quantity`, D944). Display precision is a read-time
|
|
64620
|
+
* preference. A datetime control's shape is `SourceInfo.dateTimeShape`.
|
|
64030
64621
|
*/
|
|
64031
64622
|
var ControlStatusSchema = zod.z.object({
|
|
64032
64623
|
kind: ControlKindSchema,
|
|
64033
64624
|
/** Current value. Numeric kind → number; select/text/datetime → string.
|
|
64034
64625
|
* Datetime values are ISO 8601 strings (full timestamp, date-only,
|
|
64035
64626
|
* or time-only — HA accepts all three forms). */
|
|
64036
|
-
value: zod.z.union([zod.z.number(), zod.z.string()]),
|
|
64627
|
+
value: zod.z.union([zod.z.number().meta(readingMeta("device")), zod.z.string()]),
|
|
64037
64628
|
/** Acceptable values when `kind === 'select'`. Empty for other kinds. */
|
|
64038
64629
|
options: zod.z.array(zod.z.string()),
|
|
64039
64630
|
/** Ms epoch when the slice was last updated. */
|
|
64040
64631
|
lastChangedAt: zod.z.number(),
|
|
64041
|
-
/**
|
|
64042
|
-
|
|
64043
|
-
|
|
64044
|
-
|
|
64045
|
-
/**
|
|
64046
|
-
|
|
64047
|
-
min: zod.z.number().optional(),
|
|
64048
|
-
/** Maximum allowed value. Populated live from HA `attributes.max`.
|
|
64049
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
64050
|
-
max: zod.z.number().optional(),
|
|
64051
|
-
/** Step increment. Populated live from HA `attributes.step`.
|
|
64052
|
-
* Meaningful for `kind === 'numeric'`; absent for other kinds. */
|
|
64053
|
-
step: zod.z.number().optional(),
|
|
64054
|
-
/** Suggested decimal places for numeric display. Populated live from HA
|
|
64055
|
-
* `attributes.suggested_display_precision`, or derived from `step` when the
|
|
64056
|
-
* HA attribute is absent. Meaningful for `kind === 'numeric'`; absent for
|
|
64057
|
-
* other kinds. Falls back to auto-formatting when absent. */
|
|
64058
|
-
precision: zod.z.number().int().min(0).max(10).optional(),
|
|
64059
|
-
/** Date-picker granularity for `kind === 'datetime'`. 'date' → date-only,
|
|
64060
|
-
* 'time' → time-only, 'datetime' → full timestamp. Absent for other kinds
|
|
64061
|
-
* (UI defaults to 'datetime'). Derived live from the device's HA domain
|
|
64062
|
-
* (date.* / time.* / datetime.*) or, for input_datetime, from the entity's
|
|
64063
|
-
* `has_date`/`has_time` attributes on each push. */
|
|
64064
|
-
format: zod.z.enum([
|
|
64065
|
-
"date",
|
|
64066
|
-
"time",
|
|
64067
|
-
"datetime"
|
|
64068
|
-
]).optional()
|
|
64632
|
+
/** Minimum allowed value, in the device quantity's base unit. */
|
|
64633
|
+
min: zod.z.number().optional().meta(readingMeta("device")),
|
|
64634
|
+
/** Maximum allowed value, in the device quantity's base unit. */
|
|
64635
|
+
max: zod.z.number().optional().meta(readingMeta("device")),
|
|
64636
|
+
/** Step increment, in the device quantity's base unit. */
|
|
64637
|
+
step: zod.z.number().optional().meta(readingMeta("device"))
|
|
64069
64638
|
});
|
|
64070
64639
|
var ControlSetValueInputSchema = zod.z.discriminatedUnion("kind", [
|
|
64071
64640
|
zod.z.object({
|
|
@@ -64153,9 +64722,9 @@ var CoverStatusSchema = zod.z.object({
|
|
|
64153
64722
|
state: CoverStateSchema,
|
|
64154
64723
|
/** 0 = fully closed, 100 = fully open. Null when the device has
|
|
64155
64724
|
* no intermediate position surface. */
|
|
64156
|
-
position: zod.z.number().min(0).max(100).nullable(),
|
|
64725
|
+
position: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64157
64726
|
/** 0 = closed slats, 100 = open slats. Null when no tilt support. */
|
|
64158
|
-
tiltPosition: zod.z.number().min(0).max(100).nullable(),
|
|
64727
|
+
tiltPosition: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64159
64728
|
/** Ms epoch when the slice was last updated. */
|
|
64160
64729
|
lastChangedAt: zod.z.number()
|
|
64161
64730
|
});
|
|
@@ -64258,9 +64827,9 @@ var NormalizedRangeSchema$1 = zod.z.object({
|
|
|
64258
64827
|
var DayNightStatusSchema = zod.z.object({
|
|
64259
64828
|
mode: DayNightModeSchema,
|
|
64260
64829
|
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
64261
|
-
sensitivity: zod.z.number().optional(),
|
|
64830
|
+
sensitivity: zod.z.number().optional().meta(readingMeta("none")),
|
|
64262
64831
|
/** Delay before the IR-cut filter flips, in seconds. */
|
|
64263
|
-
switchDelaySec: zod.z.number().optional(),
|
|
64832
|
+
switchDelaySec: zod.z.number().optional().meta(readingMeta("duration")),
|
|
64264
64833
|
lastFetchedAt: zod.z.number()
|
|
64265
64834
|
});
|
|
64266
64835
|
/**
|
|
@@ -64487,11 +65056,11 @@ var DishwasherStatusSchema = zod.z.object({
|
|
|
64487
65056
|
/** Feature keys of the programs the appliance currently offers — drives the UI selector. */
|
|
64488
65057
|
availablePrograms: zod.z.array(zod.z.string()),
|
|
64489
65058
|
/** Seconds remaining on the active cycle, or null when not running / not known. */
|
|
64490
|
-
remainingSeconds: zod.z.number().int().nonnegative().nullable(),
|
|
65059
|
+
remainingSeconds: zod.z.number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
64491
65060
|
/** Seconds the delayed start is set to (time until the cycle starts), or null. */
|
|
64492
|
-
delayedStartSeconds: zod.z.number().int().nonnegative().nullable(),
|
|
65061
|
+
delayedStartSeconds: zod.z.number().int().nonnegative().nullable().meta(readingMeta("duration")),
|
|
64493
65062
|
/** Cycle completion 0..100, or null when not applicable. */
|
|
64494
|
-
progressPercent: zod.z.number().min(0).max(100).nullable(),
|
|
65063
|
+
progressPercent: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
64495
65064
|
/** True when the door is reported open; null when the door state is not known. */
|
|
64496
65065
|
doorOpen: zod.z.boolean().nullable(),
|
|
64497
65066
|
/** True when the door is latched (locked) during a cycle; null when not reported. */
|
|
@@ -64515,7 +65084,7 @@ var DishwasherStatusSchema = zod.z.object({
|
|
|
64515
65084
|
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
64516
65085
|
machineCareDue: zod.z.boolean().nullable(),
|
|
64517
65086
|
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
64518
|
-
machineCareRemainingRuns: zod.z.number().int().nonnegative().nullable(),
|
|
65087
|
+
machineCareRemainingRuns: zod.z.number().int().nonnegative().nullable().meta(readingMeta("count")),
|
|
64519
65088
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
64520
65089
|
halfLoad: zod.z.boolean().nullable(),
|
|
64521
65090
|
hygienePlus: zod.z.boolean().nullable(),
|
|
@@ -64530,7 +65099,7 @@ var DishwasherStatusSchema = zod.z.object({
|
|
|
64530
65099
|
/** Feature keys of the events currently raised (salt low, rinse aid low, program finished, …). */
|
|
64531
65100
|
activeEvents: zod.z.array(zod.z.string()),
|
|
64532
65101
|
/** Numeric error code when the appliance reports one; null otherwise. */
|
|
64533
|
-
errorCode: zod.z.number().nullable(),
|
|
65102
|
+
errorCode: zod.z.number().nullable().meta(readingMeta("none")),
|
|
64534
65103
|
/** Name of the raised alert-level event while the appliance is in error; null otherwise. */
|
|
64535
65104
|
errorLabel: zod.z.string().nullable(),
|
|
64536
65105
|
/** Ms epoch of the last value received from the appliance; 0 = never. */
|
|
@@ -64761,7 +65330,7 @@ var DoorbellStatusSchema = zod.z.object({
|
|
|
64761
65330
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
64762
65331
|
lastPressedAt: zod.z.number().nullable(),
|
|
64763
65332
|
/** Counter since provider start. Resets on reboot. Useful for metrics/debug. */
|
|
64764
|
-
pressCountSinceStart: zod.z.number()
|
|
65333
|
+
pressCountSinceStart: zod.z.number().meta(readingMeta("count"))
|
|
64765
65334
|
});
|
|
64766
65335
|
var DoorbellPressEventSchema = zod.z.object({
|
|
64767
65336
|
deviceId: zod.z.number(),
|
|
@@ -64826,17 +65395,7 @@ onPressed: {
|
|
|
64826
65395
|
history: "none",
|
|
64827
65396
|
customize: doorbellCustomize
|
|
64828
65397
|
};
|
|
64829
|
-
|
|
64830
|
-
* Enum-state sensor — a string value picked from a finite option set.
|
|
64831
|
-
* Drives HA `sensor` entries with `state_class: enum` (HVAC action
|
|
64832
|
-
* states, weather conditions, contact-source channels, mode strings).
|
|
64833
|
-
* The option set is stable across observations; it is persisted in the
|
|
64834
|
-
* device config blob (via the control slice at adoption) and is NOT
|
|
64835
|
-
* stored in `sourceInfo`.
|
|
64836
|
-
*/
|
|
64837
|
-
/** Locale-render shape for an ISO `value` carried by a `DateTimeSensor`-role
|
|
64838
|
-
* enum sensor: `date` (date-only), `time` (time-only), `datetime` (both). */
|
|
64839
|
-
var EnumSensorDateTimeFormatSchema = zod.z.enum([
|
|
65398
|
+
zod.z.enum([
|
|
64840
65399
|
"date",
|
|
64841
65400
|
"time",
|
|
64842
65401
|
"datetime"
|
|
@@ -64844,12 +65403,11 @@ var EnumSensorDateTimeFormatSchema = zod.z.enum([
|
|
|
64844
65403
|
var EnumSensorStatusSchema = zod.z.object({
|
|
64845
65404
|
value: zod.z.string(),
|
|
64846
65405
|
/**
|
|
64847
|
-
* Set
|
|
64848
|
-
* as
|
|
64849
|
-
*
|
|
64850
|
-
* a time-only sensor → `'time'`.
|
|
65406
|
+
* Set when `value` is a timestamp rather than an enum state, so history
|
|
65407
|
+
* does not learn ISO strings as states. The display shape (date / time /
|
|
65408
|
+
* datetime) lives on `SourceInfo.dateTimeShape`, written once at adopt.
|
|
64851
65409
|
*/
|
|
64852
|
-
|
|
65410
|
+
timestamp: zod.z.boolean().optional(),
|
|
64853
65411
|
/** Ms epoch when the slice was last updated. */
|
|
64854
65412
|
lastFetchedAt: zod.z.number()
|
|
64855
65413
|
});
|
|
@@ -64876,11 +65434,11 @@ var enumSensorCapability = {
|
|
|
64876
65434
|
* History (D850): the value as an `enum` series (an appliance's program or
|
|
64877
65435
|
* operation state, an HVAC action). The option set is per device, so the
|
|
64878
65436
|
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
64879
|
-
* `
|
|
65437
|
+
* `timestamp` carries a clock, not a state, and is not recorded.
|
|
64880
65438
|
*/
|
|
64881
65439
|
history: { fields: { value: {
|
|
64882
65440
|
kind: "enum",
|
|
64883
|
-
skipWhenSet: "
|
|
65441
|
+
skipWhenSet: "timestamp"
|
|
64884
65442
|
} } },
|
|
64885
65443
|
/** Clock fields: written, but excluded from the compare that decides
|
|
64886
65444
|
* whether persisting is worth a SQLite commit. */
|
|
@@ -64900,13 +65458,13 @@ var EventFireSchema = zod.z.object({
|
|
|
64900
65458
|
deviceId: zod.z.number(),
|
|
64901
65459
|
eventType: zod.z.string(),
|
|
64902
65460
|
data: zod.z.record(zod.z.string(), zod.z.unknown()).nullable(),
|
|
64903
|
-
timestamp: zod.z.number(),
|
|
64904
|
-
seq: zod.z.number()
|
|
65461
|
+
timestamp: zod.z.number().meta(readingMeta("none")),
|
|
65462
|
+
seq: zod.z.number().meta(readingMeta("count"))
|
|
64905
65463
|
});
|
|
64906
65464
|
var EventEmitterStatusSchema = zod.z.object({
|
|
64907
65465
|
eventTypes: zod.z.array(zod.z.string()),
|
|
64908
65466
|
lastEvent: EventFireSchema.nullable(),
|
|
64909
|
-
eventCountSinceStart: zod.z.number()
|
|
65467
|
+
eventCountSinceStart: zod.z.number().meta(readingMeta("count"))
|
|
64910
65468
|
});
|
|
64911
65469
|
var eventEmitterCapability = {
|
|
64912
65470
|
name: "event-emitter",
|
|
@@ -65359,10 +65917,10 @@ var FanDirectionSchema = zod.z.enum(["forward", "reverse"]);
|
|
|
65359
65917
|
var FanControlStatusSchema = zod.z.object({
|
|
65360
65918
|
/** Active speed as 0..100 inclusive. Null when the device has no
|
|
65361
65919
|
* speed surface (single-speed fan). */
|
|
65362
|
-
percentage: zod.z.number().min(0).max(100).nullable(),
|
|
65920
|
+
percentage: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
65363
65921
|
/** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
|
|
65364
65922
|
* a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
|
|
65365
|
-
percentageStep: zod.z.number().positive().optional(),
|
|
65923
|
+
percentageStep: zod.z.number().positive().optional().meta(readingMeta("percentage")),
|
|
65366
65924
|
/** Active preset mode (`auto` / `quiet` / `turbo` / vendor-specific)
|
|
65367
65925
|
* — empty string when no preset is active or supported. */
|
|
65368
65926
|
preset: zod.z.string(),
|
|
@@ -65483,7 +66041,7 @@ var FeatureProbeStatusSchema = zod.z.object({
|
|
|
65483
66041
|
/** Camera/firmware model string. `null` when the firmware doesn't expose it. */
|
|
65484
66042
|
model: zod.z.string().nullable(),
|
|
65485
66043
|
/** Channel count for NVR/Hub devices; `1` for standalone cameras; `null` pre-probe. */
|
|
65486
|
-
channelCount: zod.z.number().nullable(),
|
|
66044
|
+
channelCount: zod.z.number().nullable().meta(readingMeta("count")),
|
|
65487
66045
|
/**
|
|
65488
66046
|
* Ms epoch of the last SUCCESSFUL probe. `0` before the first probe
|
|
65489
66047
|
* completes — drivers' `getAccessoryChildren()` should treat zero as
|
|
@@ -65606,9 +66164,54 @@ var gasCapability = {
|
|
|
65606
66164
|
* whether persisting is worth a SQLite commit. */
|
|
65607
66165
|
volatileStateFields: ["lastChangedAt"]
|
|
65608
66166
|
};
|
|
66167
|
+
/**
|
|
66168
|
+
* How many members of a helper group answered (D944). Counts are integers,
|
|
66169
|
+
* not measurements: zero included is a real count, never a stand-in reading.
|
|
66170
|
+
* The reading itself stays on the output capability. History is none — the
|
|
66171
|
+
* series that later statistics read is the output cap's own history block.
|
|
66172
|
+
*/
|
|
66173
|
+
var GroupStatusSchema = zod.z.object({
|
|
66174
|
+
/** Members whose current value entered the aggregate. */
|
|
66175
|
+
included: zod.z.number().int().nonnegative().meta(readingMeta("count", {
|
|
66176
|
+
precision: 0,
|
|
66177
|
+
label: "Reporting"
|
|
66178
|
+
})),
|
|
66179
|
+
/** Members left out: offline, unknown, or not a finite reading (D393). */
|
|
66180
|
+
excluded: zod.z.number().int().nonnegative().meta(readingMeta("count", {
|
|
66181
|
+
precision: 0,
|
|
66182
|
+
label: "Excluded"
|
|
66183
|
+
})),
|
|
66184
|
+
/** `included` + `excluded`. */
|
|
66185
|
+
total: zod.z.number().int().nonnegative().meta(readingMeta("count", {
|
|
66186
|
+
precision: 0,
|
|
66187
|
+
label: "Members"
|
|
66188
|
+
}))
|
|
66189
|
+
});
|
|
66190
|
+
var groupStatusCapability = {
|
|
66191
|
+
name: "group-status",
|
|
66192
|
+
scope: "device",
|
|
66193
|
+
deviceNative: true,
|
|
66194
|
+
mode: "singleton",
|
|
66195
|
+
deviceTypes: [DeviceType.Sensor],
|
|
66196
|
+
methods: {},
|
|
66197
|
+
status: {
|
|
66198
|
+
schema: GroupStatusSchema,
|
|
66199
|
+
kind: "push"
|
|
66200
|
+
},
|
|
66201
|
+
runtimeState: GroupStatusSchema,
|
|
66202
|
+
/**
|
|
66203
|
+
* Runtime-state durability: **session** — recomputed from members on the
|
|
66204
|
+
* next source event; a restored count would outlive the readings it named.
|
|
66205
|
+
*
|
|
66206
|
+
* See `RuntimeStateDurability`. Enforced by
|
|
66207
|
+
* `scripts/check-runtime-state-durability.ts`.
|
|
66208
|
+
*/
|
|
66209
|
+
durability: "session",
|
|
66210
|
+
history: "none"
|
|
66211
|
+
};
|
|
65609
66212
|
var HeatingValveStatusSchema = zod.z.object({
|
|
65610
66213
|
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
65611
|
-
position: zod.z.number().min(0).max(100).nullable(),
|
|
66214
|
+
position: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
65612
66215
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
65613
66216
|
lastFetchedAt: zod.z.number()
|
|
65614
66217
|
});
|
|
@@ -65651,9 +66254,9 @@ var HumidifierStatusSchema = zod.z.object({
|
|
|
65651
66254
|
/** Whether the humidifier is currently on. */
|
|
65652
66255
|
on: zod.z.boolean(),
|
|
65653
66256
|
/** Current measured relative humidity (0..100). Null when not reported. */
|
|
65654
|
-
currentHumidity: zod.z.number().min(0).max(100).nullable(),
|
|
66257
|
+
currentHumidity: zod.z.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65655
66258
|
/** Target relative humidity (0..100). Null when no setpoint surface. */
|
|
65656
|
-
targetHumidity: zod.z.number().min(0).max(100).nullable(),
|
|
66259
|
+
targetHumidity: zod.z.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
65657
66260
|
/** Active mode (`auto` / `normal` / `baby` / vendor). Null when the
|
|
65658
66261
|
* device has no mode surface. */
|
|
65659
66262
|
mode: zod.z.string().nullable(),
|
|
@@ -65663,9 +66266,9 @@ var HumidifierStatusSchema = zod.z.object({
|
|
|
65663
66266
|
* `idle` / `off`). Null when the device doesn't report it. */
|
|
65664
66267
|
action: zod.z.string().nullable(),
|
|
65665
66268
|
/** HA `min_humidity` attribute. Null → UI uses 0. */
|
|
65666
|
-
minHumidity: zod.z.number().nullable(),
|
|
66269
|
+
minHumidity: zod.z.number().nullable().meta(readingMeta("humidity")),
|
|
65667
66270
|
/** HA `max_humidity` attribute. Null → UI uses 100. */
|
|
65668
|
-
maxHumidity: zod.z.number().nullable(),
|
|
66271
|
+
maxHumidity: zod.z.number().nullable().meta(readingMeta("humidity")),
|
|
65669
66272
|
/** Ms epoch when the slice was last updated. */
|
|
65670
66273
|
lastChangedAt: zod.z.number()
|
|
65671
66274
|
});
|
|
@@ -65735,22 +66338,13 @@ var humidifierCapability = {
|
|
|
65735
66338
|
* `sourceInfo`.
|
|
65736
66339
|
*/
|
|
65737
66340
|
var HumiditySensorStatusSchema = zod.z.object({
|
|
65738
|
-
/** Current relative humidity, 0..100. */
|
|
65739
|
-
percent: zod.z.number().min(0).max(100).meta({
|
|
65740
|
-
|
|
66341
|
+
/** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
|
|
66342
|
+
percent: zod.z.number().min(0).max(100).nullable().meta(readingMeta("humidity", {
|
|
66343
|
+
precision: 0,
|
|
65741
66344
|
label: "Humidity"
|
|
65742
|
-
}),
|
|
66345
|
+
})),
|
|
65743
66346
|
/** Ms epoch when the slice was last updated. */
|
|
65744
|
-
lastFetchedAt: zod.z.number()
|
|
65745
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
65746
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
65747
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
65748
|
-
unit: zod.z.string().optional(),
|
|
65749
|
-
/** Suggested decimal places for numeric display.
|
|
65750
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
65751
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
65752
|
-
* auto-formatting when absent. */
|
|
65753
|
-
precision: zod.z.number().int().min(0).max(10).optional()
|
|
66347
|
+
lastFetchedAt: zod.z.number()
|
|
65754
66348
|
});
|
|
65755
66349
|
var humiditySensorCapability = {
|
|
65756
66350
|
name: "humidity-sensor",
|
|
@@ -65781,12 +66375,7 @@ var humiditySensorCapability = {
|
|
|
65781
66375
|
} } },
|
|
65782
66376
|
/** Clock fields: written, but excluded from the compare that decides
|
|
65783
66377
|
* whether persisting is worth a SQLite commit. */
|
|
65784
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
65785
|
-
customize: {
|
|
65786
|
-
version: 1,
|
|
65787
|
-
advanced: "derive",
|
|
65788
|
-
targets: []
|
|
65789
|
-
}
|
|
66378
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
65790
66379
|
};
|
|
65791
66380
|
/**
|
|
65792
66381
|
* Image display cap. Models a single still image exposed by an integration —
|
|
@@ -65807,7 +66396,7 @@ var ImageStatusSchema = zod.z.object({
|
|
|
65807
66396
|
* entity exposes no `entity_picture` (yet). */
|
|
65808
66397
|
url: zod.z.string().nullable(),
|
|
65809
66398
|
/** Ms epoch of the upstream last-updated timestamp. Null at cold-start. */
|
|
65810
|
-
lastUpdated: zod.z.number().nullable()
|
|
66399
|
+
lastUpdated: zod.z.number().nullable().meta(readingMeta("none"))
|
|
65811
66400
|
});
|
|
65812
66401
|
var imageCapability = {
|
|
65813
66402
|
name: "image",
|
|
@@ -65895,19 +66484,19 @@ var NormalizedRangeSchema = zod.z.object({
|
|
|
65895
66484
|
*/
|
|
65896
66485
|
var ImageSettingsStatusSchema = zod.z.object({
|
|
65897
66486
|
/** Normalized 0–100. */
|
|
65898
|
-
brightness: zod.z.number().optional(),
|
|
66487
|
+
brightness: zod.z.number().optional().meta(readingMeta("none")),
|
|
65899
66488
|
/** Normalized 0–100. */
|
|
65900
|
-
contrast: zod.z.number().optional(),
|
|
66489
|
+
contrast: zod.z.number().optional().meta(readingMeta("none")),
|
|
65901
66490
|
/** Normalized 0–100. */
|
|
65902
|
-
saturation: zod.z.number().optional(),
|
|
66491
|
+
saturation: zod.z.number().optional().meta(readingMeta("none")),
|
|
65903
66492
|
/** Normalized 0–100. */
|
|
65904
|
-
sharpness: zod.z.number().optional(),
|
|
66493
|
+
sharpness: zod.z.number().optional().meta(readingMeta("none")),
|
|
65905
66494
|
mirror: zod.z.boolean().optional(),
|
|
65906
66495
|
flip: zod.z.boolean().optional(),
|
|
65907
66496
|
rotate: ImageRotateSchema.optional(),
|
|
65908
66497
|
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
65909
66498
|
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
65910
|
-
warmth: zod.z.number().optional(),
|
|
66499
|
+
warmth: zod.z.number().optional().meta(readingMeta("none")),
|
|
65911
66500
|
exposureMode: ExposureModeSchema.optional(),
|
|
65912
66501
|
backlightMode: BacklightModeSchema.optional(),
|
|
65913
66502
|
lastFetchedAt: zod.z.number()
|
|
@@ -66204,10 +66793,10 @@ var IntercomAbilitySchema = zod.z.object({
|
|
|
66204
66793
|
/** Codecs accepted by firmware, in preference order. Driver-authored strings. */
|
|
66205
66794
|
codecs: zod.z.array(zod.z.string()),
|
|
66206
66795
|
/** Sample rate (Hz) the firmware expects. Reolink typical: 16000. */
|
|
66207
|
-
sampleRate: zod.z.number(),
|
|
66796
|
+
sampleRate: zod.z.number().meta(readingMeta("none")),
|
|
66208
66797
|
duplex: zod.z.enum(["half", "full"]),
|
|
66209
66798
|
/** Max in-flight audio backlog before drop (ms). Server uses this to bound latency. */
|
|
66210
|
-
maxBacklogMs: zod.z.number()
|
|
66799
|
+
maxBacklogMs: zod.z.number().meta(readingMeta("duration-ms"))
|
|
66211
66800
|
});
|
|
66212
66801
|
var IntercomStatusSchema = zod.z.object({
|
|
66213
66802
|
/** True while a talk session is open. */
|
|
@@ -66434,13 +67023,13 @@ var LawnMowerControlStatusSchema = zod.z.object({
|
|
|
66434
67023
|
activity: LawnMowerActivitySchema,
|
|
66435
67024
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
66436
67025
|
* reading. */
|
|
66437
|
-
batteryLevel: zod.z.number().min(0).max(100).nullable(),
|
|
67026
|
+
batteryLevel: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
66438
67027
|
/** 0..100 mowing-completion percentage of the current task, or null when no
|
|
66439
67028
|
* task is active / progress is unavailable. */
|
|
66440
|
-
progressPercent: zod.z.number().min(0).max(100).nullable(),
|
|
67029
|
+
progressPercent: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
66441
67030
|
/** Current device/event code (dynamic — mostly status, sometimes an error),
|
|
66442
67031
|
* or null when unknown. */
|
|
66443
|
-
currentCode: zod.z.number().nullable(),
|
|
67032
|
+
currentCode: zod.z.number().nullable().meta(readingMeta("none")),
|
|
66444
67033
|
/** Human label for {@link currentCode}, or null when undecodable. */
|
|
66445
67034
|
currentCodeLabel: zod.z.string().nullable(),
|
|
66446
67035
|
/** Severity of {@link currentCode}. `error` (and often `warning`) warrants UI
|
|
@@ -67164,7 +67753,7 @@ var MediaPlayerStatusSchema = zod.z.object({
|
|
|
67164
67753
|
state: MediaPlayerStateSchema,
|
|
67165
67754
|
/** Volume as 0..100 inclusive. Null when the device has no volume
|
|
67166
67755
|
* surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
|
|
67167
|
-
volumeLevel: zod.z.number().min(0).max(100).nullable(),
|
|
67756
|
+
volumeLevel: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
67168
67757
|
/** Mute toggle distinct from volume=0. Null when no mute surface.
|
|
67169
67758
|
* Pair with `DeviceFeature.MediaPlayerMute`. */
|
|
67170
67759
|
isMuted: zod.z.boolean().nullable(),
|
|
@@ -67177,10 +67766,10 @@ var MediaPlayerStatusSchema = zod.z.object({
|
|
|
67177
67766
|
currentMedia: MediaInfoSchema.nullable(),
|
|
67178
67767
|
/** Current playback position in ms. Null when not seekable or
|
|
67179
67768
|
* nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
|
|
67180
|
-
positionMs: zod.z.number().int().nonnegative().nullable(),
|
|
67769
|
+
positionMs: zod.z.number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
67181
67770
|
/** Total duration of the current media in ms. Null when unknown
|
|
67182
67771
|
* (live stream) or nothing is playing. */
|
|
67183
|
-
durationMs: zod.z.number().int().nonnegative().nullable(),
|
|
67772
|
+
durationMs: zod.z.number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
|
|
67184
67773
|
/** Shuffle toggle. Null when no shuffle surface.
|
|
67185
67774
|
* Pair with `DeviceFeature.MediaPlayerShuffle`. */
|
|
67186
67775
|
shuffle: zod.z.boolean().nullable(),
|
|
@@ -67550,7 +68139,7 @@ var motionCustomize = {
|
|
|
67550
68139
|
eventName: "onMotionChanged"
|
|
67551
68140
|
},
|
|
67552
68141
|
deviceTypes: [DeviceType.Camera],
|
|
67553
|
-
apply: "
|
|
68142
|
+
apply: "add",
|
|
67554
68143
|
applyAuthority: {
|
|
67555
68144
|
kind: "camera-sensors",
|
|
67556
68145
|
timeoutField: "motionCooldownMs"
|
|
@@ -67647,7 +68236,7 @@ var MotionStatusSchema = zod.z.object({
|
|
|
67647
68236
|
* it, every provider seeded it at boot, and every session left it
|
|
67648
68237
|
* `detected: true` after its detach.
|
|
67649
68238
|
*/
|
|
67650
|
-
autoClearAfterMs: zod.z.number().nullable()
|
|
68239
|
+
autoClearAfterMs: zod.z.number().nullable().meta(readingMeta("duration-ms"))
|
|
67651
68240
|
});
|
|
67652
68241
|
/**
|
|
67653
68242
|
* Payload of `motion.onMotionChanged` event + the corresponding bus
|
|
@@ -67684,12 +68273,18 @@ var motionCapability = {
|
|
|
67684
68273
|
methods: {
|
|
67685
68274
|
/**
|
|
67686
68275
|
* Pull the current motion state synchronously. Convenience shortcut
|
|
67687
|
-
* for consumers that don't need the full status object
|
|
67688
|
-
*
|
|
67689
|
-
* `getStatus` once the auto-injected status surface lands in every
|
|
67690
|
-
* consumer.
|
|
68276
|
+
* for consumers that don't need the full status object. A composed
|
|
68277
|
+
* group answers from its slice (D944): unknown throws, it is not off.
|
|
67691
68278
|
*/
|
|
67692
68279
|
isDetected: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.boolean()) },
|
|
68280
|
+
/**
|
|
68281
|
+
* A composed motion group serves `isDetected` from `detected` (D944).
|
|
68282
|
+
* Without this the cap stays uncomposable (`has-commands`).
|
|
68283
|
+
*/
|
|
68284
|
+
composedMethods: { isDetected: {
|
|
68285
|
+
kind: "slice",
|
|
68286
|
+
field: "detected"
|
|
68287
|
+
} },
|
|
67693
68288
|
events: {
|
|
67694
68289
|
/**
|
|
67695
68290
|
* Fires every time the runner transitions a camera between
|
|
@@ -67829,7 +68424,7 @@ var MotionZoneRegionSchema = zod.z.object({
|
|
|
67829
68424
|
* the grid region(s). */
|
|
67830
68425
|
var MotionZoneStatusSchema = zod.z.object({
|
|
67831
68426
|
enabled: zod.z.boolean(),
|
|
67832
|
-
sensitivity: zod.z.number(),
|
|
68427
|
+
sensitivity: zod.z.number().meta(readingMeta("none")),
|
|
67833
68428
|
/** Grid region(s). Today exactly one `grid` shape. */
|
|
67834
68429
|
regions: zod.z.array(MotionZoneRegionSchema),
|
|
67835
68430
|
lastFetchedAt: zod.z.number()
|
|
@@ -68201,7 +68796,7 @@ var NavigationStatusSchema = zod.z.object({
|
|
|
68201
68796
|
following: zod.z.boolean(),
|
|
68202
68797
|
flash: zod.z.boolean(),
|
|
68203
68798
|
lightMode: NavigationLightModeSchema,
|
|
68204
|
-
lightLevel: zod.z.number().min(40).max(100),
|
|
68799
|
+
lightLevel: zod.z.number().min(40).max(100).meta(readingMeta("none")),
|
|
68205
68800
|
/** Ms epoch when the slice was last updated. */
|
|
68206
68801
|
lastChangedAt: zod.z.number()
|
|
68207
68802
|
});
|
|
@@ -68335,13 +68930,13 @@ var NetworkLinkStatusSchema = zod.z.object({
|
|
|
68335
68930
|
* one whose reading has not landed must not be drawn at 0 %. Consumers
|
|
68336
68931
|
* SKIP a null rather than coerce it.
|
|
68337
68932
|
*/
|
|
68338
|
-
signalPercent: zod.z.number().min(0).max(100).nullable(),
|
|
68933
|
+
signalPercent: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
68339
68934
|
/** Raw received signal strength in dBm, when the firmware reports one. */
|
|
68340
|
-
rssiDbm: zod.z.number().optional(),
|
|
68935
|
+
rssiDbm: zod.z.number().optional().meta(readingMeta("signal-level")),
|
|
68341
68936
|
/** Network name of a wireless link, when the firmware reports it. */
|
|
68342
68937
|
ssid: zod.z.string().optional(),
|
|
68343
68938
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
68344
|
-
lastUpdated: zod.z.number()
|
|
68939
|
+
lastUpdated: zod.z.number().meta(readingMeta("none"))
|
|
68345
68940
|
});
|
|
68346
68941
|
var networkLinkCapability = {
|
|
68347
68942
|
name: "network-link",
|
|
@@ -68791,7 +69386,7 @@ var NotifierStatusSchema = zod.z.object({
|
|
|
68791
69386
|
lastError: zod.z.string().nullable(),
|
|
68792
69387
|
/** Number of deliveries currently buffered server-side (rate-limited
|
|
68793
69388
|
* notifiers may queue). 0 when the provider sends synchronously. */
|
|
68794
|
-
queueDepth: zod.z.number().int().nonnegative(),
|
|
69389
|
+
queueDepth: zod.z.number().int().nonnegative().meta(readingMeta("count")),
|
|
68795
69390
|
/** Per-feature capability matrix — authoritative source for the
|
|
68796
69391
|
* compose-form field gating. */
|
|
68797
69392
|
supports: NotifierSupportsSchema
|
|
@@ -68883,11 +69478,9 @@ onSent: { data: zod.z.object({
|
|
|
68883
69478
|
* cap fits (HA `sensor` whose `device_class` we don't have a typed cap
|
|
68884
69479
|
* for: water flow, distance, weight, frequency, signal strength, …).
|
|
68885
69480
|
*
|
|
68886
|
-
* The
|
|
68887
|
-
*
|
|
68888
|
-
*
|
|
68889
|
-
* The UI reads them directly from the slice — they are the single source
|
|
68890
|
-
* of truth for generic numeric rendering and do NOT live on `sourceInfo`.
|
|
69481
|
+
* The quantity is not on this slice. It is chosen when the device is
|
|
69482
|
+
* adopted and stored once on `SourceInfo.quantity` (D944). `value` is in
|
|
69483
|
+
* that quantity's base unit. `null` is a refused sample (D393).
|
|
68891
69484
|
*
|
|
68892
69485
|
* Prefer the typed alternatives (`temperature-sensor`, `humidity-sensor`,
|
|
68893
69486
|
* `ambient-light-sensor`, `pressure-sensor`, `power-meter`,
|
|
@@ -68896,15 +69489,8 @@ onSent: { data: zod.z.object({
|
|
|
68896
69489
|
* numeric values land here.
|
|
68897
69490
|
*/
|
|
68898
69491
|
var NumericSensorStatusSchema = zod.z.object({
|
|
68899
|
-
|
|
68900
|
-
|
|
68901
|
-
* Populated live from the upstream source on each state push.
|
|
68902
|
-
* Absent for unitless sensors. */
|
|
68903
|
-
unit: zod.z.string().optional(),
|
|
68904
|
-
/** Suggested decimal places for numeric display.
|
|
68905
|
-
* Populated live from the upstream source when provided.
|
|
68906
|
-
* Falls back to auto-formatting when absent. */
|
|
68907
|
-
precision: zod.z.number().int().min(0).max(10).optional(),
|
|
69492
|
+
/** Reading in the device quantity's base unit. `null` when refused (D393). */
|
|
69493
|
+
value: zod.z.number().nullable().meta(readingMeta("device")),
|
|
68908
69494
|
/** Ms epoch when the slice was last updated. */
|
|
68909
69495
|
lastFetchedAt: zod.z.number()
|
|
68910
69496
|
});
|
|
@@ -68928,11 +69514,11 @@ var numericSensorCapability = {
|
|
|
68928
69514
|
*/
|
|
68929
69515
|
durability: "restored",
|
|
68930
69516
|
/**
|
|
68931
|
-
* History (D850): recorded series. The unit is
|
|
69517
|
+
* History (D850): recorded series. The unit is the device quantity's base,
|
|
69518
|
+
* resolved when the series is read — the cap has no single unit.
|
|
68932
69519
|
*/
|
|
68933
69520
|
history: { fields: { value: {
|
|
68934
69521
|
kind: "gauge",
|
|
68935
|
-
unitFrom: "unit",
|
|
68936
69522
|
minIntervalMs: 3e4
|
|
68937
69523
|
} } },
|
|
68938
69524
|
/** Clock fields: written, but excluded from the compare that decides
|
|
@@ -69333,23 +69919,26 @@ var PetFeederStatusSchema = zod.z.object({
|
|
|
69333
69919
|
/** Food currently in the bowl (grams). Null when the device has not
|
|
69334
69920
|
* reported a reading yet. On dual-hopper models this is the combined
|
|
69335
69921
|
* bowl reading; per-hopper levels live in `food1`/`food2`. */
|
|
69336
|
-
foodLevel: zod.z.number().nullable(),
|
|
69922
|
+
foodLevel: zod.z.number().nullable().meta(readingMeta("none")),
|
|
69337
69923
|
/** Hopper-1 food level (grams) on dual-hopper feeders; null on
|
|
69338
69924
|
* single-hopper models. */
|
|
69339
|
-
food1: zod.z.number().nullable(),
|
|
69925
|
+
food1: zod.z.number().nullable().meta(readingMeta("none")),
|
|
69340
69926
|
/** Hopper-2 food level (grams) on dual-hopper feeders; null on
|
|
69341
69927
|
* single-hopper models. */
|
|
69342
|
-
food2: zod.z.number().nullable(),
|
|
69928
|
+
food2: zod.z.number().nullable().meta(readingMeta("none")),
|
|
69343
69929
|
/** Derived low-food flag — mirrors the HA `food_level` binary_sensor
|
|
69344
69930
|
* (`device_class: problem`, on = low). True when the bowl is empty /
|
|
69345
69931
|
* below the feeder's low threshold. */
|
|
69346
69932
|
lowFood: zod.z.boolean(),
|
|
69347
69933
|
/** Battery charge 0..100 (%). Null on mains-powered models or when the
|
|
69348
69934
|
* device has no battery reading. */
|
|
69349
|
-
batteryPower: zod.z.number().min(0).max(100).nullable(),
|
|
69350
|
-
/**
|
|
69351
|
-
*
|
|
69352
|
-
|
|
69935
|
+
batteryPower: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
69936
|
+
/**
|
|
69937
|
+
* Desiccant life remaining, stored in seconds (duration base, D944).
|
|
69938
|
+
* Providers convert from the days the feeder reports. Null when the
|
|
69939
|
+
* model has no desiccant sensor.
|
|
69940
|
+
*/
|
|
69941
|
+
desiccantLeftDays: zod.z.number().nullable().meta(readingMeta("duration")),
|
|
69353
69942
|
/** True while a feed is in progress. */
|
|
69354
69943
|
feeding: zod.z.boolean(),
|
|
69355
69944
|
/** Decoded connectivity / power status (HA petkit device-status enum).
|
|
@@ -69360,7 +69949,7 @@ var PetFeederStatusSchema = zod.z.object({
|
|
|
69360
69949
|
* with `errorCode` for consumers that want the raw integer. */
|
|
69361
69950
|
error: zod.z.string().nullable(),
|
|
69362
69951
|
/** Raw device error code (0 / null = no error). */
|
|
69363
|
-
errorCode: zod.z.number().nullable(),
|
|
69952
|
+
errorCode: zod.z.number().nullable().meta(readingMeta("none")),
|
|
69364
69953
|
/** True for D4S/D4SH dual-hopper hardware — gates the per-hopper UI. */
|
|
69365
69954
|
isDualHopper: zod.z.boolean(),
|
|
69366
69955
|
/** Child-lock (manual-lock) setting — buttons on the unit are disabled. */
|
|
@@ -69370,7 +69959,7 @@ var PetFeederStatusSchema = zod.z.object({
|
|
|
69370
69959
|
/** Play a chime when dispensing. */
|
|
69371
69960
|
feedSound: zod.z.boolean(),
|
|
69372
69961
|
/** Speaker / prompt volume level (device-scaled integer). */
|
|
69373
|
-
volume: zod.z.number(),
|
|
69962
|
+
volume: zod.z.number().meta(readingMeta("none")),
|
|
69374
69963
|
/** Ms epoch when the slice was last refreshed from the cloud. */
|
|
69375
69964
|
lastFetchedAt: zod.z.number()
|
|
69376
69965
|
});
|
|
@@ -69489,7 +70078,7 @@ var petFeederCapability = {
|
|
|
69489
70078
|
},
|
|
69490
70079
|
desiccantLeftDays: {
|
|
69491
70080
|
kind: "gauge",
|
|
69492
|
-
unit: "
|
|
70081
|
+
unit: "s"
|
|
69493
70082
|
}
|
|
69494
70083
|
} }
|
|
69495
70084
|
};
|
|
@@ -69950,36 +70539,19 @@ var platformProbeCapability = {
|
|
|
69950
70539
|
*/
|
|
69951
70540
|
var PowerMeterStatusSchema = zod.z.object({
|
|
69952
70541
|
/** Instantaneous power draw in watts. */
|
|
69953
|
-
watts: zod.z.number().optional().meta({
|
|
69954
|
-
unit: "W",
|
|
69955
|
-
label: "Power"
|
|
69956
|
-
}),
|
|
70542
|
+
watts: zod.z.number().optional().meta(readingMeta("power", { label: "Power" })),
|
|
69957
70543
|
/** Cumulative energy in kilowatt-hours since the meter was reset. */
|
|
69958
|
-
kwhTotal: zod.z.number().optional().meta({
|
|
69959
|
-
unit: "kWh",
|
|
69960
|
-
label: "Energy"
|
|
69961
|
-
}),
|
|
70544
|
+
kwhTotal: zod.z.number().optional().meta(readingMeta("energy", { label: "Energy" })),
|
|
69962
70545
|
/** Voltage in volts. */
|
|
69963
|
-
volts: zod.z.number().optional(),
|
|
70546
|
+
volts: zod.z.number().optional().meta(readingMeta("voltage")),
|
|
69964
70547
|
/** Current in amperes. */
|
|
69965
|
-
amps: zod.z.number().optional(),
|
|
69966
|
-
/** Apparent power in volt-amperes
|
|
69967
|
-
va: zod.z.number().optional(),
|
|
70548
|
+
amps: zod.z.number().optional().meta(readingMeta("current")),
|
|
70549
|
+
/** Apparent power in volt-amperes. */
|
|
70550
|
+
va: zod.z.number().optional().meta(readingMeta("apparent-power")),
|
|
69968
70551
|
/** Power factor (0..1) if reported. */
|
|
69969
|
-
powerFactor: zod.z.number().min(0).max(1).optional(),
|
|
70552
|
+
powerFactor: zod.z.number().min(0).max(1).optional().meta(readingMeta("ratio")),
|
|
69970
70553
|
/** Ms epoch when the slice was last updated. */
|
|
69971
|
-
lastFetchedAt: zod.z.number()
|
|
69972
|
-
/** Live display unit of the single metric this slice carries (e.g. HA
|
|
69973
|
-
* `attributes.unit_of_measurement` → 'V' / 'A' / 'W' / 'kW' / 'kWh').
|
|
69974
|
-
* Each upstream `sensor.*` entity surfaces ONE device_class, so one
|
|
69975
|
-
* unit per slice is unambiguous. The UI prefers this over the role's
|
|
69976
|
-
* canonical unit so a 'kW' / 'Wh' feed renders verbatim. */
|
|
69977
|
-
unit: zod.z.string().optional(),
|
|
69978
|
-
/** Suggested decimal places for numeric display.
|
|
69979
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
69980
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
69981
|
-
* auto-formatting when absent. */
|
|
69982
|
-
precision: zod.z.number().int().min(0).max(10).optional()
|
|
70554
|
+
lastFetchedAt: zod.z.number()
|
|
69983
70555
|
});
|
|
69984
70556
|
var powerMeterCapability = {
|
|
69985
70557
|
name: "power-meter",
|
|
@@ -70043,12 +70615,7 @@ var powerMeterCapability = {
|
|
|
70043
70615
|
} },
|
|
70044
70616
|
/** Clock fields: written, but excluded from the compare that decides
|
|
70045
70617
|
* whether persisting is worth a SQLite commit. */
|
|
70046
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
70047
|
-
customize: {
|
|
70048
|
-
version: 1,
|
|
70049
|
-
advanced: "derive",
|
|
70050
|
-
targets: []
|
|
70051
|
-
}
|
|
70618
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
70052
70619
|
};
|
|
70053
70620
|
/**
|
|
70054
70621
|
* Presence cap. Models HA `person.*` and `device_tracker.*` entities
|
|
@@ -70068,11 +70635,11 @@ var powerMeterCapability = {
|
|
|
70068
70635
|
*/
|
|
70069
70636
|
var GpsLocationSchema = zod.z.object({
|
|
70070
70637
|
/** Latitude in decimal degrees, -90..90. */
|
|
70071
|
-
latitude: zod.z.number().min(-90).max(90),
|
|
70638
|
+
latitude: zod.z.number().min(-90).max(90).meta(readingMeta("angle")),
|
|
70072
70639
|
/** Longitude in decimal degrees, -180..180. */
|
|
70073
|
-
longitude: zod.z.number().min(-180).max(180),
|
|
70640
|
+
longitude: zod.z.number().min(-180).max(180).meta(readingMeta("angle")),
|
|
70074
70641
|
/** Reported accuracy in meters (lower = better). */
|
|
70075
|
-
accuracyMeters: zod.z.number().nonnegative()
|
|
70642
|
+
accuracyMeters: zod.z.number().nonnegative().meta(readingMeta("length"))
|
|
70076
70643
|
});
|
|
70077
70644
|
var PresenceStatusSchema = zod.z.object({
|
|
70078
70645
|
/** `home` / `not_home` / any user-defined zone name. */
|
|
@@ -70084,7 +70651,7 @@ var PresenceStatusSchema = zod.z.object({
|
|
|
70084
70651
|
gps: GpsLocationSchema.nullable(),
|
|
70085
70652
|
/** Optional battery level of the tracking device (0..100). Null
|
|
70086
70653
|
* when not reported. */
|
|
70087
|
-
batteryPercent: zod.z.number().min(0).max(100).nullable(),
|
|
70654
|
+
batteryPercent: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
70088
70655
|
/** Ms epoch when the slice was last updated. */
|
|
70089
70656
|
lastChangedAt: zod.z.number()
|
|
70090
70657
|
});
|
|
@@ -70134,19 +70701,10 @@ var presenceCapability = {
|
|
|
70134
70701
|
* `sourceInfo`.
|
|
70135
70702
|
*/
|
|
70136
70703
|
var PressureSensorStatusSchema = zod.z.object({
|
|
70137
|
-
/** Current pressure in hPa. */
|
|
70138
|
-
hpa: zod.z.number(),
|
|
70704
|
+
/** Current pressure in hPa. `null` when the sample was refused (D393). */
|
|
70705
|
+
hpa: zod.z.number().nullable().meta(readingMeta("pressure", { precision: 0 })),
|
|
70139
70706
|
/** Ms epoch when the slice was last updated. */
|
|
70140
|
-
lastFetchedAt: zod.z.number()
|
|
70141
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
70142
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
70143
|
-
* role's canonical unit. Absent → fall back to the canonical unit. */
|
|
70144
|
-
unit: zod.z.string().optional(),
|
|
70145
|
-
/** Suggested decimal places for numeric display.
|
|
70146
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
70147
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
70148
|
-
* auto-formatting when absent. */
|
|
70149
|
-
precision: zod.z.number().int().min(0).max(10).optional()
|
|
70707
|
+
lastFetchedAt: zod.z.number()
|
|
70150
70708
|
});
|
|
70151
70709
|
var pressureSensorCapability = {
|
|
70152
70710
|
name: "pressure-sensor",
|
|
@@ -70687,8 +71245,8 @@ var ptzCapability = {
|
|
|
70687
71245
|
var AutotrackTargetTypeSchema = zod.z.string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
|
|
70688
71246
|
var PtzAutotrackSettingsSchema = zod.z.object({
|
|
70689
71247
|
targetType: AutotrackTargetTypeSchema,
|
|
70690
|
-
stopDelaySeconds: zod.z.number().int().min(0).max(300),
|
|
70691
|
-
disappearDelaySeconds: zod.z.number().int().min(0).max(300)
|
|
71248
|
+
stopDelaySeconds: zod.z.number().int().min(0).max(300).meta(readingMeta("duration")),
|
|
71249
|
+
disappearDelaySeconds: zod.z.number().int().min(0).max(300).meta(readingMeta("duration"))
|
|
70692
71250
|
});
|
|
70693
71251
|
/**
|
|
70694
71252
|
* One option the camera advertises as a valid `targetType`. Drivers
|
|
@@ -70842,7 +71400,7 @@ var RunningStateStatusSchema = zod.z.object({
|
|
|
70842
71400
|
/** null = unknown — never coerced to false (D393). */
|
|
70843
71401
|
running: zod.z.boolean().nullable(),
|
|
70844
71402
|
/** Epoch ms the current boolean began; null while `running` is null. */
|
|
70845
|
-
since: zod.z.number().nullable(),
|
|
71403
|
+
since: zod.z.number().nullable().meta(readingMeta("none")),
|
|
70846
71404
|
source: RunningStateSourceSchema.meta({ label: "Source" }),
|
|
70847
71405
|
phase: zod.z.string().nullable(),
|
|
70848
71406
|
/** null until a reading has been published (D393). */
|
|
@@ -70857,7 +71415,6 @@ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
|
|
|
70857
71415
|
/** Generic Customize target for the running boolean (D936). */
|
|
70858
71416
|
var runningCustomize = {
|
|
70859
71417
|
version: 1,
|
|
70860
|
-
advanced: "derive",
|
|
70861
71418
|
targets: [{
|
|
70862
71419
|
id: "running",
|
|
70863
71420
|
cardinality: "scalar",
|
|
@@ -70877,7 +71434,7 @@ var runningCustomize = {
|
|
|
70877
71434
|
DeviceType.Thermostat,
|
|
70878
71435
|
DeviceType.PetFeeder
|
|
70879
71436
|
],
|
|
70880
|
-
apply: "add
|
|
71437
|
+
apply: "add",
|
|
70881
71438
|
path: "running",
|
|
70882
71439
|
sources: [
|
|
70883
71440
|
{
|
|
@@ -72516,9 +73073,9 @@ var RecordTriggerSchema = zod.z.enum([
|
|
|
72516
73073
|
*/
|
|
72517
73074
|
var RecordWindowSchema = zod.z.object({
|
|
72518
73075
|
trigger: RecordTriggerSchema,
|
|
72519
|
-
day: zod.z.number().int().min(0).max(6),
|
|
72520
|
-
startMinute: zod.z.number().int().min(0).max(1439),
|
|
72521
|
-
endMinute: zod.z.number().int().min(1).max(1440)
|
|
73076
|
+
day: zod.z.number().int().min(0).max(6).meta(readingMeta("none")),
|
|
73077
|
+
startMinute: zod.z.number().int().min(0).max(1439).meta(readingMeta("none")),
|
|
73078
|
+
endMinute: zod.z.number().int().min(1).max(1440).meta(readingMeta("none"))
|
|
72522
73079
|
});
|
|
72523
73080
|
/** Status of one physical volume, as the camera itself describes it. */
|
|
72524
73081
|
var OnboardStorageVolumeSchema = zod.z.object({
|
|
@@ -72617,10 +73174,10 @@ var RecordingOnboardStatusSchema = zod.z.object({
|
|
|
72617
73174
|
/** Master "record to the card at all" switch. */
|
|
72618
73175
|
enabled: zod.z.boolean().nullable(),
|
|
72619
73176
|
overwriteWhenFull: zod.z.boolean().nullable(),
|
|
72620
|
-
preRecordSec: zod.z.number().nullable(),
|
|
72621
|
-
postRecordSec: zod.z.number().nullable(),
|
|
73177
|
+
preRecordSec: zod.z.number().nullable().meta(readingMeta("duration")),
|
|
73178
|
+
postRecordSec: zod.z.number().nullable().meta(readingMeta("duration")),
|
|
72622
73179
|
/** Length of one recorded file, in minutes. */
|
|
72623
|
-
segmentMinutes: zod.z.number().nullable(),
|
|
73180
|
+
segmentMinutes: zod.z.number().nullable().meta(readingMeta("none")),
|
|
72624
73181
|
/** The primary track's weekly windows, flattened. */
|
|
72625
73182
|
windows: zod.z.array(RecordWindowSchema),
|
|
72626
73183
|
/**
|
|
@@ -72636,7 +73193,7 @@ var RecordingOnboardStatusSchema = zod.z.object({
|
|
|
72636
73193
|
* provider reporting a non-zero count also reports the schedule as not
|
|
72637
73194
|
* writable.
|
|
72638
73195
|
*/
|
|
72639
|
-
unreadableWindows: zod.z.number(),
|
|
73196
|
+
unreadableWindows: zod.z.number().meta(readingMeta("count")),
|
|
72640
73197
|
/**
|
|
72641
73198
|
* The camera is scheduled to record and has NO usable storage.
|
|
72642
73199
|
*
|
|
@@ -73502,7 +74059,7 @@ var CamStreamDescriptorSchema = zod.z.object({
|
|
|
73502
74059
|
url: zod.z.string().optional(),
|
|
73503
74060
|
codec: zod.z.string().optional(),
|
|
73504
74061
|
resolution: CamStreamResolutionSchema.optional(),
|
|
73505
|
-
fps: zod.z.number().positive().optional(),
|
|
74062
|
+
fps: zod.z.number().positive().optional().meta(readingMeta("rate")),
|
|
73506
74063
|
label: zod.z.string().optional(),
|
|
73507
74064
|
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
73508
74065
|
deviceFeatures: zod.z.array(zod.z.string()).optional(),
|
|
@@ -73589,18 +74146,18 @@ var StreamProfileSchema = zod.z.enum([
|
|
|
73589
74146
|
]);
|
|
73590
74147
|
/** The current encoding config of one stream profile. */
|
|
73591
74148
|
var StreamProfileConfigSchema = zod.z.object({
|
|
73592
|
-
width: zod.z.number(),
|
|
73593
|
-
height: zod.z.number(),
|
|
74149
|
+
width: zod.z.number().meta(readingMeta("none")),
|
|
74150
|
+
height: zod.z.number().meta(readingMeta("none")),
|
|
73594
74151
|
codec: zod.z.enum(["h264", "h265"]),
|
|
73595
|
-
framerate: zod.z.number(),
|
|
73596
|
-
bitrate: zod.z.number(),
|
|
74152
|
+
framerate: zod.z.number().meta(readingMeta("rate")),
|
|
74153
|
+
bitrate: zod.z.number().meta(readingMeta("bitrate")),
|
|
73597
74154
|
bitrateMode: zod.z.enum(["vbr", "cbr"]).optional(),
|
|
73598
74155
|
encoderProfile: zod.z.enum([
|
|
73599
74156
|
"high",
|
|
73600
74157
|
"main",
|
|
73601
74158
|
"baseline"
|
|
73602
74159
|
]).optional(),
|
|
73603
|
-
gop: zod.z.number().optional(),
|
|
74160
|
+
gop: zod.z.number().optional().meta(readingMeta("none")),
|
|
73604
74161
|
/**
|
|
73605
74162
|
* Whether THIS profile currently carries an audio track. READ-ONLY here.
|
|
73606
74163
|
*
|
|
@@ -74078,12 +74635,7 @@ var switchCapability = {
|
|
|
74078
74635
|
label: "On",
|
|
74079
74636
|
kind: "boolean"
|
|
74080
74637
|
}
|
|
74081
|
-
}] }
|
|
74082
|
-
customize: {
|
|
74083
|
-
version: 1,
|
|
74084
|
-
advanced: "derive",
|
|
74085
|
-
targets: []
|
|
74086
|
-
}
|
|
74638
|
+
}] }
|
|
74087
74639
|
};
|
|
74088
74640
|
/** C0 controls, DEL and the C1 range: none of them belongs in a name. */
|
|
74089
74641
|
function hasControlCharacter(value) {
|
|
@@ -74793,35 +75345,21 @@ var tamperCapability = {
|
|
|
74793
75345
|
* entries with `device_class: temperature` and any future native
|
|
74794
75346
|
* thermometer.
|
|
74795
75347
|
*
|
|
74796
|
-
*
|
|
74797
|
-
*
|
|
74798
|
-
* (climate-control's `currentTemp`, energy analytics) can compose
|
|
74799
|
-
* without per-source unit fixups. The canonical display unit (`°C`) is
|
|
74800
|
-
* a descriptor constant in the UI (ROLE_DESCRIPTOR), not stored in
|
|
74801
|
-
* `sourceInfo`.
|
|
75348
|
+
* The number is Celsius (D944). Providers convert on ingest. A failed
|
|
75349
|
+
* conversion is `null`, never a guess. Display unit is a read-time preference.
|
|
74802
75350
|
*
|
|
74803
75351
|
* Status `lastFetchedAt` lets staleness-aware consumers detect a
|
|
74804
75352
|
* frozen feed (provider hung) distinct from a "temperature hasn't
|
|
74805
75353
|
* changed" steady state.
|
|
74806
75354
|
*/
|
|
74807
75355
|
var TemperatureSensorStatusSchema = zod.z.object({
|
|
74808
|
-
/** Current temperature in Celsius. */
|
|
74809
|
-
celsius: zod.z.number().meta({
|
|
74810
|
-
|
|
75356
|
+
/** Current temperature in Celsius. `null` when the sample was refused (D393). */
|
|
75357
|
+
celsius: zod.z.number().nullable().meta(readingMeta("temperature", {
|
|
75358
|
+
precision: 1,
|
|
74811
75359
|
label: "Temperature"
|
|
74812
|
-
}),
|
|
75360
|
+
})),
|
|
74813
75361
|
/** Ms epoch when the slice was last updated (push or poll). */
|
|
74814
|
-
lastFetchedAt: zod.z.number()
|
|
74815
|
-
/** Live display unit from the upstream source (e.g. HA
|
|
74816
|
-
* `attributes.unit_of_measurement`). The UI prefers this over the
|
|
74817
|
-
* role's canonical unit, so a Fahrenheit feed renders '°F' not '°C'.
|
|
74818
|
-
* Absent → the UI falls back to the role's canonical unit. */
|
|
74819
|
-
unit: zod.z.string().optional(),
|
|
74820
|
-
/** Suggested decimal places for numeric display.
|
|
74821
|
-
* Populated live from the upstream source when provided (e.g. HA
|
|
74822
|
-
* `attributes.suggested_display_precision`). Falls back to
|
|
74823
|
-
* auto-formatting when absent. */
|
|
74824
|
-
precision: zod.z.number().int().min(0).max(10).optional()
|
|
75362
|
+
lastFetchedAt: zod.z.number()
|
|
74825
75363
|
});
|
|
74826
75364
|
var temperatureSensorCapability = {
|
|
74827
75365
|
name: "temperature-sensor",
|
|
@@ -74852,12 +75390,7 @@ var temperatureSensorCapability = {
|
|
|
74852
75390
|
} } },
|
|
74853
75391
|
/** Clock fields: written, but excluded from the compare that decides
|
|
74854
75392
|
* whether persisting is worth a SQLite commit. */
|
|
74855
|
-
volatileStateFields: ["lastFetchedAt"]
|
|
74856
|
-
customize: {
|
|
74857
|
-
version: 1,
|
|
74858
|
-
advanced: "derive",
|
|
74859
|
-
targets: []
|
|
74860
|
-
}
|
|
75393
|
+
volatileStateFields: ["lastFetchedAt"]
|
|
74861
75394
|
};
|
|
74862
75395
|
/**
|
|
74863
75396
|
* toast — system-scoped singleton capability that streams toast
|
|
@@ -75203,16 +75736,16 @@ var VacuumControlStatusSchema = zod.z.object({
|
|
|
75203
75736
|
state: VacuumStateSchema,
|
|
75204
75737
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
75205
75738
|
* reading. */
|
|
75206
|
-
batteryLevel: zod.z.number().min(0).max(100).nullable(),
|
|
75739
|
+
batteryLevel: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
75207
75740
|
/** Current fan-speed token (provider-verbatim). Null when unknown or
|
|
75208
75741
|
* the vacuum has no speed control. */
|
|
75209
75742
|
fanSpeed: zod.z.string().nullable(),
|
|
75210
75743
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
75211
75744
|
availableFanSpeeds: zod.z.array(zod.z.string()),
|
|
75212
75745
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
75213
|
-
progressPercent: zod.z.number().min(0).max(100).nullable(),
|
|
75746
|
+
progressPercent: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
75214
75747
|
/** Current error code (0 / null = no error). */
|
|
75215
|
-
errorCode: zod.z.number().nullable(),
|
|
75748
|
+
errorCode: zod.z.number().nullable().meta(readingMeta("none")),
|
|
75216
75749
|
/** Human label for {@link errorCode}, or null when none / undecodable. */
|
|
75217
75750
|
errorLabel: zod.z.string().nullable(),
|
|
75218
75751
|
/** Ms epoch when the slice was last updated. */
|
|
@@ -75308,7 +75841,7 @@ var ValveStatusSchema = zod.z.object({
|
|
|
75308
75841
|
state: ValveStateSchema,
|
|
75309
75842
|
/** 0 = fully closed, 100 = fully open. Null when the device has no
|
|
75310
75843
|
* intermediate position surface. */
|
|
75311
|
-
position: zod.z.number().min(0).max(100).nullable(),
|
|
75844
|
+
position: zod.z.number().min(0).max(100).nullable().meta(readingMeta("percentage")),
|
|
75312
75845
|
/** Ms epoch when the slice was last updated. */
|
|
75313
75846
|
lastChangedAt: zod.z.number()
|
|
75314
75847
|
});
|
|
@@ -75416,9 +75949,9 @@ var vibrationCapability = {
|
|
|
75416
75949
|
*/
|
|
75417
75950
|
var WaterHeaterStatusSchema = zod.z.object({
|
|
75418
75951
|
/** Current measured temperature. Null when not reported. */
|
|
75419
|
-
currentTemp: zod.z.number().nullable(),
|
|
75952
|
+
currentTemp: zod.z.number().nullable().meta(readingMeta("temperature")),
|
|
75420
75953
|
/** Target temperature setpoint. Null when no setpoint surface. */
|
|
75421
|
-
targetTemp: zod.z.number().nullable(),
|
|
75954
|
+
targetTemp: zod.z.number().nullable().meta(readingMeta("temperature")),
|
|
75422
75955
|
/** Active operation mode = HA `state` (`eco` / `electric` / `gas` /
|
|
75423
75956
|
* `heat_pump` / `high_demand` / `performance` / `off`). Null when the
|
|
75424
75957
|
* device reports an unknown state. */
|
|
@@ -75429,9 +75962,9 @@ var WaterHeaterStatusSchema = zod.z.object({
|
|
|
75429
75962
|
* has no away surface. */
|
|
75430
75963
|
away: zod.z.boolean().nullable(),
|
|
75431
75964
|
/** HA `min_temp` attribute. Null when not reported. */
|
|
75432
|
-
minTemp: zod.z.number().nullable(),
|
|
75965
|
+
minTemp: zod.z.number().nullable().meta(readingMeta("temperature")),
|
|
75433
75966
|
/** HA `max_temp` attribute. Null when not reported. */
|
|
75434
|
-
maxTemp: zod.z.number().nullable(),
|
|
75967
|
+
maxTemp: zod.z.number().nullable().meta(readingMeta("temperature")),
|
|
75435
75968
|
/** Ms epoch when the slice was last updated. */
|
|
75436
75969
|
lastChangedAt: zod.z.number()
|
|
75437
75970
|
});
|
|
@@ -75516,25 +76049,18 @@ var waterHeaterCapability = {
|
|
|
75516
76049
|
* Forecast deferred — current conditions only for v1.
|
|
75517
76050
|
*/
|
|
75518
76051
|
var WeatherStatusSchema = zod.z.object({
|
|
75519
|
-
/** Verbatim
|
|
75520
|
-
* when no condition has been reported yet. */
|
|
76052
|
+
/** Verbatim condition state (`sunny`, `cloudy`, `rainy`, …). Null when none yet. */
|
|
75521
76053
|
condition: zod.z.string().nullable(),
|
|
75522
|
-
/** Current temperature in
|
|
75523
|
-
temperature: zod.z.number().nullable(),
|
|
75524
|
-
/** Temperature unit string (e.g. `°C` / `°F`). Null when not provided. */
|
|
75525
|
-
temperatureUnit: zod.z.string().nullable(),
|
|
76054
|
+
/** Current temperature in Celsius. Null when not provided or refused. */
|
|
76055
|
+
temperature: zod.z.number().nullable().meta(readingMeta("temperature", { precision: 1 })),
|
|
75526
76056
|
/** Relative humidity (0..100). Null when not provided. */
|
|
75527
|
-
humidity: zod.z.number().min(0).max(100).nullable(),
|
|
75528
|
-
/** Barometric pressure in
|
|
75529
|
-
pressure: zod.z.number().nullable(),
|
|
75530
|
-
/**
|
|
75531
|
-
|
|
75532
|
-
/** Wind speed in the reported unit. Null when not provided. */
|
|
75533
|
-
windSpeed: zod.z.number().nullable(),
|
|
75534
|
-
/** Wind-speed unit string (e.g. `km/h` / `mph`). Null when not provided. */
|
|
75535
|
-
windSpeedUnit: zod.z.string().nullable(),
|
|
76057
|
+
humidity: zod.z.number().min(0).max(100).nullable().meta(readingMeta("humidity")),
|
|
76058
|
+
/** Barometric pressure in hPa. Null when not provided or refused. */
|
|
76059
|
+
pressure: zod.z.number().nullable().meta(readingMeta("pressure")),
|
|
76060
|
+
/** Wind speed in metres per second. Null when not provided or refused. */
|
|
76061
|
+
windSpeed: zod.z.number().nullable().meta(readingMeta("speed")),
|
|
75536
76062
|
/** Wind bearing in degrees (0..360, meteorological). Null when not provided. */
|
|
75537
|
-
windBearing: zod.z.number().nullable(),
|
|
76063
|
+
windBearing: zod.z.number().nullable().meta(readingMeta("angle")),
|
|
75538
76064
|
/** Ms epoch when the slice was last updated. */
|
|
75539
76065
|
lastFetchedAt: zod.z.number()
|
|
75540
76066
|
});
|
|
@@ -75562,12 +76088,12 @@ var weatherCapability = {
|
|
|
75562
76088
|
*/
|
|
75563
76089
|
durability: "session",
|
|
75564
76090
|
/**
|
|
75565
|
-
* History (D850): recorded series.
|
|
76091
|
+
* History (D850): recorded series. Numbers are the quantity base (D944).
|
|
75566
76092
|
*/
|
|
75567
76093
|
history: { fields: {
|
|
75568
76094
|
temperature: {
|
|
75569
76095
|
kind: "gauge",
|
|
75570
|
-
|
|
76096
|
+
unit: "°C",
|
|
75571
76097
|
deadband: .2
|
|
75572
76098
|
},
|
|
75573
76099
|
humidity: {
|
|
@@ -75577,12 +76103,12 @@ var weatherCapability = {
|
|
|
75577
76103
|
},
|
|
75578
76104
|
pressure: {
|
|
75579
76105
|
kind: "gauge",
|
|
75580
|
-
|
|
76106
|
+
unit: "hPa",
|
|
75581
76107
|
deadband: .5
|
|
75582
76108
|
},
|
|
75583
76109
|
windSpeed: {
|
|
75584
76110
|
kind: "gauge",
|
|
75585
|
-
|
|
76111
|
+
unit: "m/s",
|
|
75586
76112
|
deadband: .5
|
|
75587
76113
|
}
|
|
75588
76114
|
} }
|
|
@@ -76666,6 +77192,103 @@ function createDeviceExtensionProvider(options) {
|
|
|
76666
77192
|
}
|
|
76667
77193
|
};
|
|
76668
77194
|
}
|
|
77195
|
+
function isBinaryReducer(reducer) {
|
|
77196
|
+
return reducer === "any" || reducer === "all";
|
|
77197
|
+
}
|
|
77198
|
+
function includedValue(reducer, member) {
|
|
77199
|
+
if (member.state !== "fresh") return null;
|
|
77200
|
+
if (isBinaryReducer(reducer)) return typeof member.value === "boolean" ? member.value : null;
|
|
77201
|
+
return typeof member.value === "number" && Number.isFinite(member.value) ? member.value : null;
|
|
77202
|
+
}
|
|
77203
|
+
function median$1(values) {
|
|
77204
|
+
const sorted = [...values].toSorted((a, b) => a - b);
|
|
77205
|
+
const mid = Math.floor(sorted.length / 2);
|
|
77206
|
+
const right = sorted[mid];
|
|
77207
|
+
const left = sorted[mid - 1];
|
|
77208
|
+
if (right === void 0) throw new Error("median requires at least one finite number");
|
|
77209
|
+
if (sorted.length % 2 === 1) return right;
|
|
77210
|
+
if (left === void 0) throw new Error("median requires at least one finite number");
|
|
77211
|
+
return (left + right) / 2;
|
|
77212
|
+
}
|
|
77213
|
+
function reduceNumbers(reducer, values) {
|
|
77214
|
+
if (reducer === "min") return Math.min(...values);
|
|
77215
|
+
if (reducer === "max") return Math.max(...values);
|
|
77216
|
+
if (reducer === "sum") return values.reduce((sum, value) => sum + value, 0);
|
|
77217
|
+
if (reducer === "median") return median$1(values);
|
|
77218
|
+
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
77219
|
+
}
|
|
77220
|
+
function reduceBooleans(reducer, values) {
|
|
77221
|
+
return reducer === "all" ? values.every((value) => value) : values.some((value) => value);
|
|
77222
|
+
}
|
|
77223
|
+
function countsOf(included, total) {
|
|
77224
|
+
return {
|
|
77225
|
+
included,
|
|
77226
|
+
excluded: total - included,
|
|
77227
|
+
total
|
|
77228
|
+
};
|
|
77229
|
+
}
|
|
77230
|
+
function fatalReason(members) {
|
|
77231
|
+
const reasons = members.flatMap((member) => member.state === "unavailable" && member.fatal === true ? [member.reason ?? "source gone"] : []);
|
|
77232
|
+
return reasons.length === 0 ? null : reasons.join("; ");
|
|
77233
|
+
}
|
|
77234
|
+
function emptyOutcome(empty, counts) {
|
|
77235
|
+
if (empty === "null") return {
|
|
77236
|
+
kind: "value",
|
|
77237
|
+
value: null,
|
|
77238
|
+
counts
|
|
77239
|
+
};
|
|
77240
|
+
return {
|
|
77241
|
+
kind: "unavailable",
|
|
77242
|
+
fatal: false,
|
|
77243
|
+
reason: "no member included — unknown is not 0 or off",
|
|
77244
|
+
counts
|
|
77245
|
+
};
|
|
77246
|
+
}
|
|
77247
|
+
/** Pure. `members` is not mutated. An empty included set is null or unavailable, never 0 or false. */
|
|
77248
|
+
function evaluateAggregate(input) {
|
|
77249
|
+
const included = input.members.flatMap((member) => {
|
|
77250
|
+
const value = includedValue(input.reducer, member);
|
|
77251
|
+
return value === null ? [] : [value];
|
|
77252
|
+
});
|
|
77253
|
+
const counts = countsOf(included.length, input.members.length);
|
|
77254
|
+
const gone = fatalReason(input.members);
|
|
77255
|
+
if (gone !== null) return {
|
|
77256
|
+
kind: "unavailable",
|
|
77257
|
+
fatal: true,
|
|
77258
|
+
reason: gone,
|
|
77259
|
+
counts
|
|
77260
|
+
};
|
|
77261
|
+
if (input.publish === "included") return {
|
|
77262
|
+
kind: "value",
|
|
77263
|
+
value: counts.included,
|
|
77264
|
+
counts
|
|
77265
|
+
};
|
|
77266
|
+
if (input.publish === "excluded") return {
|
|
77267
|
+
kind: "value",
|
|
77268
|
+
value: counts.excluded,
|
|
77269
|
+
counts
|
|
77270
|
+
};
|
|
77271
|
+
if (input.publish === "total") return {
|
|
77272
|
+
kind: "value",
|
|
77273
|
+
value: counts.total,
|
|
77274
|
+
counts
|
|
77275
|
+
};
|
|
77276
|
+
if (included.length === 0) return emptyOutcome(input.empty, counts);
|
|
77277
|
+
if (isBinaryReducer(input.reducer)) {
|
|
77278
|
+
const flags = included.filter((value) => typeof value === "boolean");
|
|
77279
|
+
return {
|
|
77280
|
+
kind: "value",
|
|
77281
|
+
value: reduceBooleans(input.reducer, flags),
|
|
77282
|
+
counts
|
|
77283
|
+
};
|
|
77284
|
+
}
|
|
77285
|
+
const numbers = included.filter((value) => typeof value === "number");
|
|
77286
|
+
return {
|
|
77287
|
+
kind: "value",
|
|
77288
|
+
value: reduceNumbers(input.reducer, numbers),
|
|
77289
|
+
counts
|
|
77290
|
+
};
|
|
77291
|
+
}
|
|
76669
77292
|
/**
|
|
76670
77293
|
* Frozen unit → spec table. `•` in the doc marks each dimension's canonical
|
|
76671
77294
|
* unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
|
|
@@ -76793,6 +77416,11 @@ var UNIT_TABLE = {
|
|
|
76793
77416
|
factor: 1609.344,
|
|
76794
77417
|
offset: 0
|
|
76795
77418
|
},
|
|
77419
|
+
"m²": {
|
|
77420
|
+
dimension: "area",
|
|
77421
|
+
factor: 1,
|
|
77422
|
+
offset: 0
|
|
77423
|
+
},
|
|
76796
77424
|
lx: {
|
|
76797
77425
|
dimension: "illuminance",
|
|
76798
77426
|
factor: 1,
|
|
@@ -76897,6 +77525,121 @@ var UNIT_TABLE = {
|
|
|
76897
77525
|
dimension: "percentage",
|
|
76898
77526
|
factor: 1,
|
|
76899
77527
|
offset: 0
|
|
77528
|
+
},
|
|
77529
|
+
L: {
|
|
77530
|
+
dimension: "volume",
|
|
77531
|
+
factor: 1,
|
|
77532
|
+
offset: 0
|
|
77533
|
+
},
|
|
77534
|
+
mL: {
|
|
77535
|
+
dimension: "volume",
|
|
77536
|
+
factor: .001,
|
|
77537
|
+
offset: 0
|
|
77538
|
+
},
|
|
77539
|
+
gal: {
|
|
77540
|
+
dimension: "volume",
|
|
77541
|
+
factor: 3.785411784,
|
|
77542
|
+
offset: 0
|
|
77543
|
+
},
|
|
77544
|
+
s: {
|
|
77545
|
+
dimension: "duration",
|
|
77546
|
+
factor: 1,
|
|
77547
|
+
offset: 0
|
|
77548
|
+
},
|
|
77549
|
+
ms: {
|
|
77550
|
+
dimension: "duration",
|
|
77551
|
+
factor: .001,
|
|
77552
|
+
offset: 0
|
|
77553
|
+
},
|
|
77554
|
+
min: {
|
|
77555
|
+
dimension: "duration",
|
|
77556
|
+
factor: 60,
|
|
77557
|
+
offset: 0
|
|
77558
|
+
},
|
|
77559
|
+
h: {
|
|
77560
|
+
dimension: "duration",
|
|
77561
|
+
factor: 3600,
|
|
77562
|
+
offset: 0
|
|
77563
|
+
},
|
|
77564
|
+
d: {
|
|
77565
|
+
dimension: "duration",
|
|
77566
|
+
factor: 86400,
|
|
77567
|
+
offset: 0
|
|
77568
|
+
},
|
|
77569
|
+
B: {
|
|
77570
|
+
dimension: "information",
|
|
77571
|
+
factor: 1,
|
|
77572
|
+
offset: 0
|
|
77573
|
+
},
|
|
77574
|
+
KiB: {
|
|
77575
|
+
dimension: "information",
|
|
77576
|
+
factor: 1024,
|
|
77577
|
+
offset: 0
|
|
77578
|
+
},
|
|
77579
|
+
MiB: {
|
|
77580
|
+
dimension: "information",
|
|
77581
|
+
factor: 1024 ** 2,
|
|
77582
|
+
offset: 0
|
|
77583
|
+
},
|
|
77584
|
+
GiB: {
|
|
77585
|
+
dimension: "information",
|
|
77586
|
+
factor: 1024 ** 3,
|
|
77587
|
+
offset: 0
|
|
77588
|
+
},
|
|
77589
|
+
TiB: {
|
|
77590
|
+
dimension: "information",
|
|
77591
|
+
factor: 1024 ** 4,
|
|
77592
|
+
offset: 0
|
|
77593
|
+
},
|
|
77594
|
+
kB: {
|
|
77595
|
+
dimension: "information",
|
|
77596
|
+
factor: 1e3,
|
|
77597
|
+
offset: 0
|
|
77598
|
+
},
|
|
77599
|
+
MB: {
|
|
77600
|
+
dimension: "information",
|
|
77601
|
+
factor: 1e6,
|
|
77602
|
+
offset: 0
|
|
77603
|
+
},
|
|
77604
|
+
GB: {
|
|
77605
|
+
dimension: "information",
|
|
77606
|
+
factor: 1e9,
|
|
77607
|
+
offset: 0
|
|
77608
|
+
},
|
|
77609
|
+
"°": {
|
|
77610
|
+
dimension: "angle",
|
|
77611
|
+
factor: 1,
|
|
77612
|
+
offset: 0
|
|
77613
|
+
},
|
|
77614
|
+
dBFS: {
|
|
77615
|
+
dimension: "sound-level",
|
|
77616
|
+
factor: 1,
|
|
77617
|
+
offset: 0
|
|
77618
|
+
},
|
|
77619
|
+
dBm: {
|
|
77620
|
+
dimension: "signal-level",
|
|
77621
|
+
factor: 1,
|
|
77622
|
+
offset: 0
|
|
77623
|
+
},
|
|
77624
|
+
mired: {
|
|
77625
|
+
dimension: "colour-temperature",
|
|
77626
|
+
factor: 1,
|
|
77627
|
+
offset: 0
|
|
77628
|
+
},
|
|
77629
|
+
kbps: {
|
|
77630
|
+
dimension: "bitrate",
|
|
77631
|
+
factor: 1,
|
|
77632
|
+
offset: 0
|
|
77633
|
+
},
|
|
77634
|
+
Mbps: {
|
|
77635
|
+
dimension: "bitrate",
|
|
77636
|
+
factor: 1e3,
|
|
77637
|
+
offset: 0
|
|
77638
|
+
},
|
|
77639
|
+
fps: {
|
|
77640
|
+
dimension: "rate",
|
|
77641
|
+
factor: 1,
|
|
77642
|
+
offset: 0
|
|
76900
77643
|
}
|
|
76901
77644
|
};
|
|
76902
77645
|
/** Resolve a unit's `UnitSpec`, or `undefined` when the spelling is unknown. */
|
|
@@ -77051,11 +77794,45 @@ function expressionOutcome(source, read, now, stateful) {
|
|
|
77051
77794
|
deadline: deadlines.length > 0 ? Math.min(...deadlines) : null
|
|
77052
77795
|
};
|
|
77053
77796
|
}
|
|
77797
|
+
function aggregateRead(reading) {
|
|
77798
|
+
if (reading.state === "unavailable") return {
|
|
77799
|
+
state: "unavailable",
|
|
77800
|
+
fatal: reading.fatal,
|
|
77801
|
+
reason: reading.reason
|
|
77802
|
+
};
|
|
77803
|
+
return {
|
|
77804
|
+
state: reading.state,
|
|
77805
|
+
value: reading.value,
|
|
77806
|
+
...reading.state === "stale" ? { reason: reading.reason } : {}
|
|
77807
|
+
};
|
|
77808
|
+
}
|
|
77809
|
+
function aggregateField(source, read) {
|
|
77810
|
+
const outcome = evaluateAggregate({
|
|
77811
|
+
reducer: source.reducer,
|
|
77812
|
+
members: source.reads.map((item) => aggregateRead(read(item))),
|
|
77813
|
+
publish: source.publish,
|
|
77814
|
+
empty: source.empty
|
|
77815
|
+
});
|
|
77816
|
+
if (outcome.kind === "value") return {
|
|
77817
|
+
state: "fresh",
|
|
77818
|
+
value: outcome.value,
|
|
77819
|
+
reason: null,
|
|
77820
|
+
deadline: null
|
|
77821
|
+
};
|
|
77822
|
+
return {
|
|
77823
|
+
state: "unavailable",
|
|
77824
|
+
value: null,
|
|
77825
|
+
reason: outcome.reason,
|
|
77826
|
+
fatal: outcome.fatal,
|
|
77827
|
+
confirmed: true
|
|
77828
|
+
};
|
|
77829
|
+
}
|
|
77054
77830
|
function evaluateCompositionField(input) {
|
|
77055
77831
|
const { source } = input;
|
|
77056
77832
|
switch (source.kind) {
|
|
77057
77833
|
case "from": return fromReading(input.read(source), source);
|
|
77058
77834
|
case "expression": return expressionOutcome(source, input.read, input.now, input.stateful);
|
|
77835
|
+
case "aggregate": return aggregateField(source, input.read);
|
|
77059
77836
|
case "code": return {
|
|
77060
77837
|
state: "unavailable",
|
|
77061
77838
|
value: null,
|
|
@@ -77402,6 +78179,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
77402
78179
|
featureProbe: featureProbeCapability,
|
|
77403
78180
|
flood: floodCapability,
|
|
77404
78181
|
gas: gasCapability,
|
|
78182
|
+
groupStatus: groupStatusCapability,
|
|
77405
78183
|
heatingValve: heatingValveCapability,
|
|
77406
78184
|
humidifier: humidifierCapability,
|
|
77407
78185
|
humiditySensor: humiditySensorCapability,
|
|
@@ -81664,6 +82442,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
81664
82442
|
access: "view",
|
|
81665
82443
|
role: "viewer"
|
|
81666
82444
|
},
|
|
82445
|
+
"groupStatus.getStatus": {
|
|
82446
|
+
capName: "group-status",
|
|
82447
|
+
capScope: "device",
|
|
82448
|
+
addonId: null,
|
|
82449
|
+
access: "view",
|
|
82450
|
+
role: "viewer"
|
|
82451
|
+
},
|
|
81667
82452
|
"heatingValve.getStatus": {
|
|
81668
82453
|
capName: "heating-valve",
|
|
81669
82454
|
capScope: "device",
|
|
@@ -91486,6 +92271,33 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
91486
92271
|
icon: "flame"
|
|
91487
92272
|
}]
|
|
91488
92273
|
},
|
|
92274
|
+
"group-status": {
|
|
92275
|
+
scope: "device",
|
|
92276
|
+
noun: t("Group", "Gruppo"),
|
|
92277
|
+
state: [
|
|
92278
|
+
{
|
|
92279
|
+
kind: "numeric",
|
|
92280
|
+
field: "included",
|
|
92281
|
+
quantity: t("the members reporting", "i membri che rispondono"),
|
|
92282
|
+
label: t("Reporting", "Rispondono"),
|
|
92283
|
+
icon: "users"
|
|
92284
|
+
},
|
|
92285
|
+
{
|
|
92286
|
+
kind: "numeric",
|
|
92287
|
+
field: "excluded",
|
|
92288
|
+
quantity: t("the members left out", "i membri esclusi"),
|
|
92289
|
+
label: t("Excluded", "Esclusi"),
|
|
92290
|
+
icon: "users"
|
|
92291
|
+
},
|
|
92292
|
+
{
|
|
92293
|
+
kind: "numeric",
|
|
92294
|
+
field: "total",
|
|
92295
|
+
quantity: t("the member count", "il numero di membri"),
|
|
92296
|
+
label: t("Members", "Membri"),
|
|
92297
|
+
icon: "sigma"
|
|
92298
|
+
}
|
|
92299
|
+
]
|
|
92300
|
+
},
|
|
91489
92301
|
"humidity-sensor": {
|
|
91490
92302
|
scope: "device",
|
|
91491
92303
|
noun: t("Humidity", "Umidità"),
|
|
@@ -91519,7 +92331,6 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
91519
92331
|
field: "value",
|
|
91520
92332
|
quantity: t("the reading", "il valore"),
|
|
91521
92333
|
label: t("Reading", "Valore"),
|
|
91522
|
-
unitField: "unit",
|
|
91523
92334
|
icon: "gauge"
|
|
91524
92335
|
}]
|
|
91525
92336
|
},
|
|
@@ -91655,7 +92466,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
91655
92466
|
field: "temperature",
|
|
91656
92467
|
quantity: t("the outdoor temperature", "la temperatura esterna"),
|
|
91657
92468
|
label: t("Temperature", "Temperatura"),
|
|
91658
|
-
|
|
92469
|
+
unit: "°C",
|
|
91659
92470
|
icon: "thermometer"
|
|
91660
92471
|
},
|
|
91661
92472
|
{
|
|
@@ -91671,7 +92482,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
91671
92482
|
field: "windSpeed",
|
|
91672
92483
|
quantity: t("the wind speed", "la velocità del vento"),
|
|
91673
92484
|
label: t("Wind", "Vento"),
|
|
91674
|
-
|
|
92485
|
+
unit: "m/s",
|
|
91675
92486
|
icon: "wind"
|
|
91676
92487
|
},
|
|
91677
92488
|
{
|
|
@@ -91679,7 +92490,7 @@ var SENSOR_CAP_VOCABULARY = {
|
|
|
91679
92490
|
field: "pressure",
|
|
91680
92491
|
quantity: t("the air pressure", "la pressione atmosferica"),
|
|
91681
92492
|
label: t("Pressure", "Pressione"),
|
|
91682
|
-
|
|
92493
|
+
unit: "hPa",
|
|
91683
92494
|
icon: "gauge"
|
|
91684
92495
|
}
|
|
91685
92496
|
]
|
|
@@ -92023,6 +92834,7 @@ var CAP_NAMES_WITH_STATUS = [
|
|
|
92023
92834
|
"feature-probe",
|
|
92024
92835
|
"flood",
|
|
92025
92836
|
"gas",
|
|
92837
|
+
"group-status",
|
|
92026
92838
|
"heating-valve",
|
|
92027
92839
|
"humidifier",
|
|
92028
92840
|
"humidity-sensor",
|
|
@@ -92152,6 +92964,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
|
|
|
92152
92964
|
filesystemBrowseCapability,
|
|
92153
92965
|
floodCapability,
|
|
92154
92966
|
gasCapability,
|
|
92967
|
+
groupStatusCapability,
|
|
92155
92968
|
heatingValveCapability,
|
|
92156
92969
|
humidifierCapability,
|
|
92157
92970
|
humiditySensorCapability,
|
|
@@ -93226,6 +94039,11 @@ Object.freeze({
|
|
|
93226
94039
|
form: "single",
|
|
93227
94040
|
optional: false
|
|
93228
94041
|
}],
|
|
94042
|
+
"groupStatus.getStatus": [{
|
|
94043
|
+
name: "deviceId",
|
|
94044
|
+
form: "single",
|
|
94045
|
+
optional: false
|
|
94046
|
+
}],
|
|
93229
94047
|
"heatingValve.getStatus": [{
|
|
93230
94048
|
name: "deviceId",
|
|
93231
94049
|
form: "single",
|
|
@@ -95035,7 +95853,7 @@ Object.freeze({
|
|
|
95035
95853
|
});
|
|
95036
95854
|
/**
|
|
95037
95855
|
* Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
|
|
95038
|
-
* `runtimeState`.
|
|
95856
|
+
* `runtimeState`. 73 caps: 38 `restored`, 35 `session`.
|
|
95039
95857
|
*
|
|
95040
95858
|
* A cap absent from this map has no runtime-state slice at all. A cap PRESENT
|
|
95041
95859
|
* with `durability: 'session'` has one and has decided not to keep it.
|
|
@@ -95153,6 +95971,10 @@ var RUNTIME_STATE_POLICY = {
|
|
|
95153
95971
|
durability: "restored",
|
|
95154
95972
|
volatileFields: ["lastChangedAt"]
|
|
95155
95973
|
},
|
|
95974
|
+
"group-status": {
|
|
95975
|
+
durability: "session",
|
|
95976
|
+
volatileFields: []
|
|
95977
|
+
},
|
|
95156
95978
|
"heating-valve": {
|
|
95157
95979
|
durability: "session",
|
|
95158
95980
|
volatileFields: ["lastFetchedAt"]
|
|
@@ -95347,7 +96169,7 @@ var SESSION_ONLY_POLICY = {
|
|
|
95347
96169
|
};
|
|
95348
96170
|
/**
|
|
95349
96171
|
* Cap history catalog, projected from every `*.cap.ts` `history` block.
|
|
95350
|
-
* 41 caps with series (
|
|
96172
|
+
* 41 caps with series (75 series), 31 caps answered `'none'`.
|
|
95351
96173
|
* Field keys are `runtimeState` paths (`a.b` into fixed objects only).
|
|
95352
96174
|
*/
|
|
95353
96175
|
var HISTORY_CATALOG = {
|
|
@@ -95364,12 +96186,12 @@ var HISTORY_CATALOG = {
|
|
|
95364
96186
|
},
|
|
95365
96187
|
"pm25": {
|
|
95366
96188
|
kind: "gauge",
|
|
95367
|
-
unit: "
|
|
96189
|
+
unit: "µg/m³",
|
|
95368
96190
|
deadband: 1
|
|
95369
96191
|
},
|
|
95370
96192
|
"pm10": {
|
|
95371
96193
|
kind: "gauge",
|
|
95372
|
-
unit: "
|
|
96194
|
+
unit: "µg/m³",
|
|
95373
96195
|
deadband: 1
|
|
95374
96196
|
},
|
|
95375
96197
|
"aqi": {
|
|
@@ -95399,10 +96221,16 @@ var HISTORY_CATALOG = {
|
|
|
95399
96221
|
deadbandPct: 10,
|
|
95400
96222
|
minIntervalMs: 6e4
|
|
95401
96223
|
} },
|
|
95402
|
-
"battery": {
|
|
95403
|
-
|
|
95404
|
-
|
|
95405
|
-
|
|
96224
|
+
"battery": {
|
|
96225
|
+
"percentage": {
|
|
96226
|
+
kind: "gauge",
|
|
96227
|
+
unit: "%"
|
|
96228
|
+
},
|
|
96229
|
+
"volts": {
|
|
96230
|
+
kind: "gauge",
|
|
96231
|
+
unit: "V"
|
|
96232
|
+
}
|
|
96233
|
+
},
|
|
95406
96234
|
"binary": { "on": { kind: "boolean" } },
|
|
95407
96235
|
"brightness": { "percentage": {
|
|
95408
96236
|
kind: "gauge",
|
|
@@ -95486,7 +96314,7 @@ var HISTORY_CATALOG = {
|
|
|
95486
96314
|
},
|
|
95487
96315
|
"enum-sensor": { "value": {
|
|
95488
96316
|
kind: "enum",
|
|
95489
|
-
skipWhenSet: "
|
|
96317
|
+
skipWhenSet: "timestamp"
|
|
95490
96318
|
} },
|
|
95491
96319
|
"fan-control": {
|
|
95492
96320
|
"percentage": {
|
|
@@ -95559,7 +96387,6 @@ var HISTORY_CATALOG = {
|
|
|
95559
96387
|
},
|
|
95560
96388
|
"numeric-sensor": { "value": {
|
|
95561
96389
|
kind: "gauge",
|
|
95562
|
-
unitFrom: "unit",
|
|
95563
96390
|
minIntervalMs: 3e4
|
|
95564
96391
|
} },
|
|
95565
96392
|
"pet-feeder": {
|
|
@@ -95573,7 +96400,7 @@ var HISTORY_CATALOG = {
|
|
|
95573
96400
|
},
|
|
95574
96401
|
"desiccantLeftDays": {
|
|
95575
96402
|
kind: "gauge",
|
|
95576
|
-
unit: "
|
|
96403
|
+
unit: "s"
|
|
95577
96404
|
}
|
|
95578
96405
|
},
|
|
95579
96406
|
"power-meter": {
|
|
@@ -95677,7 +96504,7 @@ var HISTORY_CATALOG = {
|
|
|
95677
96504
|
"weather": {
|
|
95678
96505
|
"temperature": {
|
|
95679
96506
|
kind: "gauge",
|
|
95680
|
-
|
|
96507
|
+
unit: "°C",
|
|
95681
96508
|
deadband: .2
|
|
95682
96509
|
},
|
|
95683
96510
|
"humidity": {
|
|
@@ -95687,12 +96514,12 @@ var HISTORY_CATALOG = {
|
|
|
95687
96514
|
},
|
|
95688
96515
|
"pressure": {
|
|
95689
96516
|
kind: "gauge",
|
|
95690
|
-
|
|
96517
|
+
unit: "hPa",
|
|
95691
96518
|
deadband: .5
|
|
95692
96519
|
},
|
|
95693
96520
|
"windSpeed": {
|
|
95694
96521
|
kind: "gauge",
|
|
95695
|
-
|
|
96522
|
+
unit: "m/s",
|
|
95696
96523
|
deadband: .5
|
|
95697
96524
|
}
|
|
95698
96525
|
}
|
|
@@ -95726,7 +96553,6 @@ var HISTORY_ITEM_CATALOG = { "consumables": {
|
|
|
95726
96553
|
},
|
|
95727
96554
|
"remaining.value": {
|
|
95728
96555
|
kind: "gauge",
|
|
95729
|
-
unitFrom: "remaining.unit",
|
|
95730
96556
|
deadband: 1,
|
|
95731
96557
|
displayName: "Remaining"
|
|
95732
96558
|
}
|
|
@@ -98620,6 +99446,12 @@ Object.defineProperty(exports, "historyItemFieldPath", {
|
|
|
98620
99446
|
return historyItemFieldPath;
|
|
98621
99447
|
}
|
|
98622
99448
|
});
|
|
99449
|
+
Object.defineProperty(exports, "historyUnitFor", {
|
|
99450
|
+
enumerable: true,
|
|
99451
|
+
get: function() {
|
|
99452
|
+
return historyUnitFor;
|
|
99453
|
+
}
|
|
99454
|
+
});
|
|
98623
99455
|
Object.defineProperty(exports, "hydrateSchema", {
|
|
98624
99456
|
enumerable: true,
|
|
98625
99457
|
get: function() {
|
|
@@ -98704,6 +99536,12 @@ Object.defineProperty(exports, "isObjectInput", {
|
|
|
98704
99536
|
return isObjectInput;
|
|
98705
99537
|
}
|
|
98706
99538
|
});
|
|
99539
|
+
Object.defineProperty(exports, "isReadingQuantity", {
|
|
99540
|
+
enumerable: true,
|
|
99541
|
+
get: function() {
|
|
99542
|
+
return isReadingQuantity;
|
|
99543
|
+
}
|
|
99544
|
+
});
|
|
98707
99545
|
Object.defineProperty(exports, "isSecretClear", {
|
|
98708
99546
|
enumerable: true,
|
|
98709
99547
|
get: function() {
|